ivy-2.4.0-rc1/000077500000000000000000000000001226750426600130215ustar00rootroot00000000000000ivy-2.4.0-rc1/.checkstyle000066400000000000000000000030511226750426600151570ustar00rootroot00000000000000 ivy-2.4.0-rc1/.classpath.default000066400000000000000000000043711226750426600164340ustar00rootroot00000000000000 ivy-2.4.0-rc1/.classpath.ivyde000066400000000000000000000022761226750426600161320ustar00rootroot00000000000000 ivy-2.4.0-rc1/.gitignore000066400000000000000000000003471226750426600150150ustar00rootroot00000000000000.classpath .ivy2 bin build doc/style/.svn doc/xooki/.svn lib test/jar-repos test/test-repo/bundlerepo/*.jar test/test-repo/ivyrepo/org.apache.ivy.osgi .DS_Store doc/samples/target-platform/bundles doc/samples/target-platform/cache ivy-2.4.0-rc1/.project000066400000000000000000000030401226750426600144650ustar00rootroot00000000000000 ivy org.eclipse.jdt.core.javabuilder org.eclipse.pde.ManifestBuilder net.sf.eclipsecs.core.CheckstyleBuilder org.eclipse.pde.PluginNature org.eclipse.jdt.core.javanature net.sf.eclipsecs.core.CheckstyleNature org.apache.ivyde.eclipse.ivynature ivy-2.4.0-rc1/.settings/000077500000000000000000000000001226750426600147375ustar00rootroot00000000000000ivy-2.4.0-rc1/.settings/org.eclipse.jdt.core.prefs000066400000000000000000000537551226750426600217400ustar00rootroot00000000000000#Tue Jun 05 13:48:46 CEST 2007 # *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=20 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_compact_if=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_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 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_selector_in_method_invocation=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.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 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.clear_blank_lines=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=true org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=100 org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=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 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_empty_lines=false org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 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=true org.eclipse.jdt.core.formatter.indentation.size=4 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=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=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_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 org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert 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_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 org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert 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_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not 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_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 org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert 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_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 org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert 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_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_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 org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert 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_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false org.eclipse.jdt.core.formatter.lineSplit=100 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.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_tabs_only_for_leading_indentations=false ivy-2.4.0-rc1/.settings/org.eclipse.jdt.ui.prefs000066400000000000000000000230221226750426600214050ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true formatter_profile=_Ivy Conventions formatter_settings_version=10 internal.default.compliance=default org.eclipse.jdt.ui.text.custom_code_templates= sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true sp_cleanup.add_missing_deprecated_annotations=true sp_cleanup.add_missing_methods=false sp_cleanup.add_missing_nls_tags=false sp_cleanup.add_missing_override_annotations=true sp_cleanup.add_missing_override_annotations_interface_methods=true sp_cleanup.add_serial_version_id=false sp_cleanup.always_use_blocks=true sp_cleanup.always_use_parentheses_in_expressions=false sp_cleanup.always_use_this_for_non_static_field_access=false sp_cleanup.always_use_this_for_non_static_method_access=false sp_cleanup.convert_to_enhanced_for_loop=false sp_cleanup.correct_indentation=false sp_cleanup.format_source_code=true sp_cleanup.format_source_code_changes_only=false sp_cleanup.make_local_variable_final=false sp_cleanup.make_parameters_final=false sp_cleanup.make_private_fields_final=true sp_cleanup.make_type_abstract_if_missing_method=false sp_cleanup.make_variable_declarations_final=true sp_cleanup.never_use_blocks=false sp_cleanup.never_use_parentheses_in_expressions=true sp_cleanup.on_save_use_additional_actions=false sp_cleanup.organize_imports=true sp_cleanup.qualify_static_field_accesses_with_declaring_class=false sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 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_trailing_whitespaces=false sp_cleanup.remove_trailing_whitespaces_all=true sp_cleanup.remove_trailing_whitespaces_ignore_empty=false sp_cleanup.remove_unnecessary_casts=true sp_cleanup.remove_unnecessary_nls_tags=false sp_cleanup.remove_unused_imports=false sp_cleanup.remove_unused_local_variables=false sp_cleanup.remove_unused_private_fields=true sp_cleanup.remove_unused_private_members=false sp_cleanup.remove_unused_private_methods=true sp_cleanup.remove_unused_private_types=true sp_cleanup.sort_members=false sp_cleanup.sort_members_all=false sp_cleanup.use_blocks=false sp_cleanup.use_blocks_only_for_return_and_throw=false sp_cleanup.use_parentheses_in_expressions=false sp_cleanup.use_this_for_non_static_field_access=false sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true sp_cleanup.use_this_for_non_static_method_access=false sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true ivy-2.4.0-rc1/.settings/org.jayasoft.ivyde.eclipse.prefs000066400000000000000000000021431226750426600231500ustar00rootroot00000000000000#Sun Sep 03 16:43:34 PDT 2006 # *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** acceptedTypes=[inherited] eclipse.preferences.version=1 ivy_conf_path=file\:///./ivysettings.xml retreive.pattern=none ivy-2.4.0-rc1/CHANGES.txt000066400000000000000000002505001226750426600146340ustar00rootroot00000000000000 Apache Ivy (TM) - The agile open source dependency manager - http://ant.apache.org/ivy ============================================ for detailed view of each issue, please consult http://issues.apache.org/jira/browse/IVY Committers Matt Benson Jean-Louis Boudart Maarten Coene Charles Duffy Xavier Hanin Nicolas Lalevee Jon Schneider Gilles Scokart Contributors Ingo Adler alex322 Mathieu Anquetin Andreas Axelsson Stephane Bailliez Karl Baum Mikkel Bjerg Per Arnold Blaasmo Jeffrey Blattman Jasper Blues Jim Bonanno Joseph Boyd Dave Brosius Matthieu Brouillard Carlton Brown Mirko Bulovic Ed Burcher Jamie Burns Wei Chen Chris Chilvers Kristian Cibulskis Andrea Bernardo Ciddio Archie Cobbs Flavio Coutinho da Costa Stefan De Boey Mykhailo Delegan Charles Duffy Martin Eigenbrodt Stephen Evanchik Robin Fernandes Gregory Fernandez Danno Ferrin Benjamin Francisoud Wolfgang Frank Jacob Grydholt Jensen John Gibson Mitch Gitman Scott Goldstein Pierre H�gnestrand Scott Hebert Tobias Himstedt Aaron Hachez Ben Hale Stephen Haberman Peter Hayes Scott Hebert Payam Hekmat Achim Huegen Matt Inger Anders Jacobsson Anders Janmyr Steve Jones Christer Jonsson Michael Kebe Matthias Kilian Alexey Kiselev Gregory Kisling Stepan Koltsov Heschi Kreinick Sebastian Krueger Thomas Kurpick Tat Leung Costin Leau Antoine Levy-Lambert Andrey Lomakin William Lyvers Sakari Maaranen Jan Materne Markus M. May Abel Muino J. Lewis Muir Stephen Nesbitt Joshua Nichols Bernard Niset Ales Nosek David Maplesden Glen Marchesani Phil Messenger Steve Miller Mathias Muller Randy Nott Peter Oxenham Douglas Palmer Jesper Pedersen Emmanuel Pellereau Yanus Poluektovich Roshan Punnoose Jean-Baptiste Quenot Carl Quinn Damon Rand Geoff Reedy Torkild U. Resheim Christian Riege Frederic Riviere Jens Rohloff Andreas Sahlbach Brian Sanders Adrian Sandor Michael Scheetz Ben Schmidt Ruslan Shevchenko John Shields Nihal Sinha Gene Smith Simon Steiner Johan Stuyts John Tinetti Erwin Tratar Jason Trump Tjeerd Verhagen Richard Vowles Sven Walter James P. White Tom Widmer John Williams Chris Wood Patrick Woodworth Jaroslaw Wypychowski Sven Zethelius Aleksey Zhukov 2.4.0-rc1 ===================================== - DOCUMENTATION: Broken link in documentation (IVY-1405) - DOCUMENTATION: Explicitly document that threaded use is not supported. - NEW: the buildobr task can now work a set of resolved artifacts: useful for managing an OSGi target platform - NEW: fixdeps task: serializes transitively resolved dependencies into an ivy.xml file - NEW: IvyDependencyTree task : display a dependency tree on the console - NEW: Support Conditional Setting of a Property (IVY-1367) - NEW: Exposing some parent metadata (organisation, module, revision, branch) as properties (IVY-1288) - NEW: symlinkmass feature based on symlink feature of ivy:retrieve (IVY-1252) (Thanks to Gene Smith) - NEW: Agent authentication for SSH and SFTP transports (IVY-1421) - NEW: New OSGi resolver 'osgi-agg': a chain resolver dedicated to better handle OSGi dependencies - NEW: Add support for "packed" artifacts: .pack.gz bundles in an OSGi P2 repository for instance - IMPROVEMENT: New LockStrategy available based on NIO FileLocks (IVY-1424) - IMPROVEMENT: Optional ivysettings directives (IVY-1392) (thanks to Yanus Poluektovich) - IMPROVEMENT: add support for source bundles from p2 repositories - IMPROVEMENT: add support for source URI from OBR repositories - IMPROVEMENT: Also copy original metadata artifact (e.g. POM) on ivy:install (IVY-1431) (Thanks to Erwin Tratar) - IMPROVEMENT: useOrigin will do avoid copy with url resolvers configured with a 'file:/' URL - IMPROVEMENT: add support for source artifacts in buildobr task - FIX: In IvyDE, Ivy fails to parse ivy-settings.xml file if it contains element (thanks to Gregory Amerson) (IVY-1441) - FIX: ParseException when "Bundle-Description" is present in OSGi MANIFEST.MF (IVY-1438) - FIX: NIO FileLocker released locks too early (IVY-1424) (thanks to Charles Duffy) - FIX: Ssh Resolver doesn't work with Java 7 (IVY-1408) (thanks to Mykhailo Delegan) - FIX: Parsing publication date in Ant tasks not thread-safe (IVY-1412) - FIX: NullPointerException when using httpclient and server doesn't return content-type header (IVY-1400) (thanks to Frederic Riviere) - FIX: Properly handle evicted nodes in ResolveReport - FIX: Artifact repository locking did not correctly handle threaded use (IVY-1454) (thanks to Carsten Pfeiffer) - FIX: Better support for "Bundle-RequiredExecutionEnvironment" from an OSGi MANIFEST.MF - FIX: When inheriting a module descriptor, also merge the exclude rules - FIX: Correct application of mediators (ie. override) during conflict resolution (IVY-1455) - FIX: Fix revision number mapping across namespaces (IVY-1423) - FIX: fix a NPE when loading a composite P2 repository with no children - FIX: fix missing configuration when fixdeps is used with a partial resolve - FIX: XmlModuleDescriptorWritter doesn't support fully extra infos elements (IVY-1457) 2.3.0 ===================================== - FIX: Ivy generates wrong revision in URL for Maven snapshots (IVY-1396) - FIX: Maven2: resolve failure when parent has with dependency in 'import' scope (IVY-1376) - FIX: IvyPublish fails when using extend tags with no explicit location attribute (IVY-1391) - FIX: *.lck files created by "artifact-lock" lock strategy are not cleaned up if ivy quits abruptly (IVY-1388) (thanks to Wei Chen) 2.3.0-rc2 ===================================== - DOCUMENTATION: Documentation and Implementation mismatch of makepom (IVY-1383) (thanks to Thomas Kurpick) - DOCUMENTATION: added link to extra beginners guide (IVY-1381) - FIX: Ivy default cache path with non-ASCII character lets it crash (IVY-1378) - FIX: latest.integration isn't resolved against a Maven snapshot repository (when uniqueVersion = true) (IVY-1036) - FIX: Resolve does not deliver all dependent artifacts (IVY-1366) (thanks to Wolfgang Frank) - FIX: Ivy descriptors are merged incorrectly when there is an element (IVY-1356) - FIX: SimpleDateFormat is not thread safe (IVY-1373) - FIX: Maven 'hk2-jar' packaging is now supported (IVY-1357) - FIX: Maven 'orbit' and 'pear' packaging is now supported (IVY-899) - FIX: Memory leak and infinite loop in ModuleId.java (IVY-1362) - FIX: Unnecessary warning when parent ivy.xml is not found (IVY-1346) - FIX: StackOverflowError when using and ../ivy.xml is not the parent ivy.xml (IVY-1437) - FIX: NullPointerExeption in AbstractOSGiResolver (IVY-1343) (thanks to Thomas Kurpick) - FIX: Delivered ivy descriptor inconsistent with resolve report / retrieve and other post-resolve actions (IVY-1300) (thanks to Ed Burcher) - FIX: The Updatesite resolver is downloading Eclipse features instead of Eclipse bundle/plugin - FIX: ivy:buildlist task confused by extends feature using two parents (IVY-1363) (thanks to Mitch Gitman and Jean-Louis Boudart) - FIX: ivy.xml extends feature complains about Windows filesystem path (IVY-1359) (thanks to Mitch Gitman and Jean-Louis Boudart) - FIX: buildlist task chokes on absolute path to parent Ivy module (IVY-1364) (thanks to Mitch Gitman and Jean-Louis Boudart) - FIX: The ignore circular dependency strategy is clobbering the warn strategy (IVY-1353) (Thanks to Carl Quinn) - FIX: Buildnumber and IvyFindRevision Ant tasks should honour defaultBranch setting (IVY-1344) (Thanks to Ales Nosek) - FIX: ApacheURLLister.retrieveListing() fails if the encoding of the URL list is different from the default encoding (IVY-1060) (Thanks to Robin Fernandes) - FIX: global exclude rules is not applying to root ivy files 2.3.0-rc1 ===================================== - DOCUMENTATION: Bad example in Project dependencies Tutorial (IVY-1263) - DOCUMENTATION: remove deprecated defaultCache setting from examples (IVY-1273) (thanks to Joseph Boyd) - DOCUMENTATION: link to FAQ is incorrect in distribution files (IVY-793) (thanks to Joseph Boyd) - DOCUMENTATION: The tag version-matchers is missing attribute in documentation (IVY-1292) (thanks to Per Arnold Blaasmo) - DOCUMENTATION: wrong default resolver documented on the 'How does it work' page (IVY-1265) - DOCUMENTATION: Correct outdated links to configuration pages (IVY-1266) - NEW: [orgPath] can now be used as token in ivy/artifact patterns - NEW: New Ant datatype ivy:resources, an Ant resource collection like ivy:cachepath or ivy:cachefileset (IVY-334) - NEW: ivy:resolve and post resole task can now have inlined dependencies declaration. - NEW: Import Bushel into Ivy core (IVY-1241) - NEW: An new resolver 'mirroredurl' which can handle a list of mirrored URL repositories (IVY-468) - NEW: Support for a jar resolver (IVY-1312) - IMPROVEMENT: ivy:install task does not allow specification of conf (IVY-1313) (thanks to Nihal Sinha) - IMPROVEMENT: ivy:makepom ignores the artifact type in generated dependencies (IVY-1229) (thanks to Douglas Palmer) - IMPROVEMENT: ivy:makepom now honors exclusion of artifacts in generated pom files (IVY-1294) (thanks to Jens Rohloff) - IMPROVEMENT: Added support for dynamic revisions in tag (IVY-1281) (thanks to Jean-Louis Boudart) - IMPROVEMENT: ivy:makepom child element dependency should support the type and classifier attributes (IVY-1262) - IMPROVEMENT: ivy:retrieve can now create a path or fileset containing the retrieved artifacts (IVY-1235) - IMPROVEMENT: Improve diagnostics in ssh resolver (IVY-1267) (thanks to Stepan Koltsov) - IMPROVEMENT: ivy:retrieve now accepts a nested mapper type. - FIX: Exclude doesn't work when there is some circular dependencies (IVY-1309) - FIX: Impossible to get artifacts when data has not been loaded for multiple dynamic revisions (IVY-1333) - FIX: Ivy didn't properly handle some file: URLs (IVY-1340) - FIX: fallback mechanism didn't work properly for private configurations - FIX: /localivy target does not work when building Ivy jar (IVY-1338) (thanks to Ben Schmidt) - FIX: The showprogress=false attribute of ivy:resolve doesn't do what it should (IVY-1052) (thanks to Joseph Boyd) - FIX: extends ignores defaultconfmapping/defaultconf/confmappingoverride attributes from parent's configurations and dependencies tags (IVY-1213) - FIX: NullPointerException when providing empty password to (IVY-1335) - FIX: [originalname] not expanded for source and javadoc types during publish in ivy:install (IVY-1324) - FIX: cannot resolve from repositories that return HTTP 204 in response to an HTTP HEAD request (IVY-1328) - FIX: extra attributes lost from info when ivy file is merged with parent (IVY-1206) - FIX: ivy:report ant task intermittently "cannot compile stylesheet" (IVY-1325) - FIX: Maven 'eclipse-plugin', 'jbi-component' and 'jbi-shared-library' packaging is now mapped to 'jar' extension (IVY-899) - FIX: Infinite loop in latest-compatible conflict manager (IVY-1233) (thanks to Payam Hekmat and Sven Zethelius) - FIX: extends section of ivy.xml info does not replace variable in location tag (IVY-1287) (thanks to Jean-Louis Boudart) - FIX: Valid Path does not work for Filesystem Resolver (IVY-1268) - FIX: quiet="true" does not surpress download 'dots' on packager resolver (IVY-1269) - FIX: Dynamic version resolution result can be incorrect when ivy metadata contains extra attributes (IVY-1236) - FIX: NullPointerException in FileUtil#forceDelete. - FIX: XmlModuleDescriptorUpdater is a mess that produces broken xmls in many cases (IVY-1010) - FIX: ivy.xml that contains UTF-8 encoded umlauts cannot be bigger than 10000 bytes (IVY-1253) - FIX: Can not use a v[revision] in an artifact pattern of a filesystem resolver (IVY-1238) - FIX: Cached ivy.xml is invalid if the description contains the ampersand entity (&) (IVY-1237) - FIX: Couldn't authenticate against sites having the same address as the proxy server (IVY-1234) - FIX: OutOfMemoryError when uploading large files using commons-httpclient (IVY-1197) (thanks to Torkild U. Resheim) - FIX: Only the last dependency descriptor is taken into account on the same module (IVY-1240) - FIX: UseCacheOnly doesn't respect the cache configuration in the ivysettings (IVY-1227) - FIX: UseCacheOnly is influenced by the TTL on cached metadata (IVY-1243) - FIX: ConcurrentModificationException on ivy settings loading (IVY-1250) - FIX: Module inheritance sometimes fails to locate parent descriptor in deliver process (IVY-1248) (thanks to Jean-Louis Boudart) - FIX: on an empty configuration produces a very slow-to-evaluate fileset (IVY-1272) - FIX: Ivy does not apply overridden properties to m2 parent dependency versions specified using properties (IVY-1299) - FIX: Ivy does not apply overridden properties to m2 parent dependency versions specified using dependencyManagement properties (IVY-1301) 2.2.0 ===================================== - DOCUMENTATION: Spelling fixes on artifact description page (IVY-1230) - DOCUMENTATION: Added missing documentation about the ivy:publish child elements. - DOCUMENTATION: Grammar, spelling, and clarity of Settings File documentation (IVY-1216) (thanks to Steve Miller) - DOCUMENTATION: Grammar, spelling, and clarity of Tutorial documentation (IVY-1222) (thanks to Steve Miller) - NEW: the ivy:makepom Ant task can use a custom template file to generate the pom.xml - NEW: Ivy can now generate OpenPGP compatible ASCII armored detached signatures when publishing artifacts. - IMPROVEMENT: the child of ivy:publish now accepts any attribute - IMPROVEMENT: Handle attributes in description subelements (IVY-1214) (thanks to Jean-Louis Boudart) - IMPROVEMENT: Use IvyAuthenticator only when it is really necessary (IVY-1211) - IMPROVEMENT: MakePom task handling of mulitple artifacts for Maven2 (IVY-770) (thanks to Jesper Pedersen) - IMPROVEMENT: ivy:makepom now has an option to disable the generation of an extra Ivy comment block in the POM - IMPROVEMENT: ivy:makepom now accepts a list of configurations to include (IVY-1005) (thanks to Jesper Pedersen) - IMPROVEMENT: ivy:makepom can generate a element in the pom (IVY-1215) (thanks to Jesper Pedersen) - FIX: ApacheURLLister doesn't handle some truncated linknames properly (IVY-1232) (thanks to John Tinetti) - FIX: Ivy cannot handle Maven pom with parents depending back on theirselfs (IVY-1225) - FIX: artifactreport ant task doesn't honor log attribute (IVY-1212) - FIX: XmlModuleDescriptorWriter does not write the transitive attribute (IVY-1207) (thanks to Abel Muino) - FIX: Ivy info/extends/extendsType attribute is misspelled by XmlModuleDescriptorWriter (IVY-1203) (thanks to Jason Trump) 2.2.0-rc1 ===================================== - DOCUMENTATION: Limit the width of running text in documentation (IVY-1030) - DOCUMENTATION: Refer to the maven wiki instead of listing some maven2 mirrors ourselfs (IVY-491) - DOCUMENTATION: Fixed several grammatical and typographic errors in documentation (IVY-1172) (thanks to J. Lewis Muir) - DOCUMENTATION: ivy-doc.xsl does not show configurations (IVY-1151) (thanks to Jasper Blues) - DOCUMENTATION: Added documentation of the 'changing' attribute on the ivy:resolve Ant task (IVY-1180) - NEW: Support ivy.xml parent mechanism (IVY-742) (thanks to Jason Trump and Jean-Louis Boudart) - NEW: Make ivy.xml available (IVY-1158) - IMPROVEMENT: added support for 'gzip' and 'deflate' HTTP Content-Encoding (IVY-1194) - IMPROVEMENT: retrieve doesn't retrive files if the current one is more recent (IVY-1044) - IMPROVEMENT: better diagnostics when reporting bad ivy file in cache (IVY-1190) - IMPROVEMENT: Support changing="true" for inline retrieve (IVY-1180) - IMPROVEMENT: Enhance task to access the 'publication', 'branch' and published artifacts as ant propeties (IVY-395) (thanks to Carl Quinn) - IMPROVEMENT: Ivy doesn't support Maven 2.0.9 'import' scope (IVY-807) - IMPROVEMENT: resolver attribute for listmodules task (IVY-1057) - IMPROVEMENT: discover 'src' sources in maven repos (IVY-1138) - IMPROVEMENT: Trace a message when a property file referenced from the settings doesn't exixts (IVY-1074) - IMPROVEMENT: use defaultconf in combination with defaultconfmapping (IVY-1135) (thanks to Jon Schneider) - FIX: The ivy-module version used by XmlModuleDescriptorWriter is hard coded to '1.0' (IVY-1199) - FIX: makepom ignores artifact type in ivy.xml and hardcodes 'jar' in the output pom (IVY-736) (thanks to Aaron Hachez) - FIX: Ant output wasn't always prefixed by the name of the Ivy task - FIX: Resolved Ivy properties written to cache during ivy:resolve incorrectly represents forced revisions (IVY-1159) - FIX: Namespace rules not properly applied to parent projects (IVY-1186) - FIX: LatestVersionMatcher.needModuleDescriptor() does not honor custom statuses (IVY-1170) (thanks to Carl Quinn) - FIX: Proxy authentication could fail when using commons-httpclient - FIX: Packager resolver always extracts all files from archives even when the packaging instructions contains include tags (IVY-1179) (thanks to Stefan De Boey) - FIX: Ivy cannot connect to URLs with '_' in their hostname - FIX: Transitive dependencies resolutions issue when eviction is triggered (IVY-1178) - FIX: Can't deal with [VERSION] version pattern from Maven (IVY-1177) (thanks to Richard Vowles) - FIX: verbose/debug messages were not logged while running ivy:configure task - FIX: ApacheURLLister does not allow directories not containing a dot on Artifactory (IVY-1175) (thanks to Anders Jacobsson) - FIX: artifact-lock strategy could hang Ivy when resolving dynamic revisions - FIX: Authentication won't work in some situations (IVY-1168) (thanks to Sven Walter) - FIX: Using SFTP resolver with full pattern URL prevents use of dynamic versions (IVY-1167) (thanks to Gregory Fernandez) - FIX: parent.groupId is not resolved in maven 2 parser (IVY-1169) (thanks to Achim Huegen) - FIX: Creation of symlinks problematic in Windows with Cygwin 1.7 (IVY-1165) - FIX: add ability to programmatically change default resolver (IVY-1163) (thanks to Jason Trump) - FIX: ivy.settings.dir space escaping problem (IVY-1162) - FIX: Ivy cannot parse alternate format for Maven MD5 files (IVY-1155) - FIX: Ivy does not close URL connection to ivy-report.xsl properly (IVY-1152) - FIX: Artifact report throws NPE when artifact is not in cache (IVY-1150) (thanks to Steve Jones) - FIX: resolve fails for transitive relocated maven modules when the type of the dependency was set to 'jar' - FIX: optional dependencies, sources and javadocs aren't resolved when a maven module is relocated - FIX: Encountered 'multiple artifacts retrieved to same file' error when module does not have multiple artifacts (IVY-1148) - FIX: Use of a shared DocumentBuilder causes SAXException during parallel resolutions (IVY-1147) - FIX: metadata lock files not always deleted from cache (IVY-1145) (thanks to Jason Trump) - FIX: FileSystem resolver with m2compatible=true throws error when publishing modules with dotted organisation names (IVY-968) - FIX: ivy:retrieve sync="true" does nothing if first variable is optional (IVY-1142) (thanks to Andreas Axelsson) - FIX: Latest Compatible Conflict Manager + Extra Attributes in Dependencies' IVY files == infinite loop (IVY-956) - FIX: Resolve with Extra Attributes, Forced Dependencies causes invalid delivered ivy file (IVY-1079) - FIX: ResolveEngine.getDependencies does not work using extra attributes (IVY-1115) - FIX: ignored in dynamic resolve mode (IVY-1131) - FIX: IvyNodeEviction.cleanEvicted has bad comparison logic (IVY-1118) - FIX: ChainResolver doesn't pass the specified 'checkmodified' attribute to the cache (IVY-1133) - FIX: Ivy couldn't handle maven POMs that depend on theirselves - FIX: SearchEngine.listModules returns MRID without extra attributes (IVY-1128) (thanks to Michael Scheetz) - FIX: IvyBuildNumber non-deterministic behaviour (IVY-1120) - FIX: Change spelling of 'occured' to 'occurred' (IVY-1123) - FIX: Ivy deliver fails to replace dynamic revision when using extra attributes (IVY-1111) (thanks to Michael Scheetz) - FIX: IbiblioResolver not always correctly configured when using JRE 1.5 (IVY-1124) (thanks to Flavio Coutinho da Costa) - FIX: VstfpRepository.readResponse uses bad compare logic (IVY-1119) (thanks to Dave Brosius) - FIX: URLResource does not properly support authentication (IVY-1106) (thanks to Heschi Kreinick) - FIX: Excessive hits to missing URLs uses up all ports on Windows (IVY-1105) - FIX: ivy parse exception when using (IVY-1102) - FIX: Change org.apache to commons-cli at jdbc-example (IVY-1109) - FIX: Fixed name snapshots are not updated even if they are marked as changing and the publication date is changed in repo (IVY-938) - FIX: Cannot publish wildcard configurations other than * (IVY-1171) 2.1.0 ===================================== - DOCUMENTATION: little improvement of the documentations of the ivy:buildlist and ivy:resolve Ant tasks. - FIX: Credentials were not set properly for URLs that require authentication when using HttpClient. 2.1.0-rc2 ===================================== - DOCUMENTATION: not all attributes of publish task are documented (IVY-963) (thanks to Jon Schneider) - DOCUMENTATION: missing documentation for the 'Version Pattern Matcher' (IVY-871) (thanks to Jon Schneider) - DOCUMENTATION: added missing documentation for the 'keep' attribute on the (post)resolve Ant tasks (IVY-1091) - DOCUMENTATION: wrong url in installation.html (IVY-1054) - NEW: configuration intersections (IVY-1093) - NEW: configuration groups (IVY-1097) - NEW: added built-in versionmatcher: 'Version Pattern Matcher' (IVY-871) - IMPROVEMENT: Retrieve ant task doesn't support dynamic resolve mode (IVY-1085) - IMPROVEMENT: Added support for NTLM authentication (IVY-1094) (thanks to Mathieu Anquetin) - IMPROVEMENT: Standalone runner should accept all the same parameters as ant tasks (IVY-1090) - IMPROVEMENT: Pre and post retrieve artifact events (IVY-1084) - FIX: Ivy didn't fail when an outdated artifact in cache couldn't get deleted - FIX: ivy:resolve ignores branch in "dynamic" resolve mode (IVY-1087) (thanks to Aleksey Zhukov) - FIX: [originalname] not expanded during retrieve when module descriptor contains extra attributes (IVY-1096) - FIX: The Ant output wasn't always prefixed by the name of the task - FIX: Ivy buildnumber task does not find artifact in Sonatype Nexus repo (IVY-1069) - FIX: Publish with SSH (sftp or ssh) prevents enclosing java process to terminate (IVY-1075) - FIX: Ibiblio resolver throws IndexOutOfBoundsException when using snapshot versions with usepoms='false' (IVY-1028) - FIX: Wrong BuildException messages (findmodules) (IVY-1056) - FIX: PomModuleDescriptorBuilder does not resolve ejb type dependencies to jar extension (IVY-1058) (thanks to Andrey Lomakin) - FIX: Ivy doesn't handle maven dependencies with type 'test-jar' correctly (IVY-1066) - FIX: transitive dependencies and conflict management (IVY-1083) - FIX: exclude does not work in non-trivial conf case (IVY-983) - FIX: The artifact report task is generating duplicate artifact entries (IVY-1098) 2.1.0-rc1 ===================================== - IMPROVEMENT: Fail the retrieve when multiple artifacts of same module are mapped to same file (IVY-1050) - IMPROVEMENT: ivy initialization shouldn't fail if properties file doesn't exist (IVY-1038) - IMPROVEMENT: ivy:resolve ant task does not support "branch" attribute (IVY-1035) - IMPROVEMENT: Ability to strip revConstraint attribute from delivered Ivy files (IVY-989) - IMPROVEMENT: enhanced error message when defining an artifact for an unknown configuration. - IMPROVEMENT: display the revision of the resolved module in ivy-report.xsl (IVY-1024) (thanks to Carlton Brown) - IMPROVEMENT: resolver attribute for buildnumber task (IVY-1019) (thanks to Martin Eigenbrodt) - IMPROVEMENT: add refresh parameter to post resolve tasks (IVY-1017) - IMPROVEMENT: Remove excessive HEAD requests for URL repository (IVY-996) - IMPROVEMENT: add -version option on command line (IVY-1014) - IMPROVEMENT: support resolve refresh in command line (IVY-1013) - IMPROVEMENT: Error message is not clear when specifying an invalid value for checksums (IVY-977) - IMPROVEMENT: catch AccessControlException on System.getProperties() (IVY-1015) - FIX: Error message: "impossible to get artifacts when data has not been loaded" , on certain modules only (IVY-987) - FIX: Ivy doesn't handle the classifier attribute of artifacts inside dependency elements (IVY-1041) - FIX: Buildnumber task does not work for chained resolvers (IVY-1037) - FIX: Dependencies don't inherit exclusions from dependencyManagement (IVY-974) (thanks to John Gibson) - FIX: Dependency Configuration Negation does not work (IVY-982) - FIX: Ivy retrieve does not honor validate="false" from ivysettings (IVY-992) - FIX: Snapshot issues when using ibiblio resolver with m2compatible is false (IVY-1028) - FIX: Ivy Standalone hangs after publishing to SSH resolver (IVY-1009) - FIX: overwrite='false' completely prevents publishing into url repositories (IVY-1007) - FIX: Fixed broken logo link in ivy-report.xsl (IVY-1024) (thanks to Carlton Brown) - FIX: Support for opensll sha1 and md5 checksum (IVY-1006) - FIX: TTL does not work as expected (IVY-1012) - FIX: Listing of URL's under a given URL does not handle fully specified URL's (IVY-959) (thanks to Randy Nott) - FIX: returns wrong result when resolve fails (IVY-970) - FIX: listing possible token values doesn't work properly for the ibiblio resolver - FIX: Ivy deliver fails to replace dynamic revision (IVY-999) (thanks to Martin Eigenbrodt) 2.0.0 ===================================== - IMPROVEMENT: Extend packager resolver to allow arbitrary ant tasks in build instructions (IVY-994) (thanks to Archie Cobbs) - IMPROVEMENT: Ivy Standalone setting to overwrite publications (IVY-976) - IMPROVEMENT: Support useOrigin for artifacts with a set url attribute (IVY-965) (thanks to alex322) - FIX: NullPointerException at PomModuleDescriptorBuilder.addDependency (IVY-995) - FIX: Log levels aren't respected in certain cases using the standalone functionality (IVY-960) (thanks to Patrick Woodworth) - FIX: NPE in LogReportOutputter (IVY-961) - FIX: NullPointerException when resolving module wihout revision in the pattern (IVY-980) - FIX: IO problem while parsing ivy file (Resetting to invalid mark) (IVY-975) - FIX: Cannot parse maven2 poms containing an UTF-8 BOM - FIX: Files with non-latin symbols fail to download (IVY-962) 2.0.0-rc2 ===================================== - DOCUMENTATION: Filesystem resolver: talks about "patterns" but does not mention these must become absolute file paths (IVY-910) - NEW: Allow authentication credentials to be specified in settings file (IVY-943) (thanks to Randy Nott) - IMPROVEMENT: Error messages on use of relative paths can be cyrptic (IVY-909) - IMPROVEMENT: Maven accepts illegal XML for its pom's, Ivy not (IVY-921) - IMPROVEMENT: Ivy should set the ${basedir} property (IVY-953) - FIX: NullPointerException in AbstractPatternsBasedResolver when organization is null (IVY-928) - FIX: NullPointerException when Ivy cannot locate pom parent (IVY-927) - FIX: Cannot configure items with java.io.File attributes (IVY-905) - FIX: Environment properties in ivy settings are no longer resolved (IVY-907) - FIX: Resolve failed on certain proxy environment (IVY-911) - FIX: Ivy can't handle bare POM ${groupId} property (IVY-913) (thanks to Tom Widmer) - FIX: Properties needed to parse version in POM (IVY-914) (thanks to Tom Widmer) - FIX: build.xml: checkstyle + checkstyle-report dont work together (IVY-919) - FIX: Maven packaging of "pom" should add a "jar" artifact if present (IVY-920) - FIX: StackOverflow when using ivy:settings with "ivy.instance" as id (IVY-924) - FIX: Maven Pom reader doesn't handle optional dependencies correctly in some instances (IVY-926) (thanks to Phil Messenger) - FIX: ivy:settings doesn't work if id is a property (IVY-925) - FIX: HttpClientHandler hanging in certain cases (IVY-930) (thanks to Scott Hebert) - FIX: Can't download files containing space or + in their names by HTTP (IVY-923) - FIX: Maven2 parser doesn't support POMs with as root (IVY-932) - FIX: Default retrieve, publish and deliver patterns doesn't include the [classifier] token (IVY-935) - FIX: Can't use latest.release for pom dependencies (IVY-936) - FIX: Unable to resolve snapshot versions depending on xml elements order (IVY-940) - FIX: pre-resolve-dependency event doesn't export branch information (IVY-941) (thanks to Jaroslaw Wypychowski) - FIX: cachefileset produces an empty fileset when the cache refers to libs in directories that only have the root directory in common (IVY-948) (thanks to Chris Wood) - FIX: Extra Attributes specified in the Dependency's Module Descriptor are not available to resolvers (IVY-929) (thanks to Scott Hebert) - FIX: Support for passing arbitrary arguments to the -main invoked class when using the standalone mode is severely limited (IVY-952) (thanks to Patrick Woodworth) - FIX: Correctly set ivy.resolved.configurations property when the conf string includes a negation operator (IVY-951) (thanks to Patrick Woodworth) - FIX: Maven pom license url can contain xml entities (IVY-950) - FIX: Maven pom license has name as optional element (IVY-949) - FIX: Ivy doesn't throw an error when the parent POM cannot be loaded (IVY-931) - FIX: Maven pom parser is not handling pom property ${project.parent.version} (IVY-955) - FIX: inline resolve ignores the transitive attribute (IVY-958) 2.0.0-rc1 ===================================== - NEW: Report version of Ivy in HTTP headers (user-agent?) when Ivy downloads artifacts (IVY-878) - NEW: Add publish support to URL resolver (IVY-848) (thanks to Brian Sanders) - NEW: Better support for local builds (IVY-857) - NEW: Retain original dependency constraint rules in resolved ivy file (IVY-739) - NEW: Add a new resolve mode (optionally per module) to utilize dynamic constraint rule metadata (IVY-740) - NEW: Add transitive dependency version and branch override mechanism (IVY-784) - NEW: Add new packager resolver (IVY-829) (thanks to Archie Cobbs) - IMPROVEMENT: DualResolver should also provide setDescriptor method instead of setAllownomd, which is deprecated for the other resolvers (IVY-903) - IMPROVEMENT: Parse license information in poms (IVY-892) - IMPROVEMENT: Change 'alwaysUseExactRevision' default value to false (IVY-891) - IMPROVEMENT: Better and more homogeneous relative paths handling (IVY-387) - IMPROVEMENT: undeprecate configure task (IVY-849) - IMPROVEMENT: Detect missing artifacts on publish asap (IVY-862) - IMPROVEMENT: Allow to set the branch at deliver/publish time (IVY-859) - IMPROVEMENT: Add defaultconf in publications tag of ivy file (IVY-801) - IMPROVEMENT: Support atomic publish with sub directory structure (IVY-856) - IMPROVEMENT: Provide ant task to retrieve information from published ivy modules (IVY-838) (thanks to David Maplesden) - IMPROVEMENT: Install task fails but reason is not displayed without using -debug or -verbose (IVY-834) - IMPROVEMENT: SSH resolver doesn't support keyboard-interactive authentication (IVY-836) (thanks to Tobias Himstedt) - IMPROVEMENT: declare source and javadoc artifacts in maven2 modules (IVY-325) - IMPROVEMENT: Set the last modified attribute of files downloaded from repositories (IVY-823) - IMPROVEMENT: If DNS is playing up, Ivy takes a lot longer to sort project dependencies (IVY-817) - IMPROVEMENT: make it possible to specify permissions of published files for the SSH resolver (IVY-764) - IMPROVEMENT: Load Ivy version number into some Ant property (IVY-790) - IMPROVEMENT: Make Ivy standalone runnable with no required dependencies (IVY-757) - IMPROVEMENT: add branch attribute in ivy:install task (IVY-727) - IMPROVEMENT: Parse description information in ivy files (IVY-766) - IMPROVEMENT: Parse description and home page from poms (IVY-767) - IMPROVEMENT: Change allownomd and skipbuildwithoutivy into a more semantically correct name (IVY-297) - IMPROVEMENT: Smarter determination if an expression is exact or not for RegexpPatternMatcher and GlobPatternMatcher - IMPROVEMENT: Check branch consistency during resolve (IVY-858) - IMPROVEMENT: Give the possibility to not compute ivy.deps.changed (IVY-876) - IMPROVEMENT: Add a memory cache for the module descriptor that are parsed from the cache (IVY-883) - IMPROVEMENT: Improve performance (IVY-872) - IMPROVEMENT: Additional descriptions of build.xml targets (IVY-499) - FIX: Publish Ant Task 'warnonmissing' ignored (IVY-867) - FIX: Ivy stand-alone ignores -cache argument (IVY-901) (thanks to Chris Chilvers) - FIX: ivy.cache.dir.${settingsRef} is set to default instead of the defaultCacheDir from the ivysettings.xml after ivy:resolve (IVY-898) - FIX: Ivy ibiblio resolver chokes on variables while checking descriptor consistency (IVY-818) - FIX: Enable consistent support of the configuration negation operator (IVY-894) (thanks to Patrick Woodworth) - FIX: add variable expansion in extra attributes (IVY-798) - FIX: Invalid URL when using dynamic ranges (IVY-885) - FIX: can't use gotoNode with a node which has not been visited yet (IVY-874) - FIX: Ivy Publish Task Fails When XML Comments Exist Next to Dependency Declarations (IVY-888) - FIX: Incorrect directory path resolve when running from a different directory (IVY-232) - FIX: Ivy#listTokenValues(String, Map) does not filter returned values, and does not use maven-metadata.xml files with IBiblio resolver (IVY-886) - FIX: Circular Dependency messages in a resolve do not reflect the configuration used during the resolve (IVY-708) - FIX: Failure to transitively install Maven2 artifacts with namespace (IVY-440) - FIX: Unwanted eviction of dependencies when optional attributes in dependency and info tags are in consistent (IVY-745) - FIX: HTTP Handlers ignore unsuccessful response codes (IVY-864) (thanks to James P. White) - FIX: Deliver delivers the wrong version when a dynamic revision is evicted before being resolved (IVY-707) - FIX: Inconsistency with "multi-project" tutorial (IVY-667) - FIX: URLRepository does not allow some valid file scheme uri's (IVY-884) - FIX: Incorrect parsing artifactPattern attribute in a sftp resolver (IVY-661) (thanks to Alexey Kiselev) - FIX: Maven2 "ejb" packaging is not supported (IVY-873) - FIX: Config files with # in path can't be read (IVY-868) (thanks to Simon Steiner) - FIX: Cache can't distinguish artifacts with classifiers (IVY-803) (thanks to James P. White) - FIX: Reports showing double dependencies in certain cases (IVY-578) - FIX: Dynamic revision resolve does not throw error when configuration is missing (IVY-861) - FIX: Referenced resolver not found in macro (IVY-860) - FIX: Ivy files are not retrieved when using useOrigin=true (IVY-713) - FIX: NPE in Ivy:install task if the repository cache dir has been cleared (IVY-843) - FIX: Maven version ranges with ( ) are not supported (IVY-678) (thanks to Michael Kebe) - FIX: Ignore maven metadata files when listing revisions (IVY-765) - FIX: haltonmissing on publish task does not prevent the other files to be published, even with an atomic publisher (IVY-656) - FIX: Transitive dependencies resolves incorrectly when different modules uses the same dependency with different configurations in the same build (IVY-541) - FIX: transitive attribute set to false because of dependency (IVY-105) - FIX: Wrong check for defaultCacheArtifactPattern (IVY-840) - FIX: NPE in ivy:install if ivy.settings.xml contains custom attribute for a module (IVY-838) - FIX: Ivy unit tests fail because 'classifier' attribute of 'artifacts' element is missing in ivy.xsd (IVY-837) - FIX: Ivy build system: fix build.xml to allow "ant coverage-report" behind a proxy (IVY-832) - FIX: NPE in AbstractResolver.exists() if a resource cannot be found (IVY-831) - FIX: Ivy distribution jars contains duplicate entries (IVY-828) - FIX: ivy:report will generate an HTML file that references non-existent ivy-report.css (IVY-826) - FIX: dynamic resolveMode not being dynamic on branch (IVY-825) - FIX: Filesystem repositories can not have () in the path (IVY-797) - FIX: Type tag in poms not supported (IVY-762) - FIX: An empty exclusion tag results in an IllegalArgumentException (IVY-821) - FIX: Maven scope defined in POM dependencyManagement section not honoured (IVY-811) - FIX: SFTPRepository incorrectly calculates last modified time for resources (IVY-815) - FIX: Filesystem resolver does not evaluate [branch] token when publishing (IVY-814) - FIX: Using ivy:settings with the "id" attribute not behaving as expected (IVY-809) - FIX: onMissingDescriptor doesn't work due to == comparison (IVY-805) (thanks to Ben Hale) - FIX: revision token is not set in report outputpattern (IVY-272) - FIX: Ivy uses the first set of configurations it sees when resolving multiple versions of a module (IVY-681) - FIX: Eviction fails for libs not providing their ivy configuration and providing artifacts named different between lib versions (IVY-537) - FIX: Memory leak in ModuleRevisionId.java (IVY-791) - FIX: conflict manager scoping does not work as expected (IVY-465) - FIX: ivy.original.xml file using artifact pattern in cache and causing problems (IVY-787) - FIX: ivy:retrieve with sync="true" removes the .svn directory (IVY-763) - FIX: Ivy silently fails XML errors in ivyrep (IVY-579) - FIX: Extra Attributes are not available to resolver after resolve if cache was empty (IVY-773) - FIX: NullPointerException during ResovleEngine.downloadArtifacts. (IVY-592) - FIX: setting m2compatible on ibiblio resolver overwrite root and pattern settings (IVY-437) (thanks to Jing Xue) - FIX: unable to resolve snapshot versions (IVY-501) - FIX: No error or warning when a resolver references a non-existent cache (IVY-777) - FIX: ivy properties defined in an include file not available in the file that includes it (IVY-780) - FIX: SFTPRepository.list(String) hides exceptions (IVY-751) - FIX: Wrong error message for republishing a module (IVY-752) - FIX: resolve fails to put metadata in cache (IVY-779) - FIX: multiple cleancache and inline retrieve error (IVY-778) - FIX: buildlist evicts modules with the same name, but different organisation (IVY-731) - FIX: Out of memory/Stack overflow for new highly coupled project (IVY-595) - FIX: Compatibility with maven's dependencyMangement (IVY-753) - FIX: ivy:settings fails when override is not set to 'true' (IVY-771) - FIX: NPE when specifying both resolveId and inline in an Ivy:Resolve (IVY-776) - FIX: repreport task not working against a repository structured by branches (IVY-716) - FIX: Ivy reports a conflict when the same file is supposed to be retrieved at the same location twice (or more) (IVY-743) - FIX: StackOverflowError when configuration extends itself (IVY-696) - FIX: XML schema ambiguity (IVY-750) - FIX: ivy-resolve fails when a project has different dependencies in different branches (IVY-717) - FIX: PublishEventsTest fails when Ivy sources are located in a directory with a + (IVY-755) - FIX: XML entity parsing does not work properly (IVY-737) (thanks to Patrick Woodworth) - FIX: Cachefileset task silently fails with parent dir ".." construct (IVY-638) - FIX: SFTP should verify input parameter for hostname (IVY-734) - FIX: Classpath issues with vfs ftp while being used as a bundle (IVY-785) - FIX: Relative include in a settings must be evaluated relatively to the settings file (IVY-372) - FIX: The Bundle-Version is 0.0.0 in the build artifacts (IVY-802) - FIX: Fix the encoding used in XML reports (IVY-816) - FIX: Properties tag in ivy conf do not support relative path (IVY-89) - FIX: Ivy causes IveDE to fail where a properties file is relative to ivyconf.xml (IVY-573) - DOCUMENTATION: Fixed more than a hundred (100+) obsolete "configuration" references; replaced with "settings" (IVY-863) (thanks to Sakari Maaranen) - DOCUMENTATION: Elaborated documentation of ivy files and deliver/publish tasks (IVY-847) (thanks to Sakari Maaranen) - DOCUMENTATION: Ivy terminology elaboration and illustration (IVY-852) (thanks to Sakari Maaranen) - DOCUMENTATION: Broken link in documentation in Ivy files section, info element page (IVY-788) - DOCUMENTATION: Add new cache information to resolver doc (IVY-772) (thanks to Carlton Brown) 2.0.0-beta2 ===================================== - NEW: Introduce RepositoryManagementEngine (IVY-665) - NEW: Add support for importing environment variables (IVY-608) - NEW: Add ability for buildlist task to start build from specified module in the list (IVY-697) (thanks to Mirko Bulovic) - NEW: Cache dynamic revision resolution (IVY-694) - NEW: Make resolve console output configurable per resolve (IVY-715) - IMPROVEMENT: branch and extra attributes missing from info Ant task (IVY-721) - IMPROVEMENT: Review settings loading in Ant (IVY-703) - IMPROVEMENT: Move useOrigin to repository cache manager (IVY-700) - IMPROVEMENT: Make IBiblio resolver compatible with maven proxy (IVY-466) - IMPROVEMENT: Use namespace aware validation (IVY-553) - IMPROVEMENT: use ModuleRevisionId instead of ModuleId in IvySettings#getResolver (IVY-691) - IMPROVEMENT: Flexible cache management (IVY-399) (With contribution of Adrian Sandor) - IMPROVEMENT: Decrease memory footprint (IVY-662) - IMPROVEMENT: Downgrade Ant version requirement to 1.6 to build Ivy (IVY-687) - IMPROVEMENT: In the ResolveReport class, add the possibility to filter the evicted module while getting the list of DownloadArtifact (IVY-704) (thanks to Nicolas Lalev�e) - IMPROVEMENT: Refactor the PomModuleDescriptorParser in order to allow easier integration of maven pom - FIX: ivy:install task not using validate attribute (IVY-728) - FIX: Bad conflict resolution leads to bad "configuration(s) not found" error (IVY-729) - FIX: Resolving for muyltiple configurations when one is not in the list of available configurations does not abort the build (IVY-720) - FIX: Branch attribute considered as both a standard and extra attribute on module info (IVY-726) - FIX: Branch attribute not set on deliver when using a non default branch (IVY-724) - FIX: NullPointerException reported instead of error in ivy:cachepath (IVY-690) - FIX: NPE when calling retrieve if some artifacts are not available locally (IVY-712) - FIX: When in ssh plugin we does not set username in scheme, Ivy always try to connect with guest username, even if we change one in panel. (IVY-710) (thanks to Ruslan Shevchenko) - FIX: NPE in SshCache during publish with ssh resolver without passFile (IVY-709) (thanks to Ruslan Shevchenko) - FIX: Update install ivy build file example (IVY-705) (thanks to Benjamin Francisoud) - FIX: Ivy swallows ParseException when using a latest strategy requiring module descriptors (IVY-702) (thanks to Nicolas Lalev�e) - FIX: Problem with cached Ivy files which have extra attributes (IVY-693) - FIX: Detection of newer and better artifacts should not happen if 'checkModified' is set to 'false' (IVY-389) (with contribution from Johan Stuyts) - FIX: Ivy doesn't respect the order of the ivy patterns as defined in the settings (IVY-676) - FIX: XmlModuleDescriptorWriter doesn't write the deprecated attribute of the "ivy-module/configurations/conf" element (IVY-664) - FIX: XMLModuleDescriptorWriter does not write extra attributes (IVY-471) (with contribution from Mikkel Bjerg) - FIX: latest compatible conflict manager fails with circular dependencies and dynamic revision (IVY-663) - FIX: Strict conflictmanager seems to not support dynamic revisions (IVY-474) - FIX: NPE in namespace transformation during the ivy:findrevision and ivy:resolve task execution (IVY-659) (thanks to Andrea Bernardo Ciddio) - FIX: Maven test scope includes all runtime dependencies (IVY-682) - FIX: Inherit depedencies defined in parent pom (IVY-683) - FIX: Incorrect ivy from maven pom generation when classifier are user (IVY-714) (thanks to Ruslan Shevchenko) - FIX: m2 incompatibility - IVY does not recognize property section(IVY-637) - FIX: Maven test scope not mapped to test conf (IVY-744) (thanks to Danno Ferrin) - TASK: Remove cache attribute on Ant tasks (IVY-685) - Improvement in coding conventions (IVY-511) (with contribution from Markus M. May) 2.0.0-beta1 ===================================== - NEW: Share cache with locking (IVY-654) - NEW: support atomic publish operation (IVY-492) (with contribution from Geoff Reedy) - NEW: latest compatible conflict manager (IVY-648) - NEW: Add a task/code to create M2 POM files from Ivy configurations (IVY-416) - NEW: [Build] Publish the ivy sources (IVY-646) (thanks to Nicolas Lalev�e) - IMPROVEMENT: Ease performance auditing (IVY-655) - IMPROVEMENT: Maven Dependency Management is not used to determine artifact version (IVY-616) (thanks to Jim Bonanno) - IMPROVEMENT: split the cache into an downloaded artifacts cache and a metadata cache (IVY-628) - IMPROVEMENT: add publish triggers to event system (IVY-650) (thanks to Jason Trump) - IMPROVEMENT: Only display unique circular dependencies during Resolve (IVY-653 IVY-514) (with contribution from John Williams) - IMPROVEMENT: Adding option 'cp', which makes it possible for main to be loaded from file (IVY-543) (thanks to Tjeerd Verhagen) - IMPROVEMENT: BasicURLHandler should use method=head for getURLInfo (IVY-611) (thanks to Jim Bonanno) - IMPROVEMENT: artifactproperty should not overwrite the existing properties (IVY-587) - IMPROVEMENT: Support *(private) and *(public) in the confs parameter of the resolve (IVY-588) - IMPROVEMENT: replace * by *(public) when resolving inline (IVY-589) - IMPROVEMENT: ivy html reports now refers http://ant.apache.org (partial IVY-414) - IMPROVEMENT: Improvements on hello ivy example (IVY-626) (with contribution from Jacob Grydholt Jensen) - IMPROVEMENT: Make the root attribute in the ivyrep resolver mandatory (IVY-625) - IMPROVEMENT: New text representation for main module metadata concepts (IVY-649) - FIX: m2 incompatibility - IVY does not recognize property section (IVY-637) - FIX: m2 incompatibility - IVY does not recognize parent pom (IVY-636) - FIX: Attempt to download a file with & in its name causes SAXParseException in Ivy (IVY-635) - FIX: Bad IvyContext scope causing memory leak and bad handling of subproject builds (IVY-639) - FIX: Resolution failure when no ivy.xml file present (IVY-630) - FIX: ${parent.version} property is not recognized in maven2 pom (IVY-620) - FIX: Handle relocation tag in maven 2 pom (IVY-586) - FIX: Ivy doesn't work with Ant 1.6.2 (IVY-614) - FIX: EmptyStackException when upgrading from 1.4 to 2.0 (IVY-610) - FIX: Ivy:retrieve fails through proxy server (IVY-529) - FIX: java.lang.IllegalArgumentException: Invalid uri when working with version ranges (IVY-390) - FIX: Ivy settings include -tag url attribute does not work correctly (IVY-601) - FIX: Static revision replacement is not working when a dynamic revision is evicted by a transitive dependency (IVY-603) (with contribution from Matthias Kilian) - FIX: NullPointerException whilst resolving transitive dependencies (IVY-590) - FIX: cachepath based on a resolve done in a previous build broken (IVY-583) - FIX: Resolving dynamic version fails when using multiple patterns if only one pattern find a revision and others don't (IVY-602) - FIX: Invalid character in IvyRetrieveTest causing most tests to fail (IVY-604) - FIX: ivy:settings and ivy:retrieve with explicit id causes unwarranted DEPRECATED warning (thanks to Jacob Grydholt Jensen) - REFACTORING: Extract a settings interface for the different engines - TASK: Review all tutorials to make sure they are in sync with 2.0 (IVY-591) (with contribution from Jing Xue) - TASK: Satisfy the US export control laws for software "specially designed" to use cryptography. (IVY-593) 2.0.0-alpha2-incubating ===================================== - NEW: Add cleancache task (IVY-565) - NEW: A checkstyle report is generated (IVY-483) (thanks to Jan Materne) - NEW: Hide private or specific conf when publishing (IVY-77) - IMPROVEMENT: File buffer increased to 64KB (IVY-551) - IMPROVEMENT: Expose default cache location as an ant property (IVY-563) - IMPROVEMENT: Expose Ivy variables as Ant Properties (IVY-564) - IMPROVEMENT: Change default cache location (IVY-530) - IMPROVEMENT: Upgraded VFS dependency to 1.0 and removed dependency on VFS-sandbox (IVY-498) - IMPROVEMENT: Use maven2 repository to download dependencies - IMPROVEMENT: Allow "main" parameters to be passed directly (instead of using -args flag) (IVY-480) (thanks to Archie Cobbs) - IMPROVEMENT: Remove @author tags (thanks to Stephane Bailliez) - IMPROVEMENT: Remove use of deprecated elements in ivysettings.xml (IVY-505) (with contribution from Jan Materne) - IMPROVEMENT: Buildlist onlydirectdep attribute (IVY-473 and IVY-504) (with contribution from Mikkel Bjerg) - IMPROVEMENT: Code / XML Polished (IVY-554) (with contribution from Tjeerd Verhagen) - IMPROVEMENT: Javadoc improvements (IVY-544) (with contribution from Tjeerd Verhagen) - IMPROVEMENT: Unit test improvements (IVY-545) (thanks to Tjeerd Verhagen) - IMPROVEMENT: Dependent jars missing in ivy binaries (IVY-481) - FIX: Retrieval not expanding "[originalname]". (IVY-631) - FIX: Ant target "clean" on Ivy multi-project tutorial points to wrong cache directory. (IVY-548) - FIX: Variables not replaced during deliver (IVY-520) (thanks to John Williams) - FIX: XmlModuleDescriptorWriter does not produce matcher attribute on include and exclude rules (IVY-556) - FIX: pom.groupId is not recognized in maven 2 pom parser (IVY-550) - FIX: Evicted modules report depends on the order of the dependencies (IVY-526) - FIX: Ivy does not work on Turkish machines (IVY-65) - FIX: Ivy does not handle multiple version dependencies in maven2 poms correctly (IVY-494) - FIX: pom parser doesn't necessarily processes all important information (IVY-524) - FIX: element of Ivy file in cache is not updated when using namespaces (IVY-516) - FIX: Retrieve Ant task ignores resolveId attribute (IVY-522) (thanks to Scott Goldstein) - FIX: The deprecated "keep" attribute on post resolve tasks causes an error (IVY-517) - FIX: Some circular dependencies not retrieved (IVY-400) - FIX: ${version} property not recognized in poms (IVY-512) - FIX: Bug on handling dependency artifacts when a module configuration is specified (IVY-507) - FIX: Configure fails when having httpclient in classpath without commons-logging (IVY-502) - FIX: packaging data not parsed in maven 2 pom (IVY-500) (thanks to Jeffrey Blattman) - FIX: install ant task: requires default resolver in ivy settings (IVY-477) - FIX: Ant project reference lost from context on multiple ant calls in single thread (IVY-497) (thanks to Jaroslaw Wypychowski) - FIX: EOL in the doc pages (IVY-470) - FIX: Cache is storing ArtifactOrigin properties with no guarantee of unicity and types telescope during resolve. (IVY-430) (thanks to Stephane Bailliez) - FIX: ivy:install ant task does not fail on error (IVY-475) (thanks to Jeffrey Blattman) - FIX: Credentials are shown in build log even if debug is not enabled (IVY-486) (thanks to Gilles Scokart) - FIX: Post-Resolve task shouldn't set the 'resolveid' (IVY-489) - FIX: build fails without emma code coverage JARs present (IVY-478) - FIX: buildlist broken - regression in 2.0.0-alpha1-incubating (IVY-493) - FIX: Circular dependency startegy in buildlist (IVY-509) - FIX: ivy should stop telling me off twice for ivyconf.xml files (IVY-513) - FIX: Allow relative path in ivy.xml files (IVY-347) 2.0.0-alpha1-incubating ===================================== - NEW: define artifacts not declared by the dependency module descriptor (IVY-419) - NEW: Module wide exclude (IVY-431) - NEW: The default public resolver used is now ibiblio with m2 compatible mode (IVY-463) - IMPROVE: OSGIfy ivy artifacts (IVY-464) (thanks to Costin Leau) - IMPROVE: Let user specify Ivy file when using a post-resolve task (IVY-455) - IMPROVE: IvyArtifactProperty and IvyArtifactReport tasks should be a post resolve task (IVY-452) - IMPROVE: Rename ivy configuration in settings to remove ambiguity on configuration meaning (IVY-438) - IMPROVE: Please typedef CacheResolver as "cache" for us (IVY-359) - IMPROVE: ivy:retrieve should be able to create symlinks (IVY-353) (thanks to John Williams) - IMPROVE: Ability to have multiple roots in the task (IVY-340) (thanks to Matt Inger) - IMPROVE: Refactoring / documentation / test of matcher package (IVY-375) (thanks to Stephane Bailliez) - IMPROVE: Add a unit test to verify that latest.integration accepts released modules (IVY-394) (thanks to Gilles Scokart) - IMPROVE: New "modules in use" section in console report at the end of resolve (IVY-373) (thanks to John Wiliams) - IMPROVE: Generated XML reports now contains more information about the resolved module (IVY-446) - FIX: ivy-retrieve failure when explicit absolute 'ivy.dep.file' path specified (IVY-396) - FIX: IvyPostResolve Task doesn't reuse Ivy file of previous resolve (IVY-458) - FIX: Ivy standalone is passing null args to main method when invoking with no args (IVY-457) - FIX: Invalid error report with m2compatible resolver (IVY-456) - FIX: IvyPostResolve Task doesn't use specified cache for the resolve (IVY-453) - FIX: XmlModuleDescriptorWriterTest not working with Java 6 (IVY-374) - FIX: Conflict managers ignored, when assigned to modules in Ivy configuration (setting, ivyconf.xml) (IVY-448) - FIX: Ivy should fail if ';' has been used in publications/artifact/@conf of ivy.xml (IVY-441) - FIX: Ivy should fail where dependency uses undefined configuration (IVY-442) - FIX: Dynamic revision not calculated properly when using multiple directories (IVY-427) - FIX: LatestRevisionStrategy.sort() doesn't sort as specified (IVY-435) - FIX: setting m2compatible on ibiblio resolver overwrite root and pattern settings (IVY-437) - FIX: ivy.revision property not set correctly for second resolve (IVY-429) - FIX: NPE when no organisation or no name is provided in module element of ivyconf (IVY-422) - FIX: FileUtil#copy(File src, File dest, CopyProgressListener l, boolean overwrite) (IVY-420) - FIX: Invalid pom parsing when version is only declared in parent (IVY-436) - FIX: ${project.groupId} and ${project.version} not processed correctly in poms (IVY-425) - FIX: Incorrect pom parsing with profile (IVY-423) - FIX: Ivy doesn't recognize maven2 classifiers (IVY-418) - FIX: PomModuleDescriptorParser fails with nested profile dependency (IVY-392) (thanks to William Lyvers) - FIX: Static revision replacement is not working when delivering an artifact with a dependency having extra attributes (IVY-415) - FIX: Static revision replacement is not working when delivering an artifact with a dependency on a branch (IVY-404) - FIX: latest-time conflict manager not working properly (IVY-407) - FIX: LatestRevisionStrategy do not consider all dynamic revisions properly (IVY-383) (thanks to John Williams for the unit test) - FIX: IOException during publish causes NullPointerException (IVY-371) - FIX: Comments in ivy.xml duplicated (IVY-336) (thanks to Gilles Scokart) - FIX: Ivy failure when the ivy.xml file contains non US-ASCII characters (IVY-346) (thanks to Gilles Scokart) - FIX: Urlresolver is not possible to use dynamic revisions on nonstandard repository structure (IVY-350) (thanks to Pierre H�gnestrand) version 1.4.1 - 2006-11-09 ===================================== - IMPROVE: ability to rebuild all dependent projects from a leaf (IVY-101) - IMPROVE: Artifact pattern list attribute for the ivy:publish (IVY-113) - IMPROVE: Measure code coverage (IVY-323) - IMPROVE: add release target to build file (IVY-339) - IMPROVE: Add a 'conf' parameter to the ivy 'publish' ant task (IVY-322) (thanks to Emmanuel Pellereau) - FIX: retrieve fails when resolve is done with useOrigin set to true (IVY-304) - FIX: IVY complains about non-existent reports in the cache directory (IVY-315) - FIX: Typo in failureproperty attribute of Ant resolve task (IVY-327) (thanks to Jean-Baptiste Quenot) - FIX: ivy:resolve useOrigin fails to behave correctly (IVY-332) - FIX: ChainVersionMatcher doesn't handle IvyAware children version matchers (IVY-331) - FIX: latest. does not work properly when no matching revision exist (IVY-318) - FIX: attribute name in macrodef is not handled as expected (IVY-319) - FIX: confmappingoverride doesn't work for configurations extending from "*(public)" (IVY-326) version 1.4 - 2006-10-09 ===================================== Version 1.4-RC2 has been promoted to 1.4 on 2006-10-09, with documentation update. Known bugs and limitations: - references in resolvers are not resolved 'in-time' with macrodef (IVY-319) - latest. does not work properly when no matching revision exist (IVY-318) - IVY complains about non-existent reports in the cache directory (IVY-315) - retrieve fails when resolve is done with useOrigin set to true (IVY-304) version 1.4-RC2 - 2006-09-27 ===================================== - FIX: m2compatible flag is ignored for display of failed artifact searches (IVY-303) - FIX: AntCallTriggerTest and AntBuildTriggerTest fail when run from ivy build.xml (IVY-310) - FIX: Classloader problem with ant (IVY-311) - FIX: Make resolve overview more compact (IVY-299) - FIX: Could not write to "tmp:///webdav_tmp.c1" because it is read-only (IVY-312) version 1.4-RC1 - 2006-09-17 ================================= Incompatibility with previous versions: --------------------------------------- * usage: - no known major incompatiblity - build list task now requires a configured ivy instance (configure will automatically be called if you don't call it explicitly) - publish now requires the published ivy file to have the published revision (automatic if you use deliver) * API: - Numerous API changes especially in the BasicResolver class and subclasses due to the introduction of VersionMatcher, this may break some custom dependency resolvers or other tools or plugins depending directly on Ivy API Changes: -------- * thanks to Jayasoft: - NEW: ivy report generate full graph from automated build (IVY-155) - NEW: support for build number calculation (IVY-276) - NEW: find modules in repository (IVY-275) - NEW: explicitly specify artifact download URL (IVY-271) - NEW: introduce branch management (IVY-269) - NEW: resolve dependencies directly without using an ivy file (IVY-268) - NEW: ability to invoke any build scripts for dependencies (IVY-68) - NEW: support sftp repository (IVY-267) - NEW: pluggable version matcher (IVY-219) - NEW: support for version ranges (IVY-295) - NEW: dependency based on dependency status (IVY-47) - NEW: add possibility to define extra attributes in ivy files (IVY-217) - NEW: option to omit specific confs and allow the rest (IVY-66) - NEW: use custom classloader for plugins (IVY-220) - NEW: adding to SPECIAL_MEANINGS in LatestRevisionStrategy (IVY-121) - NEW: Allow use of system properties in ivyconf.xml (IVY-228) - IMPROVE: allow to use file-system repository directly without cache (IVY-211) - IMPROVE: deliver task use a default value for revision (IVY-252) - IMPROVE: better documentation distribution (IVY-274) - in progress - IMPROVE: define conflict manager per organisation/module in ivyconf (IVY-270) - IMPROVE: transitive parameter in resolve (IVY-21) - IMPROVE: add syncing feature in retrieve (IVY-33) - IMPROVE: use of md5 and/or sha1 files to check downloads (IVY-27) - IMPROVE: possible to use m2compatible without automatically using POMs as well (IVY-263) - IMPROVE: support for circular dependencies (IVY-202) - IMPROVE: make status list configurable (IVY-242) - IMPROVE: use only ivy patterns for listing revisions when module desciptor is required (allownomd = false) (IVY-166) - IMPROVE: implement strict haltonfailure if ivy.xml is not found (IVY-110) - IMPROVE: artifact's "name" attribute could be omitted (IVY-231) - IMPROVE: ivy standalone now return error status (IVY-152) - IMPROVE: log messages do not display most specfic resolver name (IVY-170) - IMPROVE: prints URL before downloading in verbose mode (IVY-257) - IMPROVE: incorrect value in status attribute causes silent failure (IVY-259) - IMPROVE: suport empty dependencies tag in an ivy file (IVY-281) - IMPROVE: isolate dependency resolution from artifact downloading (IVY-254) - IMPROVE: Pass artifact to repository when calling "put" (IVY-192) - IMPROVE: Do not publish ivy file with bad revision, and allow to force the deliver when calling publish task (IVY-245) - FIX: Problem with multiple artifact includes in transitive dependencies (IVY-283) - FIX: Endless recursion in report (IVY-284) - FIX: http url lister doesn't work when link text has spaces (IVY-282) - FIX: Incorrect ant log level (IVY-279) - FIX: Wrong resolution of dependencies if artifacts specified explicitly (IVY-261) - FIX: Multiple versions of dependencies appearing in retrieve (IVY-264) - FIX: Too many false CircularDependencyException errors thrown (IVY-230) - FIX: CircularDependencyException not always thrown (IVY-184) - FIX: NullPointer in BasicResolver (IVY-258) - FIX: Bad diagnostics message when no space left (IVY-250) - FIX: Maven2 POM support can find groupId from "parent" element (IVY-262) - FIX: Parent version is expected to be equal to the module version in POM (IVY-241) - FIX: problem with cache and returnFirst (IVY-207) - FIX: modules splitted across a chain are not handled correctly (IVY-206) - FIX: problem with conf extension and latest revisions (IVY-240) - FIX: The clean-cache target in /src/example/hello-ivy/build.xml file refers to ${user.home}/.ivy-cache instead of ${user.home}/.ivy/cache/ (IVY-265) * thanks to Ivy Community: - NEW: SSH Resolver added and aligned with SFTP resolver (IVY-273) (thanks to Andreas Sahlbach) - NEW: ability to turn off transitivity at configuration level (IVY-103) (thanks to Karl Baum and Maarten Coene) - NEW: a conflict manager that is able to allow implementation changes but not api changes (1.2.x - OK), (1.x.x - Not OK) (IVY-223) (thanks to Anders Janmyr) - NEW: enhance standalone mode to execute java program by creating classloader of dependant jars from cache (IVY-210) (thanks to Peter Hayes) - NEW: addition of Vfs Resolver which uses Commons-Vfs to resolve files (IVY-128) (thanks to Glen Marchesani, Matt Inger and Stephen Nesbitt) - IMPROVE: use global properties in the recursive delivery (IVY-222) (with the contribution of Roshan Punnoose) - IMPROVE: better handling of authentication (thanks to Christian Riege) - FIX: Ant log messsages not embedded in task log (IVY-280) (thanks to Gilles Scokart) - FIX: Ivy fails when downloading from a server that supports NTLM authentication (IVY-213) (thanks to Damon Rand) - FIX: Delivered Ivy files with incomplete last line. (IVY-125) (thanks to Matthias Kilian) - FIX: the vfs resolver should not log passwords (IVY-292) (thanks to Antoine Levy-Lambert) * thanks to Maarten Coene: - NEW: add failureproperty parameter to the resolve task (IVY-285) - NEW: Add type filtering to retrieve task (IVY-260) - NEW: Add selectors to the configuration mapping (IVY-253) - NEW: Add Ant task to retrieve information from an Ivy file without doing a resolve (IVY-255) - NEW: add option to cachepath task to create a path with local artifact paths (IVY-221) - NEW: allow extending configurations to override the mapping of their super configurations (IVY-218) - IMPROVE: Retain artifact filenames along the publish/resolve/retrieve process (IVY-54) - IMPROVE: report Ant-task doesn't process the reports in batch (IVY-247) - IMPROVE: make ReportOutputter pluggable and customizable (IVY-205) - IMPROVE: add wildcard support for extending configurations (IVY-235) - IMPROVE: add support for xslt parameters in the report task (IVY-227) - IMPROVE: comments now aren't lost when delivering ivy files (IVY-226) - IMPROVE: add sort of 'fallback'-mapping to the defaultconfmapping attribute (IVY-215) - IMPROVE: artifact origin is not included in the default report (IVY-251) - FIX: VFS Resolve fails when trying to resolve a + version (IVY-237) - FIX: report Ant-task doesn't use outputpattern for generating graphml reports (IVY-246) - FIX: report Ant-task doesn't call init() on the internal XSLTProcess (IVY-248) - FIX: value of confmappingoverride from imported configurations is lost when writing Ivy file (IVY-239) - FIX: including configurations doesn't import the confmappingoverride setting (IVY-238) - FIX: NullPointerException when the creation of Ivy file in cache fails (IVY-234) - FIX: Ivy file containing 2 different versions of the same module is not deliverd correctly (IVY-229) - FIX: ModuleRevisionId encode/decode doesn't work if revision is empty (IVY-233) - FIX: cachepath task should preserve the order of the dependencies (IVY-225) - FIX: specifying a defaultconfmapping adds dependencies of each unlisted configuration (IVY-214) * thanks to Johan Stuyts: - NEW: always update artifacts when revision matches a regex pattern (IVY-189) - NEW: provide Ant task for generating report about artifacts depended upon (IVY-194) - IMPROVE: change default cache artifact pattern to handle missing extension (IVY-196) * thanks to Karl Baum: - NEW: "this" symbol for configuration mappings (IVY-183) - IMPROVE: performances improved (IVY-187) version 1.3.1 - 2006-03-30 =============================== - FIX: retrieval of multiple artifacts in different configurations does not work as expected (IVY-188) - FIX: configuration http url include doesn't work with commons http client (IVY-203) - FIX: problem with conflict resolution in transitive dependencies (IVY-199) - FIX: pb with force when it comes after a conflict which has already been solved (IVY-193) - FIX: POM files that reference to the parent artifact download fails (IVY-195) (thanks to Tat Leung) - FIX: M2 compatibility does not take into account the . replacement for publishing artifacts (IVY-191) (thanks to Peter Hayes) - FIX: artifactproperty does not set the [conf] token in the pattern to the correct value. It is always set to 'default'. (IVY-123) (thanks to Peter Oxenham) version 1.3 - 2006-03-17 =============================== This version is the same as 1.3-RC3 promoted to release status. For known bugs and limitations, please refer to http://jira.jayasoft.org/ version 1.3-RC3 - 2006-03-06 =============================== - IMPROVE: Retrieve task now also optionally do ivy file downloads (IVY-167) (with the contribution of Costin Leau) - FIX: ivy variable substitution in ivy files (IVY-186) - FIX: force attribute is not treated as it should in some cases (IVY-182) - FIX: problem reading 'invalid' POMs (IVY-153) - FIX: cryptic NPE due to spelling error in ivy.xml (IVY-177) - FIX: conflicts with dynamic revisions not resolved properly (IVY-181) - FIX: incorrect configuration definition gives misleading NullPointerException (IVY-175) - FIX: throw an error when using a non-existing conflict manager as default (IVY-179) (thanks to Maarten Coene) - FIX: eviction problem with different conflicts in multiple confs (IVY-173) version 1.3-RC2 - 2006-02-15 =============================== - IMPROVE: ivy now supports ${pom.version} in poms (IVY-174) - IMPROVE: adds the possibility to disable concistency check (IVY-163) - IMPROVE: add possibility to choose matcher on include exclude and conflict manager rules in ivy files, and on resolver per module in ivyconf (IVY-161) - IMPROVE: add regexp management in the install ant task (IVY-154) - FIX: httclient is not registered for https urls (IVY-171) - FIX: post resolve tasks like retrieve or cachepath should be able to run from cache information (IVY-169) - FIX: resolve fails without appropriate message when cache is empty and a module in the repository has no revision (IVY-165) - FIX: resolve problem with configuration inheritance (IVY-164) - FIX: some files in cache detected by not used by Ivy for subsequent retrieves (IVY-159) - FIX: HTML report shouldn't display the dependencies of evicted modules (IVY-158) (thanks to Maarten Coene) - FIX: bug when an organisation or module or revision contains a space (IVY-157) - FIX: cos-nonambig warnings (IVY-156) version 1.3-RC1 - 2006-01-25 =============================== --> compatiblity with previous version: - the default place for the cache has changed, it is now in {USER_HOME}/.ivy/cache, instead of {USER_HOME}/.ivy-cache please move this directory if you want to avoid unnecessary downloads - modules are now logged as they are found, set ivy.log.module.when.found variable to false to avoid this - NEW: namespace system: a resolver can be declared to belong to a namespace, which itself specify the transformation to apply to convert it from and to system namespace (IVY-147) - NEW: pluggable module descriptor parsers let define new kind of module descriptor (IVY-146) (thanks to Maarten Coene) - NEW: a new install task let add modules found in a repository in another one, even transitively (IVY-141) - NEW: maven2 pom compatibility: most resolvers are now able to handle m2 pom as project metadata and there is a new convertpom task able to convert a pom file to an ivy file (IVY-140) - NEW: include configurations from external file (IVY-88) - NEW: a new default resolver which let override ivy files and artifacts found on public repository (ivyrep / ibiblio) and let publish modules in a local repository (IVY-132) - NEW: ivyconf file inclusion in ivyconf files (IVY-99) - NEW: macrodef feature in ivyconf for defining macro resolvers with parameters (IVY-98) - NEW: conf fallback mechanism (IVY-145) - NEW: exclusion now let exclude whole modules (IVY-144) - NEW: ability to use a dependency instead of an ivy file in standalone mode (IVY-96) - NEW: ability to output a path of dependencies in cache from the standalone mode (IVY-92) - NEW: it is now possible to reference existing resolver in resolver containers (IVY-35) - NEW: overwrite attribute in the publish task now let force overwrite of read only files (IVY-83) - NEW: add a conflict manager ("strict") making build fail when a diamond conflict is found (thanks to Christer Jonsson) (IVY-118) - IMPROVE: generate xml report using ivy:report task (IVY-143) - IMPROVE: possibility to configure ivy so that special revisions are not queried as fixed one at all (IVY-139) - IMPROVE: better url querying management (IVY-138) (thanks to Bernard Niset) - IMPROVE: do not add resolver info in ivy files in cache so that they can be safely used as usual ivy files in a repository (IVY-137) - IMPROVE: review default conf mapping management (IVY-134) - IMPROVE: add possibility for a chain to behave like a dual chain (IVY-131) - IMPROVE: add possibility to avoid overwrite of an ivy variable when setting them in ivyconf.xml (IVY-127) - IMPROVE: ability to exclude the root project from the buildlist (thanks to Constantine Vetoshev) (IVY-124) - IMPROVE: exclusion of artifacts now works on transitive artifacts, and exclusion can specify organisation and/or module (IVY-116) - IMPROVE: now dynamic revisions replacement by deliver task can be turned off (IVY-120) - IMPROVE: better performance with deep transitive dependencies - IMPROVE: allow optional parts in the patterns (IVY-102) (thanks to Maarten Coene) - IMPROVE: ability to define variable directly in ivyconf.xml (IVY-100) - IMPROVE: ability to use no revision in pattern with latest.integration dependency, artifacts being updated according to revision change in ivy file (if checkmodified is set to true) (IVY-95) - IMPROVE: ability to specify a root module in buildlist to filter out unnecessary build files (IVY-93) (thanks to Kristian Cibulskis) - IMPROVE: import system properties as ivy variables in standalone mode - IMPROVE: string identifying a module is now clearly different from a path - IMPROVE: better error message when publish fails due to readonly destination (IVY-83) - IMPROVE: some javadoc improvements (IVY-136 IVY-129) (thanks to Stephen Nesbitt) - FIX: problem resolving dependencies when 2 module versions have different configurations (IVY-151) - FIX: problem with inheritance between public and private conf (IVY-149) - FIX: no variable replacement during the deliver step (IVY-133) - FIX: conflict badly solved in some complex cases (IVY-130) - FIX: mapping on conf * now only takes public configurations (IVY-126) - FIX: bad dependency ivy files now causes failure (IVY-112) - FIX: stack overflow error in contradictory conflict cases (IVY-117) - FIX: publish now doesn't call deliver when not necessary (IVY-119) - FIX: cachefileset was returning all artifacts for empty configuration (IVY-108) - FIX: transitive and changing attribute were not copied in ivy files in cache (IVY-94) - FIX: chain resolver now support latest strategy configuration (IVY-90) - FIX: raise a clean error when a cyclic variable definition is found (IVY-75) - FIX: clean ant project reference at the end of the build to improve usability in ide launching multiple builds in the same vm (like netbeans) (IVY-87 - IVY-115) - FIX: ivy is now able to use simple ivy files in cache (doesn't need resolver info, use default one if no resolver is given) (IVY-86) - FIX: private conf not accessible from other modules (IVY-76) - FIX: root module configurations isolation bug fixed (IVY-84) - FIX: changed the place where ivy stores master ivy files in cache to not overlap with dependencies one (IVY-85) - FIX: bug in ResourceHelper didn't let override resource easily (IVY-80) - FIX: throws a circular dependency exception when a circular dependency is found instead of failing silently (IVY-79) version 1.2a - 2005-09-14 =============================== Note : version 1.2 previously published on ivy site was not the real 1.2 due to a bad release operation version 1.2a should then be used instead - new ivy.deps.changed property set if there are changes since last resolve (IVY-71) - new buildlist task: calculate order of dependencies of subprojects for easy multi-projects builds (IVY-69) - accept organization as token (IVY-55) - added type filtering mechanism on resolve task (IVY-45) - detect and warn about resolver using ivy cache as repository (IVY-53) - new transitive attribute on dependency, which enable to disable transitive dependency management on a particular dependency (thanks to Ingo Adler) (IVY-20) - new '@' in dependency configuration mapping declaration, used to indicate that a configuration maps to itself useful with *, '*->@' meaning that all configurations of the module maps to their equivalent (same name) in the dependency (IVY-52) - new changing attribute on dependencies indicate that the dependency artifacts may change even without revision change, but with only a new ivy file with new publication date - new useRemoteConfig on conf tag in ivyconf.xml, tells to use remote configuration file for repository config - new type filtering in cachepath task - new cachefileset task: builds an ant fileset of artifacts in cache - publish task now uses srcivypattern for ivy files finding and for delivery - better debug and error messages (IVY-60 IVY-61) - added a javadoc target in ant build (thanks to joshua nichols) - FIX: module descriptors sort was failing in some case cases (fix by Karl Baum) - FIX: Ivy complains about schema directive (IVY-64) - FIX: 'null' status attribute in module descriptor (IVY-62) - FIX: report header contains incorrect link after resolve for multiple, comma-separated configurations (IVY-57) - FIX: error retrieving dependencies with a '+' in their revision if the ivy file doesn't exist - fixed by maarten coene (IVY-59) - FIX: trying to resolve latest with no revision in pattern caused a StackOverflowError (IVY-56) - FIX: now handle transitive eviction (IVY-51) - FIX: resolve now store resolved file id in ivy variables, so that multiple resolve calls can be followed by multiple retrieve, each retrieve will use the last resolve info (IVY-49) - FIX: IllegalStateException on retrieve done from command line - FIX: checks ivy files data consistency with asked info (org, module name and revision) - FIX: use AUTH configuration for configuration file - IMPROVE: added publish handling from command line (IVY-48) version 1.1 - 2005-06-13 =============================== - remote configuration (if available) of ivyrep and ibiblio patterns and roots - new detailed messages when ivy fails to reach an url (thanks to Nicolas) - new artifactproperty task, which enables to set a property for each dependency artifacts resolved by ivy - new defaultconf attribute in ivy file dependencies, to change the default conf to use in the file when no conf is specified for a dependency - add the ability to change the xsl file and report name pattern used by report task - http listing now compatible with tomcat listing (tested with 5.0.28) - pub revision in deliver task now defaults to timestamp if not provided by any other way - debug messages improvements, with configuration dump among others - new var task, enables to set ivy variables from ant - now defaults for ivyrep and ibiblio resolver are configurable by variables - refactoring: introduce the notion of BasicResolver, Repository, Resource, RepositoryResolver, making much easier the task of writing basic resolvers - added checkmodified attribute on all basic resolvers, which defaults to ${ivy.resolver.default.check.modified} This makes ivy check last modified date of ivy files to see it its cache is up to date - artifacts download are now first made to a temp file, which is renamed only at the end of the download. This prevent interrupted downloads to be considered as finished - FIX: handle proxy configuration with http-client (thanks to Nicolas) - FIX: remove dependency on ant outside of ant integration classes - FIX: resolve problem when conflicts on latest revisions - FIX: allow use of any kind of URL in IvyRepResolver (both ivyroot and artroot) and IBibiblioResolver - FIX: chain resolver can now be used for artifacts part of dual resolver - FIX: now detects and warn about circular dependencies - FIX: cachepath task now takes pathid as parameter instead of id, to prevent special handling from ant - FIX: ivy.xsd: set artifact minOccurs to 0 in publications Thanks to John Shields from Robert Half International, Inc.: - FIX: no more infinite loop when a conflict occurs between a latest subversion and a fully resolved revision - FIX: BasicURLHandler now closes its connections - FIX: ApacheURLLister now works with capital letter in revisions and truncated names - now use of ivy variables is allowed in ivy files - added a null check in pattern helper substitute version 1.0 - 2005-04-26 =============================== 1.0-rc3 has been promoted to 1.0 on 2005-04-26 Known bugs and limitations: - cyclic dependencies result in StackOverflowError - infinite loop in rare cases when a conflict occur between a latest subversion and a fully resolved revision - url connections not closed properly when not using commons-httpclient - latest does not work with http urls in some cases, when the name of the link is truncated in the web page version 1.0-rc3 - 2005-04-21 =============================== - IMPROVE: added debug messages on variables setting - FIX: ivyconf now able to load a properties file given as url - FIX: deliver pub date now actually defaults to 'now' - FIX: all tasks attributes now substitute ivy variables version 1.0-rc2 - 2005-04-18 =============================== - IMPROVE: improved messages: more debug, more verbose, and more details on failures - FIX: bug with '\' in path patterns - FIX: bug with relative paths patterns - FIX: configure task tries ivy.conf.file as relative to base dir and to current dir - FIX: file system resolver publishes ivy files with ivy pattern - FIX: 0 content length considered as non existing (behaviour of jre 5.0 on linux) => empty ressources are now considered as non existing version 1.0-rc1 - 2005-04-12 =============================== - add report task, which enables to generates reports of dependencies, including a graph ready to be layed out by yEd - add exclude feature in dependency - include exclude feature now handles regexps - new latest strategy: latest revision now uses a "php version_compare" like algorithm, whereas lexicographic comparison is now available in latest lexicographic - enhance xml resolve report details - FIX: better separation between root configurations - FIX: XmlModuleDescriptorUpdater now preserves xml header - FIX: modules number in report (displayed at the end of resolve) version 0.9 - 2005-04-06 =========================== - clearly differenciate pattern tokens from variables, by using brackets as delimiter in pattern tokens => WARNING: this introduce changes in all patterns syntax, and thus does not provide compatibility with previous versions - ChainResolver are now able to publish (delegating the call to the first resolver in the chain) - DualResolver sub resolvers are now registered in Ivy - more precise message on eviction - add validate attribute on most resolvers - ivy files validation handling review - use ivy variables in ant tasks to get default values for attributes - documentation update for configuring ivy - FIX: dependencies order not taken into account during resolve - FIX: evicting modules also evict confs - FIX: NPE during resolve when a dependency ivy file has no publication date - FIX: check nullity of artifact download reports version 0.8 - 2005-03-30 =========================== - added validate attribute on resolve, retrieve and publish, which allows to disable ivy file validation against ivy.xsd (useful to parse future compatible ivy files) - ant properties are now available in ivyconf file - unified default properties in ivyconf, with better independance from url or file - added ext on artifacts: this enable to distinguish artifact extension from artifact type, util in cases where it differs (example: 'src' type with 'zip' extension, 'ivy' type with 'xml' extension, ...) - added publish artifacts feature, which enable to publish declared artifacts of a module to a repository described by a dependency resolver. It currently works only with filesystem resolver. - url resolver now handles latest with file urls and http ones (tested only with apache server) - added latest strategy concept: the way to determine which artifact is the latest is now configurable on resolvers handling latest. - added parameter on chain resolver to say if it should return first found or try to find the latest among all if asked - a module can now publish no artifact, useful for virtual modules consisting only of integration of other modules - added conflict management at resolve time: during resolve, modules in conflict can be evicted and thus not downloaded - added ivyrep resolver, using ivyrep to find ivy files, and ibiblio for artifacts - use ivyrep instead of ibiblio as default resolver - added more info in ivy files (description, homepage, ivy authors, license, public repository, ...) - now cache layout is configurable, using cacheIvyPattern and cacheArtifactPattern attributes on conf element in ivyconf.xml - changed default cache layout: artifacts are separated by type - added cachepath task, which enables to build an ant path of artifacts in cache required for a conf version 0.7 - 2005-03-11 =========================== - added latest sub revision feature: you can now select the latest sub revision of a module using a +. For instance, "1.0+" selects the latest revision starting with 1.0. (thanks to jonas for the idea) - haltonfailure now defaults to true (as suggested by Jeroen) - shorter info lines to better view important info (as suggested by Jeroen) - retrieve now checks if files are up to date before copying them from cache. This feature can be disabled using the checkUpToDate attribute in ivy configuration file. - do not download dependencies when not necessary during publication (as suggested by Daniele) - bug fix: better handling of publish without recursive delivery version 0.6.1 - 2005-02-11 ============================= - bug fix: conf extends problem with publications - bug fix: typedef badly handled in ivyconf.xml - bug fix: default properties loading in ivy configure loaded using task classloader version 0.6 - 2005-02-03 =========================== + functional - added haltonfailure attribute on resolve and retrieve task, so that build can be halt when resolve or retrieve fails - added dependency artifacts filtering feature, enabling to work better with ibiblio - ibiblio resolver can now be configured to use any maven like repository, with root and pattern attributes - added download progression info on resolve - default cache is now in user home (.ivy-cache in user home), so that cache is shared by default for all projects of the same user - added public access to method getDependencies(...) in Ivy, which resolve dependencies without downloading artifacts - added DualResolver, which allows to have ivy files in one place and artifacts in another one + non functional - added some unit tests - deep review of ivy file reference documentation + bugs and refactoring - bug fix: SimpleURLResolver not handling the case when there is no ivy file - refactoring: URLResolver renamed to AbstractURLResolver - refactoring: SimpleURLResolver renamed to URLResolver version 0.5.1 - 2005-01-16 ============================= - Bug Fix: NPE in publish task when no delivery.list.file is provided - documentation update version 0.5 - 2005-01-12 =========================== initial public version ivy-2.4.0-rc1/LICENSE000066400000000000000000000337171226750426600140410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ------------------------------------------------------------------------------ License for JCraft JSch package ------------------------------------------------------------------------------ Copyright (c) 2002,2003,2004,2005,2006,2007 Atsuhiko Yamanaka, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------ License for jQuery ------------------------------------------------------------------------------ Copyright (c) 2007 John Resig, http://jquery.com/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ivy-2.4.0-rc1/META-INF/000077500000000000000000000000001226750426600141615ustar00rootroot00000000000000ivy-2.4.0-rc1/META-INF/MANIFEST.MF000066400000000000000000000120031226750426600156070ustar00rootroot00000000000000Manifest-Version: 1.0 Main-Class: org.apache.ivy.Main Bundle-Version: 2.4.0 Bundle-Name: Ivy Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.apache.ivy Bundle-Vendor: Apache Software Foundation Bundle-DocURL: http://ant.apache.org/ivy/ Import-Package: com.jcraft.jsch;resolution:=optional, javax.crypto;resolution:=optional, javax.swing;resolution:=optional, javax.swing.event;resolution:=optional, javax.xml.parsers, javax.xml.transform, javax.xml.transform.sax, javax.xml.transform.stream, org.apache.commons.httpclient;resolution:=optional, org.apache.commons.httpclient.auth;resolution:=optional, org.apache.commons.httpclient.methods;resolution:=optional, org.apache.commons.httpclient.params;resolution:=optional, org.apache.commons.httpclient.protocol;resolution:=optional, org.apache.commons.net.ftp;resolution:=optional, org.apache.commons.vfs;resolution:=optional, org.apache.commons.vfs.impl;resolution:=optional, org.apache.commons.vfs.provider;resolution:=optional, org.apache.commons.vfs.provider.ftp;resolution:=optional, org.apache.commons.vfs.provider.local;resolution:=optional, org.apache.commons.vfs.provider.sftp;resolution:=optional, org.apache.commons.vfs.provider.url;resolution:=optional, org.apache.oro.text;resolution:=optional, org.apache.oro.text.regex;resolution:=optional, org.apache.tools.ant;resolution:=optional, org.apache.tools.ant.filters;resolution:=optional, org.apache.tools.ant.taskdefs;resolution:=optional, org.apache.tools.ant.types;resolution:=optional, org.apache.tools.ant.types.resources;resolution:=optional, org.apache.tools.ant.util;resolution:=optional, org.apache.webdav;resolution:=optional, org.bouncycastle.bcpg;resolution:=optional, org.bouncycastle.jce.provider;resolution:=optional, org.bouncycastle.openpgp;resolution:=optional, org.w3c.dom;resolution:=optional, org.xml.sax, org.xml.sax.ext, org.xml.sax.helpers Export-Package: org.apache.ivy;version="2.0.0", org.apache.ivy.ant;version="2.0.0", org.apache.ivy.core;version="2.0.0", org.apache.ivy.core.cache;version="2.0.0", org.apache.ivy.core.check;version="2.0.0", org.apache.ivy.core.deliver;version="2.0.0", org.apache.ivy.core.event;version="2.0.0", org.apache.ivy.core.event.download;version="2.0.0", org.apache.ivy.core.event.publish;version="2.0.0", org.apache.ivy.core.event.resolve;version="2.0.0", org.apache.ivy.core.event.retrieve;version="2.0.0", org.apache.ivy.core.install;version="2.0.0", org.apache.ivy.core.module.descriptor;version="2.0.0", org.apache.ivy.core.module.id;version="2.0.0", org.apache.ivy.core.module.status;version="2.0.0", org.apache.ivy.core.pack;version="2.4.0", org.apache.ivy.core.publish;version="2.0.0", org.apache.ivy.core.report;version="2.0.0", org.apache.ivy.core.repository;version="2.0.0", org.apache.ivy.core.resolve;version="2.0.0", org.apache.ivy.core.retrieve;version="2.0.0", org.apache.ivy.core.search;version="2.0.0", org.apache.ivy.core.settings;version="2.0.0", org.apache.ivy.core.sort;version="2.0.0", org.apache.ivy.osgi.core;version="2.3.0", org.apache.ivy.osgi.filter;version="2.3.0", org.apache.ivy.osgi.obr;version="2.3.0", org.apache.ivy.osgi.obr.xml;version="2.3.0", org.apache.ivy.osgi.p2;version="2.3.0", org.apache.ivy.osgi.repo;version="2.3.0", org.apache.ivy.osgi.updatesite;version="2.3.0", org.apache.ivy.osgi.updatesite.xml;version="2.3.0", org.apache.ivy.osgi.util;version="2.3.0", org.apache.ivy.plugins;version="2.0.0", org.apache.ivy.plugins.circular;version="2.0.0", org.apache.ivy.plugins.conflict;version="2.0.0", org.apache.ivy.plugins.latest;version="2.0.0", org.apache.ivy.plugins.lock;version="2.0.0", org.apache.ivy.plugins.matcher;version="2.0.0", org.apache.ivy.plugins.namespace;version="2.0.0", org.apache.ivy.plugins.parser;version="2.0.0", org.apache.ivy.plugins.parser.m2;version="2.0.0", org.apache.ivy.plugins.parser.xml;version="2.0.0", org.apache.ivy.plugins.report;version="2.0.0", org.apache.ivy.plugins.repository;version="2.0.0", org.apache.ivy.plugins.repository.file;version="2.0.0", org.apache.ivy.plugins.repository.jar;version="2.3.0", org.apache.ivy.plugins.repository.sftp;version="2.0.0", org.apache.ivy.plugins.repository.ssh;version="2.0.0", org.apache.ivy.plugins.repository.url;version="2.0.0", org.apache.ivy.plugins.repository.vfs;version="2.0.0", org.apache.ivy.plugins.repository.vsftp;version="2.0.0", org.apache.ivy.plugins.resolver;version="2.0.0", org.apache.ivy.plugins.resolver.packager;version="2.0.0", org.apache.ivy.plugins.resolver.util;version="2.0.0", org.apache.ivy.plugins.signer;version="2.2.0", org.apache.ivy.plugins.signer.bouncycastle;version="2.2.0", org.apache.ivy.plugins.trigger;version="2.0.0", org.apache.ivy.plugins.version;version="2.0.0", org.apache.ivy.tools.analyser;version="2.0.0", org.apache.ivy.util;version="2.0.0", org.apache.ivy.util.cli;version="2.0.0", org.apache.ivy.util.extendable;version="2.0.0", org.apache.ivy.util.filter;version="2.0.0", org.apache.ivy.util.url;version="2.0.0" Bundle-ClassPath: . Bundle-RequiredExecutionEnvironment: J2SE-1.5 ivy-2.4.0-rc1/NOTICE000066400000000000000000000011141226750426600137220ustar00rootroot00000000000000Apache Ivy (TM) Copyright 2007-2014 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). Portions of Ivy were originally developed at Jayasoft SARL (http://www.jayasoft.fr/) and are licensed to the Apache Software Foundation under the "Software Grant License Agreement" SSH and SFTP support is provided by the JCraft JSch package, which is open source software, available under the terms of a BSD style license. The original software and related information is available at http://www.jcraft.com/jsch/. ivy-2.4.0-rc1/README000066400000000000000000000042441226750426600137050ustar00rootroot00000000000000 Apache Ivy (TM) [version] --------------------------- Supported Platforms -------------------- Apache Ivy requires Java level 1.4; it has been tested with Sun Java SDK v1.4.2 Even if not mandatory, Apache Ivy is most of the times used with Apache Ant, for which version 1.6.0 or greater is required. Installation ------------- Please read doc/install.html for installation instructions. Getting Started ---------------- For an introduction to Apache Ivy and how to use it, please read the documentation located in the doc subdirectory. A good place to start is the index.html Licensing --------- This software is licensed under the terms you may find in the file named "LICENSE" in this directory. Crypto Notice ------------- This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See for more information. The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache Software Foundation distribution makes it eligible for export under the License Exception ENC Technology Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for both object code and source code. The following provides more details on the included cryptographic software: The Ivy ssh resolver requires the JSch library . The sftp and https resolvers requires the Java Cryptography extensions . The PGP signature generator requires the BouncyCastle Java cryptography APIs . ivy-2.4.0-rc1/RELEASE_NOTES000066400000000000000000000136011226750426600147750ustar00rootroot00000000000000 Apache Ivy (TM) v2.4.0-rc1 Release Notes ----------------------------------------------------------------------- CONTENTS 1. What is Apache Ivy? 2. Status of this release 3. Major Changes in this Release 4. Migrating from Jayasoft Ivy to Apache Ivy 5. How to Get Involved 6. How to Report Issues 7. Committers and Contributors for this release 8. List of Changes in this Release 1. What is Apache Ivy? Apache Ivy is a tool for managing (recording, tracking, resolving and reporting) project dependencies. It is characterized by the following: 1. flexibility and configurability Apache Ivy is essentially process agnostic and is not tied to any methodology or structure. Instead it provides the necessary flexibility and configurability to be adapted to a broad range of dependency management and build processes. 2. tight integration with Apache Ant while available as a standalone tool, Apache Ivy works particularly well with Apache Ant providing a number of powerful Ant tasks ranging from dependency resolution to dependency reporting and publication. 2. Status of this release This is the development branch of Ivy. Any release branch should have a more accurate description here. As of this writing, the current production quality version is 2.3.0, published by the ASF on January 21st, 2013. 3. Major Changes in this Release This section describes what has changed between version 2.3.0 and this version of Apache Ivy which may cause incompatibilities. For a full list of detailed changes, please refer to CHANGES.txt file. This new version of Apache Ivy is fully compatible with 2.3 versions. 4. Migrating from Jayasoft Ivy to Apache Ivy Please see release notes from 2.3.0 or prior for migration instructions from Jayasoft Ivy (1.x). 5. How to Get Involved The Apache Ivy project really needs and appreciates any contributions, including documentation help, source code and feedback. If you are interested in contributing, please visit http://ant.apache.org/ivy/get-involved.html. 6. How to Report Issues The Apache Ivy project uses JIRA for issue tracking. Please report any issues you find at http://issues.apache.org/jira/browse/IVY 7. Committers and Contributors for this Release Here is the list of people who have contributed source code and documentation to this release. Many thanks to all of them, and also to the whole Ivy community contributing ideas and feedback, and promoting the use of Ivy. The list would be too long, but Ivy couldn't be what it is without you! Committers Jean-Louis Boudart Maarten Coene Charles Duffy Nicolas Lalevee Contributors Gregory Amerson Mykhailo Delegan Carsten Pfeiffer Yanus Poluektovich Frederic Riviere Gene Smith Erwin Tratar For the list of people who have contributed since Ivy inception, see CHANGES.txt file. 8. List of Changes in this Release For a full release history of Ivy see the file CHANGES.txt For details about the following changes, check our JIRA install at http://issues.apache.org/jira/browse/ivy List of changes since Ivy 2.3.0: - DOCUMENTATION: Broken link in documentation (IVY-1405) - DOCUMENTATION: Explicitly document that threaded use is not supported. - NEW: the buildobr task can now work a set of resolved artifacts: useful for managing an OSGi target platform - NEW: fixdeps task: serializes transitively resolved dependencies into an ivy.xml file - NEW: IvyDependencyTree task : display a dependency tree on the console - NEW: Support Conditional Setting of a Property (IVY-1367) - NEW: Exposing some parent metadata (organisation, module, revision, branch) as properties (IVY-1288) - NEW: symlinkmass feature based on symlink feature of ivy:retrieve (IVY-1252) (Thanks to Gene Smith) - NEW: Agent authentication for SSH and SFTP transports (IVY-1421) - NEW: New OSGi resolver 'osgi-agg': a chain resolver dedicated to better handle OSGi dependencies - NEW: Add support for "packed" artifacts: .pack.gz bundles in an OSGi P2 repository for instance - IMPROVEMENT: New LockStrategy available based on NIO FileLocks (IVY-1424) - IMPROVEMENT: Optional ivysettings directives (IVY-1392) (thanks to Yanus Poluektovich) - IMPROVEMENT: add support for source bundles from p2 repositories - IMPROVEMENT: add support for source URI from OBR repositories - IMPROVEMENT: Also copy original metadata artifact (e.g. POM) on ivy:install (IVY-1431) (Thanks to Erwin Tratar) - IMPROVEMENT: useOrigin will do avoid copy with url resolvers configured with a 'file:/' URL - IMPROVEMENT: add support for source artifacts in buildobr task - FIX: In IvyDE, Ivy fails to parse ivy-settings.xml file if it contains element (thanks to Gregory Amerson) (IVY-1441) - FIX: ParseException when "Bundle-Description" is present in OSGi MANIFEST.MF (IVY-1438) - FIX: NIO FileLocker released locks too early (IVY-1424) (thanks to Charles Duffy) - FIX: Ssh Resolver doesn't work with Java 7 (IVY-1408) (thanks to Mykhailo Delegan) - FIX: Parsing publication date in Ant tasks not thread-safe (IVY-1412) - FIX: NullPointerException when using httpclient and server doesn't return content-type header (IVY-1400) (thanks to Frederic Riviere) - FIX: Properly handle evicted nodes in ResolveReport - FIX: Artifact repository locking did not correctly handle threaded use (IVY-1454) (thanks to Carsten Pfeiffer) - FIX: Better support for "Bundle-RequiredExecutionEnvironment" from an OSGi MANIFEST.MF - FIX: When inheriting a module descriptor, also merge the exclude rules - FIX: Correct application of mediators (ie. override) during conflict resolution (IVY-1455) - FIX: Fix revision number mapping across namespaces (IVY-1423) - FIX: fix a NPE when loading a composite P2 repository with no children - FIX: fix missing configuration when fixdeps is used with a partial resolve - FIX: XmlModuleDescriptorWritter doesn't support fully extra infos elements (IVY-1457) ivy-2.4.0-rc1/ant.patterns000066400000000000000000000021671226750426600153730ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** #This section defines the sources to compile for ivy-ant.jar org/apache/ivy/ant/*.java #This section defines the resources to copy for ivy-ant.jar org/apache/ivy/ant/*.xml ivy-2.4.0-rc1/build-for-bin-distrib.xml000066400000000000000000000042411226750426600176330ustar00rootroot00000000000000 ======================================================================= Dependencies retrieved in lib directory Dependency report generated in report directory ======================================================================= ======================================================================= Please enter configuration (or comma separated list of configurations). Available configurations are: ${ivy.configurations} ivy-2.4.0-rc1/build-release.xml000066400000000000000000000663011226750426600162660ustar00rootroot00000000000000 Running @{antfile} @{target} > @{output} [ivy@apache:${antfile.dir}]$ ant -f ${antfile.name} @{target}${line.separator} [ivy@apache:/]$ find ${tutorial.src.dir}/build-a-ivy-repository/myrepository/no-namespace -type f -print${line.separator} ${myrepository.content} [ivy@apache:/]$ find ${tutorial.src.dir}/build-a-ivy-repository/myrepository/no-namespace/org.hibernate/hibernate -type f -print${line.separator} ${myrepository.content.deps} $ find ${tutorial.src.dir}/build-a-ivy-repository/myrepository/advanced -type f -print${line.separator} ${myrepository.content.namespace} Setting version to ${build.version} Setting status to ${status} ivy-2.4.0-rc1/build.properties000066400000000000000000000041511226750426600162370ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** lib.dir=${basedir}/lib src.dir=${basedir}/src/java test.dir=${basedir}/test/java example.dir=${basedir}/src/example build.dir=${basedir}/build classes.build.dir=${basedir}/build/classes core.classes.build.dir=${classes.build.dir}/core bootstrap.classes.build.dir=${classes.build.dir}/bootstrap ant.classes.build.dir=${classes.build.dir}/ant optional.classes.build.dir=${classes.build.dir}/optional all.classes.build.dir=${classes.build.dir}/all test.build.dir=${basedir}/build/test artifacts.build.dir=${basedir}/build/artifact distrib.dir=${basedir}/build/distrib doc.build.dir=${basedir}/build/doc reports.dir=${doc.build.dir}/reports test.xml.dir=${build.dir}/test-report test.report.dir=${reports.dir}/test coverage.report.dir=${reports.dir}/coverage javadoc.build.dir=${reports.dir}/api ivy.report.dir=${reports.dir}/ivy doc.src.dir=${basedir}/doc checkstyle.report.dir=${reports.dir}/checkstyle checkstyle.src.dir=${basedir}/src/etc/checkstyle rat.report.dir=${reports.dir}/rat ivy.minimum.javaversion=1.5 debug.mode=on ivy.install.version=1.4.1 #status=integration test.class.pattern = *Test source.. = src/java/ output.. = bin/ bin.includes = META-INF/,\ . ivy-2.4.0-rc1/build.xml000066400000000000000000000763741226750426600146630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doap_Ivy.rdf000066400000000000000000000050741226750426600152760ustar00rootroot00000000000000 2010-11-16 Apache Ivy Apache Ivy is a very powerful dependency manager oriented toward Java dependency management, even though it could be used to manage dependencies of any kind. Apache Ivy is a very powerful dependency manager oriented toward Java dependency management, even though it could be used to manage dependencies of any kind. Java Apache Ivy 2.3.0 2013-01-20 2.3.0 ivy-2.4.0-rc1/doc/000077500000000000000000000000001226750426600135665ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/ant.html000066400000000000000000000177531226750426600152530ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/apache-proposal.txt000066400000000000000000000173121226750426600174110ustar00rootroot00000000000000= Ivy Proposal = The following presents the proposal for creating a new Ivy project within the Apache Software Foundation. == Abstract == Ivy (http://www.jayasoft.org/ivy) is a java based tool for tracking, resolving and managing project dependencies. == Proposal == Ivy is a tool for managing (recording, tracking, resolving and reporting) project dependencies. It is characterized by the following: 1) flexibility and configurability - Ivy is essentially process agnostic and is not tied to any methodology or structure. Instead it provides the necessary flexibility and configurability to be adapted to a broad range of dependency management and build processes. 2) tight integration with Apache Ant - while available as a standalone tool, Ivy works particularly well with Apache Ant providing a number of powerful Ant tasks ranging from dependency resolution to dependency reporting and publication. == Rationale == Software development is increasingly characterized by leveraging externally provided components/capabilities and by a rapid release cycle. As a result it is not unusual for a project to depend on numerous third-party components which themselves may be dependent on a multitude of third-party of different or identical third-party components. Managing these dependencies - determining what the dependencies are, how they are used, the impact of a change, conflicts among dependencies, etc. - is extremely difficult and absolutely necessary. Ivy is one of a handful of tools addressing this need. While often compared to Maven - which has similar Ant tasks - Ivy differs from Maven in both its focus and philosophy. Ivy is solely focused on dependency management and is designed from the ground up to adapt to a wide range of requirements and scenarios. Examples include multiple aritfacts per module, plugin resolvers, configurable repository configurations and conflict managers. The maintainers of Ivy are interested in joining the Apache Software Foundation for several reasons: * Ivy has been hosted since its beginning in 2004 by a private company, which make people feel like it's a corporate product, thus slowing the contribution by the community. We strongly believe in the open source movement, and would like to make Ivy independent from Jayasoft. * We'd like to enjoy the benefits of utilizing Apache's infrastructure and legal protection. * It might open the door for cooperation with other projects, such as Ant or Maven. * We strongly believe in Apache philosophy, especially Meritocracy. == Current status == === Meritocracy === Ivy was originally created by Xavier Hanin in September 2004. Since then more than 20 users have contributed patches, and one of them has been promoted to the status of committer based on his merit through patch contribution. === Community === Ivy already has a growing user community, with more than 10,000 downloads since its 1.0 version and more than 500 users registered on the forum. === Core Developers === Ivy has only two core developers for the moment, but we hope joining the ASF will help increase this number. Xavier Hanin is the creator of the project, is an independant consultant and co founder of Jayasoft. He has an experience of 9 years in Java software development, uses open source projects intensively, and started his real participation in open source development with Ivy. Maarten Coene has joined the committer team in may 2006. He has an experience of 9 years in java development, is co-administrator of dom4j, ex-committer for scarab, has contributed patches to several open-source projects and is a user of a lot of open-source projects. === Alignment === Ivy has no mandatory dependencies except java 1.4. However, it is strongly recommended to be used with Ant. Ivy uses also other Apache projects, especially from Jakarta Commons. == Known risks == === Orphaned products === Due to its small number of committers, there is a risk of being orphaned. The main knowledge of the codebase is still mainly owned by Xavier Hanin. Even if Xavier has no plan to leave Ivy development, this is a problem we are aware of and know that need to be worked on so that the project become less dependent on an individual. === Inexperience with Open Source === While distributed under an open source license, access to Ivy was initially limited with no public access to the issue tracking system or svn repository. While things have changed since then - the svn repository is publicly accessible, a JIRA instance has been setup since june 2005, many new features are first discussed on the forum or JIRA - experience with a true open source development model is currently limited. However, Maarten has already a good experience with true open development process, and bring his experience to the project. === Homogenous Developers === With only two core developers, at least they are not homogenous! Xavier and Maarten knew each other only due to their common interest in Ivy. === Reliance on Salaried Developers === Maarten is not paid to work on Ivy. Xavier's case is more complex, as a co founder of Jayasoft, part of his time in Jayasoft was dedicated to Ivy and other open source developments. He now works mainly as an independent consultant, and thus is not a salaried developer. === Relationships with Other Apache Products === Ivy has a strong relationship with Apache Ant, and is often seen as a good companion of Ant. Being part of Apache could help for a closer collaboration between the two projects. === A Excessive Fascination with the Apache Brand === Even if we recognize the strong value of the Apache Brand, the purpose of joining Apache is not focused on improving the visibility of the project. The main focus of this proposition is to make Ivy a more open project, with a closer integration with Apache Ant. Even if Ivy does not join the ASF, Ivy will move out of Jayasoft umbrella and try to attract more developers. == Documentation == Further reading on Ivy can be found at: http://www.jayasoft.org/ivy == Initial Source == The initial code base can be found at: http://svn.jayasoft.org/projects/tools/ivy == External Dependencies == Ivy has no mandatory dependencies at runtime. For compilation, it requires: apache ant apache commons-httpclient apache commons-cli apache oro apache commons-vfs jcraft jsch (BSD, already used by commons-vfs and by ant) == Required Resources == === Mailing lists === * ivy-private (with moderated subscriptions) * ivy-dev * ivy-user === Subversion Directory === https://svn.apache.org/repos/asf/incubator/ivy === Issue Tracking === JIRA Ivy (IVY) An import from existing JIRA issues at http://jira.jayasoft.org/ would also be very much appreciated == Initial Committers == Xavier Hanin (xavier dot hanin at gmail dot com) Maarten Coene (maarten_coene at yahoo dot com) == Affiliations == As stated in the Reliance on salaried developers section, Xavier is a co founder of Jayasoft which used to host the project. However, Jayasoft is shifting its focus to local consulting and thus won't be involved anymore in open source development. The participation of Xavier in the project is thus made as an individual, not as a member of Jayasoft. He also strongly believe in the meritocracy principle, and he's ready to see it applied to the project whatever the consequence are for his own weight in the project. == Sponsors == === Champion === Antoine Levy-Lambert Sylvain Wallez === Nominated Mentors === Antoine Levy-Lambert Stephane Baillez Steve Loughran === Sponsoring Entity === The Ant PMC has voted the following resolution: The Ant PMC sponsors Ivy moving to the Apache Incubator. If the Ivy community wishes to move Ivy to become an Ant subproject after successful incubation, and if the ASF board agrees to it, Ant will welcome Ivy as a subproject after the incubation period. ivy-2.4.0-rc1/doc/bestpractices.html000066400000000000000000000347301226750426600173160ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/compatibility.html000066400000000000000000000037521226750426600173340ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/concept.html000066400000000000000000000611521226750426600161140ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/config.js000066400000000000000000000003771226750426600154000ustar00rootroot00000000000000xooki.util.mix({debug:true, jira: {ids: ['IVY'], url: 'https://issues.apache.org/jira'}, shortcuts: { svn: {pre: 'https://svn.apache.org/repos/asf/ant/ivy/core/trunk/'}, ant: {pre: xooki.c.relativeRoot+'use/', post:'.html'} } }, xooki.c, false); ivy-2.4.0-rc1/doc/configuration.html000066400000000000000000000026461226750426600173330ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/000077500000000000000000000000001226750426600164355ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/configuration/caches.html000066400000000000000000000026751226750426600205630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/caches/000077500000000000000000000000001226750426600176635ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/configuration/caches/cache.html000066400000000000000000000027231226750426600216200ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/caches/ttl.html000066400000000000000000000027171226750426600213630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/classpath.html000066400000000000000000000027041226750426600213100ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/conf.html000066400000000000000000000027011226750426600202500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/conflict-managers.html000066400000000000000000000027241226750426600227240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/include.html000066400000000000000000000027001226750426600207450ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/latest-strategies.html000066400000000000000000000027241226750426600227740ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/lock-strategies.html000066400000000000000000000027161226750426600224310ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/macrodef.html000066400000000000000000000027021226750426600211040ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/macrodef/000077500000000000000000000000001226750426600202155ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/configuration/macrodef/attribute.html000066400000000000000000000027371226750426600231170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/module.html000066400000000000000000000026761226750426600206230ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/modules.html000066400000000000000000000027001226750426600207720ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespace.html000066400000000000000000000027041226750426600212620ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespace/000077500000000000000000000000001226750426600203715ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/configuration/namespace/dest.html000066400000000000000000000027271226750426600222260ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespace/fromtosystem.html000066400000000000000000000027461226750426600240430ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespace/rule.html000066400000000000000000000027261226750426600222350ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespace/src.html000066400000000000000000000027241226750426600220530ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/namespaces.html000066400000000000000000000027061226750426600214470ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/outputters.html000066400000000000000000000027061226750426600215660ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/parsers.html000066400000000000000000000027001226750426600210010ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/properties.html000066400000000000000000000027061226750426600215240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/property.html000066400000000000000000000027021226750426600212100ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/resolvers.html000066400000000000000000000027041226750426600213520ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/status.html000066400000000000000000000026761226750426600206610ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/statuses.html000066400000000000000000000027021226750426600211770ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/triggers.html000066400000000000000000000027011226750426600211510ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/typedef.html000066400000000000000000000027001226750426600207620ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/configuration/version-matchers.html000066400000000000000000000027221226750426600226170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/conflict-solving-algo.html000066400000000000000000000112031226750426600206510ustar00rootroot00000000000000 Here are some explanations about the conflict management algorithm in Ivy.

First, one should have a good understanding on how Ivy resolves dependencies, and especially transitive dependencies.

During the resolve process, ivy visits each module of the dependency graph.
Let's call each module a node, including the module we are trying to resolve dependencies for.

Each node should be able to give a conflict manager for a particular ModuleId.
Let's name it node.cm(mid).

Each node should be able to matain a map from ModuleId to a resolved Collection of nodes.
This resolved collection will never contain any evicted node FOR the concerned node as far as ivy knows, dependening on where it is in graph visit.
Let's call this map resolved, and the corresponding resolved collection node.resolved(mid).

During the visit, ivy should always know from which node it came to visit another node. Let's call the first node from which ivy came node.parent. Note that this concept is slightly different from node parent, since a node can have several parents in the graph, but there is also one node.parent during the visit.

Let's say that a conflict manager is able to filter a collection of nodes to return only those that are not evicted. Let's call that cm.resolveConflicts(collection).

Let's call node.dependencies the collection of direct dependencies of a node.

Let's call node.revision the module revision id of a node.

And now for the algo. This algo attempts to evict nodes on the fly, i.e. during the ivy visit, to minimize the number of resolved modules, and thus the number of ivy files to download.

It is presented in a very simplified description language, far away from the whole real complexity, but giving a good understanding of how it works. In particular, it completely hides some complexity due to configurations management.

resolve(node) {
	node.resolved(node.mid) = collection(node);
	resolveConflict(node, node.parent, empty);
	if (!node.evicted && !node.alreadyResolved) {
		node.loadData();
		resolveConflict(node, node.parent, empty);
		if (!node.evicted) {
			// actually do resolve
			foreach (dep in node.dependencies) {
				resolve(dep);
			}
		}
	}
}

resolveConflict(node, parent, toevict) {
	if (node.revision.exact && parent.resolved(node.mid).revision.contains(node.revision)) { 
		// exact revision already in resolved
		// => job already done
		return;
	}
	if (parent.resolved(node.mid).containsAny(toevict)) {
		// parent.resolved(node.mid) is not up to date:
		// recompute resolved from all sub nodes
		resolved = parent.cm(node.mid).resolveConflicts(
		                                 parent.dependencies.resolved(node.mid));
	} else {
		resolved = parent.cm(node.mid).resolveConflicts(collection(node, parent.resolved(node.mid)));
	}
	if (resolved.contains(node)) {
		// node has been selected for the current parent
		// we update its eviction... but it can still be evicted by parent !
		node.evicted = false;
		
		// handle previously selected nodes that are now evicted by this new node
		toevict = parent.resolved(node.mid) - resolved;
		foreach (te in toevict) {
			te.evicted = true;
		}
		
		// it's very important to update resolved BEFORE recompute parent call
		// to allow it to recompute its resolved collection with correct data
		// if necessary
		parent.resolved(node.mid) = resolved; 
		if (parent.parent != null) {
			resolveConflict(node, parent.parent, toevict);
		}
	} else {
		// node has been evicted for the current parent
		
		// it's time to update parent resolved with found resolved...
		// if they have not been recomputed, it does not change anything
		parent.resolved(node.mid) = resolved; 
		
		node.evicted = true;
	}
}

ivy-2.4.0-rc1/doc/dev.html000066400000000000000000000124611226750426600152360ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/dev/000077500000000000000000000000001226750426600143445ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/dev/makerelease.html000066400000000000000000000272341226750426600175200ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/extend.html000066400000000000000000000056071226750426600157530ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ideas.txt000066400000000000000000000107651226750426600154250ustar00rootroot00000000000000- messages it is quite difficult to know exactly what messages should be output to the console or not, and it often depends on the user profile: beginner, expert, build manager, simple user, ... Being able to define the messages output in a single and homogeneous way could be a good thing. To allow this, maybe a solution could be to output messages in the code only by using keys: LOGGER.debug("unhandled.revision", mrid.getRevision()); The LOGGER would be a constant initialised with the class name. a profile wold consist in a message.properties file, associating each key (prefixed by the FQCN) to a message for the given profile. A key with no mapping result in no message at all. it would be possible to disable all messages of a class or activate only a certain level per class (as in log4j for instance) to customize a profile at runtime shifting is costly, about 400 calls to messages - promote task to update an already published module with a new status this task would also automatically update compatiblity data (see below) - tag task to add one or several tags to an already published module tag could be added in a simple properties file next to the module ivy file this properties would be updated by this task every time ivy parses an ivy file, it would try to locate corresponding tag file, and if any load tags in the module descriptor instance - compatiblity data tags could be used for to indicate that a module has some compatibility level with another one: if module A 2.0 has been tested successfully with B 1.0 and thus obtain status milestone, then a tag "compatible.with.A.2.0=milestone" is put on B 1.0 then latest version matcher code could be updated to handle something like this: latest.compatible.milestone to be able to get the latest version of a dependency with at least a tag like compatible.with.A.[any revision]=milestone since all tags should be inspected to know that, maybe using an xml file like this would be better: This would be cleaner, but less simple, and less flexible than using a tags system, which could be used for other use cases. Another solution would be to put two tags on B 1.0: one with A revision, and one without. The tag without the revision could be used for latest.compatible.*, meaning that the last compatiblity status only would be used. For instance, A 2.0 is said to be release compatible with B 1.0. using latest.compatible.release is thus resolved to B 1.0. But now A 2.1 is built, and a first test tell that it is (at least) milestone compatible with B 1.0. The compatibility status of B is thus decreased to milestone, and latest.compatible.release is not resolved anymore to B 1.0, but maybe B 0.9... at least until the release compatibility tests are done on A. Then if it is release compatible, the tag is put back to the good status, and if it isn't compatible, the compatiblity status is left to milestone, which is ok. Consequently the main problem with this solution is the time before all the tests are run. So maybe a module should be promoted (and thus compatiblity status updated) only when all tests are done, or when an incompatible level is reached. Note that this solution is only acceptable in case of automatic tests. When the promotion is done by a QA team several days or even weeks after the previous status, maybe we can't wait for these tests to be done... Another solution would be to promote the module at eeach step, but only update the tag if the compatibility level is better than the previous one. Another task woudl then allow to indicate an incompatibility, if some level of tests then fails. switching between latest compatible and latest version could also be done without any modification in ivy file: use latest.* dependency revision, and configure your resolve task to use compatible only versions. this way testing absolute latest version for a continuous integration server would be easy, and if the latest version fails, latest compatible could be used easily, to test the module in a relative isolation of dependency changes. In this case the continuous integration server should notify of the first failure before notifying of the success of the compatible build: integration of latest modules has failed, but not the module itself. It would thus allow to have more often a latest successful build, even in case of api breaks. ivy-2.4.0-rc1/doc/images/000077500000000000000000000000001226750426600150335ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/images/ant-group-logo.gif000066400000000000000000000166311226750426600204030ustar00rootroot00000000000000GIF89aúA× ( 4D,D8 $P \X (8( <8H d,@X8p 0D0H@(p4Hp$,04 4H 4L((|<$\t@ 8Xˆˆ 0d$L$`Œ xT hT pH4(T$h(8x$@XT$lŒŒX$ld$XŒ,p T@4l„L,(Dd88|X,h@@@,Dd ,4DT˜ˆ$ 0<,Hd0Hd`<$H8|¨Pl(t¬¨ 0LhDHHH8”l(Œ¤<¼@ d|8 l,Œ\÷©ÿÏ´À!!°À>30&äSŸ=è=ÊφdKÈʰ%l e ¸ÀÆaÕ1W"D@¢è¢ Dì?dÄÿd¡D>À«9:Pûôc ¦áí}`ÙÖÇeW‚Œ%\`ö²¨ÂåEÀ°6ÔF‰ÆÁÇn²’íÇôP‰*X£D=m‚"mÁ†CyËßÜj€Bdé>l  d«1$ã(Q5ܺÛÞÞg(ðp‹k\䆬dàB'– 2Í4#;ˆAÂ0ˆæ ¢L ÀaqÔ郆  "kŸqpc%¶)8\}Àh +ø œA ~¤÷ñGz€û@£å›Ï}t‘‹(háˆ2sÈ(p¦,q@Œïà D¸j+˜Ä`Ù:¸]qÈB0´q‹Iýl]x¡ÈöÁ†ŒÐ%›ˆû½Ï (“ˆÈè· Šç5–ñNA´á´õô™Ç,è%ðÚ€ \ŸjØ ³CôáŽ`ôªÑÐ5.p m`Ù³À³&6! )0¡|d§ÿ¡ ×Gh Æ}‘Kׇ‹·>Òa|Ô@f7ûÛ(qˆ#¸!àðñ$ûðÃöœ?ðsˆb˜‰_˜Á yÂá{xŽZr<¬>h¯cTbÿÃÿáõ€µ&%ôÁG'nÑ’8,ÁMr( <á‹&ìËžˆóÀ]ƒDSã>À‘ºí£ cŒ»>¦B¶Ì DÛ' aЃ)î3½™qâ_8Â~Q <\¶lHÀ d›‰Å0£ p‚ùö`†2™½þçÈíc “£üË&_¹ÖÓ‡>d!-â,s‚°´^± @>¯V¯0ï“¥K–üÛº}sà"„! \¯A Ö&³pÀÀC8Œû<Ðá{±j{$~0:˜ð0Àu}Ú:û@ÃÍy—ýô¿‹<ðŽÜ¿;øå½Š `ø…ÜDÿ >þxÔà[®Çd¹ôXý– w}@Ïsÿƒ5îRUð%ÿâÝ@{„{0’ ]@PÀM­âЗ†m@[6? V _öQf%â| f‚<ÖWd°!ÛŽD ¢à/¨@ ¨'=Ü ä÷d b™÷î€@ˆ©tP÷¡ÜÀ ðhPtö¡à9ƒPøÖ0Snp^ö‘´+—æZ§€{Þ#Nãd(ôt"BP€?`w}Ò(9XTÐ]à†öa/`´ÿƒ¨õ8 ‰Ð`£ô4°™€ Ø ð‰7ÙÄ à$ÖÝ0~!ßSp³@i/“Ý Ih EÀógy  ‘ˆ#; Ñ€ÚÐ\` Ò¢ÆuÉæ„I…E€¢Üð Ý@ ÔÀ¢Ôƒˆ³`ŠÖÐ â €€ ‡à°€ùeáplà$ðiµÞŸÞÐ^Ð*®’ Þà Ñ æyž¡‚ 1I0g( °T` ^à–@y‚ x þæpªZ€ ¯0 @wPU•àmlY9@€’ˆ5KR`¶ÿÄ9K P›˜EP©°h˜ê 2ó@w2pzZ_€H.à Þ pêWPBCÜ4PpAW`€7"¤-De# á?·€ Èð Q ¥± ÃP ‰€q¦ù7`B‹àQ w½P £‚ Ü ‡@*Í ˆÈ Ïâ 2Ó1£–’àlÉÞø…jCªC<´ÐX`ÀGL —ÉÃGöŠYwgçD‚$ ç*‡ÄD6Ú/œà ¡âHtÒLdÇ Pj*µhˆkøs13 ÃÀ Ÿ€¬!ËÀ ¹ÐºC¦ù†03@;cÐ ÛÿÇHŒd*¶ÀHÝ”œP§žð£¨À61Ã6¿´¯ ›ñZGðÀ!ÀOËCy À`@çXÐ<Îó<ŸS0¶%PzP%_¹¶x`‡€ 4i µ ÉD x  Ðc³ò·VÀ/X ™ U# Ë0]Y‘!ÃÏp $ ]ú*´0P>ÎX­âYÙZ @Å S$ºÄà³¾00œÐvŠ Mp5³ RÀab×eJÛG îPhÐ~R©p×ud°•ÿPŠpR[ @uE zõñ5Pµb )à _à —™T“Љ±ÿâ #0fP8P xµ€ pg@¹à¸í’9ËP ®ð‰ƒ1„°ï1H`´“$Ø”MhˆMÅð ÍÄHÀ z@§ˆxt0³–%É9ä®1àĵ‰À["¾;‰±b Ý¥GAÒûÔ ˜0B zú‘¢P7Þ‚ QjBå“QÚ8lsÐ%ÛÍÀ¸!³ Ç@U'Ð ‹ À7¦9wIÖúŒ 0ÀoðLv‡ ¾à}œ ©; äjH’b‡´ UÀÂõÀ[¿+h@¸eèP„ƒŽŠÐ?¶Ôg)ÀÂúÀRð` aÂÿÿ0Œé𘵀IÜÔEPPÀVÜwà°VëpÙ  Ù Œìr ê"Bð ÛmÐ ¥ð¸C{0ˆ ¥—`Ô™äoð Ù**o€³Ú‡³Î² ±» M€°’Àz0 žPÖ u5Љìí—Ç —õ¡ ‹ܛàLGG`@ûgRËÂ[ËM9 o¤1æ T µŠø`ϵ0 ;[ ¢.pİLdÇËÚåpòPp0 ê í°å Fœ5\p TEËŠ4C_jB@­RÛ$BÙTˆ­) 8«M@§53CÛMP§§ÿÈwU ½õ"9Íð » —)™k•³÷±¡ rÒ` Ò„¹D~$šŠ` iðf{gŽ<=O„ ¾À P @؆ˆ¾Æ^}Óí £  òpùê0 ªBÐÐPÑíR ê¢ÊJ< ‹Ã'P>å3›Ò^à -f &MÀ½àHÒ2аG®Øö£`\Óõ±_˜GP–%2Ôÿ0¡­qÔ]cÔö¡»µrÑc!ÐXÄÉ}ôs ØàäcB ä­BŒM„øØÙ Šy6@G@±Pv³Wp“ßüÀÿ¶…Up€·Ý‰û _^cËÂiðGå,ÎÊWÁÐ`D nÍp]¨ýâЭд`â÷ÐÅ ª íðÖç£@èÊâ ½ ´0éñäeÀ‹£FM]Ð4;þ3€¹ƒMì¹3PÒY t ½ð^pÜ ‘\ •Ü Pëÿ3ÅWဎüô»;Y2°eã`é §Ï,–þù Ô 9Ѓß` )ÿO—úÓ³T:êpçÐò ëîîíàÜ(ÞÖáNîªÊ-ÊYSxæp Ê: 'Ðæ¢1¸BI0Jç³cà²å½IezØÑ#b¡@—€I Wpvöpx`ål0÷µ²ºò÷á ”€“±’ÓÕ[+ÁpR%YõÁ¸»´8‚ó:Ÿ < å×ÊàîÊ-:ßíÌ­ ´€×Á#õI\õ »"?à ® 1f+J;n/PB´Ó›Ô*Np$ÂkÐ*6K­DiWÀ¦÷á ¤÷˜æAìZžˆ¸€Ù0B:ðS€¼ÿÐÆðâêD™GGð£ÿ ÓŒ—S¹[9裠 Ùp˜Öá® ò? çéé)CzÍ Qð mAõ‰ÀÄQ*R—D®"ÄÐ…¡=f(ÌùcÈ'… i kÛÆ =,6j4ƒJ&lØ éZÓè 6gμa£C'ž–Þº›tÄF¯_˜Ü8³\8?GPØ åì&8jAÃ=uJË‘*Á˜Rg­¨ QÄ€òÃÔ[T`³´HY5Ë*I.”©k§euU](¯üúí[àÂÜ ªÄÉ»wnš*Gæ?†YòdÊ•-_Æ YH-.ŽkûåÓ±a®JEI4¬U©DF"ÔÿÆÌHLÒÀÊn* æH¼xã *OŒ±¸ÆK )Šid<§ˆòÒK;¦+40á±E¬ ”^ß©ãùpÓLLÄŠ¹ÐrÊ›GB¡š¥ÇE¯b¿láqƒ†@ˆ!—CbàÄ—YPñD8Ĺçži”‰0Bq.8LuF¡KÂòJÀ¯ô ŽlÖi&3Wd±Å̸Â!ž9†™\D#m˜6^peµH^è6B `#“˜! m$`0Ò1n΢f°¨V~ù…˜7œ”Kz¡ƒ<0â í´û…@y“?V&HpXšà?‚N8Ùtó—þÿDqá`Êš…-(¼'Uk'qÌçžv&­ðºK€.8  Ubt1UUWU‘‹[n‰‘‹ejŒ‚Yd)Å (’‚dè…^[à……ùãcD‰( 1ãJCþÈò"ÞŒ '¶ʼn+àì :Ê|ó )ó’3-†@`´8·LA¡NQÚ Ï–EC|”±LÕ1,B„Û¹'ÓM!<ÇDyÚQæZ²éƒU7æX2.>vLˆen%¡ Y\Id‚ú„Õ¡`؃¡`6Ø’@âØ†xaŽ=$’ȉ .Ô‰$²äÒ r{Á ˆÅ ,ÿAZD]¡µ+æ òø+F ÌÐòi/@ ê^¼€¢+‰á eòÉŽr*Dxš†ËQæœ åå­ cx™Ž'œp!PY–D.øDFZiùVW~8Á•#ùFJBæc)°­IC’¨×L'ºú¢mˤ„Š´\¤'`¨$'( _A{yˆ ùhì1@b½Mþü#F‹€ËQ%› 7M†áK§a¸álF™¦œs–¡Eˆ ?üe-ñ[FŽQäcÊb4Y†I„„‚&Ç û9ÿUH†˜aËF@H¢Ä?âýoÀËÒ ^:‹Ì e‚‚ÒÈE $ÁH?»È Æ@­ÿ-Í ¬xS1î4 y$Cz»‡<Šï4z âfu«ø•L›ëÂC¦UˆÙ%bf]Àr,â„(D€N¢€BšEâDÚ_I!™! / Dæ0d" Ó&@‹rp–ë8-ºWŽr@£¿f0Ïw‹ò™CË`DNÐ…3Hd E,Ã!ñ¬va „R › éAÉάe®!"¡ƒJöCe&@$°A˜ÙÇ8#w(“"Ó Äe,˜ÿh@é,@â ?£§Œ–! Öà ¢éÍ3$T`„ jPzô g°æ”@Pa ŠÐçà;ivy-2.4.0-rc1/doc/images/apache-incubator-logo.png000066400000000000000000000140751226750426600217130ustar00rootroot00000000000000‰PNG  IHDRå9É5ìBsRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< pHYsttÞfxtIMEÓ /vâ“IDATx^ímhž×yÇ;gÄ­ªí,cx#Î 3³¼L]µ¡l^P—´{Ú:í³áfj1Aa^kZ—ŠÖcb3Ì0±yL0/Ì+ê– A#6ñ@£ÉÌ QB§²´õpÙþh`ùÓûwäK\¾rîór?·¤GÚc¸yäç~;/×ÿü¯ë®sžsÕ¿w þ Z`ÐýÓ€rðoЃèŸx—-ÊÛo¿íÇ  Jlà­·ÞÚ›éµ[’(ƒPP7oÞLknß¾í“×–€¼äÚ:8”<£äÚvá~Ú”} Êëׯ»“'Onü¿Äxz½vjjÊ?ÞÅÀ9==í®]»æfçÜÌìœ/ßÿ|kÝ}û¾îþãþÔ­Ï͹›K×¶µÜ½Ö»äþ­èžå™3gܾ}û6ûï¿ß픋UÒÉúZØG×a®2ð¦ÏjzߥK—|èêêê;Þÿð/þÆ\{ûõu÷òðÜWïë¸ïí{Ø­Üû˜»õ㹫GFÜzç¤[øØ¸û¯—^Üöz4­É}mtÏðBmÐü½´´´«ŒÁ‚òòåË;Rþ×^{Íu»]ßž§OŸv ›å˜üâ—7A 0¿<ç–Þ3îËõÀ|þ=¿ænßó¨{éà“ õÚÿìÖ¸ùÇÉ­ž?ãÖ®îLÝJ@—{màÜP¾ñÆnvvÖ=ôÐCï ˆ.\¸à¸.·òu×áNY@òÿ‰‰‰žŸÝkÙJîïPJ™çç¿æFFF|ÛŽ;þãÆ÷ݧ>÷8ù”gtÜ}ă‘O€¹ôîÇÜõ{Áòÿÿ»ç1ÿ7 °‹‡y&ýæsŸòl[ÒN»éÚ\Àn)(oݺåc":rttÔóÊ•+þ`Ä}á…|çrŽkŽ9Ò³h099åðð°{óͶÞáRýYb(´÷Ú˜‘ïôàbÅ”Ð=¡÷Ê󹾤\¡k!q¦”‹Aöܹsnì·>îA97µà&ú\zÎÍü¨ûû¡ßv³?ì^x÷7A), (aU€ùýºk£¿êÖ?>ê.=2êþíóÏú˜´º×z·y0· ”ÎãÓŠ¸˜4öÿþ÷FCgc4¤¹ICðmȇ¾ëÿ¼Ë>W ¹O$òƒ…½æ 12ß1Àüuq,®h×À B-(ù¿´i ¬R?bÀ£G¾£Œ¼÷ÕW¾Ù¨}åÙô1¤ÔO`Nv¦]÷ðY7>ô{þøý⦆ºþ8wà´û§¡§=ƒÔ•ýö_ßÿ!Ï¢¸µ0è•Cì¹zèa÷ê'ÆÜâØ#î_žøҽ¢)`¶JŒ#!åN (¹–k¾ûúwÝwÖÿÓ­­­y7£+6k´Ö°,,(/^¼X .+aŒr¿s ¸yšù»Œr?%mZ7؃¡îZùP5ø˜á^ÔVØ/@íû ÿÎc޹ñ?ãÆî?á>:|Áƒ“ÏÓCŸöì 8g‡&Ý¥¡Oz& ÂšÄ0&®-ÀD4ÂÝ€®|fÔÇ¡tíâŒWz›Ô¡î‰³UPb€1Ætf ŒîŒââ"•2¦¸Áâ Óøš-1ìSr/†~–2 × ´.¹¸O¿Fƒ…ú‰Û+ —:‡žÅûDtÑÏÑ岑¼#Ô>¥Êà‰¨ ;“þ”Ó3îÄOM¸ÎÏ}Úºçg|=GoôƒS>=ô¥ÍcbxÚq‹âÂâÞƒò 09`O‰CaPðâæ @aÑõÉ®G¯~¾ëÕÝ•ÙJé7X@©•Wú‹i™áI/ô¸“GNz€ ƒT:~ß³œ¸¹0(ñ'ÌyæÐ¤gR€y}¥?Tq(î­0'å€=×ï{Ľü“ðî®þníØ1ïêÞªÜ^^ŽåjfyzCáíG†€Ù(1ؘË) ©‰Û Câ¶ QO™¾Œ…bAkÐÖàd^-åÂÆ@É;¬hßK˜C”‰þ§žzê®{p%C K©Á)¡Ç2.ïdú{€¯,û—Š?ôƒ&"s”÷âÆ'É"ÚÌ?p»¤Œ€@Í ”ñ×<í¿Ã½¤þsøïÖâ⢘ó~Ì?@òX·V#\]ÀbW|ktÄÇ§ßøÊ“þxþ¹'|™ßüÁígÒ-%_Cb,GÂ’"ìÀt²0$n«$OƈˆE)·"dpâ¶iCµl—¥}®”Ï $¤X (¥.rå9V§& ¤=S±¤>O’Eª]Cçé'âkL1pX  üëÏn㸤 €>rÆ=sàK^øé:ëNû¬gMaQ>¤‡'6Øô@§fP˜€Â¤‘w£þíÇýß""ùrTñ)1é[Õ5ý¾Že#‘€£â“Ô¤-z½gK@)€¬c3 H+ìJ$n ©§KD4ŠUÊ6H¦aêû+°„IâP€„Û¬ _ØÈf¥\ÇúªËbJ¼ý=¢1(ý$ËgÓ,!¯ðzè_ÛW~~ăRÜJâ?@ñ×ïtSÇN¹ß}ðs”òÉßv=ë…!)uxàÞ£®óþg}œ ‹Â–°(‚‘ˆF¨¸Â¢7¾ÄHL˜•r1(ÀȜǭ]­@Êýœ{}ÿãîëïÿE“®­\öõél¹÷·J\FŒ6–IJÉuŒ°Â’"ì0ò 1FX„iŒæìÙ³ÞÐb±% .aˆN§“J;Å",k§¤:†£>ºŒ© &LI;ëwÈôJ®ôz[ª”:ë=ÐñŸ/˜póG'6UWbÈóïýŠ?pm&`¬ü¤0'ÀÔõA8Ò@•{%NåÞÉáSw1+ ØÄ¯€æäœ€w€¾}rÜÏ‘N˜õ±ïæ®^™tëkSnmuÊ­¯/·ž®Ù:(1R-@ØNÕq¤$nv% @Âd‘„ç3ï8ëŒÆ²™e«Xj¶Dèá$vOÃÙïC‚m"U¦´1ph~•kd.6WD++ª'Ê(‚ .ãêè„(̉«‰ºŠû X‰ùvíÄÕ…Eùô‰Èpi-Œ P5£ZD$˜Ðr÷áæÂ¬W¹1/:êÙ€J ƒñ)1«dƒÞž®€zqÜ-ÎwÜì…1·º|ÂÍÏmm±i« a¥Ž%5C†âH\VQZEØñ$, ™Cœ™™ñs{+dÖe«›ll(B˜#vú‚ί»G¦R“û6™wÈû¨ŸV¯›0%í*ƒ{ä=)¡Áxýß¿á§&®þÎo¸•ñ®hXîz€âêÀ‰»‰PC\ƒ;|r“Íf˜ðßá‚RÔZaGÜV‰Q»#ÕôLN@*Ó2˜¿Gî=æÝh¯ Wn1À•ô?X€2`LÊxã‘·|¡ãþù« ¼±Þu ó]Ìk/}į¼<Ó3s¶ J (4O CjaG”V-ìà²j@ŠÛ* ™b”2©n Àº’uÌš¿ãY¹É$È»í@sµÂI{„’åõýuÉV) Å”R>¼Œw>åB÷L¹[XeÁ-žúMïÞ8>æÕS@*œÄu€V’Ö=`ªÿ“P``QÀË'å;âUaY‰=»V®0ó£’]Ûz‰i™ê€u}’ÃÑŽg_Žî¾÷ù?ÄŸ¹³]·r©ãþñù'ÜòÂÆçúRV`|óæÄ&8ç/÷àlÚV­RŒ2$=õ¡…RÜVXP.Q-Oœ8á,Tq@©ÅŒ:Á F××ÕÍcre´›Hìu²ÄI¿Ç :´u eèÀœ¢ÊÒN±çès¡ˆØØ9NTcÚUg(55ª’û¼b[ );±ÓLüV@I,Ç# .l(%«àâæ0švÌòà°0-L h‰U%«WW™ø×ˆ9U™’-¹F…M§O¸«>î^<ÿ¤ÿü«scw|Ç5œ_úËnã9ÐÖ@‰ñ„&¿…%…!Ei•¹HQZÅm Å‘ aIž”)ŲÄ@äZË””­És÷”m¡‚hÂ4Óˆ(¸¹ôúÂS~C2x$«ÇÇ¥wT]@êçFï¤äù´¼ê;¹V\S€·9¥r'#@s2¥x%íOrq9çÙ¸z`ț׺ÞÅu€ü†$ΔO¼Rh-£GXÒ.z…¬ÒªsZEiÕq¤v„!Åm<2°ÂÄ”e`*5¼’ë™ÌgΓxÔ3j%áN2ˆã²L ˆYòµ¹ôëèÈfz× ºÊBkïþVàå~€Ì!1¤,-ãœNëã}~ígõîKV•áN‰+KŒ @%qfS÷5”\kHDƒ˜vli)ÂŽVZ¸W¸ƒ€’Ô.Ü0+â‘$´ãò¬TjÕ”ýʺ¾Åí•›Z¾8ç'§|ܳ®v'=x*.ïÚ¡‘ïª)æ%qùžx–Ô;ÔaþØ\wk¼Zt]M JqžÅ×ÄÁ\㦢º¾úòÜòâÆôHÉ€º¶”1`†T;GÚ¹ÈP  Y§´â²HaIyêÔ©d^-IîLتNŒúÿê¾Ú$Ý^ b½ÚVÜËœ -CÃÙHöBgD7×–üФ:µ85€·]·VA©•À:aÇæ´Â’¢´r¿žú°q¤fH&À…ýb¹šu**™>{m¡l/Æ¥¤öòü­¸7ʭж¢=3e]¡¬êªãÈÐÚÈPÆŽN¡ÃmµJ«Ž#$,)s‰±˜’ëê¦È Ú®†î÷÷ì5¦ mèÕï} åËfÊX…dB[®‘82H›Ó KZ@J‚€VZaI GòøñãµS"RÜä(õüân鬭,ç€)û'†ÎeÊ$×5¤´êœV»6R¦>´°Ã³Äm•8RI)n+óq²aSª|’'+à$é`0Åq·î5¦ÜóîkÊè%]K²n)–¤ÐÙ¥X¡8Ræ"Cq$€dŽ’˜€¥ÊÇyÙ(*g‡ïœçíµköSîy÷5e€$ ½é•Nˆ¥Ð± VrZµ°RZvd¥z¦Wv¤Ê98_ï¢Åö£¡ Sr–oW;ï&¡GÚ/‡Á[q_q IKeìè¥X¸¬9€´q$ ˆÄ„€2¶Jãí©#n,å‰Kè~I­„©{.¢ å»â’ÇÊeº@'–ëU&”Ïž“ÿÛ²Ç@ ëôsŒÌÖ`Ó¯<Ó®w•5ž9L%ö!uM…*¤ur­ÝBú¹‰úŒm…ú7GËh ”Œù»X9gm¤VZÅm•Œ™¤ÑpY$'"O*›GâÎØ%†˜Jç™4r.{„òbë”aTãºçÚ•"ö‚Ðì±RPêw¦æ|5(QÖCóÆ¡v¸±i«œx®^¼®Ë‚­Jªf*QŸ0)wŠíˆí¦<‰V@ ›P¹ºÝ©dm$ ’Uz)–UZ¥VZ5CHF±º"ºÒM˜’ò¥:É®àˆì`¹¯Ÿ‹!„ŒÒî’¾Ó äýuk4¥/¨GhÙ[ªIî¯órAZõ‚§V²+…”“°**»:ÉÖoÛ˜R¶”ˆ)­L}èŒX #¤0¤Ž#…!¥sSéu4^)Sb<9 YÒØ¸«)ã«;˜­ôSJÙc¤Å„¤TÛ08…6°Î¥eJ@ÞRÎ:w¸núM×oÛ˜RF‡PN«(­Èœ8ÒN}`˜T†QFX’Ц܀&1e/ÆroèÀ”Ñ¥ÎÛÁ§_AI=BqvÉ:Óº¶ ¬±ý JÍ”9_§ú¯ ôS1g¶Â”9†/F¢SèB›^ÉÔ‡dìH’9 .S"ìÀÂÀ"ì0s“äî¸V”°dªCbçCÛC6a]û»Ó^?ƒÒº±0\.xRmo×yæ>W3eʽL•AÎÛ8š²åÜÛ Sæ€RFB¶¬×;:§U~´Ç¦ÐéùHaHI¡³q$€”EÀ¹ó%1eÊØC»ëްâIêyÜKùbe”çëú¦ž»ÝB5F‹œ*kŽ!Ë5ÖÉ¥fÊÔûˆaSýÌ3l_×ýª[I˜#ý–zr@É5¼æÓ YšBRZÅeã%àºÜr•0eL¬Û¸J7º©R£²62Œ7´±—Lh•9eè[J^¿Ê¢:RõÒ,kSÚŽksŸk•öÔ”ˆ´Ä€vB ]îºé0}¶ÁX=ºì×”£à¶J^ÌïGˆÒZ'ìÈvš!cÂ ÄØ—°dΖ4X S¦&Ðå™±ÑVw”MïÓ÷åf"…Ÿ¥-G¬]5‹Ä×Ð.v+Ýf6^ý(Rh$Õnv Êî,oû]_ëkl7—D¸®5PÊ艛jiw¡“=vt .«Ä‘"ì êÈ#Òu»×ÕUº-¦Ô.Y.(c†–êÀ”qµÍ”¡yÈÜ2ÄÚ*Ô%s« ØuÏyS±2[w4gÖÌS .¶¿[¥¸4†$šÛm!õ¦W6§PJ (­ÂMYª¾¶Í”%FYcn¡FJÍlÊØ»CS¹u‹ L¥`·À‰-Ëõ-J²L™jgçǘ2¤§ÞèÆY©›õyµQRèô.tvÓ+ÉØ‘U:cGÇ‘0j+nMIYäÚ¶˜RйLÚkUß«™Âþ:˜}‡§rÊ;ÈÐV)æ+orcJÂË–%lf‡Å¶ ¶È±¬›Í‰)˜2%Ài{ܪ„~ ÎÍ_Ý*‚üì#«ü¼@lm¤vBJ«’ÆÍU[Kb›f—J5ËqiôûSFRõy;a»W6s.qíO””Í^«³^R`·êu (S™MòlÍT1—·¤Î–$bLÙ$wVì¨gPê—Ê×íB§Sè$cGrZ¹ @Æ^Iyv’)y“Ô²qØÉê˜ë–c\!0öÓð9Ï”k˜¯£J¹€½€’9И0$ÏÖ °¿ÝRR/}- ¼+˜R )ñ Ó»ÐéM¯p[%9@gì`IJó9J8O1y[êk¡‡²á:5íx¹/ô+X%Ænß_—‘³÷’~Æ{B¹¡©))öP”´oÎOÆÛ˜®W¶ µ__3¥€Dâ)f·…´q¤Îi¥ÂÄ0dÉÔÇV«¯MbJ)SŽáÔ7ö YM’ÜyK•êÚËþâtÉ€B_‡ÒÏxW£5%+“R±Ÿuɾéeð í”×·1eLíÂĈB ¥¡J–õ;SR>Ü,»V/ÇØ¹'”ˆ-u†…KÓør¦”š "€.6ˆ" ¤€Ù”Ò¾±*¤~6]%R·Ýæ¶2ejæ(8ûú m˜Hظ·m°£.ÓNÇ”º,BˆðR¿è,ÏÅåŒM¢ë6&ÍÝÔ¹æÜudîv1W¶)(¥-êØªNh‰ý®Š4ic+[»ßV¦l”Râ…ÐÑTYÍ$nµ)l¡Éb\îºT7=XÄÒáReÂx1LžaÊw(Ò¹‹¦å]¸Œ±|MÄÔêûP¹Yõ#uµF 3q.µKBè¹úG•¬Ð£ÀH·3ý•³Ó®¹ô£ *©yBIq´¢œüÔbÎ{sm'eö|P}m”¥\_¾í!F-_Û^Ç ?Êû£×6«em2Þ½¾xpÿöwö ÍwG›7å€MwG€¸ûú©'P꛿óŸònçw_ l¦Ùí¾¢J 'Ždižhª®ä@8ÃZPÏSei”Ht\” (".T`Áh24ÔdcÁ`,IJ (f’ªI  e™Ïht;ivy-2.4.0-rc1/doc/images/closed.gif000066400000000000000000000002151226750426600167710ustar00rootroot00000000000000GIF89a³úúø²® àÜÑåâÙíëåõôñ«¦šÂÁÁÿÿÿ!ù,:ÉI«½˜ž“ë\'} µG¬á¸¾0;Emßux|ïóºpH´¨AÀ<^MRàÄl¤Xl;ivy-2.4.0-rc1/doc/images/discovery.gif000066400000000000000000000005521226750426600175330ustar00rootroot00000000000000GIF89aÕ\\w\wÉ\w­\’ÉP¦ÖWެ6ˆ´L²[¬sœ²}›«\¬É\ÉÉ\­­’ÉÉ­ÉÉ­äÉ\w\w’wÉäÉ’Éw­É’˜¬|­Éw’­\­­\’’\­­wÉÉ’ww\’’w­­’ÉÉ­ääɹ³sÀ½ŸÿüòäÉ­“&&ÿÿÿwwwÿÿÿ!ù),‡À”pH,A‹dd&G¤ÉÃPPˆDrL‡ñ± •<¡Ò  >ÃÅäU8¡Æb ðÄ's%!|(q^|q  ž‰Bd ¦(Ÿ~BHJ&ž(LC{|ŸpE°±»M) ²(´ÃËÌMA;ivy-2.4.0-rc1/doc/images/downloaded.gif000066400000000000000000000001501226750426600176360ustar00rootroot00000000000000GIF89aÂh~Єÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,-HºÜþpÙ€ÖBÞ@÷Eœ§=Shž¦º¬Rvb,«5ùÚÍ5VHŒ$;ivy-2.4.0-rc1/doc/images/error.gif000066400000000000000000000011351226750426600166530ustar00rootroot00000000000000GIF89aæò\_ócfódgõ‡ˆðOVðPWîX]ò[_ñ[`òglïnsëmqðswõzõ|€íGQñMVñNVÝJTÞKSßOWõmuômu» Â+Î)8Æ+6î;HÑ8EÝ@MñNZëU`ô`mÓV_ÜirÈ)È*È+È+Â-ä/@×cnßvÎ"9ßš¥æ«µÊ]IÎn^Â[L÷‰€÷¢šÉG>öyö€yöˆ€àa[õvróytíyuø‹ˆñŒ‰òffóomí‚€÷‹‰ð‡…ÿ¿¿Û¶¶ãÄÄÿÿÿÿÿÿ!ùF,º€F‚ƒ„……C0.33./D†F/37?22?73/…03<659941:30ƒC3A8>E>°¯A3C‚";==BE=EB=@!‚ E¿ ‚$ÖÌ%‚# (ã¼Eãã#żîEíÒF"EüBB:ˆÔb…‚*L  C‹A*20h` ¢ 2¨(¤âÄ„,€!$!4\0Á! H0 ;ivy-2.4.0-rc1/doc/images/evicted.gif000066400000000000000000000003271226750426600171470ustar00rootroot00000000000000GIF89aÄè08è8@è@HèHPðhpÀ è 0È(8Ð`pÈP@ÈXHø°¨È@8¸88èPPðxxø¨¨Ø˜˜ÿÿÿ!ù,T $ŽdižhjFJëºQ™,t]'2äì¼á$Fd@,"Œ’PÀl ¥Æ@­IRƒ`èz „Fé0µR‡R!h»‘‚B¯×å$DaÏç#T€!;ivy-2.4.0-rc1/doc/images/grippie.png000066400000000000000000000002421226750426600171760ustar00rootroot00000000000000‰PNG  IHDR*º†tIMEÕ /Go3VIDAT(Ï­ÐÁ ÀP“[OX¢3Ô©Uiqè?ýÄ‹8ÖŸ©™­h8Dœ©ª†s÷f×Q¹\w+3g÷ykvy7,]¥Dôê¢?h™•~ÓÞÍ-9þ§þÊë<ŒfIEND®B`‚ivy-2.4.0-rc1/doc/images/hibgraph-small.png000066400000000000000000000215221226750426600204350ustar00rootroot00000000000000‰PNG  IHDRÈ~y  pHYs  šœtIMEÕ?(’ IDATxÚí}il[×ï¹÷òÞË}'ÅUIm–-É–mÉ‹œÚNûÍôuŠú}(ÚÎ&íƒ`Š´("(ðо釢(^òa€ P ýРéäµMí6vâH¦eÙŠ­Å’¨%R¤¸o—w{ŽÃ(²¼Éäåbþ`yÅ{xÎïþÏÿüW„çy 8Ün÷àà ¨£v KŽã0 «O}XEÆææ¦Ñh¬O}XEF0lhh¨O}XEEQAÔ§¾N¬ºŽUG5«,çÐ:†¨†¿[&“‰Äo`±¸ššZê$¨b!"Ìîܹ18¨Á°Jå‘‘ÛubÕÈVÈ0Œ dËrÛ_dY¾‚¢uÔŠÄJ§Ór¹\È;.-ùWVÖ¥R±\.ÇSz½úÖ­™\ÝÝŽúò׎ÄJ$J¥²Ô‡ƒßÿþ÷Á`þ‰$X–óûCÑh‚ D¡Ptk+§êk_Skkk«½½=‰|òÉ'2™¬Dwyçw~úÓŸ¾üò?õ÷wîx÷ĉÞõõP}íkŠXÙlV"‘x<žâ‹ã8AÉçó¯¼òJÿ­[#…w?üðæáÃû8Žw»'¾øÅ‹ÅP_ûšÚ á‘0N]\ŒŒÄb±X,véÒ¥cÇŽí0îëõ†a|±X²¾ê5(± u´‹ÅÂqÜÆÆF>Ÿ¿ÿÝ®®V½½m==®úª× ±J‡ÃÐétÝÝÝ÷¾›ÇS*•€¢Èv‘ à8>›eë ¨ë‰ÑßlbâN6›}Ц|äÈ‹uÔ±xžG„¢(±X,ˆ>‡öôôÕ׸,@„t ‡Ãáh4ÊqœÁ`ÐjµõÙ¯Ÿ ‹ƒ@ `2™°‘Öñl+—ËI$–eE"Q}êëÄ*ö@×ñl)ï<ϳ,ë÷ûë³_"( Fól™ ÐZ\\Ìçóuý½DX[[›˜˜Éd½½½Ñ:–—}¾‚Àž\@€|^yêÔ?V±âñ¸Z­ÞÚÚ,âïYƒÅbd2™ëׯsg±XÇý³x‡†öíín÷b¥H,˜C±¹¹i2™ÂápU¥†T*=qâ`ÃÃÂtww«ÕjÀ»ï¾ÛÛÛ{ÿŸPT>•Êò|X"‘|º.ñùyM3Ÿ|2K’D °¥Õ*q\¤RÉFN§2Ô2™f ärùåeeI¬T*¥P(ëëë}}u^É‘L&Åbñòòr&“I¥Rt·ì¥Rîó——ý¡P  Ó©âñÔÒ’ÿ¯½F’M3&“>KÀ+S© Çq6[C š¯0 c¦nymmmð—ËøÎw¾³ëeëë!–åär)‚ Édfffyhè àСN‰„ ¶¤R±Á ‰0¥RæóãñúéM‚.°ßï·Ùl«««õU//¢ÑhÁ‚ÚØhjl4`¸ö / ærÔ¡C‚ (jµ‰îÙº¬V#˲IÕ,ƒŽ…B:®žb_ðœ|ËËË>Ÿ/‘HØl¶`0¨Õj¡)±€ÆÆÆS b1 wÃd²Tù¢étjdäJ%þb€×ë{ÛÛ»Š5$¯weyy„$÷xôæ8 “9{zÃ_—––6664Í‘#GÇ' E"I’Ùl6™L l—Hyw»Ý(Š ©Tj2™Jq Ç£Ó­étª§gdpðùâ}ë½kÇŸ~BàСç'''3™ŒÓé4›ÍÕ"Y ›ÙÚÚ*ìO˜`Çr¹¼ÍV¡…Á-“IçóùXöFoo¯ÀµŸª‰Xp×/…3zïáÏãã³2™äöí9•J‘ËQ$Ix½FÑÔdN¥² ¾ŽŽfš¦m¶†ë×'ÍfýÆFØç ªÕrµZqð`G‰‡$Ïåòb1±ºÐhÍÍæT*;?oH&“~||Öé´cê÷o"òOÿô»Ý>8x¢uA!ˆUu/ѶûÛßþÖï÷?~\¯ ZŠ¢N»J%‡Ñjf³^"!$1Eåu:•\.¡(Úá°…Ã1­V©PÈhšÉå(“IWÄ!½ù曂¸\v;†DQ”ɤ‹ ©TLQy­öÞ,ƒÏ´ÙŒ<Ï.WwÅr!ˆ•ËåÄbq&“Ù!®Þ{ï½¢´¨˜˜˜ðz½z½¾««Õj…hý¼»ÕР #‰ØbÑomÅq\tâĽJ»½a›ºíEëEÏó8Î`ÛuH€`0ÒØhš™Y¶Z 8wî|«©É ªB+Ng2’$·—.ŠD"‡cß¾'޹^__×h4©Tjss³««kyyùõ×_—Ëå€ÝC…nÝš=þ¸Z-Ÿ]Q*ess«Ãî¦ÿÆÆÆ½}Ííûå/)—ËÝî¬p·oϽð ^¯ÞØ·¶ÖZ€šNèp8LQÇq6›­ðâôôtggçÞ>-™L Žãòù¼ßï¤bërÙ3™œÇã‹IAJ’ … {ä0 mmµ&“™ÉÉ…‡œd766ÆÇÇ«Ñø'„ÄŠÇ㉄¦éÂtC}koÞM›Í&‰<Ã0ù|þqŽ™.W#`ÿ~'üU¡(ÉÉÔf³177Ç0Ìã\Guúôá‡\c6›;;;§§§:Îår¡ÕPíYbq·Ã°¶¶¶]z=`|s¡úCÁ”¬Õj§¦ÜvûÞÝÛù<‡ã{ï¥Óé0|àÓ±i&'çåò=ªá,ËsœT"‘*~E"‘±±1Én·ÛKd,ŽéG©Ûí†?š_~üñÇ'Nœ(zJE2™Ìd2{þs Ãt:]qG‰DhšÞ£š‚¢:nWùDÓ´×ë ƒÐ®±ýš®®®J¨¹"œK§½c”K‘¨£P(vøÂÊŽe{ã8îp8`Ö·Û}ìØ±gByÏd2Á`°¥å^s‘ÙÙÙ½©íu%$I6›e SÞ£Z}ñ¢Ã0™LlµˆB!Éfó2™$ÇbÉöö&³YßРkll"ˆ2·›fY–ÜX_éõjŠ¢óyZ"!Åb’aŠÊ Úë×'{z\†îÛçP©TÂ2ff–77£Z­’$q@2™!\©”ÍÏ{Ïœ9R¬»`K —«÷ã>Ü™LæøC!k¯©É EI’H§s ^šf¤R2—£Ö×ÃV«qaÁÇ0@°r<Ï¿ûPèÓGVÌ0ìæf4M¬¯‡)*/•’jµ<Žñ<‰$‚ÁÀf3®¬lln–6Þ2•J½ûî»…©‹ÇSáp4—£xd³Ôò²?‰çryXô¦ˆgÃp8lµZ}>_y…lÒG®Ü÷¾÷=‹ÅòÒK_ýò—{óÓýëOººº…ù&¿úÕ¯&''ÿýß¿óòË{)(õ—¿ÜÑj»JDú—^z©©©é»ßýŸçÏ÷F"‰l–²ÙŒ…}*Mj4÷Ò!Ýî™ÁÁ¯?ýMiš?zôè7Ž9"<±DY\%N¿ù曃ƒƒ££ïo}xø¶ÓiŸšZ<{öÈíÛš¦þ¬€ŒÝnßsñ–']¼ï~÷»ããîÏSwÿ~çÿxE§S£(b4j1 •JÅ››Ñ#G>ªF£)ÑP“Éäý× ^¿þ.Š¢z½À²ì¥K£§O÷OO/©ÕбŠÇae–eË"±DZ§÷ßÿĉÃÃÃçÏŸ‰D»z6 ©R)“ÉÄÇ¥R™šéØØØóÏ¿P¬±R5<<|æÌ™wÞy'“ÉX­V à ƒL&[\\©T\ø¶¹Úa¤ iþòå˧OŸ.Ö2;vŒ$É®®®Âa“¦9ž¿gt@Qtß>Àé”~^7âŠ5WƒaiiéСC·nݪbmu‚Àç>uw¿~}AmyÃ0’$ÅÅÍqƒ#)È' à¶à~éëøä“ë<ÿ¤Ýþþpœøøã‡††Š2TXžd»µ¥­íøèèìÃpKÑ¢Öá8®\aÊOl¹Ñh´ƒƒÏ=æÅýë~¿Ö æûqôèÞ™ÑÕÕ522R¢8“Él2 Z\T,g³Ù²ØßKë„Öjµ6›mbb¢ZTN½^ïr¹FFFjCƒv8ËËËAPUSÄ‚ºöÓCF£±¥¥ett´ˆ¥R©‰„ÅbY__¯)b™L¦P($•JÓét­‡Åb±X,·nݪ ¹eµZ…/RZbét:‘H¤ÓéîÞ½[]‹a·Ûõz}mâ9C¤Óéf ª'–Ùl‹Å¹\®ê–¤©©I¡PLMMU5±ÚÛÛ=Ïc6r®b©Tªd2 ëžW—¦ÑÒÒB’$,…]¥‰D4MK$Ÿí’+ï°ÓIwww•.ËåÂq|nn®z¹…a˜Ãáðx<‚ºÔ ‚ 2™,‘Häóù*]˜¶¶¶ééé?üp‡5Žçy—Ë¥×ë+|ü °ëLí  ÕjU*•ÏçƒÛb¥•Ë~L<¨çÏððð±cÇ*°&Åòòr(jmm]YY9tèÐ76“–|Fìv{8Îf³mmmU½¡ì 艫ÀÁðQ¥RIÓ4ôí (*äÙ°äÄ‚¾*A‚¨ä¢{ƒD"Q©T•60Ng49tèEQ¥R)dmÒ’ ¦M’$™Ëåäryéš—Q{üÆL‚–4ÂqzÁ;::²Ùìêêjí‹ ˆ|>ïp8;;;«Ý,´+Ž=zóæÍJ¡R©œ››»|ùr(ï SSSJ¥2‘H`V®HÙRoˆ:Îëõ–´•úÓA±XüꫯþÇü³D.nd!Ï’´<8((± Ã0…Ý]«ÕÆb±Bû“*Åððð‰'nݺ¥P(d2Y 8tèÐÕ«WÍfsÅ&æ;Î×_ýÈE_Ÿ£èîvû„Þ Q…ѱ8Ž3 ãr¹ÊXP ˆ_ ­V«Ñhà†xýúõгÑhlnnŽÇŸ¸ EÑ‹‹k…_½ÞÇ=Úr!DЦB¡H$>Ÿ¯¥¥¥ΆÉdÒl6“$¹±±÷w’$ÍfóÒÒRkkkŽy||ük_ûÚßÿþçæV++ë™LÇEJ¥Ìï±,×Új!Üãñêt*AœNûÔÔ‚ÅbŒÇS~ðÎy‘³X /ºÏž="a““ V«‘ ðS§–‡Xð`h0ÆÆÆZZZT*Uµï†PDÝoìu:}ô‘ÍfcY¶ÒzQ;wî[ßú†a"MÂÔ •JÐéT™LN©”‹DØþýN–eišmmµúý›Z­R"!Åb6ÒÎå¨#GöéõjApḨPQ¡ Ä*lÐ@×ÙÙY!ÍK¾¾¾_ÿú×ù|¾»ÛV”z(‡èõmmE(ñÚk¯ù|—ŒF­Ñø¹¹\~m-ètڣѤÃa‹ÇSp½½í …4™LïÛ× H&Ó Ãvw;+âT>-M»‹ oÙlÖívÏÏ{þøÇÿm4'aÐí^ ÄzP=)žçãñËrn÷ÄùóÇggWÖ,} °ÕÜl^YÙ04¯­m¶†¡¡¾J!–L&‹D" èÕjX•T¯×_¹r¥šL¦ææææ•·ß~û­·ÞBÑÇ=ÓÓ4“ÏÓ2Ùg³‘LfŠíâ®´n¾L&—L¦3™\K‹¾b·U*Ž‹w¹ì"&•ŠÓéìã)!šollx<ž¶¶¶†††›7o–¥”@‰°´´´¶¶¦V«»»»·»¢ççç5ïæfÇ1Ç«PH3J*û|A¥RÖÔdÊf©……µ¦&†¡Z­jvvÅf3æóL(•ÉÄ"‘Èïßììl¡¨üÀÀ~·;08ø?ž~´ï¿ÿ¾Ùëím{”Ð¥$ò‰Þr»}ƒƒ_ÔÜ•\•Jµ¶¶†¢hH[[[‡††ZZZnܸqíÚµt:L&Ãá0|—$qEår‰J%on6+Ò¦&“Å¢‹ ±˜lj2éõj à ^¯‹ –e1 M¥² ÑØhÂ04“)Zt^4}å•W)ü†½téz.—ÿÓŸ>|ðÁX6ûY†ÏƒWž­P*•æóyH©*­öþÈ'g``€¦éÛ·o///¿ñÆ¿øÅ/4àpظ÷ÿÃqüx KJ$â|>¯PÈ xp¹ŠfÊŸ˜˜8uêT8”B xž§iZ§S§Ó9ƒA½·= ûÉO~"€òîõzv»=‘H$Yù-ö2•fµZïÞ½KÄüüüÀ@s!¯qq-Ü ‡cn÷¤ÓiûÓŸ>nl4ß¾íI$R±Xj||–¦™+Wnj4JŠ¢®_Ÿ …¢&Ḱ¶–²ÛÛžrx8Žëõz޹¿ÂÀŽÃ{S“Y"!m6#ŽcF£Ž íKX[KØíBo…ÛÑØØIVØÚÚºuëV$ùÝï~•˜ .üìg?ûæ7¿ùy_Ç0l2™æy>Î1 K"Žãþþ÷óóÞÍÍèúzH£QNLÌß½»¼µgÙ⟚ý~ÿ[o½åóy¥DB¢ŸáÑ; ÇñÙ,W6;¬á!—ËËÞ£±ˆÐét'‘HàV844tÿ©^&“tw;xžç8EÑø‡“†Ùí ‡w!ÂóAXm…ãø`p«èCÇãÓÓY“©ÈYÑ‚ ¼Xb!¢ÓéÂá°Ñh>©¤8xð ÏógΜá8îûßÿþƒvyAG–å®^ýdh¨ï÷¿ÿûÐÐÁp8*—ËššLPÅ0äá»ÕÀq\WW—J¥`Z"–H$Òh4Xôðe: ?RñT*•r¹üin™TȳX___XX˜žž¾p¡í!{ t† ˆÇSóó>›ÍØÔTÂ.~¿_¯×§ÓiaX%±$ †a©T |Z¬½½½¤wüøã÷ZZˆGB‡‡7ΞýVë%ÿùÏþñüÆo;£@I$ÍÏ{ÞwíÚÁÁ°N8Š"››¥R¾¸¸O‚^oà1žç£ÑhSSœ|µZíõzµZíÚÚZuK£Ñl'“`¾ÂÅŵÍ͈V«Ìd(FÁ0l,–Êfsv»‰¦i§Ó^”»är¹7n˜L¦S§N^|ñÅ1g8.òûC¹\E Cù<½±þóŸ‡íö†µµÍ®®–h4éñx%2ܲÛME$|rhš‰D …Ã0³ÙLÓtéB^…SÞ¡º>otÑoÇ9Žƒa-€‹Ý&“$MˆD˜ßbF§SÏÍ­ÌήüÛ¿]xz¥øÎ;ù|þĉÛ¿ÎÔÔÔÉ“Ÿ•DT(df3OÓÌÆF8K)2’$?{ö¨XLìÛç`YÎb1H$$‚ z½º¸Þêêjss3ìkàÀøbSSØ-ò§Êˆ+H’lll¼|ùòSjÍ/¿üò¹sç^|±ð/ÿò"Èç‚9v–åB8y²šGGG÷l°efÿþý;4âßüæ7ÿùŸÿçÊ•_m—X° ·Ù¬@o]_ßîZænG§rW„Ãáææfã‚Ël6ûýþÖÖVX€ª·ßþö·¿ño¬¬¸Á¶š¶‹‹k&p å£G±’e$ñx=::ºkûtžç/\¸`±X*¤¦Ã08Ž/-- Ü5R8—´–HmÇ0,lmmE"‘]/ÐëÕ Ú†]k«uo·hhh…B>Ÿ$Ižçß{ï½]ËœLMMíß¿¿r*…,,,8Î\.'°V8‰S KD,“Éd6›e2YAmßa}Ÿßs HGGÏóPt½úê«÷76óz½v»eY¯×ÛÜÜ<222888==ÝØØX˜ÀƒÂßW8bA—N‰>VƒÙ¾xjµÃíö>Ò@Ê0úÇ”áç?¤§áâââ¾ð…L& -K8N&“F£Ñçó•‹Xå‚pÄR(@fìа««€^!§rvvê1R©Ôf³Q3‘âñ¸Ýn/Ëê¾™LFà>·@˜ÐäÂÞtãÆ ½^/‘HJt$,#8Ž»zõêsÏ=WQ£ššš‚e¤”J¥Á`òÖ‚*ïÇ †ÒmˆeÄøøx[ [[[*•*‰¿ è§P(ª±ÊíÃAQMÓŠžÈâ LWâr«àÛ©%ŒÁúf…l6+X £2 EQžçkŒX0Š¿,=Õމ‰‰”È'[YÄ‚GBØ`½fˆuóæÍ Ô® Ä’H$å*(,(±`ÙÇ«·4÷øý~“ÉTÉ9m‹‹‹‡£Æ‰Ãýìv»Ïç« bMOO ìƒ{üó N§ƒ‹²$Û zX€kß¾}‹‹‹N§³¤÷Êå²33³ô ÙlÖ†ÓÃTétðÊ Ïó===•Éø………BèUY *Ë]бFFþßñãöG¦ÅŒüE«ýÆý™ Ã,,,D" Ãöïß/¼åº( Ö3G, •ŠÄâGŸÔÔj1˲ۉ5??ÄIœåIDAT‡E"‘Ãá(‹û¶(Ï-4\•‘^5K,ˆ;w<$I0 ›ÉäŒFM&CÅãÉL&g³5äó4¬'¶=‚”eY—Ëår¹ªú[ &®¯¯[­ÖgˆX0F¹¶ŸH$’ÏçM¦{jÓêj@¥’%“–eE"lc#LQy³Ùàõ&'::šA±#H+DÁ:xð œå»j–XДe2™>øàƒR8°hšþú׿~îܹ/ù(àK_z`GûçŸ?Z«r ·ÿPûÄÒh4ÑhÔjµ–HD×^{íÂ… ³³W>oÎYËçi’$¶¶â‡wÚ̃‚?—±-YyˆUôJ¿´´¤Õj_zé¥û/ÐëÕ‰Dzcc—¤{¯×[б$‰Ñh¬jbƒA¨ pWF‡ÐÄ’Éd¥°ŽÂ®ˆ‚ÀÂ/»I²-±˜°Ûr9ê~…¯ íÅãñ……E;::ª´`øÚÚZoo/ ‘HV©¡üÄ‹ÅÙl¶èKQT*•jnn.LåŽî ííM»þ!Çñ°@á—ËÅóüìììÌÌ ŽãmmmJ¥²Šˆ•Ïç¡­a~~¾¯¯ïY!(uô~ ¸É´Ïí^~¤Ãï÷x ÒÙÙ ivvÆ/ìÛ·¯ò 0mŸ[˜Sÿ KÒáèp8žÖ¼ItŒär¹ÙÙÙª(O_xÆÊÛP¸ ĪÆîb±*.š¦WVV\.W</£RµS|KX3ÔQ$0 «o^½zµðbÙ}…e ´‘Ö QD‰‰D’Éäö€‘ ³Ù\ÆQ•!}yyY"‘¼.u”ccc}}}eTÞË ±¬Vëúúz}íK½?–‘Uå!AEÕ×¾¶Ö§ öP®Ìœ:±j•ÐÀ¶N¬D¹2sêĪq”×™SNbAÓtuå½È€QYõÙ/*!Ѽ<%:òùü­[·j²)f%Àét–½j Ö~©ãÙÝ ë¨«Ž:ö‚ÿ­b­—]Ð!ôIEND®B`‚ivy-2.4.0-rc1/doc/images/hibgraph.png000066400000000000000000001445171226750426600173410ustar00rootroot00000000000000‰PNG  IHDR†Æ–>‚sRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÈÍIDATx^í½VW™ç¯&(™0Š)Y$ØX:‚l¤:d˜¥cˆ´Š™ž Å0N2!†ÌÃLˆ »ü˜®È8¨Ä+`pä—íEtº&(¤iv{©.ª7E¥’’”Pâ†b»,Š¢¨ü¾ä$×›ûï½ï}ï½ï=÷~º(êí·Ï=ç9ŸóÜ÷~ßsžóœw¿ñÆïâo8qâÄŠ+z{{A@€ò# IÊ»wï^²d @ @€@žÞ•gc´U|O<ñĺuëŠo'B€ P&HÒ2f }¹ï¾û¶mÛ–BET@€b@’ÆFU‚Zµ×Ú}5úJ/!@( $iQF¢ vÜvÛmG-ˆ1˜@€@E I+2Ðq»9zôè³gÏÆ-M9@€ $iËRÇ¥K—®¿þú²ô†~@€ ` $©5C•ƒ¡“&MÊ¡!š€ @nHRüá8°`Áˆ@€ œ Is^èæ”þII  m"ÆA€ PFHÒ2ŽjÒ>mxó'éÕ\@€@’&WÊËÈ“_Êa¥S€ â@’Œò³P¤ 'ͯ=Z‚ @o@’â  íöÚt@€ 3$iÎÀ Ýœ’’*5i¡MÄ8@€ÊHIZÆQMÔ'Ú¤£›]ÊE€ @ !HÒ†ð•ébm¯îËÔ#ú@€€-¤¶ŒTævîÞ½{É’%™7C€ @ÀGIŠS¼Eà‰'žX·n8 @€@þ¤ù3/h‹Ò£R¥5³ @(5$i©‡·žÎiÕ^k÷õ\AY@€ $i:KP‹ö6i‡S :B @°Ž’Ôº!ËÊ`e€R¨¬j§^@€ NIŠw\#  ùÊ“ @€ ÐHÒ¦`/\£:GT§‰Î, ‚ @ ¤ÕçZ½@°›’ÔîñKÅzé©ÒTª¢’hm½Eó£Å‘¤ÿ­¥¥¥€ 0 €šHIÚDøEizùòå»ví*Š5Ø‘6…6q½Þ/…¯\9.“Òî%õA€€Ýx0Ø=~©X?o޼ǧR•À›ú¯9ñ£aí"I è'˜@ ¹¤Íå_ˆÖµŠúÊ+¯ÂŒÈ€’4¨T @)@’¦ Ôºê®\¹¢<ùúß:Ë18&$iLPƒ &@’6~!š>}úôرc a FdCIš Wj… 4 IÓ¤ic]Š"9s¦–csLHÒ˜ (@M$€$m"üB4½oß>òäb$23IšZ*† Ô ISCiiEÊHº~ýzKÇì8âHÒ8ejnÛ饟Œ5Ò)Q';îã e TŠ’´RÃÐYÛ´uëÖªS(uÿãÈÍ8ejJÒM›îŸ?ÿS5‹©’´ÔGç $!€$MB­L×hÕþÀeê}ñ“›¿ýmÏ£Þw÷ÝŸ>~|çøñcŒ”Ô›=öÕøòý÷éw¿ûwóæÄ‰9qb—ÊLž|ó‹/þàØ±gôbܸÑ'Oîvè‘#OßqÇ'Üm1KŠ+B€@|HÒø¬ÊYò¶Ûnëíí-gßèÕ›¤áŠÏ>û­«WïÜùè¬YSŒ¸\¶ìs?üáF½Ð›_ùÊçÍ›ú«~½råW/¼ðÝ»îú“§žú¦®’•*u$éܹŸdრĤ‰Ñ•äÂ#F\¸p¡$¡AÂ$éM7}@ÊRšò÷¿ñºëÞkÄå7Ž0o^¾|ô†ÞgÞ2ä=*c^«6iSçµya¦Hß^‘ë¤(fIñG@ˆOIŸU Kž={vÔ¨Q%ì]r“†Ã† õoErv „-Ç;ïkŠTªIŠßA€@bHÒÄèÊp¡òäO›6­ =©j¶o̲߮ѽ“¤£GÐÌwÒ<¨g–TrfIkJRpÿxæPýžØÞTU‡¥ß€B I+í===ííí•F`yçûûû‡ªÃ¤M/]ºØ›0Iª=LO?ýˆô¢‚Gg̘ìÄ’vww™7—/_ä—јØÞd¹Ca> ¦@’6 }Vú'%*‚%ؘÀêÕ«Í åÈ‘#׬Y£™oOUa’ôõ×_ÐæúÅ‹çjý„ 6êÓÙqÿàƒ÷8;îkÎ’ú<‹øž‰RfI7B(+$iYG6V¿6lذq£¶Wóc1ÁÁÁÑ£G»×Í,XÐÝÝ}åÊÓ«TrŽúß#ÞÑ¢_ß³îýøHR‹= Ó!äBI𠿢6¢)R-øÕ:ìŠK`×®]žhNý:~üø'žxâüùóùKÒC‡¶OŸ>ñ¿ø~˜le–4îÐR€@e I+3ÔA3gŽÂIhîͯrxÇ:wÝuWþ’´æ”*’´ÒŸ;t€@$i¥ýbìØ±´oFÓl•¦cO絽ɭ•¯¿þúÎÎNç$©=#‰¥€ªKIZݱWϵY;l›¶‚5‡Zi:–t~Û¶mŽmiiÙ¼y³çì$©%#‰™€*MIZÝáW”¡¶Å„õ_aˆÚÊ]]:–ôÜ ¢¾Z(™×¿`$“¤JVêlÃ\ˆ÷Zs±Þ]€…{Kü 3!äGIš뢵¤ëmmmaVi瓦ߊf3öx(ëÓºuë¢/Lá’ôܹ›=ûãÑnÚtÿüùŸªK‰¾3Wƒ @ø$iu½aÇŽŠ8 ë¿ÔêÁƒ«KÇ’ž;™ž"ìM IgÍš¢,NcÆ|(LqšCíÔìʽo bÌ„ \ IsÁ\ÈF”‘Tla¦)ïúÙ³g i8FÕG pÔ,it®{jÏÂ}}Ã@i@ˆ$€$­®ƒ(T4li^ûc´k»ºhšÚs¥ßš0aB„ /½ôÒ¨Q£âÛ˜@’FRo¦H£5kô‚>±¤ñ‡’€*BIZ‘è¦6Äh[}`ÿûúú&MšT]4Íëù¹sçfÏž­Ø6mÚ4þüø6¦.I5E*UŠ$?”„ š¤5•¶€D§¤g`÷tÐ’%KJÛówlÖ¬Y”1cÆ„ÙxäÈ‘;®YÆÔ%©ç¼€;œê²¿ÀÃ…i€ $ij(­«HɃ”B(Ðìè0Sëzj‘Áš%•µŠmîܹM_¸çÆùHR‹ S!–’´°C“­aJ`-º`Á%¹ÌÖj'&IÍi´fõךÖ,©¿žÆjÆ @ €$­¨7(“eD´¨þê²¢Ôòêv˜$Õ©Tin’4ÁôgÌKX¸ÏË•h€€5¤Ö Uº†jTS¡ujU ÂM× j $¦Ø|Aœ±ø%žËŒ©/C’Æ9 A¨$i•FÛÕW¥ÒùLž@­(¯|»]S±Õ,à¶IšïèÑ $!€$MB­×(I¾N±ìHÄj :nE<ŠÓ/@‘¤VŒ#FB€@|HÒø¬JUréÒ¥:P4°K’ª§:•ŠB5:Ã,i5Æ™^B°›’ÔîñKl}Äžz-è‡ê”¸9.l"IÒK—´)*I¶¦,®ºråWuÍò6MC€@n¤¹¡.VC{êÉU¬¡jØšÖÖ–ÞÞYˆËdu ìkiii¸[T@¥"€$-ÕpÆïŒ’’†í©?~ü+¯¼¿*JœÀ† ×Þ~{2ù˜ÅU ˆ )¸Ï` ü IógÞüÏž=«£›íˆN¡ß|Ó± ~ƒƒÿgæÌ)R¥š+Õ¢y*3Njz`àÇó&Mš888X?¸€ÊLIZæÑ ëÛÑ£Go»í¶À¿’ª”!UºaÃêI“&x2›æükKËGÖ¬y=ZJ£S€$€$m •—G¤yÚ½{÷’%K¬ìFC€ `-$©µC×€áyòÉÕW.… @ !$iBpV_‘'?"_©Õ]Æx@€ŠLIZäÑÉÊ6-Ík>°vŘ*Ò4«†©€ @’VÑ/æÌ™sðàÁÀžk'¾öãW }† @ y¤Ícß¼–ÃòäG$‡jž±´ @€@ù IË?Æþ†åÉHUELô€ ¼ Ió"]˜v"¦BwìØ¡íM…±C @¨ $iUFÚégÄThÄNüÊa¢Ã€ äHIš#ìb4‘ ?b'~1lÇ @€ÊIIZÎqèUDžü°mO•cD‡!@È—’4_Þh-bu>lÛS¬Æ@€ÊLIZæÑ ì[Øê< *ç t€ PHÒ E^†„ϤäùJ¡Ÿ—´@€þ@IZ9o;Ÿ)"Æ´rŒè0 @ù@’æË»­½ë]ÁƒN¨ &@€*JIZ­]°`Áª…ƒÞB€ P HÒbŒC^VDäÉ'T^ƒ@;€ x I«åayò/]º4räHý_-ô€ b@’cò²â‰'žP̨¿µÍ’æeí@€ w@’VË!î»ï>í¬÷÷YQ¤Š%­ z @€@a I 3¹–'óæÍ³§¹E#€ T’´Z–'ùòå³§Õ¢Co!@h$i“À7©Ù°<ùííí===M2Šf!@¨:$i…<@꯿þúÀ;öüùóbAW!@($i‘F#c[¶ÕKŒŽ1"ãÆ©€ „@’VÈ9¶ÕKª*Æ´B è* @#€$-Ø€diŽ60) ”¿…½{÷.]º4Ë–©€ D@’VÈ?6¼ùãï°Ò?mܸ±B è* @#€$-Ø€diNXž|m·ß¾}{–-S7 @`–x“€ÎgR8©ÆÌ™3{{{=ヒ@€@8Íh(ôëÊ•+ëãÿó¼yóöíÛçy_«üð… ÔE@Ë÷zÊ,Z´H úOœºjk¼ð›"¬rñ£a]F’6îQÔP7éQ©RÿeŠF?}ú´ç}ŘÖÝ*@€Þ$ - ÓŒ©æMõHêëëk $©[ž"I›â„UoT«öZ»÷PÐV»‘#Gú·ák)?ðèѪC¤ÿ€ Ð0-è¯^½zÔ¨Q’§[·n•Tm¸Ê:*@’"IëpŠfA@{›ü1æú\Ð'‚¿9¥R¶¹,Ì N@€€8 úšѲ¾&MòÙ¡$E’r6™€bCýßDwíÚ¥¿eÒ©þóœšÜš‡ 2гIKszîè9¥ÙÓ¬Ÿ>HR$io#{ú¤¥yåÉ÷Û»yófm‡ô¼¯ü«ùötK!@À>ÚØ S ´ ¯³%RìÐ×%ŠRëéé‰è<’Ijß½Q&‹uD“îp:;;ý ô 9מ§2uŸ¾@€€E´ÅVÉöµC_ú²Þ”û:äE¢³¥¥EQªšañ÷IŠ$µè^(¡©Pê{Ç$=ýK$ZÍÌ`ZB.t €ŠJ@p%+gΜ©yS-èin%Ž¥ZÔѦæðz‰ZmÕíïïw_˜…$?ÿSGŽ<-©×Óó/_øÂ<½xýõ6o~àþû¿ôÀ_Ök£o½µåСíÓ§OÔë—_~~òä›o¹eÜ‹/þÀü5ð’¾¾gÇ=dÈ{f̘lšH÷;îã8eÒ$ ©P}ãôרÀóçÏ{Þ׿qãÆ4›§.@€@R£fA_ñ¦ZЯy,»Ò Iêü´µµ9Û§²¤'Oî¾í¶[¯^=.áøÚk?•j\¹ò‹æÅóÏÿ“T©Ñ‘ãÇ‘U1½îìüìSO}SgÍK•š¿^¢¿JÅê¯ÇŽ=3uêÇÒÕ£ª IšÔ+¹.)À<ù£ŠõW©TÆšUMÚ×A€2! E|%„ñÈÍ¿¦.ìTáúõýÐC?¾ÒT>j”¯oÍhŽýAóZ¦êÀ$óú†Þ缎¸dÅŠŽGùM¾!›ú?$i&žJ¥´r¡Åž ̇¯o¢ ‚Êá@(%“RXš_ªj®tïÞ½YÌ’J)¾ôÒO$C£JÝ­kÙÝ‘¤Ž¦ô›xÉï~÷ï Ò½óÎ;4‹$-‚ƒaCCHêŸøÔj¾?¾’qN6Ô<C€ò" d2ny§‡ÚªU«œPÔŒ$iW××–-ûÜ“O*‰Íµ¹Ìoá—î¦5KzùòQw™ÀKLM‘8ðmE Iór"ÚÉŒ€¶ÛûÚ£ûÖÓ¦BpÚÛÛ33„Š!@Ð*Ÿv5Iª¹R­z¶Ld!I5E*½(‰© L&„T ڭŠ%3g†–T» vî|ÔKxɬYSL,©¦HµÏ Iš¡ëPu>””Ôj¨¤§–0<(êT™Šó±ŠV @éPƘ¡C‡Fd'ÍB’jUÝlœÿùÏÿù®»þD/ÌöùµkÿjéÒ;~ì—¤§Oï›0áÃ'~äøñ毗è¯Ú¡¯¥éQí¾G’¦ë-Ô–7­Åkg½¿Õ±cÇ*/±ç}mÌß¾]_Èø XF@ëÊKê?ªÐÝ,$iêJ1· ÙÞd™‹Ûn®Ž¶×÷þ^è{¤ÿ@áÀL¥¶À~@€€!€$uë]$)÷E®”ŒÍŸú^ó£:ÜÂc‡ª–øý:5Wsi € $)’43ç¢âZÜíßY¨Su”¨ת¿C€j8vìØôéÓ‡ ¦ÿO:xÁK/½¤Ìƒþ?©üĉuíŒ3TOíÆb—@’"Ic; Ó&°nÝ:mZòÔ˜ôP§;%þý÷龬ªô¦$ã¯-É~B'?éü'½ptçË/?/±+9kRñ;¥:©õÝõúè£÷Ý}÷§¥­ÇcZ|ðÁ{¾÷½‡‘¤Ü”M& ¼Á:MÔcD`¦Òhá¾ÉæÒ< ”ˆÀ¹sçV®\˜[Ð} ½®NÛíµÜ/ƒƒƒŠ+MIœYÆ‹é_>ü:GÕ¹_{¤^ൟùÌì_üâû¦äÊ•_4‡Žê¬Q©R·d|úéG~x™[’vv~ö©§¾é>wÔ±ß_.Ô©¤Ï>û-ÉbVªÃHM‹jzáÂ6$iŠ^DUI‡Z¼x±ÿ8kOÁÀµã+VlÙ²E%µévÙ2©´Ô~âHÒM›îß¿ÿI†s_èŸCu ^ûþ÷73¬ú7jÔH§ðèÑÔëžž1a¦úßD©:mÝpÃûµŽz) @°@ÍXÒ@éÖà›ÒšŠýÍo~Ö`= .W£Ò¦ag>Kj¡ [k²B4p¾NVÔ©µ½Äp@€@,M‘¤’’:½éž{”i1 $ Ó7ï½w!§7Åò eJ þ„¨¢K%U35†Ê!@M'Ð,Iš©îL\9³¤MwȪ˜ݺuþ Ñ‘#G*qU¸ÐO@¨*$©[¿"I«zäÞïÀ™üžÎœ93vìØÜ­£A@€@Þ¤HÒ¼}ŽöD pÓ’ÃG‰â-€ P¯¼òÊš5k¢sl#I‘¤%puûºà_£Wî'­Ñ{2@©ØÆíëC€ÞI`ÕªUZìîîVÊm?ž$©U’Q¤¤ÿtQžpÏ—^ú‰ûDPç¯*¯”OºVYEÍᢙþcáž('þSš”J³¤žæçÍ›§sGs²‰f @™¸pá¨Q£LzÑñãÇkïÄùóçÝ­å I•¾Ô¤ݳçñùó?¨)7mº?ðO:ÀiÛ¶oè’­[¿îæ”*E’fæ‰TüNþSš×èGíÉ] H@€€¥vìØáÎx?tèÐÎÎÎÇ›îä I©l îCç÷yúŽ;>h‰rˆšD•QÊ” Ù‰QS3’ÔR'·ÏliMårÛí?ò^_õ…2puþc1 ”—€d¥VÿÜr3Ùë¬užSÿÅ‹¿œ:õcþætüRØÂýðá×9åݯ3²IZÞÛ¥H=SÀ¨òä{,òy¯yÓiÓ¦Épl ü€Öñ´çA™ax¶yófÏB| ©¶¶6¿ZmiiÑåyÎ’ju~ÿþ'=jÒL‘¾=Cé u›8Ú®6E’r§åA@FãiÉŸJ›8J4ñ  @¨‡€²ek ¾µµU+~Ú´?ÀÌ¿pßÞÞ®ù³µ77Iªãéu}à©Ti˜$e–´¡¬%óäK¤Jªº{ £Du÷ZÒ'Ì„ òÐi‚‘Ê£i=¡ê -sooR š^õhÙ|$é¹sÿ¶råu´½_’z¦o=´Ý^ËýzspðâJÓ 4¦8þô®â˜‚%éÐ&zÅܸë \Ê×ê†ô®Ô@ˆO@ùDµp§9Q…“uuuI\Æ¿Ö)i’@iwïöíÛ=M™$é¡CÛ/ž{éÒ‘hAhÉŠ[¶<¨ »º¾¶lÙç¤ |€K GÀ¿“)0”¾D&»í ×a ‚  è´uëVÉPE‹*¬··7q'ô˜[ºtit 9HÒqãF»§B]{Ûß9ê¶Äy}òänå2ä=š. Ëiš¢N%–4±³qaü;™üó¦º{î]G¥… ¤D@Ùì-Z4bÄˆŽŽŽ½{÷Öµ@ŸØ„$iŠ’1몤‰‰ ë àßÉäŸ7ݵk—gq¿Ž( @¨Ÿ€³ƒ^3£z0yv8Ô__}W IÝ2IZŸ÷P:ÿYöZÎðìdÒYÀ%š /WA€@]´@/*ªhÑÕ«Wkn>Ó¢#‘¤HÒºü–Â)PRROd·ÿ0'%ªu“£ @€@=‰6¦…;-Ðk]N ôÊîÔDTHR$iݯŠMëÐ&} õôܘ“ò½å¼bRÅÁ Ï€*I ¿¿_9˜ôè™9sæ¶mÛ<§ 6 ’IÚ,ß«h»þÍõ~‘ªï©ÚÞXQ@t€²! z P­ËIŒj£m³èÃ:'IZ3=S֛РR¿Ò¦KšÍM@­.:¦B«$n$þÌùJGª °A€' ÀÐ}ûöiïü¨Q£´^¯›*Z³#­­“{{wD6׌·´Ü\“XnH•Ÿê\Ò7TÏ1¡ÚؤíMn#”N)…s5‹Æ @ t´@¯íJR¢&Åý™3gŠÜÅ io¿£¹Z° ­wtüÙºuk‹3XHÒâŒEš–(|GÝ5úßéìì”rM³Uê‚ Ê0gÐÏ™3GGUk¤¯¯ÏŠ®Ëì™3?ÑÞþ'š+ <ð³ z1;3ÔkÍJNšô±æn5ó8 ’ÔŠ;¨n#µ«Q;Ý—ùßÑÞ&­æ×]5@€@á H jÞÁsœzê¿*B¬° ôC$¶aÆI“nIˆ-j½~Íš‡ ¥G5^HÒ®$2P_[<è¾ÔŸ¦tèСçÿ&j‹ @ ù¾©™KÍ8è°èåË—k«kómÂÄ#€$ÇɶR*é©'·U¬>³lëöB€@0sR¼ÖÐЩU2fpë I­²X{òäûsB)C¾öEƪ‹B€ P`f^ûæébîs/0?L+ $iQF"E;ü)Hý9¡Ö¯_ÏQ¢)2§*@9ÐeÊ”°q ¼¶Ôƒ\ÝÎ!IK8öþ<ùž øþ•ýR K€JD@¹–´F¯m©Zò*x.z?õ‹/N:ÕóþðáÃwܯ=ů-ÑÀÒ•?@’–ÐüYñõ•Z2ÔéªòCI¤–°çt €@¹(`Ô$uR´•"G-ݺ´iÓ¦ýû÷{FÆ}ººÕ)xm¹™Þ¼EIZBWðdÅ×'švbºûé--!º@ÀfŠ­Z³fY£·:ÎêôéÓkלZg–4ìZ›ÛC IKè·Ýv›ûX&ÿn'}Àékw {^¢.½y¸ÈúÖÖÿdËY ùÛÙÒòQ-vcG‰œñ­®˜oðI¿«·´LÐAá)º¢öžj¾¥¥EÓî.êܹs+W® œÜÕv{-Ê«SB§¸Rï"®µ6×$€$­‰È¾ž­KþÝNþ“œìëd©-Öt[Û¬ööÛuó¥KG²;éØÞšuFsÿ::*+xŠR ÔnÕPçÞôÉÙæXp|Ò}ã¼íŠ6mÚÇtE­huuui^ûè•:ÚÒ5z·Ÿ:thñâÅaIûW¬X±eË•W¯—-[æqÐèkòf..*$iQG¦»ÿIN 4Å¥™ذaô¨½z1OË;:Ú= Î2’ÊWºaÃ#Ò£yެumutü™æJ“yŠ–§•I³ Êxï^ãJV[q®7nœ{RÙ愞ØNð/&ø:À~×hZðÉ8ÞǵF¯³KFŽ©•zMß´¥a’´xcÒ˜EžOJ¢ø$w•ž´ùµÆÕ™àñçñ£2§*UŠOÆñÉhWTBhí£×²Ž_’0­’ûÐWÄ"€$…É¢BžIP%Q‚e·ýž´ùu­:¦òøóøG’æyGà“q|2P’j~óæÍR¢Ê¡¸©ì£ÏÓñh«R¤enÏf&Ïá¢þIÓ²õ¿ýáñçñ$ÍÓÙñÉ8>鑤Z—7kô‡FŒæé±´e#$©£e³'O¾>¥J ü“¦eë)úÃã?ÎãIš§³ã“q|ÒHRIϽ{÷ê£XbTËVJr’çHÑì%€$µwì‚-÷¬ËkÕ^2Ô)ÊQ¢VŒ7ÿ8$ižÎŒOÆñIQRèQ£F)ݽҿ“Ô)O¥­@’–`ÿÐÿqöž“œ8JÔŠñ.ëãßéWºd{S^îÅ‘wE.FCïk“fX£ÏÁ'i¢|¤¥SO¨¨_¡r”¨ã]ÖÇ?’Ô ÷ 4²¬>™LøFHR{‡Ë!ÐtHÒ¦Ašxòä{~å(Ñ4YgYWØïå—ŸŸ<ùæ[n÷â‹?0Òßþ¶ç±Ç¾úÀ_¾ÿþ/ýîwÿnÞœ8ñ#'Nì?~Œ «ä±cÏèŸq£OžÜ³@`µªäСíS§~Ì]U_ß³úuÈ÷̘1ùÈ‘§ýxUõè£÷Ý}÷§ß)“Lnxß¹sÿ¶téÿ÷÷ª€yÓß»±coÒ‰8÷ܳ`ýú¿Vù0õÀ,i–ÎøVÝ’ÔF· t­@·|IšƒËÑD IK5èž<ùž_ý;•ªó%êLد³ó³O=õÍþþI•}¶lÙç~øÃz±sç£_ùÊçÍ›³fMѯ:Kæ…¾{×]¢K®^=.=*í³@`µÏ>û-OU²D:UÕJøJ­úUãŠæ*™$Þ~ú½)ë˜íïÝìÙ7Æ?óÌ?È$$i}òÈßôôü‹1Ãÿ鍊>`þ$“®»î½¦€^ 2¯Õ–3uêéÝðá×½þú ú«ÞwŠù›`–4ÇŽ¤6ºe kº}ؽèí¸b®H%&€$-ÕàzR>yr”zþZªž—«3‘s0ï}î’Æ õèE#Igg`(gÍÑÕ*Z`óæ|åwÞaT¡ù1í:—»©i¶¿#îzË^1Kj£[ºV Û×¼¤µœ‹¿C .$i\RV”sçÉ?{ö¬~uÌæ(ÑâŒ`{{»YÚÖ¬vww·_„=þOŸÞ7a‡µ¡^»×̓ÐÙ,Åæì¸o|–4~µ²dúô‰šsÒÞ)í¾÷«Fƒ*'ÀâÅsµ÷_Æ;¢¿ùÍÏî½w¡¶Ò_¼øKó¦¿w*/ý­ÝúªÁ)æo‚ÕÒÆ}[{‡*’úÐX¿~½>.|øÚ7Eמ¤zŠe*ïìÐî: •›@_Št¦Ç-[ZZ¶nݪƒ1Kæ“1]«Þ» WLÅ©¤²¤åzÏ<èºuë4÷ætϳû>Y·=O,~MÀüùóKöø¯÷¹^oùÔ‡€  Ô;.,$Mödá*°p_6ðL‹zvß{»OÖye6UµÉ®å*7}CðOGmÞ¼YÓQÌ’Ö+eЩÜ\Út¯n·Ô̽Õ,ßó5)Ž[⊩¸"•T–³¤åzÏ´¨û8{ÿa÷ɺ­àTíÉMv-W9æëÄ’ê…v;i†ÛǜǿSÊÍ¥»ÛÑ£cÇŽÕ&'m‘tjÆ'ãø$®˜Š+RIe IË3ôK—.Õ,¦ÓwÊ'ÏV§d}ÖóI¡ffŸÄ´¿¾µµU.¥‚Ò·Eû«jÊã_@ñž§¯ Õ¶zå ×ÿ§N=ç6G\çAÞ`t@bot.ܵk—Ñ£JµwïÞøY »ø—7âŸñ[i°$®Ø¸+RC• IË3úî•zOÊ'Ïš~²>wuu¹÷K%«„«´:¯ô±Û·oH˜Ÿ¿$=wîßtêwX»“'ßlÒNíÙó¸RŠzÛÑ×6øŒs9: ÁÛJ1âúš´jÕªÀ/H¦òü}Ò=ôøgJ« ®Ø +ryÅ IËãî•zÏV§TŽ•Òlkyx5©'O}Ç¢üÿÊx¯¬¢cÆ|(ú٬Öü{Ƽ6­§¾¿t@ƒ¾|æÌw²ÀÚò÷I÷@Çô±@ÿÌÎñpÅË!à!€$-K¸Wê=Ó¢%Ú××§ð²°“]ʱ=Éÿñ¯Y(=_k¶«|õS§~Ì?KçÚì”’4·­éÙ¯jnÄ?35ÌS9®˜ƒ+ÒD‰ IK2¸ž³š<Ó¢%ª0«¼j¯•Í &úʱcǦOŸ>lØ0ýêÔ)™ˆkܯYÿšínÚtÿþýO>ãk^›2@Ôåu5=¶€³¤ÆyjúX„fç~îšqÅ’ífu ÖZ#âJ“µ¬ŒÙj"Ùµ¶_uîܹٳg‡=l&Ož|üøqõqÏž=J)êélôµvIR¹ví_…=ÚkÊ…ì4: .¯‹öØ¢ù¤Oð]Ó¦ÿ¢ý3;÷C’Úþ ýÅ!€$-ÎX4d‰r3)ƒ S…; ©çO šÑ‘Bª0Á…å¸dÖ¬YŠ[3fLtw®^½ª¹RO™˜×z®j–¼‹hW+§+W~ñÊ•_!I‹ïÕ1½.Ðc-•¤5ýIZ|¿ÅB IKâ:¨I…LgYÓ3uD㮨9¥L1S§&Ÿ”ä)S§Ù:7µ†å…Š q'Ãwg€ò,è×Û‚fX•ªÞ«(ß8ÖÖõöî¬ù¤€ üT1y3§†h­­ÿ ŸŒ¾ã~ÜÒ2!-G’ Õ:¾>ÛÍïä“rö°¦Õ õ@ P¤…Ž„Æ¸óä‡ÉÓz«Vœ“¾¦óí¼^n©”ß°ááööÛQœ1üŽŽEιe©À§’@ú`ioŸcDª»¸ßѱ #WT •ò›*•Š–õµ¸¿zõjk±²Ï­Z>HÒ2Œ©û|&wÎüFŽUrÓÎÎÎ2б°ʽ5sæ'ÚÛ?ÝÛûlıòUÖZ¯×ü¨ôè¤I“„ËÂA¶Ìä7}rf{û¼ÞÞ]¹r¼Ê¾çé»h <ßѱ0W4›¢ô™ïlŠêëë³Ì™0!¤ep }jÞôĽŸ©‘£DU§;—Ž}Ð7 ‚;ïݴ^¯H;ôhnŽO†Ý€MqEmP`•³)J3ÊÌOºÓÜnÊ‚’4 ªy×yýõ×;{˜Ü¯”ì,;Å0;–Uû¼’ö ÔO@ŸóÒ£R¥ZÙ×d¶¾Íê”Ä[ëoŸ+ $i:›X‹;ëSØëzÍSDTFAQõZBy@ˆI@2T«[úô–01b„Ž3U>–d1[¤R$€$Mfsªrg}ršø(QMŽjŠTKÍé­B€@ôÿIS§Ú] T€ -Ðî(åcaSTÃ\© CHÒ áæSµ;ë“;A©ö'%›éÔ^NmêdÕ>Ÿá£@YÐ(å™Öî‚ÆãѵYV•ëG’Z?úné) ª_M—ôXyCtOߪ“iÙmq  ØB ­­M©ûm±;­#€$µnȼ»e¨{‹½{~üNê°6H9û÷ã_HI@(7叨¸qc¹ûHïšHIÚDøé4íNDêÈÐÄG‰jbU‡…¤cµ@€@‰(6Lëo%ê])$i±Æ#5N"R· M|”¨æYõ¡“À . rжWå,wé] I›?¦•ˆÎ|ì–¡æô¹zPšeå !z½^n”‡ P:5ЬRëü»‰$ÍŸyš-jfT¡Ÿ¦Fí”×§yí0ߞΩ›7o^üò”„ JX´hÑÞ½{+Õe:›$in¨3iÈ=3êÞz¯xPå%­·IeWN¶I¿Þ†(@6`‡“£f‹ÍHR[F*ØN÷̨;듳š¿{Zýת='†Ç'FI@U# $PÎr\ÕúN³&€$Íšp¶õ»cF}N ôI®DÊË—/ÏÖ\j‡ › hòBᤜ¥bó×v$iqÇ&ŽeîÅzgfÔ=u§SfÚ´iº0~yJB€@ (Û Žƒª`ÇérÖ¤Yζþûî»ÏälÒ7WIRÓX‚£D=ª‰U¾øf;ZÔ@À~ìp² Ú$iA&¦YÎqMÒ”Z¸7W%8JtõêÕR·1¥ T–€¢¼ôȨl÷éxv¤Ù±Í£fç¸&wPi‚£D5ÃÚÛÛ›‡Å´@6ÐÃBéYlî¶”’´ Ó,%%UjRv‘&8JT3¬---¬ÚÇdN1@U& ‡éYªìÙõIšÛÌkvÇ:'Ý»WðcZ %{%ÉY˜b€ Pq Öâ*NŒîÇ!€$C© eÜê3p?ŽÝJDªŒ§OŸŽS˜2€ ;€š¤5·ÀîÝ»59jìsVð=ø1íÞµk‡ˆÆdE1@÷î€@ -HÒ´H6¡¥2Ûäݹñë=JT{ö%m›`=MB€€ÜgYÛÙ¬."$iG%¦MΖ&wnüºŽ=sæÌÈ‘#9D4&pŠA€€$ØG 7Ô$€$­‰¨¸œ-MNnüzÕâKGGGq{ˆe€ PHõ®È²U,HÒbG]Ö8‡Ú;ñ£õ%êdÚ¯«] C€@Å 8Ëtç@÷S$€$MfÞU9kôÎ·Õ oþÄ´C«öªÁ¤5å€ Ÿ;œâ³¢dLHÒ˜  WLRR»ìYŽ6u–ò㘫åþ5kÖÄ)I@€€›@½qbЃ@MHÒšˆ ZÀÙðèÖ¦ãÇ×ÇDL‹§M›vøðᘅ)@p¨ë‰:Ô$€$­‰¨ <¨õzç$ÌwkÓšFë*eׯYŒ€ @ìFÀ1Ò%€$M—g~µ9yòu%ª%ûøQ§ùõŠ– @Àuí^°¤O˜ÙLHÒfÒo¤m'ñ“ó¡PW°¹¦H9D´þ\ @ âœÅºŠs ûi@’¦E2ïzœÄOΖ¦øG‰öõõµ¶¶æm1íA€@‰œ={V›kKÔ!ºÒdHÒ&@âæ Íwj«“ꉟ¸xÕªU]]]‰›æB@€€°Ã 7H‘’4E˜¹Vå(Q¥‚2¹EÑv\¹reÔ¨Qñ7æçÚ+ƒ {,]ºT1cöØ‹¥…&€$-ôðDg¨“.~Џ½{÷Λ7ÏÖnc7 †€³«¡0aˆÅ¤VžÁ㜠ê컯ٟE‹mß¾½f1 @€¢ °Ã I‘’4E˜ùUåä{Ú¶m›v5©á˜É8¤eGŒÁ!¢ù -A(/=MFŽÉ3¥¼#œkϤ¹âN«1grÔÙe3e±&S;;;Ó2ƒz @ ân»í6Í’TÝO…’4ŒyWâLŽ:J4æ¶ÇŽŽŽ}ûöåm.íA€@I °Ã©¤Û„n!I›½ñ&×­[§ rÕc”hÌ£DÏŸ?ßÒÒ¢÷@ € ¨ë”ˆA ‚’ÔJ÷0éñ%3À|ëÖ­ÊHje‡1€ I@‰±•”°¦a”e¤– ˜1×Äî8Î:~tgˆø±r°1€@ °Ã©Àƒc™iHRË̘kÖëÄOqByø"kåHc4 ˆv`ỂÍ$€$m&ýÄm›<ùNŽâ8ÓŸNøiâF¹€ à'3 !è MIjŸ‡8yòM¨˜‹&1·äÛ‡‹!@ ©âŸÕÒT3i¼è¤E!¿}Nž|³VgE޹ľÞb1 ›@ü­‹Ý¬k2$i“ AóÎ÷ÑÑ£GkÆ4Î×S'£~‚渀 M€…8<¤qHÒÆæ]ƒ !u2@Õ âQ"R}Xœ9s&oCi€ªA æ ‚Õ€A/@’&×ÄËÌF%g-¾æsúhm¦i@(2cÇŽMŸ>}ذaúÿÔ©S~S'L˜Ö…š“#Eî;¶„’´ Q‡&O¾³^_s¹Ä”¯£ŠB€@ÅLž<ùøñãêôž={æÏŸïéý¹sçfÏžý®w…j†˜'¶T *Ý­’´>^E(mR>™¯¤Îîû0ÃbîÇ/B¿°€šNàêÕ«š+õ˜1kÖ¬¾¾¾1cÆ„™WóaÔô~a@ñ I‹?F^ Í®&3÷Yó‹iœÍOö!Àb@ȆÀÅ‹§NêŸ%Õ;³¤úkÍ%»lì¥Öò@’Ú7–æCÁÌ•:ÙòúQ3ÒÔ¾þc1 dF`Ó¦Mû÷ï¬>Z’Æ9G03«©¸ ¤–¢³8bpŠþÐ.{}mÕŽ{Ë:‰¹€ Ð §OŸ^»vmXËÑ’TG·(á`3¬¦Í’@’Z6f£½#L£å²ÑÅ\@Í# =L+W®Œ˜Åˆ–¤5Éš×3Z¶ƒ’ÔŽqr¬4±¡æÎ¯¹u)Z°ZÖsÌ… Ì:thñâÅz¬D´-Ik>’2³ŠKBIjÙ@šàQ3ý}”('¼Y6´˜ @ yÆ'ÅéüC<4Z’ª<ó ÍÀ2´Œ$µlÍÑ &[þŽ;KÖš;Ÿ,ë9æB€@± °Ã©ØãStë¤E!}&÷“ÙGo„iX&Mš¤iT˺‡¹€ `-è‰k»…á9@’æ:­f̲ˆ‘› 'UPi`ÍÎq£iµK=€ hŒá!@’6B¯ ך<ù&”yhDôjì¦I@¨óxª@Gébú¤é3Í®FÝçºÛÍ×ЈÓÛ”ÂC””4;K¨€ à'±|.D@’Úä!f‹½¢HK‘ΰ©cØ Ûtww»·'ó!páÂ…è›uÛ?¶ÝÐØ[HÒB CL#Œ 5 "6Ô³ç1&OŠA ®®.}9Ô97É.ç*XJ ­­M_Æ¢7ɳ-í f7—’´¹üëkÝÜê&T˜î41¦5¿ÈÖ×0¥!7 vtttvvêH P5ëׯ_³fMt¯ÙáT5¯H±¿HÒaf^•™5 Âr<ñ 5óa ªPäÌÌ™37nÜqâbUÙÐïJèééÑ-P³«ÚÌ aZ³ à!€$µÉ%Ìü¨îöÿý¿ÿ÷È‘#w5ÁjS¯°6ؾ}{KK˾}ûl0! ³Å¶fÆkC™Ð¯@¥HR›Y÷ùóÏ?¯O„°´£Z¯×ª= 8lTl-<͉êÛ Ö%˜ø)üXa`æôR,ut3ìpÊ|JÚ’Ô¦ÕCqÿþýú?ì„ ³óɦ.a+ŠM@ÙÖ´§P1Ü{ °.'zú´··G7‘&'+iÆNHR›ÆM‹õ?øÁœN~ÓIgÓpbká ôõõiÙAS>~¬00'Z+Г(úŽ0ëû9D3%"€$µf0ÏŸ??jÔ(³Ã)Pz*7¾ÂLyvZ3¢Zl •%x´Ø£„uM  MoootÃìpjÂÀØß$’Ôš1TDí®0¹ŸÈTjM'1 `‚G[[[Éë?/Ôœ5jMg0…$ ´¾Š“#óh!£ŠB@{þô$Šc‡SQFË*;¤Ö —öX<ôÐCf³…ÿa˜jáÞšÎ`(ŠG@·•ôhÍó‹g8A oZIˆ³Ö§°äÙyÛJ{ö@’Z3Vš"ýú׿~Ûm·iǽærÜvëÛª–òµ½ÉšÎ`(ŠDÀ:mÚ42iX°¥¸V½ùm`Š;~Eµ IZÔ‘ñÙ¥@Ò‡~XzÔ¿“‘%kFC‹G@™ž4壯|d-Þà`QA (œTwM´qæ¸Á‚v³ IIZÈa 2jìØ±÷w§µE¾7î|kFC F@OV-/ÖÜ>\0«1M& pÒ¡C‡Fo ;ҥɦÓ| I <8ï4M÷ÿâÅ‹õìÔò¢û/ ÙQ€©Žµ¦' P¸‹¾àéÞ9pà@ÌÁXF@›îwíÚa´Â`“ÃXÖOÌÍ‘’4GØ 4eòäKŒ~ë[ßÒÚ½»&=PýðhŠK!P~º¡ÚÚÚtC]þÁ¦‡ÙغuëòåË£ëÖšž&M²iŸZKHIjÇ =zT›4Qú7ó7žèÿn';º„•h“1­³³“àÑ&Í–@¿No‰î ;œÊ0Ò9öIš#ìšÒúÈç?ÿy-2jjçðáÃNMZ¯×›| m-—V‹€‚GuËD/8V‹½…@RZ»‹NR˜²0ik\W~HR;ÆX3£ŸùÌg´éÞs”(ñãvŒV€€‚GW¯^­;Hk0 `=¥NÓ¹ÝP¾BO¤™õ}¦Y@’fI7½º×¬Yó¹Ï}î/þâ/< %Š"esFz˜©©´´F¯›Eˈ–vŒéXîNª‰’ˆfÙá”û˜ØÝ ’ÔŽñÓÞÆ»îºK’TßJ‹õpÕ~ÆèSÝìèVB KšUð¨r¥q³d‰™º+GàôéÓ#FŒˆŽÓCJÑÛ•CC‡@’&–ûEz Îš5ë/ÿò/ׯ_ï4®DuŽhî¶Ð l" ÛDojÓ˜a«=”0Û½½Áo¸î ݶg<›l)’´É³yÝöúÑD©ûÞÖ|¢âb¤X hNTIjtÆŒ¶W°ût9PæŠèpRåÒÖE–ÐD  I-D…ÁÝxãšéùèG?꬀˜D6X‰hÝ £Š>`¦¦Ñ&ÊC`ûöíÑá¤:ïZ³'åé0=É’’4Kº)Õ­3¸?ö±éùª“*I®‘]ª)!žžÝ,Šr!x´„£K—ŠD@᤺×"ÂI5¥BÂü"X¡mA’zxŒqʤøŸÿó¾ýöÛgΜ阫)RbÆ-6ºYGÇIæHßèpÒš[ ’µËU%#PrIÚÚú±ÞÞÿŒ6o`à§ôGô‘|ÄÄâh‰$:ãFÉ”î¸ ”ÀŸߌºzкbp>J.I¾f×z½ÿ­…KõâÖ[o5'dh~”8ñ|î¶RN,IÍà Š2£éð%£(à0a’Ÿ€®{åʯÜ>Æ8Æ'P3œT7,ñfñyV¶dù%iâG`q.Ô§¤Rå›ÅzÝÕÄÌU÷v½¦É.J–àBG.H‰jÆ´···²ž`]Çß; \IšØµ4W‘F›ŸÜG½$n… ËMIjǧäøÿA›µË^ÛŠÙS\î{2¢w¶<×3ê¾vŸ(;¯¾˜)Š´²n`cÇmq]$ibïÒö&mrЏ\{#vå'n— ËDIj‡$½á†¤DõTIËäô¥.¶<׳“¤:FPøVV—Û¡°-®‹$Mì-’›Ñ‡ê 6æ&Æ[‘ ‘¤vHÒO}êSòHØÄ±l¹3»iËs=;Iªü£Uv{ûn‹ë"Iñ1-âiŸSX Ú±jÕªFêçÚÒ@’Ú!Iu ›¾ƒFŸQzg¥ƒ¶<׳“¤ø€¥lq]$i#¦ôÊVƒvApv#x«p-’´ ’ôêÕãu=³õ)©%{LCμ*Ü“}´å¹^—{Ç/Œ\°×ÿmq]|¬‹'Uü·l7R?×–ž@E%iàç£ófÖŸžS§~,þcX%eö6Mš4I‰Kï‘t°Ü’´‘› ¹`ïÝ1î¸D]¤q ãcø˜6àJtFä Ö/œjÑáÒ_‹$ ˜%Íú#²ÞúUþ—¿ü%K¥¿kv°^ωó ιL#]@.ÔôÂhdÜótQ|¬AÒ¦ûˆpR­ì+AiƒMpy‰ TT’Ž?FuŒ7ZÿNžT¾ÏkÂÔùмá†÷;÷oK—Þù÷ïoÛcþúúë/lÞüÀý÷龬׿Í[om9thûôéõzòä›õZ3 î:OœØ5cÆäaƪLOÏ¿˜VÌOXþÏ_VTxWWW‰‘®Å!ö\ïë{V^7dÈ{älGŽ<-š8ñ#¯½öS½øõ¯÷{ÓK/ýD¯õÎ-·ŒÓ ¿[zœY—«Œnyõ‹/þàØ±gôÂíØ/¿ü¼ÞQmú«ñØÀ:ýÅo½À›+ðFˆC‰2$g–T¶<ò7÷ܳà…¾;a‡ýŸ±*ðØc_Õ'°>‡÷»÷|n»?Ãåóú„WUë×ÿµ>ÌMIÿm‚¥î*Š%0ÛºuëêÕ«So” KC ¢’TOîçžÛ¤˜NéQ=h=m³fMyúéGôW=Ý¿ò•Ï›¿®\ùEóŒþùÒg¢ySÏW=’Ml¨ê|öÙoyê”ýÅ/¾¯¿ª˜QîÏÍÀ:?%µÞAF·ÒÜu‰;ö\—kéëY´¯¯O‡Ý§Þ(–†@E%©>¹ô¸õDçãìºëÞ;8xÈüõÆŽ}íŨQ#ϯѣ?è\ë®çò壞:ÝyNý΋À:?%•ޱ4>GG{®¯XÑ¡é%MÃ;;ç~þó^²äÏåKzoÛö MéõâÅs¥P=ævKÇ™5áúûß¿èäæM­$8…CžëÁÅo½ø7Bbt\Ø\q$©>WÍG¨>~õ!ìw?}W1y ÿÃÖieøðëÌZ–¼Ôù ÷ß&HÒÔ½"údQulšº=ThêJRçÃȯÝŸžZsw>øœ5w=°#> õ'§­.é{ÿ–-êÿ9sføE°¿ÎÀOɈƒÚìr8¬m„@Øs]n¦¨’Ç_yçw˜@=¹oºéz¡ÿõT~ÿû‡ëGGF»¥ÛÃ^û-©YgÄ-ãÜzáÜ\È…F\¥hׯ‘¤Î‡­Ûë'AUÀýÉñaî.é¿Mð±,üDá¤ÚzV3Ùµ³`^š:-–¤q6î…}~Ì9oê[õ«¯v›çº3ã|ÕvŠ…}\:ïK"håHSSŠ‚ÒwÏS9°ÎÀOÉóçÏ—ÆçèH FüÙøŒÜõÀokeÜüú…/ÌÓú¦™ÕºbQ̼©þE»eI*uë¬ DÔé/xËÄ¿pžЧSÍó´âHR}}rfI¿ö;³¤æû•çãT×:­èr³Ò¥7E­ÀÛÄóyûf ü4D@ù µ)¬ åØÞ¼ysC pqy X|ûÉ­uÔuwwwħa2I:þ§4á¤*Åç9a£Zô1:U±¤þùΰ§øÿñi‰>@åh­I™UÑÀ:ùâ^ÞÛ-ªgø³ïL,©;6ÚD‘îÙó¸ÞWä´BBMD©þºeÍïWn'7z×KX§¿X`+ÜVû¼Vc§M›¶~ýúˆx÷8’T¶]]_“›éÓÒ‰%u_¨(y¢Ë—/2ÎlvÝéû˜û*Ù¯¿jF@qÕ¦dàm‚$MÝ÷¢OuÑŠß’%KRo” ËAÀbI*%ªTúÀÒ™FúZ8˜L’êû÷o~ó³{ï]¨Ýš/þÒ|f™MÁk×þ•vâk/§ç z˜$ÕîU¢9*mrÒ.fs•>vçÎýdXHÒrÜZõö¢>~|§vifHgm+6.¤‰yÍ*™íƧOï3æCúßü)Ð-ë’¤ªJ{¢åÒj:¢N±ÀVo.n„z]¨‰åwíÚ¥‘:thGGGO²”xâHR¹Á£Þ§¹|EE+Ÿƒÿ3ÖÙq/•éì¸7_æL™ /Hrrs•œS¿Þ}÷§µCßù ¼M¤Y¸ÊaßOLŽí,¥Î°X’о6÷9Qhú4ììì<|ø°{T">ý¼Â¾ÃZR î´8]¨ˆ?'¾Ñ¸âxQ³Ê(‚Ðù4niiQºÖãøQ¬å#“˜ÉãšÔÿÌgf'öÏA]õàc©øî#ÂI%XkFz¤b•XGÀnI*ÜZpïÐkmNß¾}»9@IjGVÜà*øs]Á]¹Pä»C³_špkoõ}÷ݧ÷Ã>ŠMRg“&Oÿ”¶I³¤Ê­@Å;%ö]èlد·|,“XŸ7o^ooo* QIÉxä\©~]¸pai$i©†Î$"P®W%8åa㢢H<îy^ˆ$MEâhÕþúë¯;YtÍš5œü’ çòUbý,©ÎŠð|âê›z{{ût?”F’–ÏóèQ *øsb…\(ò]£hþÑ£G{>uƇ¶=)›„-ÅøXZ>¦Õù°“E÷íÛ§(»´¢ž2°[’š¯b·àÈ‘#u”ÙÀÀ@tSâ'b³.äS²L·\D_*âωï#n„"ßJîãÖ£:¤G§™;!ƒHÒ"]¶éY¬/Ø5GoÉÏÂê´…€Ý’tÑ¢EæCPÙwøQ7z[>£Ò<‰m¹´³"þŒ$mÐO xùÑ£GM ©æV­Zåž0ÖÚòQ̇mZÞ¥)Ríx «Mêq21§e õØBÀbIªÉM‘jþ?"PºÁÏA®è{¢ÿOzÎÿ(U6fe |Ä*ý¹VòLBÓÄÿø”´åvjÄÎüÙñÀ¿•Ÿ+µ“ñ[ù¿¹Ä=û¥ü¦ÚƒòÒK?qjS1½£<‘›6ݯìiî÷£oŸzïn„F,Ókµ©´µµU)'ÃõÈô£¸æu|OÃÇÒòÎéûIX8©Ôjز~ZP,–¤Zr' ¤ßàç rã™´‹Ê7®üùžÏ5e|œ=ûãaMè‰nŽvæ 7X, å´'*>øšÊ™MC¼ëÑG}饗TLïh3ò¦M›~ó›ß¸ß¾{‘–?GHRwÎì¾»óæÍzòÉ5NÌhœ€ˆÛ§®;¹Ð oǼ<úƒºæÇx¦®íK{>ÓIâ3á¤a'‹F:§rÊ”’@®’tòäÉÇÇ={öÌŸ?ßôܹs³gÏûD8yò¤.9r䈊ÅŒTá”:Ú>ìÙKªùQ]uâÄ.-•ÖõèõV: ƒµû˜ƒÞH±h'”²4£ ÃõÚ‘¤N‹—/_~ê©§î¾ûnóŽbìn½õÖ_|ñêÕ«Ò£zçN…&_û‰¾ºŠ?®ÅûgFõŽ–ô…¾{Ûm·jw”S~Ô¨‘î_õþ¥KGÜ}ûÔu_ ñíø×F;g]7Ú—Rñ4|,¾ŸÄ)q²hô¡£q*§Lùä*I|zBkªÉCsÖ¬Y}}}cÆŒ ¤ì.ï¿6»G¸V9W®ü¢Îb®W’¦Kúï|G‡°•ÏÿŠÖ£h'Ô¾D§l~ýõ×§LÑ׌k?žg˜Û·ï¹çžgžÑ¦õ·~~ýë_/[¶ÌÓåÀ{!;vGƒº´¶ÛkõSrïÊwKaEŽ*~Ô¹öÞ{>ýô#ί VQ ί5o$iÑn·=ÑΙ³ëFûRZž†$M×!u²¨¤g`O<ñ„ΛM·9j³@s$éÅ‹§Nêa§ *ÿÞ)3wî\3Kª“•„9&÷g•tóâÅs=³>þ)ÌÀǪfFM,©¶@)N]^šWVÆ«°+1iP¬&h'>|¸SƒóÚó S.§Ï|æ3¦Ø 7Üðûßÿ>ºÑÀ{¡‰’TÇ‹oÙò <°«ëkÎF%Ï}´paÛß6^jvÜ+­„^+”B¨Ÿ{n“ùSœÛ§®û¹PÓÓ-íœyºn´/¥èiøXº.‘?:qiºfP›-š#IW·ÿþ@FaŸ/¿ü²9­î¦›nR\iL¾ JÒqãÞq>^àŠ§§ çW%nT(“ßQíº½~IªCµÃ‰scŽ{ƒÅœÐý¾3UÿÎ8ËyO>ù¤3g:?â^ð÷¢AvûU˜ßê{”Rê òMv:¹x=…_{í§Úíç,Hh5_®®dgŽU[·Oƒ7Bƒ#ËåuˆvÎ<]7ú£8EOC’Öå!q +a­ÿè]¸4NÍ”)&HR ʵk×FÎüQ±¤šÕ›©ÕÕ˜#‘â#¼‘Giƒ×ªÊ—¡øÓÃ1ùP¬®ïEѳ¤/¼ð‚¶—jw”Sç¨Q£Ü¿šOaw‹Ñ÷B¦’´AŸlÊåÈ…%€+1ª¹7 SÖîËqï%è…<ÁvN|ã˜AДf UšÀyš{‰®«$HÒ,üDß!§MÓ©Ú?Ú¹ëD:eÑ4uÚE ä’´µõ–Þ^—ë ûbè~ÿûßÿ—ù—ú6©pÒÝ»w³vo×=–¢µ%ðçÄw™n„––ÓÌ•2¹’¢ke]Ukëäâ+[_KËÍY£¨`ýšLÑݳgÏúû®ÙSÍ¡V ]$PrIºaÚööÛ?‹paGG»Ä¨Â5?ªXR­Úë¼{Öî«y?—ÀŸßSºÜkZ+;vlüÅÕt˜âôzÆGÚÛÿ$ñèçsaGÇŸ­[š °80m´¤££Có)~ËõõR¥6ö›³ PrIªd=3g~\ªT_Ð#Íçó®®Vd­¾²wt|V™Û´ä!ú_þËYµj•œ`Ñ¢E:Š- o Î‚°×Ÿër~wa÷àIòªÉ©RæJ î´Æ¼7]÷R¥ü(~ÛÇþlÒ¤y|Ì ¶V©dOË—/÷›ªûWs.Vt#s PrIj> 7lX¯Ï÷f+^·´|TI†e¿r?)ô'?ù‰ŽÁPKÇ×Êîb6a¯?'¾éœÁ?"7nÔ6 Šé««ÞtÝ Åü(ni™°fÍCèÑìI«öZ»¬_ïóÅ2;òvÕ\~Ij×xZ»~ýúÿøÿãÏ~ö³¡C‡êé«ÏM)Ô3gΔ kt ÊA•6ÈË!IÏÀHs6aÐDñ I‹?F×6shc‡‚ç4KªpRY¬¸öÝ[0r˜˜ -*ùkô¹B#€@(ûî»OÙµýÖ·Jã8ˆ’Ô7P’á~ô£«W¯V,© 'eíÞ‚aÃÄ 葦tܨÒ‘Óê# íM Bó_£œ¾RÖW¥KJIjÁÀ*Îæ¦›nÒŽ{)Qsë^¸pA‹ø¬Ý[0x˜˜ e™Ñ¶?Ti.°iI˜t1þï 3Õ'¾O&aZºk¤ ©·:ÄR›‹¥DEjn]λ·`ä01_ŠiqNsÍ·qZƒjPìYàÀ:V4ðÄQ€V’ԎחKM‹êY«‡–ѬÝÛ1rX™#}[[°`ñQ¥9R§)Ä% 2Ú­ë/­{–̆q!–º’ÔŽáÕ—Ë›o¾Y§7iH‰od´öÝK§²voÇøae^¤Jµ—Ýyñ¦ÔA §§gæÌ™þ ¤G¹gëàXÞ¢HR;ÆV¤Š"Õvû­[·*`έeJöÝÛ1~X™#Å·è±8“£4x ˜ †ºC=Ъ½Öîá$©> íöóçÏ׊ýýýN„8k÷v VæN@Ï<}…SÒVðsgOƒˆ" E “ÊÐý£Å íp"a>®ƒ$µÃ4ª 9“ACûœô¬ÝsÛ1„X™/3Wªoqù6Kk€@-ô™T†ž}àÀØUœ’ÔЄè§?ýis ¨ÖëwíÚeìÖk¢ÂíB¬Ì€’ËèŒ %âνe„‚ h¡O›týS,)·*Nƒ$µÃ´±éÖ[oÕœ¨Ì•Õq5Æn%&ɰCˆ•Í  ý¨Òf€§M„ÐÉ¢ÊQêù³)Ôš>Ô*NIj‡èɪõúQ£Fé…6-ê)kì&ÇŽñÃÊæЬŒnœmÛ¶5ÏZ†þ@@‹{þCí¦pR0Uœ’ÔP^Ò?ýÓ?U´BHuë:éŸ`ÊÚ½5£ˆ¡Í  xkíçݾ}{3§M@àx¦­‡(L¯à%"€$µÆ 43úå/ÙLö´µµ9ß2Y»·f1´yÌ\©„Ýûî‹3dXb#T©£†Í6ðωš³ mì 67HIÚ À¼/7ÛíQªzÓ¶?‹k÷y í•‘€69i¾6<•±sô E!x²¨'~QÌÅŽ, I³¤›AÝf»½{—¢ÂÃýk¬ÝgÀž*+GàÂ… R¥ÚðÄ ~åÆžçE 0ü,p'~^ÑNÓ I›†>YÃJ•oæëSƒYãðlfí>^®‚€‡€Q¥Îí@ uþ“EõŒóïÄO½]*,$iÑF¤†=J¡“-ÌÿNQÿœ(k÷–+昀Q¥]]]¶Ó `18©VóŸfq—0=$i"lͻȄÝh‡“;ÓSà‡có¬¦eØM@ªtÚ´i7n´»XB0)·Ý¦®æÒvŒJ“’4Mš9ÔeĨçv Ì6¬ï¬6æ0"4QgΜiiiÙ¾}{EúK7!'ÿ~&‰TMÁäim5’´éCPŸæ\{]ãž Ì6,ñª›¼¾Ú) „0ªÔ9ÎT€@Zük}z‡{--¼¶Ôƒ$µe¤þ`§òäë'“ Êy7ðP`ÉV'W”}ýÄb€¾þ5ŠÓ‹72Xd7ÿZ_àêŸÝÄúZ¤µïï&)©ÙwïX§SÝÀcY»/Þèa‘õúúúÆŽ»oß>ë{B Pþµ¾ÀÕ¿ÂØ‹!™@’f‚5ÓJÍŽ{Ï7È@õÉÚ}¦Aå•%ÐÛÛ;bÄTie€ŽgAÀNêÏo˜E»ÔYHÒâŒE\KÌü¨g‹bઑµû¸X)zôôô¼+ã…®Öce!`78©?_©Ý=ÄúZ¤µïïŠøÖN 'UP©c]XÊ wRýâu‹ `[·nU¼8t PÚáñy¾ÒêШfO‘¤ö»“'ßìsr:ø…’pû‹!ð&ŽŽ€8l PdÇŽ›>}ú°aÃôÿ©S§ü¦N˜0!° þ‰Ï¡0Eî8¶¥BIš Æ\+q–ì=4ì ¥Ù•«‰44L@ ÷ÚGuúôé†k¢äD`òäÉÇWc{öì™?¾§ÕsçÎÍž=[/aÖxjL©ä4l…iIZ˜¡ˆmˆ³d¯å{wÚ¶°pRÖîc£¥ ŠE`×®]mmmŲ k ƒÀÕ«W5Wê)8kÖ,%¬3fLXþ‰ÿqÙ1§ˆ­¤VŽœÙ‡èÑš’ª&‹¾çG_4µÄåÊ+»ŠÑ¨6-ßoÞ¼¹Ú è½}.^¼8uêTÿ,©Þ‰˜%õO¬(º”Ôö R‹‘¤IÉ5õ:st“?ÜŸDØ©µûÇ7Õd‡’8þ¼ŽŒb÷}v\Ó<›6mÚ¿`û’ÔNªïckÖ¬i^?h9WHÒ\q§Õ˜9ºÉgãO¢aZÔ|êêÕ«Ójz < twwkùž…Ž<™ÓV#½víÚ°"$©.ñLèIw؈U\[|HÒâQ€…N©'“pØ l¯Ú'Á#ÍÊÁÆh¼ñF{{»ÒBAÅ' =L+W®ŒxÜDKRÏSL«žÐÓ²IšÉ\ëq¢HÍ ¾ÓvÄþDöÝç:B4T (R\Ë÷ì¾O*•¥OàСC‹/Öú{DÕÑ’ÔÿkmmíïïOßVj,$iñÆ$†EÎ÷Hs¸¨ûаpR©ØU«VŨ›"€@ 讟9s&kElz›À¸qã܇š™·=4Z’ª¼ç)¦UA–*âbHR+ÚÙØäO™Nj¾zò<³r¼1oÐWP}·ÊMÀóëêêb>¥Ü#îôIjå@k±^Kö2ݸEX8© Ï›7O)6¬ì0FCo¼¡¸:…³ˆ‰/”›€ç)ÖÛÛ«µûrw™Þ½5¡ (RǤ õïFŒØŸ¨¼údÓ°q¸±­°û(7O8©÷FŒqáÂ…r÷šÞ‰³¤¶º9àÞѦN7üyÝœ?™cŸX»·uȱoÐò=Éóñ…rðìÜ6mšæJËÝez‡$µØœôF›º{â9&Øý'¥|#g¾Å£Žéx{ù^3e%àÙ&¡XR¾†•u¬Ýýb–ÔÖQvöÚû¨Ï“ÓI­Ý'nëc7Þ&°wï^M#±âG”•€çdQíšX´hQY;K¿HR[aݺufï­“6ßé‰ÿ˜`çOšO%g¾­CŽÝpЗRŽdÃ#ÊJÀ¦-}ÊË[ÖÎÒ/$©õ>àdËw^8]Š'U­Ýë|BëûO PmæTâpªíeî½gpÔ¨QgΜ)s‡éÛ›ìõ'ý““£ÔÝ—ˆpR­Ý/_¾ÜÞŽc9 `˜åûè“r`K x"ДÄP;Kû‚Ù1 °pTáŠ9Éž'5ûîyŒnD1õÐ×KÝìõ_Ç(:Oš2nܸÑ1ºçÍŸ¢÷ûê$€$­XaŠeiÌQŽRÄô§Ðw®Ýú|Ý,ÌHb’TŒùq’äÊ¢ðD )ÞL¥ÆØ]»v)S©¦cŠj;v%$€$M®—9JÔ“ÂM¶N:6+›k÷EAl€@ã4™$U*mÚxUÔBøÓ?ýÓ… j†EòT¤fFg; :”ÝN…©´ŒA’¦E² õ8JÔIå6B'Ú‡}‰Ô½=räHÖî›0f4 (³_23àJ•M& õ©³ÊÞõ®wiþES¤7ÜpÃC=$=ªwÚÛÛ›lÍg@IšÔ¼ªÔÞy³þî$„r·¼téRÝÏa¶hížóîó(Ú@¶Ìò=™4²¥Lí¹0Ë}úº% êùápìÜG#‘¤yPΨ '#©¤§¨§•À72Z»×ÜjF†Q- 3³|Ï9à9c§¹¬ H’þÏÿù?µdÿüÏÿ¼aÃí­“üj•wò!ÐÒ2AÓaé† !I³¾¡2¬ßÉHêì¾w7Njâr8ý%Ãá¡jäK@Ë÷ù¶IkÈ–€YîSþ]³^ïü|âSÚÛoïíÝyéÒ‘7Þ8Á¿œ \¹ò«þþut,˜6mZŠªIšíí”iíζz÷î{w‹á¤*¦µû}ûöej!•C¹Ð7LM”’'7à4”g¹O+õ޽þúë¤Gsa4H £c¡æJÓò$iZ$›P{rTSž¦#¢ÃI·nÝÊ–ˆ& MB 3}}}ú"êÿ(ȬA*†@¶œå>íÇ9s¦Q¥Ã‡_¯ùQ4b ü·³ I³½2­Ý=9x\“ÿ¬Q·=:PG´±ï>Ó1¢räL@“I97JsÈŽ€³Üwúôéw¿ûÝF•²^_=*®\9®áHkôS«(-ƒ¨§.NjRg«“ûrÏéþš•Vƒ]ºu§0' Ð« &ÖsêÔ©‰'6lƌǎó”Ñ;Ó§O×_õ¿JÖ å{Ewq_7>LÔPî§Ûç?ÿy#I "È0C¤¹Sšo†“š4pBÔsú…ß\­Ý³¢ù£ˆU"pîܹٳg‡}ˆ+–fÛ¶mâW3yòäãÇë¯{öì™?~6…ô(’G[«Ä•¾––€{nE¾­s›¤…’ÂHÒÒÞ{õvÌIMª¥zí¿ÍQ¡.Ô"ö!¾bÅŠ-[¶èê®®®eË–yª9tèÐâÅ‹ëZÓÐe¥V¾ñZñwŽ€î“«SõåÊÌ­l߾ݜ,ÚÓó/ñ5S J&–¤Ù)Q‡*’´pwN³ ÒÃI©IMëîE|·=ÎlaFên×CëÂ… ÍêíB j<âί'OžT¦§!C†hºÔÉ<êüuܸq&)£ù‰ mýúõJžsb5fƒ@ä´mmmruÉPÍ÷+¯sÒý™3?õ Í—_~~òä›o¹eÜ‹/þÀüõ·¿íy챯>ðÀ—ï¿ÿK¿ûÝ¿›7'Nüȉ»Æ£Â*yìØ3z1nÜè“'µ0VÀjUÉ¡CÛ5+鮪¯ïYý:dÈ{f̘|äÈÓ‰möKÒ×_AÑ ê—z§×¦f×gÅfIS4Þ5ÿšŽ;ÄýPK§5jÉ€€s”hØN&ç@¶ˆÆµv쾆 ‡*!Ð|z®ëÄ?M/5ß,€@ôüR¦B÷71óúÊ•_ùå]gçgŸzê›ýý?’*5]¶ìs?üáF½Ø¹óѯ|åóæÍY³¦èWÕð ߽ë®?Ñ% ¸”•vŒY °Z‰ÎgŸý–§*Y"ªj%|5t·å1möKÒ•+¿øÚk×tùóÏÿ“T©©Ó_›ÿÂG’ÖéÎ(®T/Z›SGÝç‹zúíÈÆC+#lƒ¨€³ÐÅŠÐî{=×µ/ª¢ý§Û6ÐVgrÔ=íç—¤7Üð>T½ñÆfÏåËGõWs‰æ,ÿû9å\⨷š«ÕåjÅ¥Ò®µµbEÇ#ü ¶Å´Ù¯,Gé=úƒæµ¿6ÿ…)$µùÆÊÆö%K–8œÎŒ©§)%ÍÖò}Dû е¬Ýg3DÔ æX³fCX¾oþH`AýÌ–¦wF­ì"wä—£ÕÜï 6Ô£õ«»€_½Å)]­¢´¼þøã+ï¼óàQÕõÚì6Ò©JÚß5Ï;½«×xÿ×€·Õ?¨AW°pŸÇ&ÖâÞÕä̘zì©NªòniÛÄîÐ4 ‰ÑiÓ¦)q•S'²& u¼š’Ts„Î<¥OÎŒ ¦BYÒ@êVŸ5 ÔU­jÖéßÖÊ~àÌn]6;¶É†8µEÌ’Æam<³¤Y»½}õ»w5…꠮ 'ÕÚ}à‘¤öÁb@ ˆ€thùþÌ™3à€u´ ÷£ýhôÂý¾0OA¢žXÒîî.)'E”._®Ca¼é’Í’*3fµŠ[5±¤îXU·”¬×fÇ`…¼új·ªR,éœ93LþÚ®»î½&JÁ¹0E㑤ÖÝG™ìNMª$Pš4 lRó£sÇè¯ÚwÏY/™ @ y”<_ÉtX¾oÞÐrr ‰~Ï{ÞcTià òéÓû&Lø°6Ô?¾Ópv—?øà=ÎŽûš“ 5 įV–LŸ>Q ëÚ;¥Ý÷~³ëµÙ±Íì¸_»ö¯–.½s`àǦfm]]_›;÷“nIš¢ñHÒäÞ\Ö+Ý©ITªõ÷ÀžÖL˜¯«t-ÛrËê'ô " 1ªðd¹>Fàâ˜7o^„$ Ô©¼™57Ur:?©U”Ž9ÔR?wjR·<õÔä9#8°ÖîëÇϰŒ€¦š´âÞ}¯•–°ÕËú†¹e'ÐÓÓ#ï ›%ÍZ{Q?Û›Ê~‡¥Ñ?g£}ĉöaYKÝí³vŸÆhPŠN`óæÍîå{íÄׯE7û ðÆzHýã?þ#’´Pâ˜YRnÍwpo´Ÿ4iRà\„Zu×¥N{÷î…/ PnúÐÐÎHõQ 4wÇšk‰UZ[[ÝœyŒ€)Ð ´–Ûrî’Iš³ËÑ\Üù›¤)µ xqœpR=¥8ï¾ô…€´|¯4t¾†Òt±Õß߯®H<µµÍnoÿtoï³—.)Ô“Ï:c®\9Ñßÿß;:îVú-TiŠ7JÕ$iXšý‚ÜÌ’¦èÛe¨ê¾ûî3úq§)õô-âONI=¢©½7¿ ÈèªJ@÷¸²Âõöö®ZµjæÌ™š5’Ô|†lØðp{ûíyÔ•ÅŒÿÑѱˆhÝo¸Ü$©NÕ~yå“×ÿ§N=çwÈÁÁCÚãæ¨Ï=·iÉ’?éÆ <‰4<¬ó„ý×ý¯1Ûm¼’4Eß.CUîÜOYñã$ÌmiÔ>§2p¡€À; (,gìØ±kÐË—/WÙÖÖõö¾•@§ñg5?Õ >ΘÜ$éäÉ7›|R{ö<>þ§<þ|îܿ͞ýñ0c”_Ü;™§¹â÷×”Tš'eÂòœ­ÚˆÑ×"IÓrì’ÔãÎý¤óî%ر8 óu¡&KÂ2I•„Ý€@… èÜ`ÍúU©—EEï³^ŸúÃ[+ø)>¶+ì¼ou=¾DKk(µtéÔ©4øJ5:ḟ[Ù¶í=ÔiþdrˆÞÿ—xàËz­w$ýëýzñÚk?½õV}]ùC*û—_~^RXröÅ`Þ7?õúè£÷Ý}÷§¥žÇcZTÖï}ïá´º$妫ƒ€[†jUNðÃ.Vô˜„itÕªaĈD>Õ1…€m>¬­aª»>ÿ‡}>Oͦ·‚$MñÉßK/^ü¥õ\³¤n)éñ±Ï|fö/~ñ}óæÊ•_”ôÔ ´$Uê–ŒO?ýÈÃ/s×ÓÙùÙ§žú¦û *§¿þzt¡ŽqzöÙoI4ëä*©dÓ¢š^¸°-·OÑ·ÉKšâmÒ´ª<2ÔÉ å7(ìÄQOI­Ýkæµiý¡a@ {J›¯õC‡u„©vFæÿ°Ïç©ÙôVR|lgïEo!/Ý´éþýûŸ ô¢0cÞÿþáÎáõ£Ft®=úƒzÝÓó/&ÌTÿ+bÕ-Io¸á}ž5w§ =ºð¦›>`ö?éàPjRÓª'·OÑ·‘¤E¿÷bÚçÎá±³>f8©ŠuttÄlšb€€½”júôéF•nܸ1ÿ‡}>Oͦ·’âcÛ^gKËòœ½T§têÜÎ0 3F‡ˆ:—¸—#Ìû‘7Þ8BÿkÞsêñWèþ“S•S¿;¢À}­?Ò £» EßF’¦u4¹w:R÷|Y1ÃIm6räHýßä^Ñ< /}éKÆ »ë®»r~ØgôŒ,`µ)>¶sñˆB7’§—ju^Ëå[…ÂŒÑ$¥3K*õé÷IMÿï¬]¾|‘G’º/ôü)°M»ó´ýßѩ̒ÚƒKoœ;©{¾¿ãîùÔ,‹-â¼ûÒ» „€CàÓŸþôí·ßžçþ€Â1;“¤)Þk¹yé¡CÛ/ž½á/̘;ï¼ãÀoR¸ç«¯vë…bIçÌ™aÞ|á…ï*·”þ÷èÎ/|až¢Bݱ¤ZŽ×¢|X= NU@ªþúÃnœ1c²©íç?ÿg?»kNÑ·™%Mñ6ifUî Q„I¡†Y'a¾®ÝµkWD%Íì*mCPHzWWWnû|–Åi%ÅÇvƒoY•¹yé¸q£Ýkîíø«ãrÚð®éUó«Ùq¯ÕÍŒ üØySñ¦Îü«Ó)Å (ש¶ä›üSú×Õõµ¹s?QÏc}UÒY;ô$©jZ{¤òñÿ}IjÙ­f®; ~ôê¼64è§f·µjï¾y äL@+J¦QóVM·@nû–iõ%•zR|l§;â6֖ʈdíÒšŠýÍo~–uCþúÕ¨´ing>¥èÛHRïÇ›•LT!¤Î"Vç<¨‰Ò’t›n@ ¤Μ9£ï™:J­­­-Ï£+¬xØÇ|ƪ/)>¶Kêòut«P#á:½éž{´bym¦3Ï÷Þ»Ó›êð'ЦNÀ³XïÞíäiK‡…jëG†¦>TÔ è>UH·ngý£9ܶa{Oún=_• [Ë…ŠcSp爭6ž8±Kùº•ë[ˈÊn£Zýg¹3ðM§ž@3/ 1&u©\…JûÍo~ÓIš§ mb[)~Ýb–´$·´2¹è¹åtFÇ/E$NZ4töèîîVl·Î°Ð±ŸýýýÙu(ìaïOß½lÙç´BBmÅøÊW>ožˆÊÔ­_µd)w×]¢h6­JJ;Æ,X­D§Iî®J«¢Ò©ªVÂ7ðp§/u*ØîÉ'רÎgžù'Áxà›N=f^‚$ÍÈE{zz4¥‚$m¢ÍÔ·‘¤Ý8yW«é-Ö;­FŒFd‰ÊÛnÚƒbÐjþæÍ›u›³Ð³9öuu {ØûÓw›¬Šz>¹ÓÍhÎÒl Ö?UåߺQ³@`µªÊɧãX¨]ÌšæTÊñ°˜9§d`JcêTê'Áxà›N=f^’éc»Žá,]ÑÅ‹›îBi²ŠÃ,iéî³4:ä>´É}ê½¿î˜ óÓ0Š: ô (ºô¶ÛnÓ©ôÊŒ¡C˜Rl ìaïßýŽ“”Ûýfàëº DW«híb~üñ•JvcŒXq+HG;¢Á©30Áxà›þ M[¦Î°Då™’âc;Åá¶«*-2IZ4œ¢o3Kj×-e­QÎþ\÷©÷þkb&Ì/z2Ð9õ ÑQ˜©VEΟ?ŸJ#fIyJóDt¦5ê]X—â ,\Wµ2CS¤Êþè¤ct?­ý³¤nSu £3Kê$|3Z’^Â,i*Þè®DQ¤·Ür‹ç[GÑÄ™c‚I”sT_Wôÿ©SÏùíÔܼÁ\ï_‹Ök$iêÞ^† ÝÙò=ëøþîiíO´ ݦ¨6‰QIRØ­Zµª¯¯¯Aa’ÔŸ¾[šÝÝ]z:*¢Ô{Ñýº¦f_­@M,©;À4P’Ö©YJ÷hìwbIߌ–¤— IôCÿ劢vôhñîµÎdݳçñùó?åñ5{öÇÃzý×¢éÑ·ïîtœYÒt8¡O„h´èt§Ö/‚ñØ4B@ÂÔ„™jµ$z5_ßWu–}X[aIúngûƒÞã츯©8kˆ_­ùš‚Ò§öNi÷}ˆ ¼6¡X§²—?úè}K–ü¹¢Q% ÌåoFKÒÀK¤8³ÿZEN:Ô"Iê8€fñýgÍë+¤¬2ÊuhäéÁƒßKkh²«Gá.:×>¬~$iÀWâl½‰Ús$pöìYݱNƒ5%a~ŽƒCShÍ3éä§ÖÖV­×wuuéWÅ’:ÓNú“Û2$iFIšàPŠžSrWíÛÓî=Å¢èœB£JwìØÑH¥U­ÖßuŒ‚“š7"Ö9ÁjZF¦ROоÍ,i‚Û¤¸—¸¶÷(T¿ÑÑéô‹ÛI,ƒÐPíííš4ýä'?é^ u«R$i*i¶7%òPïEúN¥¬g*¡5yéÖ­_Ïh¤R©V¹ /ž{éÒ‘ˆÚ˜%e–4•Û¤¸•x޶w+T¿ÑÚè-PÅí –AP”ù{Þó·$Õ^fçüá*HÒ°ÓžRÑ"‘«´ g5ªÔ ‹v89 U^ºjÕ3¯+W÷-fjóÜ\uýÚ =™^Î,i5îÂú{éY‹w'Ï÷W¦õ;-ô+¨´þv¸°€nùE‹ùwŠ˜w4‡ª.5.I#r€+gøÄ‰QNe¶W.qÏc²fvqmiWΦ˜×ˆŽøw@GGû©Ñý×ÿ³]$i7†¾2)Ú©Yƒ;0ðãG„ËÓ"€$ÍÂçËP§Žrqf;ÔŸšÉG³;)» 4éJD ··W™¡Âô¨Þ×Ôé~ðƒ%it–oeÔß¶ízjÕÕÉ®ï<£³‹ë¤¥[nç$@mäi¿¦¤ÒšJIGÆ1&ÅÇv‰¼2nWô,Ûºu«[’ÆaN™|¤èÛĒƽ%¬(·nÝ:€;¦z2•ú» òI³­è2FBqh÷½ò;º™§Mæç»ßýn[[ÛW¾ò•ør-ðiå['(š3<•^~Ê” aÏËÀìâÒ²=Ôi.Ñå:Ýþþû¿¤““ôZïH2šDN¯½öÓ[omq/’¾üòó»’³/¾øó¾ù ¬ÇP%‡ºûîO+ÿøñcL‹:à{ß{¸‘|Ší8Ã]²2Ú™§ïTê”–õþöoÿ¶A/md¹ÖO EßF’–êÎõ$~òd*õwÕlw(:4@ Á‡}t–ïáïsžgîמ‡\`vqe³ÿÅ/¾oJj#³¤§^<ÿü?I•º%ãÓO?òðÃËÜ’´³ó³JÚßÿ#©Rs¹ÓG=ú«Ò”>ûì·$‹wî|Ô9hTM/\ØÖˆIñ±ÝÀðZy©I•oI•pwøðá zi#ãȵHR+­îK§OŸniÑ„AèbËt4¶{WcȘQ@  Ry؇Uâ~ßÊ¢ó¨ Ì.þþ÷73¬ú7jÔH§ðèÑÔk jÂLõ¿‰RuÚºá†÷yÖÜ?ùëÑ…7Ýô³ÿé÷¿ñºëÞkRÓª§9‚$Mìá:kP1iæò¿ø‹¿p&¹®M‘@оÍ,iâÛ¤ˆúÏdÒ^ÚhÅ©ÌJùVÄÎ` ð&}uœ0AËÜ?§Nš8qâ°aÃf̘qìØ±À2/½ô’&™b²ÌT’Æ™% Ë.®³ì‡¨;"Ö¼/yã#ô¿*Ôß#ç=ªÊ­•cjè8O÷Û1‡²4ÅHjNÓté{ßû^3jÑù•âŒeR!påÊñ}IZšÛöZGg£ÄOî.Iqj¥#¢“:uГ+»TDè ,'pîܹٳg‡}èëls“6èu`_7mÚ4þü˜2•¤ŠøÔ¢¼„a»ò#²‹k’Ò™%•úô?M—.½ó;ßYëìšrÏ’:zîëÑ´«™U•‘Žf–4¦ÿdQL¤£ªYafF2¤·wg*ŠŠJ$00ðߢcër $i]¸,(¬¼NJáæêÙƒïï€ÖDôÔ‚Ža"*I`Ö¬YZÇ3Fûl~4{zùòeýáõ×_Ÿ2eŠ¿Ä‘#Gî¸ãŽøÓ™JR…inÙò ]]_[¶ìsžgatvñ;ï¼ãÀo›KTÏ«¯*eÕµXÒ9sf˜7_xá»Ó§OÔÿÝù…/ÌST¨;–TËñZ”«GÁ© HÕ_øÃJVejûùÏÿY4òðŽ?•tóÐNKŒ*ß¶þ¬“œÜ³Úθ72(\Û8ŽŽ…Ú'–Ó"IÓ"Y”z<Ùò={ðýVj®¹áù H@³¤²*LÐh«‡c³ûµóæÜ¹s›¾pïÈÜ“'wkó»¦5]ª¥í˜]Üydjûv#™_ÍŽ{®™Q'?¥ÞT¼©6ê4ªHíôW‹ÚAo.— ž;÷“õ<öØWuôŽvèëBs‰šÖ©FžßHÒd7—™41‡º%éÍ7ÿÇööÛ5WÚ`r®FÆ´Ê× »n½ŽŽÒŠ,J6¸þ«¤i‘,J=ZÚ0)¯Í¾YvttD§l…Ñ‹ûEév@ ªÂû}E”zð˜)ÒEðHx3;Rÿé¨8ÑßüægùÛ¦F¥M<ó IšìÞ•Uê=ÅÜzT¯W®\¹aÃ7&MºÅó>¿æF ¥eš5kRÔ£×>©’y W–ÀªU«Ü)…=ª3œ¢­Õâ>ᤅP ƒ@âYRM‘J•–C’J‰êô¦{îÑÈy+æ{ï]ÈéMͺ HªÇ“öéz”ÖÌ™3›eífGIšÛæÔÜÕÕµzõj§í8ižt á¤Í-Z…@<aslÚnñâEÕ¸+ßóÓT*±¤ù«Æâ·È,i÷ó”єʸqã¤JEO[u•VB§9Œ1B¿J¤^¸p!A\RdHÒ"NÛvíÚ¥Môî+µN J#êò§ŽJÒ0×@™4+V¬Ø²e‹šÕËeË”">ø'¾B’f¤nãAfNd_Å6l˜:uê¢E‹¦l†Zñ“HÕn?WªãÇìëG@’–ÍAü+õ5²×­®ïçÏŸ/ ú²ðçד'ONž¨•’ÉȤ\¤S¦è¨Uï,é‘#OßqÇ' Òc’´ÞûJ³$Zâs®Ò¯Ì›ÔËкòHR놬¶ÁŠ¿Ñ÷K§œä©DjôeZ"Ñ)Ø *­];% ò(ˆŒÓ,éÛ2.`Q~øðëê~í¼©Lø,ÜÛî¤z8pÀé…&MÜ¿ÚÞ;ì$€$-¡c(£“N¼pwLr³æî%ͤ²±„Þ@— P‚HR×Ìb€$u©ˆRÏ,©™"P´Y¯ÑÖÏ,i=nxm3“gÓ­sÒ}]õPØ.HR»Æ+–µþŽ8r“e‘Xp)R°B’FÏ’jŠTªIjµŸj¡O³¤NüÛv­îƇ@’–Ð7üû™”©TùJ£»ºoß>ÂIKè t 1葯¸½åË—[!IµÝþâÅ_JtîÊ÷÷iOÌ’Æð¸EÈ%¬Ð¿í¡æFˆM›6íß¿?Eô ;Es $iÑF${üYŸbȦU<…“ºwë§cµäE qIÑà£7Ùå<RtÝÅZ'QšaývøEX|Nƒþsîܿ͞ýñ°J–/_´mÛ7ä![·~]¯=®rÛm·þâß×›ûöý¿:Ôó×Ë—Þr˸ßýîß“9˜ûªø}4%ûÛ)iE<7Ò4ÇÃý;™j¦‹ÑôÿÚµkÃ*G’ÆÁ^œ2HÒâŒEš– Иy4È—æHä^WüÇm#Ï×ԯ喧hNT3 šÕ‡@‚:ôMpöõ=;ḟ=d„KYêO¯¿þ”)Ú ºz®¹RÏ_¥ez¨Ó¼©Ë7o~àþû¿ôÀ_Ök½#Éøë_kžìÄk¯ýôÖ[•½á„Ó‘—_~^yõ%g_|ñæ}óX >zßÝwúøñãÇ+ñZ‹>xÏ÷¾÷p#n‡ÇñÆ;vxF'ÕÖ.¥•+WF:ˆ$ƒ½8e¤Å‹”-ñߊ1µ¦bINž²5T—º$E]…k>©vã¢é"ÅŒ*HÔÔ©ÞjDyˆfIÝrÐã3Ç_ç¼ã~í.¦@OÍ¡.]z§çÚÏ|f¶™CÕ¿•+¿(é©Ï?ÿOR¥nÉøôÓ<üð2· Ÿ}ê©oêP©Rs¹ÓG=ú«N+}öÙoÉŒ;•Â6—¨é… ÛjÞðð8®è$õ‹T§žC‡-^¼8zMI{qÊ I‹3)[¢ ¶ži’˜g²uwwë(—”­¡º¼Ô%)ê*\óyÜHm<°q%º×7I…ÜhcÄŒQœ&DÇCÂ*q¿ïŸÕåšC½ñÆãÆÖ ¥ÇßÞÿþáf†UÿFéüuôèêuOÏ¿˜0Sýo¢T¶n¸á}ž5wçOþztáM7}Àìúýï_¼îº÷š†Ô´ê©y IãøXDØhD®˜qãÆ9sÞΈ瓤®_4žË'€$mœaAkðωú·áš®ÇÛÈ‘#|°JÌ SþµN=>µ.90ðc)ýÓ¹áæêYèÔ;'Nì2ûN¦OŸ¨gX±ÀÚÛõ?¹‘¤‰}S{6ª'·sSâªta¦’4Î,©|ãÈ‘§µïqhï–¼Ž1ïKDJËêÿT¨¿GÎ;nAãÔïÖÊ55t|‘Ї×tËÀ”øž´ù5+¡€Õ¤V_”ñþÄa ‡ýµhí¯···´hJݱ0I¸F)¡©]ÌzKJ•šç«¡SJÔ¬™*Ïyäû‹ÖØ.’4ìïï×[_>õ"• ³–¤š/þR£±+ßø†U“”Î,©Ô§ß…´Öÿï¬uvM¹gI ÍUΟëÑ´«™U•‘ŽNe–4-‹¨'p>æˆÌ£‰ Is€Üœ&´§iQwÛ:b4æy¡šqéêêjŽÝ´Ú0I¸F©ÂΚfÄB§ûñ½ê¯-°]$icƒü†&Du“jrTOñt42%U˜æ–-jô»º¾¶lÙç½O;ýÕ¢Ÿ*Al’L…Õ#/ž+e¬ MåjZ{¤¤‰ý6Î…þ@R¥Ð޽8×R¦¤åÇ€^Þ̺ç5WZ³ÏZŒ9ŸZ³* äL LR®Qº G,tj~è™gþ¡»»Kùqœp@÷Bªg^Ê­3ÛE’&ó %Ä <Š)Ymž«´aÿßøF*’´év­´¦‚F~ó›ŸeQytjTÚ´Á3Ÿˆ%öÒÀ ÑšG‰¦âùTRHÒâŒEÊ–.ÓëgàQ.þ¶µa_Ÿ)ÛDuظq£‚1ü‡@ºk “k’Ô¿ÐùÇüGJú(Mà^Êô ¬-°]$i½Ž ìZÖ ;Š©ÞÚËÏŸ?ÿÃþpa%©|FqÏ÷Ü£9³¼Ï½÷Þ…œÞ”ŠETHZó(Ѭ­¢þœ Isž_sÙòæ 0 3Hâ5úXáüzBKoÕŠíСC;;;OƒTÁ0I¸F("ý ŠÏ[¿þ¯µŸI›œœ­Ðþbµ¶‹$­Ë©·nݪ¯ˆš1¬ëÂø…ÿñÿñÝï~÷'?ùÉ"KÒüÅhŠ-2Kí9 µXgY/¾ŸS²à¤ †ÌóGŽ* Ís6FX›7o–~m¨y.΀€FÐ Íœ9sæöíÛ=ÁÁ–J ØÎ¢ÄÚS¯ï‡ZUÏÀ›®U)™«o8Æ©-Zd©ÿ¤¨3ª v` ©>Ù”Ž0Îæ‡Œn ªÍŸ’4æùµèÿŠ©c]”2&Ž&j-NIÊäL`Ú´iŽ*Õ }j¯Y³Æ‘,–J Ø/ÒŒ¸Y©;Œ>¯SpŽÛäH–úOF:2Åjñð $>J4ÿ§’¢@’mDÒ´Ç9¸šؤ¾›ºu¯­ ðñ–J +ðæl¤B‡³[©×]ßÓÓ£8w§4é®_/]:’¢£*P6’4âÙxŒKÄQ¢i>&©«H¤E´m <ŠM«ùžƒFÓn–ú²%°k×.¿6Ò\©²)îÊ^Iš-5j'é]%{I"µµµ¥·×{˜'²²AÿŸ&¼ñÁ0G4E% ɲ@’–ud¯õ+ð«§îµ|_æn—ºoš6S‚t·’Ѐº#J‘¤¥ÿ:§)€À_…®nØð@{ûí *0.÷èèøŒ¾1¦0xe¬",f”£DË8Ú5ú„$-ó ž ª´Ú"Sæn—ºo«W¯6bB³ÝÚ•â?÷IZêño´sÊ´¯ùQE©êgýúõJüäþ†£/<ƒƒfΜ"Uª¹R'í<3T&ÿŽŽ?›4ib¦1ºES¯×‰Ô§ß„˜»4ÕvO™’4e …ª.0<\©dø¾^¨aŠoŒŽ0ÐÇ´V•!ìäžT$©ÎuT²'3®{Æó|ŽMë6·«$©]ãUŸµ›™4uÊmõq,Li)Qt%Iº|ù¢mÛ¾!¡¹uë×õÚ£8¥Du2¤Þ«p#FŒ8sæŒiWß’³ 4°@RŽ­¦o IK>îþÔ¤&»ù‡Ë:ð©HRç {©L÷k#:çÎý¤™%íïÿQ[Û´F”¨s-’4g‡”UR§QMJ)L9gha¤%ZMß@’–|ܵ×,)§´aàO:5q¢‚2‡Í˜1ãØ±c“”ý~úô鿝¯¾újLƒS‘¤îJüó /¿üüèÑT™›nú€âJ‘¤Šœ0AsÉ?ÑCl.x饗”4æø¦RLAÉúð8ò™ [*©‹@Øl¨ÿ0§ºª¥°¥¤–\\³S»q~}\|—S$ŸÉ~ CÌMTŸûGJôäÉ“zçÈ‘#³gÏŽiK*’4z–T±¤š•=qb׬YS*.IÏ;§Ñ ›åb3¦›6mÒÎ÷˜ã›J±yóæ)qX*UQ !HªE<…œ5R-×ZJIjéÀÅ5;05©tª¾›Æ­‚r™ÐÔÚåË—Uý믿>eŠ´Ý;~4?êüî~mN*’TÛí/^ü¥´æàà!Å•KÁ|Ö¬Y}}}cÆŒ ,=ÄæûÆwÜ‘gÜ‚N(U<²Aeæ×T XÂIÃVócUJ!› Im½¶¦&ÕÌœ"ub\M‘l >ÜiÀýÚ¼9wî\3KªeÖ¶¶¶˜¦¤"IW¬èزåA)Ñ®®¯-[ö9$Ǫ̃‰%íë{VÙ ˜%ÕЄiÊè!6£œç½”¨ôèÞ½{cºÅ 0é©'”æM²k—š KIZØ¡IǰÀÔ¤ÚÊ #Òi€Z àÖ1þyЗ_~Y©"ß Ù¼Iq¥1ÛIE’JqNž|ó!ïÑt©r”ÑéÔüÒK?ÑÚ½ÉKªLà—¤f\Â$iô›)ÒˆËczübZ¯×צHã£dvÂI9J4;æ¯IZðjÔ¼À„Ãz“HFɦq}ôšbI5?ªv³©Õᘠ¦"ISQ™uU’çÊuL’uK6Kª)R©ÒÜ$©”¨v>|¸®®Q;2”£D3^üj‘¤Å£†, ‹—$•0m¨j.n˜€¶Û_¼xQÕnÙnb,i]j2•Âe•¤ÑCì9¯¨a‡ªQ"ËI>š5dêI ,T—s”hL†å+†$-ߘz{¤Å_ãäyWñdZ¾/ç‹ÝÃ+VlÙ²E6vuu-[¶Ìc¬fFM,©vÏ(TÌ®0KTºÅÂ$uô;6ä ÈÍñ¡Nnüt»Om¨—@X )G‰ÖK²L呤eÍà¾(lT¥ž¿i{“I?ÄO HqNžÙéS'Nœ¸õÖ[.\øØc½öÚk1Û¢X• Dœ¶·Ê¸ªÖw$i%F<0f\›pGŒÿ¤ÊJ¢“(°$;¥è°˜€BEÃ’3DüÉâcz=¤õв¶l`jRõfÚ´i===Öv Ã!ýýýÊÏñ¡8G Dl` \Í+`0);HÒìØ¨fåUØ¸ß ŽŽŽ®®®Š)€@Ãt_³m¹aŠT ˆÃ™8J4âVUŠ$µj¸’v$†6ݯZµ*i­\ŽÀ®]»4E‘¿pcPeD’ŠG‰VÆB;Š$­Š\ýõþãCu²K[[[UÐO”€”¨ô¨uÊÞQúg%ˆhQ޵rDÓ6Iš6Ñ¢Ö§|OþLzgìØ±E5» úh##ɘêCFé hi>,¤„£Ds‡â6…$-îØ¤kY`˜Ž9k”ãÓEMmh ÝÎú†©G{SZ§QD0›°Äd%Šÿˆ’´*n ¤Ùf(|§···*è'ÊK@[ÃÒë”·ÓôÌú²¤ÇM˜¹%jÍ@fi(’4KºEª[;™O´ooo×~ˆ"YŠ-€@Ý”òiÔ¨Q§OŸ®ûJ.€@.tœXÄW&ŽÍeŠÞ’´è#”–}ÚÉx¢ýêի׬Y“V+Ô4…ÀòåË¿s6Å…€Ÿ€¢œ#r“nÀcÕ I«2âaÁãÛ·oïìì¬ ú 2èëëÓ)¹ñË8¶%éSt itr¨’  1 Ic@*E‘°ãƒ•EŸœ ÑŠcÊ÷hŠ6I°XˆAÂÄ °jÕ*ŽÁ‰"Í'H*û8J´ùƒT ¤…Š\ »ùµïÞ½¹˜@#€@C”ŸãC"ÈÅ9Ð|ÇÂä(ч‚¦¤ RŠ&êÓA'‹ú+ÔŒËÆSlˆª Œh¡30uFFÍQ-⌞•ZUžüÄõsaÉ IK6 5ºvHÆöíÛuLvµXÐ[XH@ù1t|(‘ß]MÞ±cGtž2Ž­¢[„÷IZ-ÛÛ¨¥@S-ô˜9s¦óŽÉU$ ¤чׇàREXôù7¤Õò­÷îŠPŽC-¯T‹½…€m$F•4ƒ)RÛÆ­ºöê¤ÐèÝôa±dÕEVíž#I«5þz¤…å2Ô†‰ÁÁÁjá ·°‡€”¨–ìI—cψUÝÒš¤JYª\fú¿ê¤èÿÛ¤Õò…ˆXrEü(qiµpÐ[ØC`ýúõjÏpaé5IÃReÕzm·×BI`ŸfªMNÕÂAo!` “ŸäÁ– f^#P34bÕ‚Õ$€$­Ö¸›³Ýû¬0SQX-ô–X¾|9LJZ2V˜ùš¤%Нx I+ç:ÀI3.þn“®r®@‡-! Å#Fp|¨%Ã…™×Ô $UŽÅW¤U÷íØ Œåª{ý/*öööèL:E5»ªK f ©Ð„ÍT—Zå{Î,iå\ "g WÎèpá ôôôèÉM6ŒÂ¾ƒ@Í@R&Að?$iå¼ByIÃN#$E\弞€rã³ï°ð£„^5I Ãi¤øÀaÙò…†ƒ4ðŠÀ®]»t¬¹ñ 5(S“@œ@Òˆ'QÍú)PVÌ’–udCûµ{÷nIÏÀ?sÜp弘€òcŒ;vïÞ½¶Ó @ N ©Vö9ïñ@’VÎ%"²G¨ÕÊa¢Ãh6M#µµµ1EÚìq ýº Ô $Uĉյ I+0Èïì¢2@i·D`·9K£rÞ@‡‹JàüùóÊøðᢈ]&`Ž Uæ²@%Š÷@’VÑ1ÂvÖG$Ò¯"&ú æXµj•r?5¯}Z†@BÔަ苙þH·ì—!IË>ÂAý‹X1ÑG‰"Ó«…>C ­¤+¾³££ã]ÿDÏ3Å3–RÈ›€ö$ÔeóÕæwåcÒ–#–Ê7Äô(-&ú«æ=ÂQ¢i/Y=HÒ’ h¬îD$„Û¶m›Ti¬Z(TTƒƒÿwƯ·¶NÌxa9…ê[Zn–Ú+æÑDZ7×¢(E³h-²¿¿¿¨Ž]( 8¤²•£D‹2`³IZ°ÉÅœˆdOú@Ñ÷×\¬ ‘L ^lk›ÑÞ~{oïÎK—޼ñƉÂþ»råWýý?êè˜?mÚÔâ¨RmuïêêRö%)Q}=Ó)i˜2ñT*-#8¤%ZÆ‘O§OHÒt8ÚUKÄnLjQvõ±²ÖnØð ôhaeh aŸÕ\is‡L¡:·S±ÔÊ_³|ùr[£D›;"´n#8¤%jãÈæc3’4ÎÅj%Zw†¥ˆ*V°&„@kk‹æG풤Ϸ´´4eH5;ÛÝݽhÑ"­$êT³}ûö)®)–Ð(l' »)N )ÇÚ>ÐÙÙ$ÍŽm¡kŽÐ·Ýv›¦Q m=Æ…P€gÁ×ëýrY+ø2;çQíééѺü¨Q£æÍ›§P¶ÏçÌŸæÊG f ©¾ûéŽ+_÷éQãò~ 4n15¤B "5)G§B¸Y•¼©íŠ?f[n’T_·V¯^­íóúêµuëV”h³•vËG@ÓŸ5ûEö뚈*[IZÑ¡È?±¿¢°¬ê6’4p¸´£BÏKeqš9s¦RŠž9sƪQÅXX@@ úšm(gZ0Í3IÚ<öMm9"ÿhÄ~ü¦šLã± Iݘ¤DõkÚ´i$rŠå=‚@RÚ¨­5¿ìq”hRÀ•¸IZ‰aöw2"À\鵬_Q.öwIª1ÔsQ‰œ´4¯]SZ¦W"'û–@ Ð>¬%ˆš&r”hMDU.€$­èèG¤Ä׊¾ì²ïØRϨ²$U* 9¶V*ªum¶ ‘“¥nŒÙÖP<Ìš5kjšÍ5U¹’´¢£.bóSEyÙÓí&JÒFšnd{“¶(íÚµKáÑÚ>O"'{\KKE@‹Ê¡V³K%ZQ• I+:úÑ«ó›Ÿ*ÊËžn7¢ ܪßHÓ NÚÞÞ®èâe¿`)R `6-é䳚u‘÷º&¢*@’Vtô£·=ê(m ©(Ë»¦ ûÛžÇûê|ùþû¿ô»ßý»QŸ}}ÏŽ7zÈ÷̘1ùÈ‘§Í›/¿üüäÉ7ßr˸_üyçĉ]*0lØÐéÓ'öôüKX±ñãÇ üXêßÉ“Ê;xíÚ×_aóæÔ¨šÖë¦'²|x1E$ e7¥³¨iG‰ÖDTñHÒê:€Ž«Qì]`ÿ‰@·×-Â$é²eŸûá7JîÜùèW¾òy# ¥;ڮǎ=3uêÇÌ›Ÿ}ê©oêôyýÕ¼#%ú‹_|_/$R7ýÅ$[Ÿ{nÓÕ«Ç¥G¥J͵+W~ñµ×~ªÏ?ÿOR¥HR{] Ë!F`ýúõ«V­ªÉ‡t.5U¼’´ºqJy:ìu‹0Izã#$¥/_>zà ï3ÒpÅŠŽGùM|š?™ú«ŽSŠÔŽÁÅÔ´s¡cƨQ#ªFþ ’Ô^×Âr„P¬×Þ½{kòá(Ñšˆ*^IZ]ˆ8ÕM³§šC­.›{&IÝïk ÞHC­àkUýñÇWÞyçÎR»¿{òÉ5[¶<¨ÿçÌ™a®õs¿ã¼v‰*BIj³sa;( L; ã„Æ.(š’´º0±¬_]d6ô¼æ,©&2YR#5EzàÀ·µìîÌ’j&Õ­%XŸy溻»:|øuaÅ%©fgÃd¨ûýFvÜÛ0,ØÒЪš´fœîq”hJU.ƒ$­îèG¤&RuÐ3”ùOÁXѹ6#bI¥)¥Qº|ù"#gÍšbbIÝÑŸ_øÂ<Å›ºcIÿøÿè׿Þ/-«kåê/(Iðê«Ý&–Ô™aõ‹T$iý “ ‡€f76nTœzŽ­Eˆ¿¿$­®D§&%¡q=CûUGŒ¡ lm&Ðë@ kî¸ðÁ{œ÷ÇïÔÖ%­§k7’vߥxúô¾ >}ذaúÿÔ©S3õÎĉ è6cÆ •ŒÙ‰t%é¦M÷ïßÿ¤Gkº›ðÏ¡&¦HÒ˜ãK1„€"ÚuHGctÜhkkkœ’”©8$iÅàÚzÊéÓ§«N¡IýŸ± ´BÐi¢qn•éééÑm³0Å €$ÅÞ" ð –#ñ@H‹€VùVmÔSÌ’Va”k÷Q ‘d½©‰€ €¢Nµw6^YJAà$)~p€>;”€ T(˯ÒV¤R•T„’´"]£›ëׯWšX@€R! - œ…– ÉêT‚$­ÎXGõTS¤:à € Æ (¡oãõPC¥ I+5Ü¡U6c…“€ Ð8e¥à–Æ1V­$iÕF<¸¿:5±¥¥€ Æ (Œ£DÇXµ¤Uñàþ*Õ9q@U pìØ±éÓ§6LÿŸ:uÊße%ß0aB#(”‘”£DXÍk‘¤Õ÷€^+ýÂ… à€ r˜Pƒñé¸ ÔK€£Dë%Fy$)>PƒÀÙ³gG &@€@|¬°ÅgEÉ0loÂ7¼Þõ.¼¯€ :p”h°(Bñkx h–Ts¥p Ä$ÀQ¢1AQ,‚’÷ð¸í¶ÛQ @€@LãÇW8ĩ@ $)Žá%À—]|€âÐQ¢Ún¿<%!€$ÅbP^Re'U”B€ PyTRÒÊc@£˜%m”`ù®×éM:„£|ý¢G€ žYP­`HÒ z.ëŒ{t@€@K—.Õ÷qJR¤¸‡—ÀÀÀÀ¤I“à@ˆC€M±q(Q¦&$iMD•+@ z农CHJàÊ•+#FŒÐƒ#i\· Iq…£F:þÁ$îy¬Ê(xŒäbäûé1‘sbè>Èëä„dü²zÈr ÒH¿—%! 1ò>Èaƒ$DAxôÉ_1ïzǽ5&K­ ò„$+.×Tàå}/H‚‹ÑyNÍÚ €•kQrÿT(ù9¨”Ô’¨²’ÂÕWTÖ´˜ë–[ê[WÿëmÜXÓÔ¸¶¾¦²J …%FQ¥XÐ?qû»ì™î±YÇÎÚ¬SS}'‚cSÃÊ,˜ 4¦–µh@¤ÿ¶EF’‘¤  œ©¶³²®aMCSÛºÚ––îú¦Æ5uµ•í••M&#_aB–$lÈ3Ȭ5”%i'`ì&Œ¶K£¶P06æqù&¬V›Ë:q¦¿¯çµ7ÞzùÌÈäTT=p•µàp4 $™˜mYáY†¯hæ-5]暦îÚæöMÍímÝÕÍ++kj:j,f#á1ç‰4 Bx "!“SŒÔA¾ŠH fï;G¤€Ùl26Ô×,©0qK*Œ<±Ð 5éÁ@ÌúÚËû¿ûáßõh,¢æ0Ù[¸ÊÀZ&ÜuÔ€’(Ä™¶ª­¢ªqeksûö†ö®m ›»*«LõD|Ä ÑŠ€Du‘ï xˆYddª›Oõ¤±ÂFž#¬¥‚Ålò` wž7°ôh@Ì)êÅšsÛÆm«¯'zí{:^_HJÚßï)ë<˜5zóÉ&«œe+ZøŠº%µõ««[·Ô7µmiîh[]×PÓf±˜*äfˆP70!ˆ–ˆuò=2’B$I ˆD±+2òx L&‰ŒFÐ!_nyݧL¢‡:䥡ÓáKµ¹µk…±µ¦¡Úb¶TTWTYŒ&+ªªàñ¸½'ÇÎØG¦F£É–Åû¹újÜ¥úH5VpËsuã–¦æöK[;:7¶´5¯©k¨í°Tš«Y#±cFÂ, sE$Þ&ñþ®Hî¼H¼CQÆÇ,õDy a%Â>&Beh ä1G*éUNËñ¸‡9mrUjrécrŒÉ×¶¬]yù³üþ±ÚúªšêºÚ†ŠK¥Ñ\aæ Í©¢$øGÇ}gŸóÅ/ÿô¡¿îô›Þ4p1e`͘¨§FÍzl|#c¬î¬®o\ßÜÚ±³µ£}S[GëºÖ–º®Ú3¦Í G ,¿xr³%bË0˜"cÈCŠË•Ã@ MÏ#XÂN e™i§Ÿ™†uB¯¥$+)@ÅqFX./‰ÿÅù»lÛªVÜtN²²±q}}CUý–ýá7?"ÿö§í½ì–†‘ "4m(›‰¦i䵫jë›w6·ulmkïØÚÚѼ´¹©¦Éb1rãXä#q,Co®¬ÄÍ£ K4~¦RÍS¦ÂOnx…AÄ&>3˜VÎÈ:¸É)€I°T nDKQQ»ÈPH}.ëè“gÏ7«Yà*«x I"XS«ÉR¿±®¡m{SKÛú¶ŽöKºZW56U7EB2£ÆÁÇÐ`ªJ­€Yd%¤’§”Ɉf§ â9†0™»M²¾Ÿ ¢$óP·â€Aàq,ÝÕ<å}¾ðêëÇûü `)Ùq¯2°ò mâ¶ËÄ,µcæ9s;o®ï®klÛÖÖÙ¹¥³«cck{ÓŠ¦ÆêJ‹‰‚Opˆ½¯øˆÁ(¦D%‰å78j‘‰xž£F•¾OIxÄ<ÊM0\œˆÒ˜ÇÀÏ€´†ˆÈûöíÝ“£L-+[lSÁ” ßœ¥Ûdi[ÝÚÕ¶½½kÉ–¥KZW}Ô^Wk1¡Y#p¡¦¡d¡Äï­ÿùÆÝþ8 Q†aâñ#Þ<,›Â¾C¢”žJoË°ÉØ‹©);ÏcìÔÀÔ¾c= @¥ƒ«,ÞSb;a’™1kî2[ê··´,¹ªséÒK–¶mèh«¯­¯5ƒÅÄPð(rÜlÍîM‡yd9®µ)LÒugãyL6¡¥Ø$©q.cŽPöƨ²"ÈcYN«tiÁÔ2>ÖÓbtÐ Úõ|[ä]Mym˜Ð•éÍ7´WXZw44w]ÑÞÙ¹}Ùò® ]MõfÞ\g$ [c>‹)L"Q0SqsÅ@RsD!v8ô®RÚ(ñ^L$S—>¾!èXŽ 0i:j1Œ“'OeIÉq¡/tÆJ¤Gh ‘ºEM¾a}mCëöŽŽ®­K—/Û¾bEçÚ¶æê ‹9î±%cNÈdT#±q†Wh¼'ù›ŒG©)ÈX6Á5qÓ%Še¢Ô¨ ­ÅÄÁÆ0±ìâ-Ü•£¢ÚÓ×{2ßûø ‹‘âúÍRœ%ø:†­YYYÝ|éò¶¥o[²¤kÓêÕ]kÛZkjj«è}'Ò!ñøŽ,Ç™=±T(1hÚ#û¡ÚI?Dq-ß7ê |/KõÓ…WùítŸè×5 °ðÆÒ/ê$âmcîà-µ«ëš6Õ54¯ojíܱlYçš%] MÍ `2@*Žž–ªÄÙˆÑIq$™% 0…Æ›dúù¸ùbÚ‰Kè¨  ÁèÐÈhïø°r'¡«ÆRq@S;g¨YSUÛ´iYS×Î Ý«._±¢uycSµ¥²’Ç@rêýq—™Ö—’&/B Á—HsÄœðä(/Úy§Oöžòýd&¢Õ ‚±T0Öt-Ùø‰5ë6ÞG4ÒÊÖÖºª†zS9:%·S7kñ÷§³Q’ŨÀf“f­<ÁasúôÉS:€R½ÆÚ¸ùŠÿ{Ç·|£©±"r3j#Y–!™@aH” ‹Z\Ï爅"òÐØÈ[¥«ˆÅi •ê¦pÌþ@=ÔT[¬“]‹)扳J<6‘x‡"}ŒL„1#4mƒ6*ÅpÛî¡ÉñÉ,P)ZàZ”ÀÚ·ç™cÿò?ï¿dë%pۭwì¢i*ªñ?6&QŒQ0Qbâ“xžƒÁT6m³#ýCC'ûûì 0)œÆ2pìëgŽ÷ùöïy³ö‰_ÿþìÏ„ûÞ}7´4¶R·ŸÚD,11Áb1ÑØQy”XCÃýÁpHÔÕâc9'}nb¢A¿·6Ú†¯}éÛ0pv ~ðíoÇOŠç©©+‡F‡‡²@¥«³¥¸ðy#AVáÆ”¤D}.Øÿò>ˆ "¦2¨æa„}A©oàl/$§Tjk«ÔãE ¬U+:íKZF &câŒòk€ñ‰‰2æiXÇ'Æ=ÒyâWɱ(%IBŒcجëNŽh$v»c~Â7ªrÑkr|â쉾^O!újÑËî›R…ˆpŠOåèåE£ÑyÙßÓû~ =Cû/n}584˜å êI¯ÆrÙ]E'xƒ1õœ,‰à÷ûK¾¯ˆ‚7N=¼ð-ðì%¨TEQûúæ`« Ãö“×ë±1*“¢(LÉ ŽŒ”~_ãÇÁt‚Ûoƒ'÷þçE ,ŸÓëÙàžlua˜ÂP$ ‘XÌm®® §?ïq{J¾¯#g_Y‘ ÂhÃg^†þ‰ã°6ÛÔ±ÞhGÜA‹µ%°°V\•¤¨… ³)­Æ F|pvì(x#MûRöžxúâó'¦†ìNg,¶Ê×¢òI²$H’’¬¡áÒ^P÷0xCŽT\ÌÈ™``ò8øÃî‹ XýgÏ…™AQÐÓW‹Xñ¼ j7 cÉÊNn ²Hln”˜=QŠA²ªSCvÏô¹h@% ¢râä‰c q‡ X‰ßIy‚M„°äÅårƒÃé*Í׫*ôÔŒâO8.`y.ë›GBî¤ó…áªtæŒ" Bl_2x‰œ2Ò~«4a†X\+Ñs™éTÔZS®!ÝÏ¡÷¸p? [{SçWÈîÙwð€;[i‚kQ&¡‰GHÏ£Âlð y’D‘íÉ‘8¥‰¾ûBNGý‰ £éŽšÃq*ä|EÆk¿}õ`6UÁ;.pA^·7{ŸƒWŽýª-õpûuKwäýÌÈÐp/P&sA0V$c"QaÕK4VF¾åÌ™3%ÙǸcÂäWÍÌGAçÎ –>öÒwhœk¡&ÀG¬§éñ9ý“péº ŽáÑ‘3…Æ®;°R3"YFŠÎˆ1<ñÄãàõù漷ߪ™#D !àì!ûé³ÿ/}*Œ•Pm®_x^´"Cue˜ÉñUšªaÓŠ+ úœ„©¡±ÈÕ¿•üKL  `׎´á°;ÀérA]mmQ_>j?¾ ‹Æ¬jÈM@ÆÒ+Yföö< ž ^8ô+pxÇÁd4Ó²çºêæ*‰vP·^þAXÖºn† ×.»Óz|ß[#9¥ .~*ù˜IÝ_–±ó,‡n`Í´7§ÐräB‡?ì'_{õíQ©¦2*è¥2ÌšŸAðzŽìž5ШmÏÏvš0•KÊlsx\o‡güœ˜ûâ #Ìõ®+>BL½¾Ö û‚þã½'@ý¢0…yÍž¸8¢©”ôY8ØÊÑj+>HùþkÿŠÆ§úÆ¥~ét ÂD(€9n‚$ °¢}a¬Í%» '›tR0{‹<¢9Ê@ÄCK[»g|æôèaz¬0ÅÙ[ŠÁJÂLk»¶R½u¨ïEê!âÕÄ]®áq9Ç^Û¿oJÇ#„Å,FPé`b@Ê?±|AAÊ4[CƒÃEçOoÿ*Ñ _¤7ÈB„8Þ¤-+wÑ×PÜã‚Kzž×æ•W?Çifï1U=LÃÖSàðMBLŒÐÅ¡ðǃ[¹ž‚$FÀe"NCŠ©±˜¹ŒL1稵ð;‘å¶æÂˆ;&Òó™l§Û5942…"Ò8 XLzj ’›(ÄF9Cµ@~c©»>08»\^µ¥>~Ç7ˆ¹yŽœÙC~ñe޽ë!ñ©‘ƒTàÏÐä& M¢ž!;‹YÕ'÷QSeuPgBM8sŠ=Zò¼Í=JÀu„˜¸]Ó ôMÀù|Ò¡@½XA¼Ú]›ï€WŽ= ÛÖ\ Wmz'}þÑÿj*õCäB¢2–TOýæ õŽ»Þ·`€¥>Ч¡«ð¯! ,‹ÊyÖÕ¯ O¨œÑ&ø@!@›õÁU™k‰+þY¨¯n…gÞüô ½O½þ#¸nÛÝÐK€¥í!‰¹:.ß4×u½Ï7N= ½Ã ’;…ôø­þ=ÀBVBýT‘ø<5ƒÄ™¸aûûÁæ¥ =Úÿ*5£÷ßøÿÓzhg®3Ö©‰á|ú*à÷.Æb ÐQÙfÏ–!± 1!Ò80u¼Û{´UTƒÂáö»ætýãÇ`÷á_QöÁXÖó‡~ wš>F£×nŸ55³:Þ7+Þ„Íh©‡I×P°ðy»w*+j(`5£ÛSîa0“cÏf;ôT9~¤šXºƒ^ Æ¢pœkøP´ÿ~ïÑïïh\ Ï|„2Z;y¼¬u-]O€ÕèØäØààÙ“ùôdzçXŘ=-PñY JýõK‘ ¯ŽŸG4^š|üàáxôYögÀ@§ FãÝýÈ/Åùˆ­Ö-Ùür#t/ÙA´O˜!-Èn—¯¿™YŸ?;~”‚ÂrQÁü¡[>¯­eËyü¶šåzÂ’NO.È~¯;`…ワóv;5Ù˜ LšAŒ_ÕU·À*"Ü¿ÿägiÀgá>±þã7Ÿ‚ÏÜûhkX¦`õú&_}å•3ùL!6U9_Àš«Ùãu@•zLða&¨¨juŠqF† Ž‚©Ò<«ƒîlZ 7_ú`ò0Ÿ¦lÆâ±¡¶‰5zY¬Vçîóù! ÏXxî¼êO‰§w%ÔËÛÖQS’ Œ†9¸WýްYõ¶ËÛÖ]sñ¼NÀKG/áKþ{æÍ‡áÏïü§ûJŠþLó(Àºe;©É»iç½d?/A0ìÍhn“×0]ã :iá!2QEš>C}õÔ¾ÿ¦‘øúÎîàÞëÿF×,§B W ”s髺úºsn˜‹Ù›!Îs*ñXè¬lØïŒ—ú„xñš×ç… Û u-s:¼9¸á@wØ›vÞGŸßºúj&‘š *"¼›j;ˆæi€WŽþ–† …0TZëÄà~ÆÈ,WQ‰.L1M:mYyUüV5ÃÍ;ï‡_½üo`N¾'óñÁ½ü£ia™¦•$%žIøÔû¾ ¯¯çF^»õ½yA…ýéí¶É¼úªÂb9gÀbòDЋ5{ó—½qfÖ4RmT,*D¬>'Œž€®u«J’&ùÁï?cö³”•Z꺠†€Y ‹ú.[ aŒA0p&ðíÔÃK÷Îâ ÈPæx8ÝK·§jèý!X]#4‘në‰>”Kr\¹éðÚñ߃Í;F#驨a­WŽþŽ2\2 "Ê1XFXóÊ·æ|=NtFj‰iíj^“?0KìèøØp?䙉Ãóܼç õL]6²AcLl¦¬­"m3i¸cíu3>¿sÝTó¡7š}|IP¡ùkªí„Ë/ËxšÕ÷]ûWo(´8xÈ‘K_U˜+S[©•+ý¢gâ²AeÊb"³˜²AeÌ2‹¿ö Î1Ù/—ÌÆ£wÇ0ñÊFÀØS<Î$RóŒúaÂ1@ËSÞÝ_SvS52Xq0dí¥¢?™4Ng+ü\KÝXÓ¹Uá`à]Wþ Ñm–b:gƒMËßFMt6ëZ' Æ^zyOrÔ_q‰¦¸M€Ù9²”žÙã ”©³—¨l}E÷©¨ª“ã8›Æ&(àK5–¶uÓ›ƒ•£èá iè=û*l]u5áÃà$.?z^»6ÝÑXH‡YØóÖ¯©^³yÆ3Âa¯ Ë.£Õ¨šÇÑÒMCh~g•fÐ Îex½ž¼ú × Jn¥––éËgö²M^E‘f/P\šøOî“Avòi¿ §Ó Š(•Xèe¡w†:jëêk¨¸NFÀo¿ò£°¤e-Ñ0›ÁÄÇq÷µkq¤ìŸ'àüã?#Ž;Í#T‰63ÐDq®q=äUDeë-¬~Å€çªÎM³>O¡{O.}uúä Õd²@r+°rŠ›#¨r™½ôC6¨RŒI®‰‡g¦,6a‹øƒ%šÀ»®þ- ô…¦§—µÖ/3Äœ|çå&âü@Jl?xË硞€5”–Þzõø“4¶”4…˜¾ikXNË\rÆš6¸æ’÷Ð hvì A©WQȈ ‚xh¨rõd  *LosV>På2{…€ª¢@–ⲕÜLÀ‡ iÀ·N€mt²dæoøÿ¹õKT'½!KE ô ¿A…1NóÓA·>xóçé¡fk"&}5ùT^P â<½HOo,iY3#/ˆé¤ën˜Ó9†Ã‘É×÷í‚¢’ËØæ¬BÌ—Pé`2ë°T¡fÕð@ã?)EñS’²ãÄ[{}÷ž’ C ¿Ûû­o²ÆWUk &ñ÷~†§NÁþ“$Þc¦èÞ@¼³ÛÞöaMM”î "È0˜ºmÍ5yAôâáÇ2r‡1¹ÈVí„ñæ2ˆpøå£y W›m¢ Ó·R0V1LeÔa(SÓ—Ëì1: ¢%Eq8.¥˜%rMúž*€': AõÒ[OÐ\`ÒÛB‘þÌŸÓ„ðþð%ªÃÒmÇm—?HozTåÐ6"Õmhjók¹ûÛ4úoHDQka©ÍÍ;ï›Óùáñz=îÈÑf{ðìi•7 }›mäÑX>±nÐØ²Ó1é¹A63e‡8fv÷cã“WSSÁ:Û:K,ÔXÁ€^Ù‰¡}нd[¼|eì-Zœ‡Z+õщ®(®™4fºï†¿›{„&‹ i…‚¨«Ðœ`õÃæ•W͘ï‡á ?a^«g”zŸ§FÞ¤ÕÉ„5‚ „»¯ùKèhZ9§óSˆHÕð3bX–Êê‚¿/’­Юæ4j0–¸¸f.;A 9þf OEÌlUFðÊê*måÝ7ÁÃÏ}šë:R¢û²õ7Ñ„ñCO}ÎŒ'ÖÒÖuŸCò7þýן¢10B›‰^ÃÏb¸½Èì-“¾óëOR¤µì”*,©‰‰ñÞw}7W¶Š›S10:22¹ú3¨rI€¥ÅVz¡^à Ô•žÏgê ¨hG‰ -j—¥y¹øµÆž¤XgË•fݬIÇò•Ý7ÒxÖ²€j,õpÓŽ{àòV×0€FJnuçZ³ûÈc°~颧®£“²ƒ™égdÓÀ,qJ°‘¯DL¦@L¯™&ÀoÞù s”b‚`?qâÄT.}Åå0}³1…z[vUgºpÏf°ìêv.fOoˆªìØumBN?T¶Ö–äâ¯h_¯÷˜è=a‹eiÌ„æ]ýqg¿îç±*M©ÙTYÐþð;ÑAÀ| ¦Š:VÀæUWÑ”NŽ-å‡BÃ?ýÙÃnÈÑ¢ÈTa.° O.Ë“¾Iäz,U´ÙÓ÷˜äHz.otjœ†V–Xx£qjX­¥^<ò8G˜LHãÍGM4nï§1%½°A¡ J"†!¶¬ÚE ¹¦ÄÏIcÉÒ˜ÃáA§ÿ•‹©Å|ßlÊfX½•«â3oª³§ë]©ŠÕL.|,‘v/jb`V^º¾d7õ– £GøoOü\ºî¦xã¾—hiÊòö ÔË3€±$û»jóí0ßk°¢ÑèYÐoªcqçS,° ­fÈöôôØjÖfOSgIQG­Á"xÅ0½ A`¸wJ9?yEûFxîÀ/Èß tÚ–'è€mà¦Kï£sBSâÙJ'''z¡ˆyƒóÁX¹ô úó™zjN€šö ¥ ϰᄠ¦WæÔÑžé9N%ËZºiÛ"Í{×׈7·•¦vóGÂGí‡YLL`ºó\*¨â¦PŽ`a$2U%wº¯$Gø–ÌÑl'ñXÌ5ðé{¾GC{a,°IÌàÀ¿øE«ž)”$âÉÅ%ôÙY‚)}KozªÀ,H”j°F–÷¦ãeÌ:Þ~G æ2Ð9h¬i¿`@Vd *÷zö倔 P…l7ëš3°lUš2¦ÕÛƒ.pœ²Î8¡ò’Ð }E”{Àç;¹&¦²œî6`éµÔ•¬³Õi·#(Ŧ´‰”A9 îa'`• ÆJ±Ð@-ã)ÁU9ŽLåÔW £¿•Àj Á#élrÚ_ \ƒe®ƒcXÑY©ï‹@ ¼Nȉš;ÌÄ”Éjzˆ¢`ëííÔÓWª:;ñÀ(Ð0ƒÙì””˜.=öš—áŒÇ —ZL »ôzÝ€sx0³Ã–Q•é†Cg?ÿ…/Œ•R_ÍVcåb,Qçßræ*k ŠæX6ÕU wæô:@”A¤)Ü#Ñ3“““r©ô…šB=ážÎVbÚ_Q‡¹Î‰°÷ áŒFï¶A}Ò¢×VØçû5¨jiΓõ¡P g>~èŘÂl€å2ƒ…€K P%¹b!)Hÿ÷á‰ãàž²/Jm…e68§û_í?ù,î{‘μ.IÜO–·Û=Pj}5Wñ®ê°V6¨D “XÔJR³ÑðŒå…‘ÁÅ·b¶0ú·'þõ½ƒS=pÃŽ÷Cs]׌I«³­ Œ;v¼>¼v¾P1YÿVÏ) а Ј 3Ì—€žŽAÎ}dt· H!pNN.x agìkÝ`ùñˆµ>zûWè<Æ}=ÿKÛ%áTyìhS"°ÿo?û9û|ȾHÆ pÉ 0H™ˆÓ%‚vÞM|«ܹl(ý;"ä­S“€ë±²Æ…(œ¼úâ‘'hƒ4œvGúFÓi^ Õ­´Üë¯î¾æ/h!šGÎX\äKy° Rr^œh4Öãóùäù°³™ ­æ=H&QÐð ñç20‡N?à‰ÉQB L¸zëÃÏ}“2NÒè=÷\÷Ixû–;i·>\ª¡¦¾~BöúÅ ÿLûˆ3wëâ±ÉÿïßÓÕ(¦ŸW‡ÝvtÖÇQçè!ð³“ÅXfå4æJg-´+GÓY‹)!kÉÃJrÚ|>·Û rˆ|eýù“ðØÞ(ÞD$FÛ{¯]²¶!ºùÒûié2ña-{‹©B/e/ìï°yŕ𞷂¶à^¿ìRý›C°ðVÿ+°mõ5”ÙpQΖú.â£pù†[3¼II½V›íì|yæ³Í¤ª9L"›eµªM¹ÄûÓõ–šf!í¹¢‘À#6«¼Ž˜?U:*„# ñ°æ§uvÞòá*sf·;¬Ù:=r°Íkнd;D„ m3i£ ÓÔx“‘ÄÅY7Ø‚gí`·æ][î€fŽÖm¾qj®\Õ¬mõKéÌllQ‰3|bâ%°uÍ5DŸ92Zp ±ØðÓO==9ŠûÎ5°Ô´›:±­ìêRrÏÊI¯áRç*äUPeo7Ü211³Äò‚è‹Í °p¾ßOžýG:ëæÒîésoÂU·°¶Ã3Øÿøó;¿Iç~‡xzNïtµ¬…{®ÿ$]CM?6uæ Û @·k´3ÒNŸ^8ü(\FD?ÎyÄYÕØ½ïÔðzlËÚÖÑ>k+¦ ÷ÿøîwC¥3”‚±´L¢œ)cqYB^Ñ`)u¶#ÚÂc`9ëêØý9üPU%²ÃÊöMpëe å4Ø ós‡~A§w]²jà¸l öýЭG?{jäXLU”8°±Sàéâ’(X"«XऋʊZjþp.#NÃŰÖé¯_º3Õ a‰FÁ<–7͵¨(ŸILj®|¬•Í\ÙžbÑ&‘è+ Sá!7ìòÅ%]™ Å1FÄéÄÕ¨/1ë9ï%šhÿÉghßQ5Ñ öŶŽ?yækñ%UàÖ/½4ÕQ9¨0ÁÑË/§f…?6Á*Öµ´»M˜€´‰6ÃÆº¨Çšˆy4ÓN~LZ`Tr ½”O„…,5‹a´ºpÎTFS‡: Áƒìƒsñ°Ó§ƒalêí—¼» ó@1ÿ¡G)bœëí[ÞM´Ò%`—j°´QO§£½mý-PO€•½þÎ 6—ä#_ùêWóf˜K«ØV6ki¥{²S?é±­tgf©"F–OÕ4`—Ðý§^Á§äýàÿáË´a-.w{ÿŸ!Û c޳ô5ì!zÓÎûáÁ›?Oû¿ãŠØBƒœ8:›WÑÖÝØÄö‘þN’×;›VÁ;¯øHÑWóúÝkÑ%àФ¶7¬ :m5¸Ô‰!Ñë{Œb_ ìßT6²Çë}æ¹ð’/¨²Mb’qòEå ™ÍXé-Q‘£°ø«lI>7嘄(ñ ÍÍæ<_wÜG§±ãÀ¦* a²uåQçì9ú[:[Cb€3–hU´}͵0é„7O?; 0“ž]!}¯p`Ü c[8ŸÃ[V^ ­ Ëh$×*¬«j¤ûzÙk=aSç….r. ±ÀÔää˜çÚ8¾„Œ•‚PtL¢Ú‹d›Ã9å1äU$;ð«ÄD[ÅX4 ¢C¹…ëÐXÝÃè£ÑªôÚP¯xCpz'©øÆô ¶B3„ÿN6¼E¯ðÎ]+ÚÀn6ÔÄýmZqyu@c€==lçïÛML.ÚùÑw~…2e±#ØOõžšÔЏ—Ê –XÙ¦J+"ŸQTZÓ9å#Š`3±H+‚èAë˜{¹Žv˜bÁÁž£¿ûnø4eœ*âΣŽjmX <ù÷ã{þƒ0H\·õnxÏÕŸÕÛ{â)*ø?òŽ/ÁÉá<íÿ€L…@‹wµQiXƒ«8­?}ÝbïŽ$‰ý_ÿú7\‹ÁêÝì|&‘Í#äçlUuÓf’¢Aˆ¹‚á}­Àyîà/¨ÆºãÊ?…ß¾ú“ #®[ø“g¾JxlZyîñ¥ÚVPuÃo‰vB–Ãô šKlÓm÷Œ¶º’öÞBo4 ¬U›aYê ÌeÚ2ž DOõ÷÷K0ÏsJ拱 Idt<Å|³¦ÙbL¢áü*(Rò<Ý„ü6'9¨ÜKÔj©_’ZÝ {~þø_¡Ql쵎@H®Vp\V`ü Ízy¸âüŽîëá`ßn†@¡GŠ^ລ;éÊ^˜pfJ4W —Çóû½=:ÎVA•©ñCÉ<óµŠ}®¢Àôðc¸|Ã-© g±æh÷áÇèbJ¨—¶¬ºŠŠþú„àÆxÎÑ»zËô=ÛÖ^KÔº\é’æ¢ „ f×>'Í玱Šñõš‰ˆy¼Å‚Mb@ŒLU8c‡ªÜ ÙíàX/pyrÑ \&9[uKQêÌØQÂ2lX~9]ƒ™HŒŽãë¢$ÒÃÇòâ¸@nó5D1æ°YmãZÑvU)°[]ñõü«Ài®%æò¥{ 6‰Šª¨³8†]–,¡90x>ê@…YŸqP3}ô_-8D>p1Ì—Ž<kº.3‚ _^NIoã}¼h}0Es.ÑWc?úŸg w5òªb,±šj£¹ê¼1–wS^“ XŒŽ£ÀhGà7æ e9~S‡£ ø}PÑšÛ”ÍT˜r9Ô÷"ܹëψ¸o¦Ñ{V’Á¡`6¾B=Öa«AWë’Äß=ù´ÍVB,\Эd9ž«ú¼K/—˜^^ÃjOó*;QÓ$ÆCÜŸï!‰‚—°ÖP:SýÎ"‚í*m!^hŽ@¥geÈÝ0ŸyÌ•—9PÁ0CLéÂ'`àè(¬¿'w¬*øõ+ߣëä$×g¶{Çà‡¿ÿìÚü.šlItòÃøïÆ÷Àßx˜®ú Ÿ_ ¢×Aјœ1ÕËh,&dÂP“‰@,$r.KË$2YÌ%)äóFåcŠä'ßbe¦N)'»‰èÕ\…fcmV‹…tÉ‹TÖU6Òµq"Bˆ.Ó‹Ëùbì ƒ©®ßñuXhƒþŠujÒæðÂÊc•ÌÎ7° 1‰ùX‹™eT^TÙfdù I?4>b@!Àbs¸Ö JX=#©‚9ôð0GØÖ°6.];ûbšAµàE°F öŸbYî›7ÝtKl¶ *vðçT¹L¢°8È] ‘7¡¨ŠCI` Z!ì @e[îþï(ÖÞ©Ô¿÷÷<Kˆ¦Â4Ë-—>@ÅÜœuRx¾„º,C$#áà~â > †ŸZ»nËÔ¹Õùb¬|&±ÐD5›nÐ5‰‚"c2:´qÏ$xmnhÞ”XMµ´ÎkÖ_=ö$ôÞüÙÔëÅ$žÏÅE˜ü‘HèYY’~:22öê•»® ÇcUQÕ`4³c9_ZµL"“Ûb Uºˆ×5‰Dg9*# xÝs]àžÀö¹ÑÖ¸vþ]˜©±º®šZa´,8“'1‡±X䲬<öýïÿðø7¾ù­TÚÆí˜8çœøó*=ÖÊ'æ ©‚˜ac’äí¨ªu¸bj™X¯ûèDÞź¬k¶¾—V…"{-´=UÂ<ò¸~@˜ê‰•«º +¹ìuMªå—/ Æ*¤vK‹µ8È_^“Î\Œ$IBkMÍð¬ôÏ&DðjŸœ ñ¾\!ìå~óÎû ðb…%ˆz‘?ú\¶Ù¸fÅÁìÀgÀçVÑ‘ÄóÓÊ=Ï×'W_Óì–“BÖß\½Ng¤-"²ä¨5Ä'à›Gú¡Dm¦Î­Ù#gç I{GÇ&î½ë¶îIÝ‚¿ úÎ{óB~üõB…äsõÜJýpbÔI€Eüo?}mxr˜N¬0Uš ]QqÐë þø­Ão<ôžÛoóf›½X4ª¢€_ƒ_ *$Áhır¥|fè-o$äéâÌxÕ)’Æcà·{ ¶£mAŠö±’0÷yÒ6>òÙ-×d1>v>V yátYecÚ•9ÛæêušZ’%$Æ|À0©¢£ ÷8Æm Þì9ü±ýSVÛÿè‡$@•¾Ì ô,Èž½üûqæ A×’ÒC ‰÷©²ª„DPüÉÔŽ;âÛ8z†—,H–òG¯ßçÿÞ¾½/þû½wßíÉf©³CÃ*K.Ñ9Šw.Z`å2‰Ù!ˆBÃe61Aˆqõ/ϰ ¨2ø!£ƒƒ î†ÄÈ™oïE‡mâ››×­y4z+ôP-ôÖâìd,=“¨5Cí–”É÷¦&b¡¨FΉ˜¾altdyáœ|0*Y]Nç§óËŸ¾7 Tts¹ÝêÄÔÄ¢hW¿ÐÖFÓš…#§™6&si ùÔg%–uXÂXJ<&ë²O€ŽW}~=C‰Ž?=âœÿdw÷šý?2°Úì‹jýv—ÖZˆræÒŠoIéŸ%ÿç0rÓX9 U:¯'”ˆÃéùþ©cß“ª ><2¸èÕà(¨ AäJTϨ“F£>•ÔV¢»€UÏO³[‘œÏÚç÷8ÿiÕÊåÏÂtj+ÅRc“SªŒŠ´Øpµ «D¶¾Òb®”Þr{=ƒÑŠ·NŒBÐæ<ç'GXJ±ÛßÛûòswP=ë MLN.ê¥úú³Z!=½%ÀÌn5z+*ļuæZ,x§X~Ü>8WÅÿôúBƒ>·ã_V­Zñ? ‘zò¸]ª Š ÉÊbÆÕ‚e¬\¬¥µ@”úÁÓ”ÞR%DütWÒøùÂðZçädb¢ §ï™¡3'îL€jK¹œö fñWv1ÀÌy‰ZQùœ‘yTÇÆOÛ'†ÁévÍ!"íÖ©/=ùøÃ\zù§µ@å°O]P+ /†¥Ø³/¸VÕi¾DÊ,в‡mB½W>gѱæZŒS±„¬Ç¢ ISFŽW’=±ÿ¶{)éb ÖŒÚí6翞<úæ] PÍ`)»uü‚]÷œ_D Ò«:˜YbÃè…DY²›Œ&¬~£“¿±­Q0LEi‚¤‚¤ó8ášùÄ–­[€Î’"ö©± T‹ XéàÒò󕨤r†²,ÛyŽñ&5ésC$KSÝœ0•Ájµ?6púØßßòŽw k±”u|HeX.ô±ØÎPÏjÅ·²Í!Ú»qã—*xwXÁ92:gÓçôEC#CÃ_þ§¯}áO¨†`º­ø´žšQá"ü"=î\%6ŒF<+˜D+s sN¬˜ ¸¡ÿÐQXzí³:¨¨€Óé{sbðô—ß¶ëÊ—ôM߈  ¬'° Ñ[Zm¼S GŒ¡g(‹ GÇÆgu äóQû¤íG{_Ùý­>ôa‡¶éQ.º±˜«½¥ÿ"úú¬Éh£¢D3ÒÞè,f²¶EágË–w}2“Æ)Pù=5òÃÅ8øE|ìùâ[ ÃX„hä1‹ÉŒÆÄÚ˜$ËﯵVD¶zõêálPôUûOŸ¸èAµØMa>1¯j0ZªÙ[Xþ«©¾î¦É!o‡3àÝ õkt{9(²,ÿÑår}³µµõ K‚¨cC}eD]@¦0séVöœé?½±{ÕwêÌfÕæ÷ÀÄа¶–’¤Cápø/{ì± ¨€Æ‚ªª–Yêd¬\Ì•½nuÆ"›Ïì;ð?oßvÉeÏí{ãn·Ï—4w„}ÂE…ga üvóæÍV-^ÕÅ,-p%ÃÉ@iF o¯? ¹£‘¯]±ríZ^eéï‘Pà¯Ï÷]K÷k™¼2K]\¦0—YÔJý¤ÄýÞ#ÇN/ÛºîÎm7îú[I¿Þwvàª×A{Ÿ2¨ ŒÖ5b.Œú Fã1£ó:€þPjŽ÷”ÇEb µ€Áè"×ëE­2V°Š”ÁTÖ\VçKc•Gy”½ÂòXãÿ 0¤„O07þäIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-demo.png000066400000000000000000000577401226750426600173070ustar00rootroot00000000000000‰PNG  IHDR£xž•BlgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<_rIDATxÚì½g$izö¤/_ÕÕ¾{ºÇûÝY;wkn=Ü"@'‚ R”(G†ÈP@ú!éÅ@H?(‘R#”@Ž"„!Î³ãýL{WÕÕå«2SïóffMÏlÏììÞîag¹9‘SÕe²Ò<ù¼Ïk¾÷3Â0ÄðüõÿáG¿þ_ýS›ùÉï”Ì7Ü0¼h˜¸nóA€&?c!|9ƒ«¼ÁC äuË”¿Á¿ ò¢Í÷d B}U?-†nC¶'ï¶iÈ{!úò< ¢mʦäoCÞƒ~wðY+ÚBßç~DŸåëÜË2ô‘¿oó9¢÷LDûÕ—mX¶ü-¯qÿy“Ÿ ô8 X<.ùŒ¿ÎÅ 8ôxú²ƒ¦íS?õ;ºŸ~ô=×1ôQ÷Åôu;Aî1À}䱄ò†#ûÒ“× ý Ï©¡ûÄßëù¦¼/¿'GÑ LÙgù=ùLߎ±'ûÒì¥ °¶åàdq¿ñ¥h÷Í{^Û>ý„>ÚxH–ðªÃ“/Œ=úòîµG¿{µ%äa;F=•²¯ºžuÞqÍëŽmž€¾%ëM9ô*ϹÁ“…O–‡ayhÀˆÜ¨ÿİÏûßCåÆ<¾›ýäK©ÜúrðXó1˜r—fä®MYÛµ—Si{QzVúšá—äÆ¿&”1ohJJlŸ,Ÿ€ñ},é¾¹VÆ[o¸µd"ût_=¹…™!§ç t»^¹j`s3ô³•k60ÍS†güjhÛpÓVÍsíëé´%Lj^¶óuÓ4. &Ĭ® öÔPB£Ÿ€ñÝ–¼ÙÆçmÀ}öK8_ñ0¿ üî¹FÓ<9ŠÇ¦ZÈå,ô ?}¤‡É\§ç€·—Œäúè¶ÌB³<¶´h…'÷41’éc³ÞÇ×ÞtqtÒÇpº…+kŽ×E0uéº=%îç G”¦'@µíš0é|6ë\OyæiÓ6^Ƽ"J`N>±b¢E?1óÿþ‚‘nH«màfm¯¾qOž<†/¼ð_¹ŒZ­*Ÿp`»ØÙ)\\qUÀym%%€^[΋gg¢+^Þ¦áà†¸{™ÜŽí …A}¼ì÷PëX¸¸ Þª¸Œ®Ù*ܬ…¹áÑÃù’˜tXâB {®¹iû‚0èYÏ3¯‰zZÜÊÓâLÎ P}z¥Ÿ˜ùÀøâ¦X.Nž<ýOÀ²LlÕ}ÔZ¢kUtÚŒ•ñÒçöÂê^F¹½ˆ—EW¦³9øH£ÒÌâV5…[ g–l\YÉàÍ?¥˜µšðRº¾”ëàøxŸ;⟾bãÌ2ÐïuÑ;F…iÈj>oÚ–€_תëÙ«^Úºä¸Ö,Óxݲ›ÊÒõ 3‘E?!Ò‹Øž€"í9QÌ*ôÑïûس{ÓÓÓp½ž0œ°žÂÒÆ-ÔÚ5ÁM •JEÐÜC6ëâ?|ö)ä Y\¸xSF#Ìãæš‰ËK..,;¸*Ï¿?7Œ¯Ÿ \ eèoÁ`ÄR¨5ô†}Ùœn§‡n–š@I~è a›_¶¨G][¼z{Áñ¬³Žk_½$ú“×”mÆó |bêN0 ½~(¸puµ;¬c6[Eݘ„+f4à†-€ P,ñòË/Â0-øÂv««ëVf^ AËÁF­…åå×ÐjÔppÿ,f§|üÍ/¶íáÚ| ¾5ŠÅZ×7]œ_pqiÞÆ-Kí šMFweŸ¬ 1HC¿/,*k³‹60%h›¾dŠéósn9igÉMÙ§åï·\Ǻ&÷ÐÓ2.Š™¯ “† .Æ<12Ë`ŠçàcW¡t*‡®€¢ÕlÉ5w„Z=®Õ‚k÷PoÚbrÛòžárIÀlÂõRð–íâÄSO£Q­beuÅBAÖÄ–˜üf»Å[W09QE¾¹ç‡Òøòž"Ƨvc~¥‰ÕšZ=œ]ñpyÃÅÍUkí,íš® „IÁµ§@X´cvƒ°(»S„eþ¢²¨çôœó¢Eç<Ï>'¯½.¦þ²aל7 ÃèšF”iùŒj$žÄ4ðÒ%¹¸MN^€fjÊ®-š±Óí—s„ TêÀPÞð°MðßÅßþþòñ÷°záV¯œÇ3?óUŒåÕRNMOÁï÷‘+ºxêÔ§5µ6¿°(ÑS,–M;]„µk(Û^Þ“ÅÏËó(Ìâ­&V:\ZöpqÎÆeѧ7YaWÙç¦4ìÇ •Gqš|‘~«éˆÝ#‡·–hQËT'ÊNÙ[nʹ"zôZ*e_öÞ¸`šæ¢lHL½hð>üŒ2šQ.ží`åô[ŸÞŽY@6“@t‘s|ds=k´–²M͇°ôý’˜îÇŸ8‰^ÊÅÒÿûuœzý,*O¿ñ»€#ãþÒ/}ŽhR«‡‚¬}·„C‡ö«4P=*¿ÍaÏþ”þÝét°°¸[P»gŸœÆÆ9L •šõð_~ñ(V×ë˜[o¡k”1·‘ƹ•4.WÒ¸±æb®êaYn–N‹äÞ(YTnˆnW´h½“ Ÿ”;í$“È–£ZÔ]g‹Zô‚çYW¤o–qV×äx;Æ6‡é0~ˆÌȳìm4Öo¢.ÎÈÕu&=á”xÒãb~-äsy¸n'D*í uÄÂ÷ñ©¾ˆvç³²ÖñÔ¯ý*œKW…},<ûè= t†R¶‡3k—^™Çìc/b«6‡©‰ |ÿìÌŽ`$_D©”†6ESSSè‹N™ˆÃ‡N`em©”‡zÇF[´ëúâuq¸æðÒ±ƒøêν(¬^„/7ÑFPÀÂfççå8*Y\«y¸¾âjªß!>ƒ¨:ƒ çËo÷…E;V§Úß20.fþs‹#\;t<»îzΪ—±ßV}ÍuͶežKrNvµ!l*f>ÀGÝÒ?\LÀèmáà§JC=Oš¸yk^˜/Àfu W¯^gÝ <€µ*ƒ×ÂŽ6FFÆày.Æ'Æ‘IgQjØ|ªˆ”õgŸ=!×=vå›&óÓ™@£££ºz·…ËË‹H ËÚ–·7¯àZõ:>?û‚8Û®\í6:AìªkØcSrƒL ZÝ„o8¨µBÜZn"ŸçÁT„;xbbæÙC8þ4j Ã3¨´‹8¿bââ’‡K¢K¯VÌmeDvXûZZëÑPX´×ë½F7ß ¹KŒ}¢?o9rꊉ¿éxΊ—¶Ï H¿gYæùÌœ€”a§^ý¨€ô¡r`bc~·ÅeÝ=;¡%Sôœ˜kbbbH¼è5}½ÓÙÀ­›kâ¨xêt;}Œ‡Ñl¬‹9­`m}塲٠2–‹Ð‰.xO^°ŽÓß2M–iY˜òÇ±ÜØmçÀ -luzøƒË×ðK‡G„Áê2&În\Áó³Ï va €é¥Ïê¾ñ¦êt…éú]qšlT!®_[ÀQÏÃ3Ç xæ`[nŒ–ü¾XÿŽõ&°°aãÒ’‹³Ë.® ƒ^_wp«žÂFKvkâ4‰WïËñùí®Û ;ä…²±gMÛúË1Hk¤çÄÜ_wSÖe‘?ãº"l¿,2y|¬)Ð?°ÓÃe¦ïx©mdôLA!ÖG>›ðíV0ñõcGöi˜‡µ ;Âz®˜YëÈ7æËgÑ`ybjG†Ë¢AÆiaX€Ê\¶+tÙ7ú˜È áK»OÉ¥´ŽpÊ*ã‹{Oi_A<÷¶88Ö+ hnžAgfZ©œ²÷j¥F} »Çż·*H—&ÐíuñèñÃxôÑcè‰V¬·éÿ»‘÷Ì:C¹1¦†BÌ ûxî0Ë6²-ˆ 5é U × o/¸8/zt^@º°•†•c¤çÅbI97Ô¢\{õv¡…ð”¼xJˆ PÏî @Wœ”}Úe\4e^6,óGÓŸ¦Á"’V¨Z4üŒÛ|¹,Ò$»ôŽ„ŸiDz(TàE%«4½¾š´»6 ﱨ´Ûn(HGF†xj³ÕŠâ„¢õ¦:*ss‹¸%R€K»Ý@:ÂÆÓ˜ÝÕb2CôØd!*fmw}X} Ÿ:õ’Ü(âX•Šò_n†LÔ‚Y´jëX9÷CŒú<¾qá»x~ú<{¹\Vî#¦=[Èx¶%¥˜!f¾#Ûj–§¯7›2v†Ø;ÞÇgŽŠÉZØÚ0¯lZ¸Q±p}ÕÆ•§WEV<¬×2¨ÊûaOO¤°©0h‡Lê ‹6wÉ »x÷R‹Zž@knZL½k¿å¸ÖÕÐ3ÏÊû¬]#‹šôè?ÀàýCåM‡rÑsÅ ÔÄd9®!®‰¾8'Ý0%æUN¬œÜ@€ÝÁ¾~^¿IPÆ mLj-¨¡½²TÐ… ìѨWþì§ŸÔ*çJeSÀØR0d:ÇtÖ€‘-j‚uò™zµ‡Úʪ€ßÒÏíËc·I©à`×§¾¬ŽÐ‘±pÓÃH˶â]Áµ c¹&Ƈ\ÔWWñÚµkøôÓìoÂLaˆ£%·€ú7Ô¨AåÄySº^ˆÝ!N÷DRtå·h‰©oŠÞÜ&¥y?OŠÉ¿*Œz¡’ÂÒ–…M}´±(xßè›ýF¯ÔB»$wÛc M˜µÚnÊÙнkŸvÄYró aг=?Üì‡F+ÀûCçÃÅŒPá¦êtZ/|dî»bb=çFì`i¹?/še Ÿ…bž3úÝJ­«™¡j}VÚA)3«ã <×Æã³£ÂhÙV[±% æ-÷ExÊŠ®YÇîìŠ8Ôl®ÜÂð~Rí‹è¹“hûž8e)Ù/9F—ìéGâ!%Ñ*§3Ùû¦ºø‚ÕÛRG«+®TÃĺ€ôÖºskÞ^vp]€zs#…º‰ŽÆHeã@t®èíTw³=%¤8%»§½˜úPdÌæ¡™ÔJ˜²_[kãBß7®4ûæk¡a]Ïd¬†yŸa)£Á(=¨Ìׯ60»ËÆP˜˜Ùµµ5±]ÑFµõMd2Y½¸K+e¬ááaD•5†èÉ’¼æ«ÉÞjl +æ”Qɬ”¾ß‹˜ sFÌÚ™àû¶xç¬Ƴ ÄÓêYŒOÊc¿«uºÂÚ¶ÏsKý ÃB×l¢Þ¬`i®Š’hÑaΙ™aÛ4X|áû[rcy ún§0;…]‡öÃu‘ßu\@f*à{¡]lXiphEG>ÿõœÃÙ§ùûÍ·?$„É–hÌ­¦|Û}-û ˜ qh—€Ôhëkrú°^7TÎ H/®Š&]qpY§[ë, x{¤Ê¢]QÒ~·41í–äý›Ølö±{í»oÏ;gþ›¿¾lÁÚ½®êïü扇”5º¨åíEjÌÆ¡#³Ø¼ñìz€‘=O£\Vð°p¢^¯ÇÌðÒ¥KbnÛêŒllT kkk8þÈ#¨V«È‹nãÅžÙµW¾ß‘sKÓßA*ÚL€*ü¨™2-ÃA=¹(ë›]ÌŒ{¨wm\bŸ8ùÆøÙ}š&4ä{‘»Êûa¹Ѫ}½±¦wM+`~ÏK¡%@m7VeÿÄçåÑ$ õ¥ #ƒAjJµª+ûÚ•ý°dŸ90ƒtÊŽÀ†Q(ŒÆ¦°pÊR³ÝéZ¨·-_t(D;ʪѠ³É½ŒàðTˆGfºø²Ñ‘#ôF« “Þ=J&½´äá¬õŠ˜ýk«yuêsiß¿"VÊìáï¸î~sqõÐÏý“Ãð{k÷¬¯û͇ïZe‹FòÅÄ5ªs¨œÿ§ðÛ=œ3óÂ6˘žž°m(è&''‘J¥ôâìÚµK3ƒB¡ `í÷ûzÚb!ùùy”JCrñ2ºÞñûAÄœ~૞ 2a®©+¯ËsS–njáFß.£»yù‘0Lí®8!Í5lV€…U_Aï0ÊeqVÌ´\@aRoT.Š#^ý–&Ðß!Ш ¬HX±"3Užr\ô¾G†Ò²?:9yÑ¿W_GBŒÊÖÅ|bkí< W·Ø3D‹ºy±$n<ÊÒPg±—T¹ÇÞt:-͆89Û•¿;êÀQ­l6Åõ­»X¿BÞÅ×n£âYÌLL}^x·bχ’•åäzbÎŽ:€´íÃ~ê× Ö ½ô8°ÍfCµY $ðÈ,'#øž}öYe²°Ò‡ Á¼Ã O—ôÄ‚£Eïdì@Y{T@Ùà5{â¥w:â@ô”Ŭ°«CD‹]¹ˆ[[T+M•sóu‚­ŽQ¡’cc&ÉÀØXÕ­–˜ÞP&_¶Ó—}è `|eH#ŒÆæ:¦kVsž0vÆL¹AÈèÝn$pùÜï™( íŠ>ˆy6\ý®/š¾škÚöð®°šZ©iÉ dDï‹õG!àÑ\量l ë¶°åŸÀe`ò[gË++maä)yâÖ7ëøö+?ÂOú8Þü®]obÏ ¿‚ÍÍMa·"r¹&ä¦$ ZVäõœ&¼ÓBýqöÉÔ«Èªó ²ˆÆGãûÂXž˜©èM”õ ì›æQÇF¼PìÙ•S]Ùlö¨!š­~¤ï„ÁnÍu4lDœLO}I‡"—Ѳ×0™—ïväó-äÐ)‹2 9ft4¢ÑÔˆ2‚Õ‹YÒÓÏA”#S#z(ˆÆŽ'ƒÈá³ÿ>7êðÄô{5¤WF»'Œ`¤ä|Ãr¹ƆíÒòRë×ûÂÞd¡²˜Õ—?÷¼ *wù$K Í¢Ôë[ H®o¿ý¶Œk!.# Ô“'O~øû-ûY&lõ0dk¨)ôï8"ö7›X_oŠ7ÍJžyùüÁÙ!Ô= Â?õ(ã ¡˜CqTº2\m+Ôàx6]Âz¿-Zµ!R@ôa{ãcy•Œ((ƒ®J ƒš7”GDº— 3ÈÛN" ¡†ŒBÝW:Qw¦ £hAöõ{â” 'ûÓ¿¸ æ8@¥Ûcl ªÒböËrÜöL äÌ© )z5´>®Ìh`³ÞÂÙsçqôØ1¼•}?ýÅœôê@ 0;;«9fjB²c£ÑÀêêê=™ñCH©#“bˆÈ¼}aÃ;eÀÈ5¬'`ì«™f’@تµõµëWÛúúØhV Š¢8$å½ô7@]L`ÖÍÁô³Úù!4lõæwÖàÝ$ö‘ÙÖªõ€k7,«Œ™icp ·AIÓÏ >ó^ù´‹PVã³GÐ'Í‘ÇqF±*7‘ç;htÖe_úÜÏéˆa?¦f:Š+[¢ûĬ¶71ÿGÿó»S(>òWñÊ÷¨ÎÈñãÇx+Ê#˜ËfUÒÜ”CCCNß6µ\“DÈ¡š™CˆZʸ®¥ëöe÷î’ìcSÁªÎŽÃ<{_ÁÊ’¶ZUœ·zOÍûЄ‹¶˜ìõÖ%¤{i-É»E‘}ñ¢=Õº§ ûCùšÍñˆU½÷^V¿+]Æ T$@…% ÂøË‘Ù”§ÕAÙTTå÷‡Ô8%dÄÃÎXW02ÇìàÀ~q`<þWÿ'9˜-4ådÿ©_ø¢8 ñ†Óâ­bîšb¾³ZAS¯7tøë/_¾Œ={öˆ÷½‚ƒ* iÂY©£?rÖÇÇÇõyrWóùmÖ{÷¡€”I¦º$AôYÈ‚—.­‰þMËñtÅÉò´OŽV«—kÈæ\äÆ½èÆ´+fÈYhöDŠˆ¶ºtDKº–‹ñì8 )Ħ8bI®~€AíÄúOñüÓ°EŠb°F©H#ŒXÕ6UVE4.Èäû— ÕY¡Îmµº*™e<@“™‡¨jg[©“9 •Zo9‹CûvãýÚ?Ä/‘Ã)}V<挋〷–† ¸¶ƒRÑfÌ`|rV™{÷îUV$à &&œ1G¾GœÞ85'Ã%üAÌïy„E#1£FSaTyô ™ðøñqåÞ½Žšì¨ÙTˆB±€•ö"ÖÛËè s*BÖÉ"'¦úAØšý£¸:æ; QÂm@ t$E¨2j´ºƒ¦V·¡FR#Œô©Ø2ÂŒå΄²Çb¥ghGƒ,žä#õ&•4‰QÒÜ¿;#÷+ézvwÚV»w‰é½ÛLs¹u«ªÎK»ÍÑžv s,µ@n¬±Ü˜šFæÉ{¾h6&È?«`5wª˜ŠY5H:¦E#*V?täXœAW¶3ê88ácjÜ.HÉ}Û¹Ÿ1y8Á_OƹÒ.«[<ôv’£q0ž“×ìòÃ'õ$9jhÀ˜5‹ÙlËK pÙ‘‰]·›à$ɼw©T¼×ívŸ}7Ò‹šQÜ.΢l_¨oܨŠNabâNf{ä‘qeÂv; Îonv,åâ$ªþ æ6ç´ãÒÚ%¢eÈcÑ+FΆ e<7þ@ŒùÀΣ¡C‚vÏ€1åŠòëC+•JÛÛÄæÇŒÛÇx$¦bei^´c ¯¾ŠÆõoá³?ss·®£%LÖé´u8‚eבòr¸zmårK“À¢CÐñÂt ó&€¼û1r8Ü¿xq#Æ„û¨‘ fg‹÷ŒpÍå¢ßËçoGÒ˜ÂdnJ·×êµT+1‹µ}aò^;£æû'åH’D H ó3|綾^G㆚%e[†{ÖÄÔs›ü-nƒ±Ën§…Õº¿›é0ªÉ š;ë§n×Çü|M÷—Ž C;ûö•±±ÑRòõárf¦#Á2ÂNqàEwý. ^aP2÷'j¦YXH§Dó¦Í™°ÞC+°>~`¼œŠ–µu¹-œ»z«gÿ5>ÿsqSL)Ù/a.‚„@" žI<䍸ÀUV$˜Ø&3ò}þM‡Àäë4óÜÁÇÏpÛëëëú;|͈‡Ô˜,G*æ1:{"npoFn¾3Ù¾mI¥l¹‘ŠÊÄS³IVd–ÈS` M“ÓÂêF7k7á‡>Ú½6ö Í¢½ìàÂEf—RjÖ¯ŒȇêixH^k unT£~Ï™–$3²ò}rÂqËÌ€} Áh$Ò=>‡'ŽÓçG6ó¨–™­Èàp戊âÉNÀCÐ$“ýÈ„,®å#ƒØ:.FÀFÀ’ý¨O:¥À¢éeœ %#²Ø‚Ÿãgæåkɶ©µ8p¢qµIu’á;€1Çë×£ø"Ójí¶¯Þ6ÁÄ*§zÕ¦Ü Ý:Æ2c &Ïöu3h]"AzàÀƒCò³:duˆÉŽ ø™³Me]K)ÍRÄAïû ‘Œ1c ‚pt4#àv´ä,Ÿwµ×Ihýí+ïSf\k¬¡”*éo7»Møò±¾±ô˜s++M-.i5ë¬ívDNLx°F5ósµ9e¿‰Ì$j‹†˜ð)Œ°¸½úzÆÜ) 5õ®˜Ÿ­uj¨´+ʬËõel¶7u0Ü¹îG_tâøˆ3*wc=Ö˜},˜m¦¥WbÒZÄ}ÔU–À1âv"è“|3™º1ñ”W$»%q’“&ùý$ýGH³Î÷iªyáYhA`NÄùð$½Èe×ÌÍÑæò‹í ¶ùîÇFM1cOýfh2G½h²e½ÞÕÚDzhÂŒ€ôfõ¦¦É`)3‹³§7„•,¸ž« ¸¬#›ñD»Ê¶S]d¬œV±Õ”ùŒ0YM ¿­&¹¤5’rG VÉÎÕJ ™´­f¿×FÍ¢i6äØ,Œ¦GÅÔ[šé)¦Š lWs8;„æ¦%ZV‡V a<•M§Í Ãí~ôË¢²àùk0÷Æÿƒ/þü^ÜZ¸Šv«©1Âd £™fèæ;ßùŽ‚6 ÑðsT’Lb”Ô‰ÉpÖH&lÈ•¦9ñÜÜœ²h’Á¹qóFD:ä ù¸ÁÃdïy”!sÒ5ÕŽI•Yqt”lR½H'‡#k½-Lç§„|5™4Ãû÷)8©7©1©9{r# 9yÔ˜sÍ[¢;Èy91§£xëMŽí6d»ô= ›DÚ'§òrþ|˜^_ÎhÓœ€.¹Ð“¿3´Ã¶:[Bx½x|©lHóÍŒPÛo ¤d¾Ó¶+þ×ǽ²0=3†qõô‰G"&¨Ì£šù¼:0ù[†Dl2•€†&›€"°¸ðu²%Mx@>'8Éž‹‹‹ ÈO}êS âû |“ \þMÐÓÛ&ƒòojU:FéT¤'al+û¿y33 t4Ó pÓY_Â;©´…á¡, ãY1¯óêl¤Eî-ìÅü\^_çÑtq¦jÀ­ŽhüшD¦¶¼åøæAœÿî«n%ûv„‰óŒ42Øè¬*k^Ú¼€1ù—ݸÖZÃHzDM4iJn n›f<ŸÊÀêÑS^.Z)×Çš½«ýƒ1.ŽßY?ÊY|ãíóD?åÇÇ1·t §f{ª ;,…¦Û·oŸ’ ãßÌ’ÁX F‘“!¬ÉÀ¦„ (ê@2i’*äw¹­DKÒT':’Û'ŸäºWô,‰õ‰Ûð][­®6Ô$HMõÄD^ÀžÃØXF‡²0`{†ö(°h"ùÙ±i961½Ôœ  .¦ h™¾'©s¤}密–ÚEŒëè®ð ñïžèÞ^§©Å=9ÇG†*à’·Ã•—j»ŠN¿/p1Yd“+qô,ÛÌf­©&'¦°>fÌxGÑ„,3“£ ocuñ°¶¤“P:œf+ó”3" •xÂ|N¦{î¹çµ®‹/âðáÃÊtô ÉtsM˜˜m®/Y…1J‚5 ‘yù^$½ˆ’ -q_fä¼4Ã0Ýn Ú1“q5M¸°°¥ãeÆËÓ&.¬ÉÅ­Ú-õrwöàÆåºör]SÃU•µ̬…\:‡ gBÍj­³‰½‡²ðÛXš‡Vè|ÞèöKy(dÊXk®k,s4;ªÛì}Ì +—å=>'ù:CC‰W ³†Ñ‚‹Å¶‰á©ty³íÓÇŒ Á°AqôØS²´|„Uà îj=£˜ÓíZ ŒÌ©AáCòC7»w& ÒÄù!°i¶£ I{`‚VS€ÖI++²²œM¢žzò¤h¨~Ü$)|Ç8˜»šh¦¹ÿ nE•ÞŠ03STM—òllì/€gyh÷#„±Æ‘1e55 So´UçÑÌO¤E7škXj,Êç[ªïvç÷áô¹uuùQ<²¥ž³'¿Q–´…Yœ¼èF7ƒåÔŠôä“>Ç“3äÚ®Æ+Y_¹%º1/àL¥LsÖPWœ¢~êcÆÛƒ…¢gW¯ß}ØEß1pù•߯/üâ߯^û‘&"ˆ— FÓÊpÍ,=jj¿Ç{lÄdL ÇXhI!M}2èŸzPu  IÖfÿþýƒ, ÃF|Î ~u~ܲëÝF™xã0M`R3’¯^Ýo¾©L©Âð¬•ÞM°»OËoi¼‘ UΔtŸ ‰NÌÍ¢±fb}Më”PvÊÊœÃÃfKn¾#®€!ºÚè´t\t&í1VÈ›âDm´64´Ãaü,åÁRc ÃéaÕ‰dNêF>¯¶7‘·3…I3â çí]ØâMa}LÀÞ‘’ŽÈòÇãZšˆsÈúi¸rðÇ9®M‘ÈR<¡Iý"A˜0b2¼ )K´"Ã:‰³Ó×>Û]ý›Ûâv4jR‚’OÂ;\âáçé±릧‘ÉzZ`äbø®á²j7¾Ét6ö¡Gšk£ŽT0‹”•B½WWI ¡¡Ìdй,ŠÓQpóXkWÔâ¶tP—HÛnb|V€lUXmu„Fs#(Ú£8{faJþþæ¦8x‹X‰1ØÂ°-ñ…:é5xŽ‹ƒåƒø&Ëü xO妔lÚ¯s|˱ ØÈÚ°s=ÿŠÛÈ»t Ëð®YÜÖ{¤×W° Lå%ƒóéˆÐ´ò1©ÜyòÉ'kˆl@@qáûÑäà`“±2É0ØÄij֑@N†'$a$šl÷òoê¨h¿ƒw”E$#ò{IùuäÕ«un&.gPÞbØC£ÝŠòÌò!j8Žû™ôfqå| ËžKÆ ô¨ (må²³.úÚö6çÄJŽ”dWySXhsmJXÒ à÷B Þ‹MÛ6KØên©L° [o†–šý&\ùÛ5‹ðäÜŒ:E‚ÑËXO͘ ;Õf„)ªóç°vù,Ì£ŸÓ#­F]™- ZS×% C2Ôx|lG/˜±Ff\¾üå/«GL0Ðt“)©“ñ1 Ëò».M"Y6qjÈŒü›L»qà¾!¦-4n‡£¶/ôœkµ¶¶éA0™Œ­—éé‚îÙðàÁ2öì)ÅZÒTM7Ñ/¡Ë‘z ûQU_J‹w݇¥`Ç1Ç(nY©´u[#Nù:&ì¸Ñ]Q]Éx%Ym5¼!ûªI¯øœ0,U†‘ë*ØsD˜´‡¥­%Õ¬®éF…¾¢Y“q9ß7C[ož‘!{X´„Û ÃîNé퇌ñBFc'„=»&±wÜ•»/…ÙüÈ ´Ó(>²‹#x¡-H&=r䈚^‚• cœ‘+™Žà#Ð" &î$Ì“åÔü˜š0õsÏÍhªcîö¦£0L_ÍY¥ÒŠGF´—/WôÌÂÔj-¨5´^Ó×Ð Sƒ”µ²ç¥3­;tÇK»vïˆD$ËxXV'„šÚý¥ª SŽH+3È9“;è¨7Nï}³»)¦ÛÖc¢4 ©æMá‡}Œš3åàwÇFVtääül„53¾‹Ö:wá[[ð4g¿ó[øÙ/ÿ5,¬Í¡)ÌHfK<^2µÍt”d¯¤¨6ñ´ÉŽd¾GyDœ¤†QÄ&>1ß(JIðòu‚7y¯ÛíÜ1Ž&ÜÁ›&Ð8>šŒHSJ†b,‘÷óÒÌW3 515Tûñ#ãiPÛyðÆ÷*º‰B@²-Dµ‘sÎ\ºdɺ·ÇÔ°ºg3÷‰všx`ïžrÉÊ;E—³6>VÌÞ%9rP›$uÖobäØIa‹,Ò¥1Œ•h4ê9šÚ¤J‡ á{d1껤˜‚Þ6Ù6 €'zï3H®ÅqÞ:ÉesÛ4ûÜ>:5mÖ8Êö>ûâsƒ±-;1#ÓvW®l ‘‘ašo’é@Æò!ƒNMåuýh+ýD%‹l(X©´g”z]n§2´‡ Œ÷«¢[\Y×™ ÆÅiäÏ‹yé£-¢šw%A“§ÉjÔ|$€’n¶‚ˆ ›B%Áëdô`R˜»ýõ¤Ž11õtd’>> xó7´FÒŠzo'<ûÚî1”sìXóµ0ª]¤¶ët|Žáá´nƒú/1¸}ÑDѦ†ŽÓŽ*ÊYÄð'™•ˆ:›L ¦=×o6zoïÔïábFc'ÓbÄÞ§¯ÓhܸüÎüñ×°ë`«Š^« `“adJVÞ$-òøœLÈ‚—±B>h4ñ,~øÊW¾¢nn‡‰FLrÒ·Ï•暟ÑvÍbþɘGïG™@JÌôKäÝ"Ε÷qñâº:Mw½ÞAKþNg\eN½ß¼°¤5Ž, #“bhS¼bañ^G ¶5i­z¢å|½aÙÿ~¾¢¿e†bIÑ ©Qt9鑼ß%ðÓò芴1S:€,ïæµ‘?ã—ŽŸFÖËÂõ\{âÈóâLåì‘jµ»£†x˜¸j¸#VM¤ vÙz"=ï ýïD„à|Ì욤ÿ’£± ǪXd>:0I?G¾FÈzÇD&CÈŒÜ.Ù0©æI~ƒß£É§%#Ó™q;î—hjó$¿Ï†š$l’IÒXÓ1}ÇlK»Ó‹ÊÇtêbW›Ú³zÜÓ©9 ¤XdN‚–Óˆ¬¶—"+à¦5u·Þ®c~®¡š›Eº» “Xî,`µ¹„=¥ÝÈŠ.\—›ŽÎµ$ž±áù¸Y»&r á¢xØnTLÛòÐi´01ùàc±W7 œ½ÖÁ“{YÜa—9ìáagFloŽ.Àêtñ¯~ÿðü§žÆ•¹óÈú[ïóê-mfIçäñÇ×à4µáÓO?­,G‡$Ñ{íGÓÊ>Žd5‡ë¾ðý;шo½õÖ þ˜0!Y•º2qˆ¨ɲ)AÍ÷4#èIg'D:8:(‹`ò{[xóšƒJÃÀ®ñ"Z]kÛø0vT\í(6âÁñ¸ý4¢(mçaeÅ”sFuùoe.€mD­[Dãl…¿Ÿ†7œRÇGËÜÖ™(˜Á¹Wö3@•€²äóQîÜç´rØ/ûœKõµçwÏ a¤¢BN»q—źkýí‹3d¢‡‘bOXÈÛ~°sÈCÝF™­Mž;õÊ,oj®Á.NÒ˜š‹B=1`˜gŽŠg É,d,šO‚kueUC<ÉÀ-šf²ŸL©TZûóp’J²f2®:q‚ȨIÝ!·tÇÝ@fdÕÊ&ZÆ./Vq\p21dFC8E‡0\H¹Ðíi pÛÅŶJ%#îeŸD¾S¿: A?bÙ¸2¯üí$ARjnÛ€qç6({³#&Žæ]m@`‡;;^ïå¸ eìwæj"žÞ·%²ÂftvÝk‚÷‡«Á|Ü‘rƒ1Eç붇™cO¢]_@IêÈúVMÌZ^ÑOOM`DLk«ÅF¡Ñ +ÖéÍÌL ËÕ„ýZ˜Ž6s7µi=Ë©r:ߊfXäwhþÒ:+®¤¹/òò¹BbñûتÕõ=: •JUÏZFö7¼¼d 3vô&2…Í|#Çö§Ô)iµ6P¶ªζ>Ú·A—ŒPH®s\üp;hq×w`ÜÆ IŸð®íÜ jžÊÈw7Ö­mð3Þá)I»¼¸ó­1Ø_C¶¬-NT¦‹z£«Ì8Z¶ÇU†˜5CíFPkZZ"Æ6½ë5Ë5¦ç¦dÄÒ­º ?ý×Mé ZQ#z¨×e¯Æ’Æï˜Ú­P4˜'àQ ²Á{£ÉŠ“[Uíÿ@½ŒöÑíºÑø¿×Õ,G«¹9¨ë3Bf|¢1 Ö–ìcskªõÓC5üÔ±¨ùæf­…åÕx[@½²ºŽûFQÈyZ{¸ó𘻺—÷óòÂw*c{°6ÄýæX‹›¦ÅÝÆúwÆ%Ã{¨§ðη#‡ͱS™ÖÓb#e§È,S¿>ÜÌH)ÓlÛøþÛ‹˜œÃna—­v µöík ÝɬCލön;‚-9!Ž˜öŒ:=lʪÆÊLGæL¬ètzðD?9"àÓ)+2szñ̘‚mý¯Ã;Š7¢zÅ(ï\‹ª‰ÎwðÆÕ*Æ1ÌA÷uÎ#h`vרää·F† ráÚhµƒ;‘Fój&Ζ9¨ö1¶ÏÍkîmñÌmÍIV÷ÆmfÓ¶Ê‘ï ámÌŸÇ0îõÌ–dôožÈx²Ë ~MAëGÆJ‡‡¬Q4ýt[$ÿC](Áôjxì ã{-¤díiŠ-2ÝY/|ÛÊÌ’XÙ€½Ÿl3.XˆQlØ „ËT[SصcÜîƒn×HÛLçà½døi8h Ç¿Òf€{ÄîÕÑhùq†gMõ+M~‹5‹,õbÞX6˜ò¢Ü7ûfqŒD»Þ®úŽÚñi‰X««!-M»êjcÏ@?Ãß `å·×V­kÆý„zº¯ü®¶”ïÖX?èÌ*x¨c9•±Ÿ„†ä9›øomÕu^mZNÀIÍë¦ ûQ‚³‘õ[ ÎûÝG­ÞËÑ÷q‹n>—1[µ™†é"çT°'¿®º`((YñíÓ¶˜ã4³«wdÏÍÈz–˜è}£-¼ô(g “šQp™a!XV¬Òþi£¹åÆwz²ÙvSð¢´Û5ëw¶¹Í–ÉKeÏ@ª×Ùèa½q 9œ9ssó‹‘÷Þhâ—~éçPzùò5,/¯Fš·ÙÀ‘#‡ä‚¶±°°ǵõ¢Ÿxì¸ì¾þÆ[ú{™LZ­g­Š£ÀÙȦ“âÄ­oT±¹YÓ?†b©€«×®cN¶••ïLMŽ£&€â´ÂÙœxÎûvcmu ëëúýÑÞ¼VVÖ´Ñ*{¤s2Ï‚ìÿÞ=»Õ‰»téŠèè4Ø/–¨µÊetjœÃÆ‘›*Êý{i¡Ï–„i¤NœÔ+8);ÝÃw¤%ð£2 û»,£Ï^úô?†óÔì 6›†öó^/x¨XD)gãÛW øKÿÄÂ^¯Š¥Ö~ñ¦m{‘ó{«<9±¢0™³ñµ£‚znaCCŒrÎiÞåô˜ÇGGpéÊ5e•$rV :ž†@e¡éÁû”y¼W{¨HwSuj­.ž¹ìOKËÒ¢Ô$‹'Æ1é…G³D<ë±SSœ'M‡Ùšª»ø.þ¤« KÁÔlILJ¨¹) m “Íèó(dj¡/´›§Û˜ZŒ¸MM±šaÞqͨÅmn‹§&iR_ƒé\Æsõõ¦™Nf²zõ±!Úùòµu|õϽýTs«÷j2&\þ33‘eí¶ê¸q}Mœ‰Ž6]u\1×}4 ÏâÉ—ßÀ£7†ðzý &öæ”%˜Ôæ€Ù1ýÐÂ?;3‰ð·ÖñwjíF•ͺmmmU™§ÎÖwCEýARÚª×Õ”qr©ŒËzÀ¼žü¦˜9¹ÑàýXGê¼)ØÞÂÃÔº?ÃÉ£!îi ÌPï·0\ÁðØl¬gã¹±åâ Ú<ˆ¼Ò¸!@Þ¬ÜÖ18LãÚ‘Æ$6í‰Öü°šAqze:t÷ò¬RiàmÞ¦X·pºÙ쿊»Š;쇋 ŠVjùÝT#êLMìïoú¸y Èu?ƒëb~&ô°B½KÛò¹{……ü)Ո湾8*#øí‹>3;Š¡ Cg¨3âî`ÀåzÞäŽ%34^Ö^©À(åÐ ´U<.n„hû-¹.Ò¶§zŒ³™ZÉÐj»^ž0™© £ma½åàÉ ›1Ý®‚¹WæØz€Ü¼a¼»‡m>ì†dß|õÿÂñýŸÃXyß=eÖÄp+#ç<5¾Ù³Ô‘{(ÁÈ^MßÁ7ß^ÀlÁ×àv§MIË¡‡R-üÏÏáìÙoklq¸\ÂÄĈj)5¯Ú2Ï@©”GµZSÂO¼¾Z×aK€òì§ŸvstÚÞ lëy©Tˆk7«˜þÞ·ÿŰ,ûÐl8º»€¯_y eæããÏâÆâ¦Æ³BÝVom`æÈ8N¯¶°¯FkkQtW ö0pqÝožg!GGÌvv[5ÔìP26©2b&‰yó{-Ì«ýë_Ç /¼0þ“\n,¾…ï¾ùÛx åâ.Ø–{:a"Ôæ€þâ…‹­¨ÏùCéÀ¨9Ôào,¢*”Zª$&uq¾†±Ñal¬4Ѩ‰´´ØÄžÙ)ÌWô<ÐáðD°qÚÜÚVTä`;}”òi-(Írð‘ ˜·Ò‘ïpBrfTþðõe|éKŸC! åÅÄ+ïâéÉ“ð×Þ@³µ…œè¾6‹ Ä̺CYq˜|¬4rÊeÍb˜v“3°)½të5Þý<Öª7Q*ŒëÄAÿèþcÇ…¡dl÷·¾õ-­2çÂô%‡Ì2K”ô…dþœéLvØýõ_ÿõŸø¥éûTëËxõüïáÅ'ÿÂ;³eA_§‰sä|X¶‹RÆœÄj»Úã=<ƒø£spìèÚ¯“=RgÑ£MÚŒpÙ»\¸j¨YŸ™Öç¶N,}æÑG!™OåvÑ+Td[ŠÝ^Ôã†&—ei¿òùYM4QcBâw‡Å<‡“ŸÕyù²Ûæ¿Ì§T¯Îæ š‘!Íxô çø±ÓXÝZÂþðG:Uý[Ãgžøs ºýèGøþ+¯àÐá#ø+å×ð{¿÷{øßùç8qâ1¼úêkèËþ]¹zU»YÝÄðÈ0¾üåŸÕŠrzÚÔ¾?NÔ‚ZR¯R†:}pôw¿Æ«N|)çmzôˆ€ð/ªÎíöZ¢_-Ü\|SnÐa¹Ù'ñêÙ¯ cŽblø§4ûUr§Ô0VfŒµŽgéwµÍšÎ“Üëm ÈB'pL‚¬|´Ù%,H‚¾Ö`;QÆ0~-€E­ñ"}eƳ‡Zw¶Èj»¸qóÕ%Ýv?.ÑïÁ× ÖãÔ¹ì¾Àétå±Ëù¨ù·¼×çŒRF/–þv3bžó80sJŽELµ—ÅùkßÂP~ϸדNå±kü(¾÷Ö?Åkçþ?|ö©¿ˆJ} o^ü×ÂQÁ²ë0BÀÙì"'Sìè(µ»Àø'ÝûùA–ÉçÏëu· s 7qöÜ5¹@ÓX˜_‚+ qTtuã›o½-š°@ŽéÅ#GÑý7?À•cSØØÚÂèpY3Q£øiÌÊZ«×Q’‹Ö‘ Ê6r›Õu\¿~KÇ;ñ(?âDãOŽ•Ã÷LœÎa™®áÀewWñª=ytäo‡2å¢:†­UÖ¶®6Râ@5[%Õ¯@.]ÖmîÏ?©¢?Êæ° ·Ž'ŽMëü‡%o$j2uiIÌÛî8³RÂ7ÿð›j’÷íÛ¯ÌGIV¥ÄYΜ9£úòÊÕkÚÛüò¥Ë8öžÒR·c±-ùìf&Åýè7ñŸýÙß]¼Œßú×O?òóZǸ)qdÈFÛ/Šl©$±È23÷z•NL!——<ƒú«d¦5NÇ9]ÈŠl²´±±)⾄ '€ùs_ÄQ¹€< ia@zÎì¨J€ñ"NOO*ÈñÅY1¯ü‘Y¹¨OECCu¤_ ŽR£{¾ð$~Ê:5è&a„Ø– Ä€© ûƒv4|4Ä|Øð»zq¦F½ã™ù£ßÿŽVŠSçP¬NgIÜfuK–£GŠYÎëšJ³ |H¹ÆÆ‡1>1¢eq#£eÞ±ãG´Äíé§Ÿ´ùûp*ªTk øôc¿¤ËÔèaäE3²íÌÓÇ~N$ÉÓ`ìž|[,ÊÝ”·óÂÞâÐßzp3m|4ÀhØ; =V@¡4´­|‰Z1‡Âq)##ÃiÑ Îæ3±Ndê0›ÐpæK4‘q‹cª@y‡Cþ,ÇïñІ@L¡¯åcô 5‡ãœãA_¦ŽÜë¡Yoi7),ˆ& µ¹f2 úNGY,ðË¿ü§cmÈŠ;Y®cÇŽÞ÷noXú“Xöïz {¦N§ðߣÙÞÄ?û·¿Žé‘ØÑpÕP:Ù¬“É99fÈx^üwÑŒÆ=?(€¾[¨ö¿ú}¡)OÅv¿×UoÚ`X˜¢„,ô´º»åê½²ð€á•®<¶ut](€òŇ:ì³ÞŠž÷(ÍNˆ­V “1¶Åª·#¯·Î ½dõN¨ñYpZïð}ÿõŸÎãÂz嬃]Ææ×±4Œ™›†xâÌ-ïÚ5%à9„ ×U²„wå»·™»xzá¤ÆCSQeZ1Òü…Ÿùû¢Ó‹êäDŸ‰¬H:ë¦\ #[ ѼÛfÙ÷¹­¶Åxp¾F5îH㟉Ÿwe·ÅK4=≲mFwKЩÃL•ð¿üΜ]0tz‹vŸ33:IQSÌâ.ñ@UQ•A6=’ÑAL!Íq§ÇŠKMI9ïj9×XÉÁB¥#;¨ ¨Wjm³"þMaÇž…ÇgÓñ˜‘QwO ~)ÊCì6¥Ú<›ÏeåêÇ©½¨àõ^`ü¸,<Ö¡ÂÔ;o6ƒ3B¤D2˜ëB¹3mY(3~ܾš÷΃ҸøŒ>³ÓwŒ ßL!»ûcesKLhéÞX>‡/[q7®u<ìµ0‘µ°RmcrÈÃjµ‹ž€GþG6­ä6̆²†85-d,Úy6Ò„j:O3âõµE÷”äôJFò¶Îi’šåˆ<;˜+x˜*u¬¶ N «SÂB šs-ît$K:Ãòbh;>RàÑi>8¼·ÓÑÔ%CED­H¹¶X§¼°ìk+èæòÎÌhÆ«¯n¼Úñßæ{ãýÀv7ßësÉ `†~#c ×B0Ð"4Óy¡üQVýú-Ë…Ø?œÑìâÐ;"4pb Z~•M  lùŒ×Êh†¬˜lÊ3bi^™æ‘At[Vϱ£Ä¿µ³‘¨ln Ñ^¿²ŽCc®â”p8iÚÛ6< ¶W/„œ–8êèýÁƒ1ùÝv›ÓšÂî-­\__ÁVm.g’¥|¨ëc»ÕÀØØ,.^zU#¦EY /|i ý¯ý·Z•ô~ãpA¬•9+"[xž{RL3'¢·G´ŽÔßÁŒÛ/~¼t¼Òà{ñjÇ,ù €¼`æ=Àfì°šwƒ5ì×òQê‰#úÆõMæVNö(`þ£_ê£#¢y,=йåšj®f=šÈ248>Ô‹SÙ¨àùÏANtêǼð¾Võ¼ˆñ˜ôçôÝî¶Ã6ÌØ`Ê :k*ûuÕ¹w)™ê-ûyG3Á²´¬ÝfÏñ¦®Åâ._9'€ªi¡†ãz¸x1ÔôÔ1Ì/œ—ÏUd­‹gýÖ7.‹#¶Í›Niü1ªÅäÊEd²uѵz®øúü|%n)õ`Œ¦‰2.ÌNñ=Ž®dñ,5³ïFûÙa×¶n›pM+ª §´é‹ã·ïð—4dVÊ[Ó~'`_¨ûjÆ„ >æ• ñcf@ÞÏ1îóü^ ¼0ÀoìØÇC³1}àŸ¯^D®íâf÷a½º$'¾©c—–‰ÆMHe„1'fäýø³Õ;r‚]³c3%eYG u#¯Œj˜1°n—yQº x/]¤/¿÷½ï`£²®€fV„ñº›7/àÖÜÛ¬  ô¢Æùì2ÆñÖÂ6£Ã'å;¯£PÌé4¦9"ÝÄèX++×Q*{8°ÿlVW±°ÐÃÞ½{¤c—ä餌àpÛÍÍ*¶Ör.Ì Sv»Qo Ék¯ÿ@,„¥7[@‡šÍ‰ÆsGUåÔä†V$1Ek’/»(»99E9Q' ø˜ëË}V“g˜œ`=£i™÷ÍÀ$ °cð„,ðËo¤³Í¤¿+â]À†»˜;½ î´zƒÓx¿²÷98bvJ…<^üì‹Qµ4=ÚFC x’“¦N‹ :®™Áo~—,Ê‹Ãδ:©9>3=¤•*ïÉ댇¡Fý}úâ…_Å#c:ñ»Å.Ïõ±¶rÇŽN˾dµ Îu8ç^I Xw¹¼ÄybŽÈÍVÄóÂP&Ø¥¡RY–ç,Î7pîÌa_z÷ÃZðñýÒwb¶S):oò˜ÉaÿáÝr^öéІ¢l•ÛÙLF‹:Ш[R i!m<ögÐ Â0C.¢á§É£fX©ñ` Q| ¡ñæ²1<ìmçÎÁüö=2oÛAdź12»!ï§!dÉû9:·ÁvS;›K¹ˆrŒKÕíŠpL¼à·Î|GM ÆÂƒ¤5²ŽÍ¶äÊÁö,ËJÆ?']'Þ‹> w(€â£( .t兯¶®Ç£{ ³`ï© ®k»aªRÙÐ4³/^13soŸ½®;‘/ afv\X®­1ÉÝû¦Å§åx\Yæ YÑ¿b–E{)OÏ ³II/GE&-WÂxò&šåd`YrœÌûR¼Ÿ`žªaøÓàœa³³ìón0&ã‹‚xíÇk/^ûÛISÐçá•­%”Ú²“e9õ L&âE"CrÒÈ“ äšdRX¸Sÿ—ûêÝZ!ïÈŒqΚá+W/ë“£ã³ÚiB{7·+1Ni*S±çØÉ‚Ù³Ùœè;βà*[òX8Þ„æßvœØ+îkˆ)Š ꊀ=vÅ2tâ&W?ÑTp\i ¹{¥’7"ûÛ Œ·knƒ{ÜŒY0½ÃšhËDC>hØç½ÐÁ¾…;KQ'Îȯ‰™nl­ б’…ì—´1ázåÊÏÂçÌá’%™"KÚ)³£ã8ï鿟h¿NÜëãÌù×ñèãûdÉx’ѱaÙ+ˆ•ÌŸ­ÌÕî¼§ê§=ÊhlëL6ßêwÎÊ5v‡<ÏÈÈ[ë÷2ÓA|¾0&1Ætö6o{ûßæÆ!Œ³Þã»ì1Ýÿ¼ùCT·šxiì8^}í{*´y‘˜KÚð9ƒòä°åÉôôô ,-ÑŽïˆ!Â÷{©X¥BQnˆ‚ü¶;ÐZÜçF£Å |4#ã ØŒ;檵~|ÓôEçvÕ ÓŠ++«Ý:ŽL¨Lˆ.2Qît‚[÷bÆÄTSt1wÙ÷pjŒŽåCc':bA§Ï@²'z)Ì`¤<ŠÏ¿üùH›Ås»„Éô¼ÈdÇd^iNHÄ|6;‹½Óó¾.¥i FYG½Î;ôꃰ—š½dhn3øñGzŠãR¸mý\A\TËç¬ÅT°Å];èqß9héq±z©UÏΨãBIÅ.]©Mvšþ›÷bÆäh…ں딇÷¸ á6ÜÀ‡x?ïäcpœŸ=ˆõÍ%ß&–×;Ú€cG¨Ù#1™<ˆÎŠ6ç‰{_@ü1Ž…©Á:DÜ{ö6êÚ( ⨑hB†­ìXû²,ÍoÜ¿sa úáÄ£“®q5·V(±Ç¤€‹!³ÐßAÔjYÃW¶–½±Ó¯ßuÒrÄqråÑÉè{\¹ù•sñ¶û‘¦õ£ö~âQOp,Rsåݽiÿ Û®/ï~ß»+“~ ÀÜÁjñNì ÈþÏkßA³ÖÅŸÞý nÞ¸®µ],$%è’ùXèÀP#&!–bÑ‹~/ŽËh|L¤cuÎéx¼³ajóÏ„U’ÙW ¼õuΠRø±Dîò¥kZÌõüùËX]^S`.-®àùÏ|ÏœzBœ”nÒöñŽ!•/àè©éìF“í#Ô*lKÆ)-˜õÜœ˜WÎ4›=žQÐÙ¶§`¼{“%ý½Þ@óF]~ûš¸ÈpR¥¢U¾v3¸ohg;è‚X?bî´bÂC†;¹µâ¬œšx¹áF‡†ñÒç÷Äí‡;ƒ°MÒ@>aÊ÷ä¨|à.¦šTËŒágó½ïþGŽÔó†°¶¹…N·‡Ë¯h°zˆ|?ªÛ\˜_Ä©O?]3“X20}èÈØ®h±Ú’fi"ÓÙ‹˜2 ã ¼¥ßç€û”WÐjš`nò¨Ó;ï*T†¾–â%W…e(Íù9â:ÙlT=›lSY^«®™¡6'‚õλ‚ñ^€ wæýL¸¹C û‡'»òOÈÏ5VQ„‹s—^WVá<,Ô‰ ~s, ;Ïryæ™g?®¶z¿Ý8ÌxP–zg™Ù_yÿî÷¿‹T&…^—E¿›(‹w=„=û§0»{R.d_C;¶}Ž1éóÓGÕñâ…g±C7//7[²h%èl‘3d½í¥^÷f¶P/Ò¥ck1E»U7`mÕPKçP¯ÕµE [£¸Ùž8}K»¦°ûË_D*4Ù¶7hßMê™–›b´äLk·­ãƒ0$~¢ ¾ÓÑ ¬~gá-„õ>vç÷ýõäøc6OZ'ó¢Ñ™¡.JÚ'Íâ“–Ç? ÑhÅ…¶¼QÈÎóøÒWŸG©œÅœ0ËÔô8r:Öúip ~¨,a.GÌ&Ó†ž“U¶²¼Žbac£ãïº_·»’…Q$B—t£r Û5\ÝŠNÿ;w}^ƒôkkëZ…~ýÖ<>·?ÎÍcå¹gqîíÓ²®fnŠù4Œ¯¼Œ²l«×ÚÔò°HrÜv„¨ˆ¢AtF'¼1Œˆ²[y00îÈû1âNÓÁ;KÐ>@^4´JçWö? ³¹¥3e ׄ?ub2“ÇS/ÒtÓq!(9Ö˜ÓøÒ”sØ'Ã=? wš1Рjßœ~¯­ÍÞ¯ìuôðItÙ/´uVÔ”—A6WºqÎû§ï¯œF¹Ô0NDTY,rz’“6Åôg³ž:;d_jKS,ÈÕ+×T\¿v7oÞÂñ£Ç1ýÜ œ@nŽ[‹h4£á¯##eÑÝ#Øuø z³BGÿ¬ æÎEgD{šÛ.5õg»-`.š•<„ÄØˆS”/8 ÑÙïñ¬Û²1w³bðŽùa˜iClÇBe76Vðdy/Þxã»qÌ+ˆÙ'š~ƒ•È~ICy»Éœtp’é2ÞK æýÆÉŒl*Á¬I‹!'†?„…ÖÖWðÆ+óøöw¾£á¦sçÎâ˜Ü$ÿéò7ÊÙÛ̧?Ûˆ6|üÉãȦ hwkƒ±;ì.ÆâÞ¹[s õ؇ÙÑlÕ·ðü‹Ïh•=u *~Pï^nŒ,Šw]\ö³ôuy/vš4½t“ò~ÒÆS½Ñ²;„FŸCWÞ w ûìôþNÀÜ1#öAA‘w%úµE-ö»)àÄÉú=édRÒ.$i¢Ä……?FØ÷}kF›S÷ÆCm·:xÖ«·0·xgÏoâà¡ý˜œšÀ‹Ÿ{NØn–+ŽA»:ƒqͦ©óõÕ nÈñÏ/Ì ˆËxóÍ·”ýxì´ä‹/¾€g;¨%=zâãøgaE[PkvÚì´6åžÕÊCc;_*Mëù:-›Æ“ÐSܰ*:Ï–J :L™nM1Ûˆ#tŒo]ï#u†‡Ñ't í÷a—ŒïúàÞ@ŽJ¶þü‘—´¯>ïà៘_üþÍ4ÇÁd˜òó)èÛ˜>ŠG|_ù)qšâˆä ¶¥¦¼ysû÷îBPÛ2·u )¦´©Ù¥Ñ±¹ ÓÚ“|t|,ê•(º’¦¶S_¥Ö °²´*útAS¦t <„/~鋸Ýõ6ˆ£²Ú¦§ýа-+¤‚ ²-ŸKÊåîȱyY2èh¹’ö`—›ƒó‚sâõbÞÌæGíÂV%º”öqüw ù÷ñ¼?p†L[.~’KäM¿O67£¾AÔöQoÃVªñßühm anì ˆÙ‡á¯Šj8ŽÍ´ÆòdŸ½;#R$šú—ï±àöÚ•8î¼Êóç/ ¶YÉ'pôØQí\K<¸ÙLVœ¦IÙn[‡òrÌ8CBlp07· fúð¡#:ëÃNp`¬²ÕiÊMÛ23Óëµ4pÆ#.ÍÐÐ0PÆJ#°Zb’/a5m¤26F¶â©ì“ü{°à½œœä¹?ZïÍ© ßî'•z ÍhêlF\—¥y[7­ ÇñÏO>ùe¬8c,úàï4ZÕAë3îø`«Wí`yáΞyUµo’ÓoÆÔÔ$†ÊCÈä2Ȥ3xé¥Ï¢,ã•ìbkÄMHÙ)£Ýäì¯+øã÷-LNN hë:\áâ¥KZŠÆ Õ‘ÃGhòÙnS³*\‡ÏåQÛ¤h›å¨šÅ2¢yµ9„—Z•m58»WKËK8~xÒrœj£oÏrqù ñ'€ìÜ);¡(¡2ë½dj>:P|ÿzÏ:#¢GfCò© üòÏÿÇÂX \¹z%ž”ÈÁ¿ú—ßÀO1ŽÉéQíØvø‘deÛ]ÝâÚ¹p:)&n·BÑÌfe¬AÓyÓ 04ZÀ¹³‘~ÍåÊò™²Ý.¯Œ o†n.Të+É¥ýqÁx7Cv߃§Òx Ôa¸S”ñO‹ïw°)ãza2»‘~ÐÆ×~ÿÃëߦ–»…f£¡¡¦B±ˆáò¨‚QÍ2| DE ñ,YNÔw’ý»Ù¬\ÆòÒŠ€mUc†tr´ÇãÞݪW™J<þÈa|nâ9ä‹Y‹pl×´ìÏ”NGLë÷ëê;7k-­ðf°Æ2<˜Ž©žw”Ya[“¨™*»;ñ¼3{¾´ÖÇÅÅNpùêÞö…+õ…Ó—6®^¿´²¼´¸ñv¥ùW{•Õå þíç›Éý Û›Ü Èá;ýím3Ù!ð0 '~¿˜ÈÂGÕçI°ƒ¡Â(~ö«OŠy-Ãã¬bbYTËŸYÛXÔ ê¼B¾ 9ã¤m1gLøÖ7ÿ6€b‘ðSOÄmHMYÀV óU‡ñ¸®l­øMt‹ÿq›Ž¬)ÑàÉdí :Ί͸;/#ëÕs˾Ü@½Þëg6–O_Z[¼viscñÖÍKµÆ¥Kýêò:úg.‰;­e‰\[±%ín?‰ö|UîÅ÷ç{2Ù-3ý~30‘©P0Ñ4¶éá¹§¿ŠÚÖ&Þzó´6†ŸžÞ…?þãoéü‡?ü᫘»uKã¡ëoÿ-¤SvsìA,$>ýÜÚw§ÿÿ³we=ndUøÔ⥗t–Î$³ef@€àm@H yàðÈ™ŸÂŸ… bØÄ3“!¡ïíÝe—ËvÙU.×r/çÜ[înœò’¥— )©dw¤¸Ýu?s¾³|‡˜«BZŠh9!ŸEC‘V¶I°@¸VUÄui%-¾Í»(qœG)EÊ„ qü®èåÁpèZ j‚nÐ;(™ÂmÔ¨WŠ–+VwÑÓ6pÓ‰Ï>%à/ÜÁ¹×Φ øE?EKÇפ|^(†| £ù'w&Á8#5øôï¿Ç5E—$–I3ˆôïýìç?EPýîÞ»ƒ'8„ŽÕÃ÷Ĉ¨wGpMªP=DÆt)UŽ%ךREߣ*âQÙÑCÝB)]öCz‘R[³Ã tá—ÿ±zùüxX9f%77ZþÀ° üº¬nÃÙT@¸âŽÞGçîÓN¿ ãaçH ¬©a/Ö².¼¹âUØÅ¯Àµab•…vú (|ðÎ÷á£_Ý3;™lJÌ«è^‰½ÊÆUj¢˜"Ù‹T‰h÷ÂG•F«*,~¦äøÂtô»x×èH*ÐEG9qÐÒõÈŸxþa Wr&ù£v³Ü:É ºfÏ7k]ÐþQÈp–.Z0–ðšt?Ã%.R-°ìU‹ÀÔ¯= _b"@WåÐh*‹¥ÉºÝ½ý¾Î<ŒÐ5’úYÜ KÀ‹ç°³J´¬\Ñ¡¨ÊiÎSdBºW¡ìÅIðãICÇàPiúa¾2õrO†Ö“\«TkwÃZ¯ïM àÿªCز©PwÎÚ¡_iÑ6Ú:Þe“*5«bÈe±ä@^=.åî@U”Ð~‰ÉŸ­‹Bö(ãs¡óŽŒåÈÒQ —º·§#J,ƒ­«sÐ͹#䤵ƒj+d¥¢ç=9ìwOzÕF½oXÍNÛu à?m‚O–nân¹µ‹VX8¾ð~SЉkçã¿p}€=€§ûí_ÃE‚q 7aHä¥Ùf5*’ÂêR×ƯtÜà`Ùüø»rÙNÒ5Å#ã‘»H9I¡l„·7ÇOãH:îo{r8é; #Á6×ÔžM‚ŽÜ+m‘E´¡•Ã`Ä¡Õc/yÓ§9«sTÕüÐì´O ®“+¤5€(‡§lºç\l´âupÑ‚uc U5¾$U÷Ìñ¨û9C–Ÿ~Bk,Xá1.)Ägk’á|EÕæ@¾²¯Å¥>£r±ÚÍÃ[W<ØÍȱÐ3(å<¨)cƲÐ1-y!„|[€Îž ÝPÜÔMU ²z:â «°•ŠànŠÁîM/¥Ht™Zø–>ÒÒªœ&‰DˆîÙÅàÆ²94ÐÚ”ÜÉan4ÈÙƒJŨ´ÍZÁ± ƒ›&D‘LtÝ â9¶¡¥ƒ„W¾¶vë¡Ø"šyw 36 !}Ù}oóÚË’Qæ €Ü4Ž” [9“«ÚœjÏÅç™Ø‚\¬÷õðhù%Þ!mÈ¢<ŸÁƒ}ZЉæ¨b\ÛG‹4šÑª †ñÁŠtˆ4Ÿ—FÑm° ‹`7Á½,Cðј":TTÑj‹¸Çd‚*0¤SC½3üÜîCµñâ‰çæ ŽstãAwva¹lùU’­fØJ¼n”‰ÆÔé4%¶#ËO§V.TÄš j:€S¡" 4ŒˆÞ3¡èàErö—šA i3èRúÌQ;ilqع)—Ò”xäl¬Gˆê2m vâ£ý1@Ó`PªÍüÃÒd”?œŒŠGÝj­×ÈÙƒ^‹ÙÝðƒ:°öc ä!Üе®klNt­Ú·?ãQù lýŽÃý-ZÆ >S…v³Dp%×Ul;Hj/KJ -S Å2H_…¿}Ñ¥á>ı« kOwÒè0šÁ XÐ'¹ã@ì„¡ñL²n´‹:£“… áí­nm“•ÃX.%w¶cZ–êæ!ªÏKbய@$«åFûÝk¾fVÑÎuF†ÑòýB‚Ï«Vìs@ À–:¾$]Â×€-9ž»óˆȲ74˜P²ñÃÒ{­ö;_ÕêEK¸ª¶!·í)z T³" Ì é½‚N®P›r ‘žÓy§´vñ¿ìgØ»Á ¹Ö­´”LZÓè¤.Ü4;• ti¡H*üdiœ©zù“€ÁqÉîžƃFì™ÃúqàË0.÷£{ykR%›¸Öç]êâa/þÛ:°>¾§©»»i©Á7 àu¸®r̲1†¤&] ÇR3Jì6S·ß‚±ç7º"õ²¥Máíínf#ØË‚\&î&ͦ\’sQ¼¯™Üx*v¯Ôñ"7k!{E÷Úîp8iQ®è9¹¼c«VµÚ6JÝV¯å›íDÿ>ðË.ž¶¿Æµ.‚Ž%„$,!Û°ÜÒíý^þ|;%Z\ø]V…oÊuÕK‰’št“,b);¥í¿g€ã©°—Ñ´yK50®ûPÄr¤aȘåq‚YÃë\°WR–¥¸Ò¡qÝ+Z;d°“£²mÊC£^´M£ÓÊMÝR¦‚ÚxÎ^SöŠ6¬B,ݳžaA‡NE q TwªïÃ7ùº²9["€)Y—˜È·î`Üãkè 9Ô­lmM!³'»M²sK§Ò8¤$F—S‹/V¼i1Ãf¡fz-³æõz+U€Çhñ*“%.|±Ž<üð”þÈ5dcaÿä›xÛøG ø½®Ëº¶E@²0жë(qn Ýð[Y7v¶!“ý!ŒÇ!4M*…1(T=ï¸2îç “nõÀêtºÝâdZËìÑ¿ÞþÔ>ñÏ‘‡è¥J–2WõÖ#Îdûº¬åÙø>£Ã›ëz‚qôÞ;w¸šÚ ½PØQ‡\•ru;>r†Ç…z3_1 fËj;¦ÕbAµ ÊWU¾Á‹øá¹ã9º²9ìk¢Ö ü5»({ä^Ã7H{ÍÀ, ,£kw>ùdüg·ß;2íN»å&¸Å„_ ƒ¥%jÏnÓXnYçPr óÞ#.Üé8¹9@V¯íhu(ÑÉÞ ê%.e.Ãvݾ×<7 g»iæ º‹‚¤«J^ËĺFßå9»7×…]ÿ`ðÇϾaÿ©uIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-dl-1.4.1.png000066400000000000000000000252141226750426600174100ustar00rootroot00000000000000‰PNG  IHDRŒš{O ¸bKGDÿÿÿ ½§“ pHYs  šœtIMEÖ -me IDATxÚí}yœTÕï÷woU7Ý44½A7;( ¸‚&$J2£cü$³«ïMŒIÞ3Î{™Œ“e3™,“(Y\Þ·˜‰/Fã¨1ã†,¢¨ ‚Š”EY”†fkènz©îªº÷üæºË9çž[] TC>E×r—sïùÞßïû[Îï¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥Vj¥VjƒÐ¨HÎmùŸ¿ôë+¿ºaçë—T”W€™AÒf õs¾Æ`ï$TÐï9v\LÇðÏãŸ+ßyˆˆåÏY'ÃÕUõíÍúü7¿ÿ©kº‹0‰c Û‹íõÅBœO>C `+ÿF[°" –ÿW‚¾½}ùsÜyL`ñ‹ö• •N¥¯pBPÊ”{¯d¦7céÍÄ{·/¸ê6òçÜ_Š•*æ}Âÿã¶|&ÌAŸLÇ÷Uûn¼í;&àN!DѨ¤c ,ª¼WE¦7]2Œ7IƒAÑŸÙÿ”o”ÝÙ â8øcE!ÇêoPµþIû…9‡-’º)ýK£ÈÉ­®öCö‰’S @-€‘™ÞLµ• e@À"R”CŽß„G#Hû£ÀžÂ P1Dj@(.¼c‘DÒ tÆ*ÀH9åøŠ¦‚¤ïØß>÷_:“.FÌp5ƨÍöeG J ÀáSé© ÁölzJ=IÀÈ”)Õ²j ¡U—:n}аt~yCåÃóPOWÊ2É0–˜aFx¦!›u*C›Iz€ýñžxб·LF~”A‚pó‘$¢ïg’D ƒJd 0¢'öÔYtL­Ù¢$½>©f!Êõ¢¸)À^§~¦cršBúTç,X'`|Ð$$=+©‚'"V IO4˪ˆ$²™Ûˆ5S5¨8bjËGóáx.Eí°N¤%Ó9°ì(¢îô¾‘¦ÎrL9‘êd’„1¨'+pàQn€È eÔ÷¬ééIeëé+âPWÉ+ÅàˆµÆüüÇÁçL¤12I#ÿ–,u¨$aú•þcû"j‰mfLlÐQÜO8¦ÆóÄô1ý%P™Ž¡{ˆJ&v¼¬|D$Ïw4Hö 0Äþ}!×@ÅÇk¬b s?7Šú¹±¤½`ø­Aîo ú{¾sS`—S€eARï(Vô†®øéšèÍ&Í¡§’µcYQvµâ§k¢}‘û`ê+"Ì +þmMxÒö7³¹¢kе>¾#Í­ ŽîëokIW¬„´s*åüãFöa3áŠ\Wžk.B)StFõ¿²YŒÁ¤nsÚø30¥~*Þ=°v­WŽúïAÜ÷§?3þ¸p ë͸¨ˆHoñJ˜ÚÌq§ãOÿ8Ïþàe|ýo¾|ÿÕþ=æ]zfM>ó.½ Wν 0ÿ;KQWÕ€s§ÌÁŠŸ¬Å¹Sæ ®ª þù¹œJûÉZ|yîUXrí‹XôÝeøø™—(ç‹;®¿ïŠŸ¬ÅãßzçOÿhžþ л_dj)QŒ@Èû€Åo<‰Kf}6Øäò9WàÿüþJìlkƄډø«þˆûWüïìÙ„ñuð?>tî_q.Ÿs|å>lÛ·%˜žt7>}ËÇ0kÒ9øÑg®Ç’õ ÕãÞs%vT æ^7 ÂÙ“ÏÁ>õS¬|çEµ³?;0³žŠ“÷1‡ÉCx½÷“¦`ѺùH»}XøÆÁoe‰$:û:ºÒ]HÚe›÷lÂùÓ>Šñµñ»ew`Rýdœ7í#ØÖº58íc¯ÿ'UÛ^FÍðZåœe‰$:{£ÇýÂþ'ýæSxáǯãö/ߦQc£ý[ûDÿ×±êros 0î•Ëìh}Ÿ8óS(K”ã“g:øyù¦ç0ï²›pùœ+ðóËnƲKïìÝ„Ëæ|‹ÖÍcѺù¸lα}ÿ–AP<ωwSî¸ÿpÑ·ð«…?ÃE¿:ßÿÓ7s~6ŠéÎSLÿ:;dñä†E×áï>|%žúîr4Žlsã¢ë°lÓRŒ­g7<]ðöÞM ‹ÖÍ,^¿YØÞº5ÖGBiÇ}ã´ã>øò½¸þ 7bþ·—bzÓ©Á¾7, û×T3N9&i×F”Ï*¢¢žcÁª4à$SŒûµ¹¤Ç·M*O”çyZz3G<åA>¯ŸT$¤°Ÿ¤ð½—Z W,ñ "ŠIƒÔ Þ‡Ý#-ö¤æðšöU#’å]tÖÍbݺ¶ñ™Sgßûãß6£òaŠWÂx7),HYvÆè¯´-K铬¤RJaF%÷ÄGá%àøÿ|°…QtRúÊC – P¶õAÃA„š´nJ*B+ÉóÄî™ð]ÎYÓý$íÉÓÔöñ·2nÕß)Ú/6H“ŒV@®Gr¿„r2܃tQBÞ4’„Ñž.Õá¥'Îr0%ǾÚÊåì‘!;ÎÿŽbü#ìo²‡ÕþÅ}¯¹ ˆKºt‹\kqzbE‰9a*ž"âgäS(5¼Ïr*%‘Ìw¼TÏØ”~ú%bkI3êH%W%À ܧÈF‹‰ÙÌv¶íÀ¦ÝoáÓg𙳿€ -ë±³­_9ÿj,ys6ì~O½¹ŸuY°ßæ=qáMsภ#ÕŽ »ßÄ]ËnUŽù¾„zðj\¿àGø§¯ÆßÍùrð[OºŸ¹ýc¸þÉâó‰s¼ V,0ŽX^%ÀäÇ …<@Ï ‘]´¾•a~xõ^|qÎWQQV‰/~è+xàÕ?ÊÃÐX=ÓÆÌÀ¸šñXºñ©`ŸgÞZ Á ÆÕ÷} «¶¯Äì‰À]WÞ«;Bèêõ‚^{ì/#íôaÕö—QSY[8o“ÿ’ÊçJ¤·ÐÛHñZ i‘lY­½Õ²û:÷àæËï@Kû.lÜý`áºÇqÒèiX¹õôeû”}\‰ÿ\4ó〃=­¨©ž ` €±s¿>÷ÂÌÄö‰IJ(“¿Xó¤²Vn¢>‹þg:JˆåÍe,"·Ã¶l¸ÂQö3ñÝzË«÷É‚m%à G9'y9ÅÌÚÃàÒ…‹áeuíM©é³ïÿÑÝ;P >ögrBJi€æNÏ ¾èGÈ^X߯ÁÁ~êIB3ËãðÀì¯kF˜‹ä¤˜4Ž’ãnec¬L1}é{Tý`›A‘ÄÑczÇpàäÆÖ"XíPFd”Ô 8J´Nž¯ó–‘8“gšl(5Lµê®Aád–t¬Õ–òç?Ës¼±7bŠHKÙéÈ1ÜF¾^.BÓzèJÓÃLRI(2ŠxS+…Ãbc3©™’$Y3:€}Ç£œÉÇZŠû\RIB~nû=CM¦A´.GPéI;–ø3‡YNL^O‰$ [)×›)B=÷%À†O×ryÕÈÓɹTÒÙ”s¹pÀBD ÎX¾EÄ ‚å½÷R³Ä‚sé6r¨Ç˜„:õ7Fšä»æ` J¿Eu¢è ±¥W–Mj AI03\ö nî\YHPY7˜Þ¾×7ÎåC¬–!ó9ŠÅ¹z‚ °„ê0AgwQTµ+vÀHõnI«¥ßTý7ޱƒe9Â1¤@0\á¡IíjæµE,²à°k ùÇuáz $AAŽ ȼ®~I²­‹‘DZJ¢¼ObR'ÞÃG€eжþ¹r„™ÃRªÐÐP(pW܀ɑN=-@¹±Rð…”¨ÓQè ó dï“D™$°0aˆà¥ yÓI|0°í÷^rùUÅB¦£Ýå<)ÔOåµÀ\g…‡×â]'k×èÿ&DiÖ@üÀ¸Zi]Žfˆôifm>À+JX $ídS*X>hÛûÇS}7!ç)K”«³ ô^*ó•œíͦ‡’J"øÞ}וW×Ô Ë*'">ñÜÕvÈÞ¾þíª=ÛwÕ´ï;ØÐÕÑ9ÊIgFfú2•eeIGõ¡!]K³Ã€0U&˜aDd¬[çÇžÊì$á@@ Èayf£ïŽñ-)-¬ ÀÈŠ,‚m„—®!Ìw8wMA¬ÌÎÂMŒ2qêõOüƆ²b°²ñ’åe¹ÛÉ×^|uËáFŵΞñ^Ûúíë|ïâd¢Üño`\4ˆô‚A˜ ÔM.§:KDc-á²XÔ•=h'²¶¢ lƒ‰á‘¼­‘ôF䙦RÕݰ/9¥"ØEŸ› úË}LÝ&u¶‚rosÄV-Õ!à‚½5”ÝbÎE¹è;»ÁµÙd#+zF¾—^ólónÛõæ ÑÃJZ­XÁ.%(Ù`‘H-€„ÿzð'¿ßuÉ·?÷ð¡¾Ö‹{³=U¶@d╞mH†ßuÿ‚ö°Ø– 6²ËYO⨓ÕÔ“B! ÎM œjÁàBžCÍÚD2¿@4Å(Yy ‚~u}Ãs’¢ñÕµM¢ýÎÅÐÕ’Ó.öv¾7ÌfÒâ_ý+ÕbÎIÜ™ãæÜ_¨×Çο:w%€ªžC]Ã×>½ºõƒ^È=VÛ‡ˆÛJ‚ò|¶eƒ¾·È†E–ò‘Û²¼¿¹ímË‚E¹÷Dæò—Ìz"5¡ß²˜d^a‚òÖ;¥Àê"í4©(aHs"°PŒðÖÿš¯ƒ9ôåî“+¸þ=ö^Áý´½}ô1°ƒÜ‹,bŒ©<¤Ä1«AHë}`µ$ûz<¿PðÏÔy­#Ä÷Ó¿60ã®ÍÿM¾¯&¿¼T ØÏ¦Èý%»°í&YgÝõ‡kó€lŽ–÷¯’ú³+}iSá§@ã¶76—u¿F++ËFæÜàLy/Pù^å3¢ ‘¿S¼¢Ò¾úñ‚ùùÒï,#˜ià)¥¢ÞeV%“êÀ3\—ßçàáÉ×O8¦û§í§P2lÃè=¶ìa`4ÑŒ7—ܶø?ÃÃÚ„'¦„$üejj^~bykbGíVlÈõåžV·ãœ¾F«…ó¥PJ¿‹œóKo°…t…´þ1 ÑkÊM¢cÿ¯÷Þõþ"æØÆó Rû®ši9U#ú3ÿ{ß]‘E]r|G󲽿Üß²»œeå"×Ui}2Þw¶O†W=ôò{Õ©q‡‘U.Ù7¹ÃâJáKޱøŸ¥ß `Q3ÝLý8ès.‚lÁ†Åvô©Qy>3ãqåk €-$ðΑ;O ”YeHR2rMÌy˜ó?%ÊBrd¾GJ?õ{‡\àuXb$¬wGþaÕÓ/lñÆ×‘„Âa“^™ºûëù$x˜ÿ7Ý×g§÷:ÝfOhJ‰NË&[‰¶ÊJ9\ÆR×V„o~†«±a5#U[“¦bÂ8²9›,#êÇE uîS¾í=O³MvèØCȉÔ7å¹Å^þtŸ¼¤ eý'ùZÂu+åÛÌ‘ÞËF‹-4¦Nyé‰[þô;mº“˜) èçå¼Ç.ÆZ§¾»ä7 oÐî¥w „7ŸãÎÔYï ¾™=ÌË0ïs€½jÁ‹Í4|l¸5¹gœ®s1•¼`uC– &©ÅI Hþùåç9±Â²0³—%|ï?DÖÉ <9L‘êáò-`Bç‘k÷rˆv"<k â¸Ì&x8uÅ—â®È¢Öß¹éñwnìê8´@‡'2…šÓ…XI>ÉH8à €V賂´U~yë¨Þ Ý®p–7¢'3‰ð)ff°‰ÍÞŽÝX¼îIüüÉŸàÒÛÿvŒy`›~þœËqJÓLÜ¿òž¥ ¥>53OËÛï|‚Oã$,$þ×Ï5øû9nÃíjî^ãþvóëë7zÒ¥ÛÓ8ó¿à£ë¼Ç;™,iÊ|Õ”êî±Ö=üæ†3®švN»³'‘ ²8bÿ¿»ôŽOÆþvÄ`ñZme®¾àhiß…^¾_ûëžn_=ñ«+\zû'Íô‰û†dÎþÊÎKÛ°­$F¿dþ£ÿõœôXê‡ñU“ãI’n4­ö{§Ã“@é–íÍWöm­°F²+¥2¶…™×ƒ××\üϨ6·=}²nVóŽŠÜ âð’´¹Ÿk0ZoSÛ>—S좧nyåá÷8ài‰”¤Š|V]òMì8ÕtÈGíêÅ+w¹›+w‚ BˆèEbõs?ïcŸºÂ—I3%€Îžt.>vú'ðÊ–Xù΋†.ÅM.£ÃK!÷óŠÙÞq³¨6.õÞÒwîoÙÓ,ñ–¾ò–FVM:ŸÙ¯ñ™^ÎêÇ_Ý^u¨±Ýeyƒ'ùnÇÜØ|)Ì‹2}Ë„•Àwÿö_‘u³¸õé› fy¾U@ùȤ)®uDÃí‘.o©ºoÝŠÕk¥ñIKÎX>š€aIÒ¤%Õt@O¦úúR©ô¦o¿S“lÌ:"‹üËw^÷>&J,û#ø0$€+Îû &ÖOÆC¯ü»Ú› .2Â-6y;ö!ˆ‹¸K×+¿â´ fΩû HXITuŒ{fñï{Ü{°ý‡ù°UÑáH˜||¦Uב-[›;ÛVf¶WX#ÙÙþÕJldVÞ6Æ‘&Õ襸›.y}õó6‹/Ͻ û;÷á/ý£$(x¦’wLê”ÈÃÉ” @gHÝ0ôE¸.jÝÉ›—þvñï¤1é ° 0q¦v›šƒ:>óÔŠöŽQ» V®`¡@á’@hf¥NÙ`~r®nŒå;¨Qby ¿óñAyrîxæßÑçô¤i¨©B‘â6dæ^áu¬†;’ë›ÐN54¶ã…ÛnëKõî•Àâ›ÐGÜ7 \H éÐT“Âg^þÓ‹[êÉ=B¸áÜ丅Ë9F qè—‰LùI”‚Ž,¼Y¦à%«±¿šq!><í#Xóîj<¿ñ™y,óñ"³DÔ®A™ºÒ/¡ÏOtÇAe²™-É{Þ^óæoóp#ó™>Á>hZu>Ó›J¥×<ôÆ[ÕV£ã Çü”pa¦d<_ EÊ@‰*[^C¸­/…Xßüĵp„ƒ[–ÜåB±¨áx`ðæ§òE¢b‡Eô%é"„‹¤•@}ïÔçW>±l©öЊ*ˆã.ŸñAÓ%Å›äÐA€Ý²½¹³æùºÍµ ?=ãô¶f ¡;ñ¢‹‘Äßž6–²rBõ—»â%L³:ñ$çòsŒߌR¼ãŽ4u¥ä6äÈ×—ï%Kž¬“A}Ù„C›ŸÚvWº·o¯Ùõ?híH§Ê²Ï”™¤ ëÕÇWn»àÿ^0r?mI–¥íLSQ嵑4Õ¤WØdmm.?ú,Âi þ*&ðKÒcîÏ‘4¹¼¾²â§krRåºY¤Ïó¦¼ü#"`¤Qü0¦œ×«Ï%gI$13'ƒÃê…x¯âoñ£Ð}‡':ÚF—4r¼ÉèŸééêî[õàê #1½Ž›Vt:åÉsQòÞü ¤ ¥\ O HÓd À ÿÊ|*öïºÀ)V”>šªÈo6Žn’Dõ§ß&=@%»;:Å0gdïÈ“‡Îº}dS"BøŒÂ`žC$?¤Ïîàü³ #Õ F²©/yNF#ƒ ;œEZ12O Ñó©Å“rù-£Ý©kŸ½û™[2éô^èú©–Þ‡ŠxG 0¦’.–šÀÜnݵ7=yì)¶¨MbA>pœu ß`Ö¸ ŦƒÁ}o8¶^ñJc½ºÙ®Îˆ€4ò\Ópæ„#2S1¥ã­Ç6ÎÛ¿kÏ»/ì;Ú¼åý’0¦U±üŠIéeïÙÚÒ=ãô3ªSvG…E6‚j1R ˜ [$Ú8‡dZõmÓ]õ)§ë˜5“ZŠ~“*-8v ©Ú…C´NeEZÕ¯ãŠ,F”×9½oÑ­o¼øÚ*ϘMè÷mE®£ SFª®šÊ$\ǵzöõõL5ut·ÓaÛVBâ,lÙDªÃâÉŸ²ª’Zy³ÏA¨Ÿfd‰c,bÈšdœø®¬–—>js]@ì i—¡¶sÒ“Kîÿ°–£æú?ÖFWO:Ÿñ¥M¢ûP§ŽšLõ”áõi‘"›Á€«Z‚±HÝÊÒœb¦7®Ádˆé„~"d‡ËÜkªI›üN’Ò’\éL±Ð H8³À„òS·.¾sþ N6»W²ŠÞ’{,ƒ>“ÐÔ“½¯ywßø¦“-ªuj„p½º&f_+§(>Rì[?~Ž Å[´ñÖnHtMnz…É0I¤œ"üÉT™†4Gµ€+Ô”Ý󿣮kݽw;Â|££îo)À 4 ŸÙ¹qGçŒÓάî+무,þEVTŒäVçH솣êˆUARˆ!¤j­]?I*®@‘$2¤YJ>;n#Êk3‡^ÏÜòÖ+kþ‚0{®ïýæ-Ç0…ð™4»»º¦}pú˜îl»mSÂlöB_÷ˆÔ¸‚Î5úIÈ[Íþô]YvT˜5)"ƒ‚Õ ?CQ¸Fð»ëʼnFuŽì¹?.ÅäRÇ‚· ÀęۖÉ?“êîádzx﨓ªÇdœ^²,Ûè—QøL¸zV8j¥Üüg™ãu“á7ÒT–É|Þ+Ž> *f²DVÈu®ôüžúúÓ¿[t»Ä[ºo9–€1ñÒTS@¢µe_º©v¨Î©$‚ƒR-Cõ²wÕ ÿÅ6´/Ú IDATÌF0å!8‘ŠäPJ‚…ÉYê¢åñ!]CçŠ8:"‹Ñ“ömyzûÍ{vìÚV ¼¥MÊÈ|&ˆl·¼³³kúigV¥Ë '¹”ˆ^ˆRstèü&"-ŒNžþªy‡ûeÆt‰G1õþLN`t³nÕåµé¶U©Ö­X]4¼åX†bT“%I˜Àܵ»«ç¤ÙÓGwgÛ6%"ñÕRTÑ`¥ þ‘F&Š€Oæ4:0ŒÒÆPrÖu$å\u`ôCËyf‘äo9æ¼åX1TÂ2ùgRÝ=¢5ÙêI#êÓn/Yd+~ Á ÅI“Ãv,eÁÏ8Sêâ_r¹Õs›«Ý ¦¬^xçcw —R4¼¥X“—Éœf_óºÉdÕ¹5‚]o9=‰Ø’J&ó‚ÂÀG$]ôÚeI#›Ý¦róºrÜ,êËÇï|í¡×æõtvï‚vPD­˜CÿLÀgönoéžvêiU}‰Îá~¥´h¡5‚ X£Èø=å™yc=Å ¥UáôH´+²1¬V\ÕóË­ë6½…0¨Ø‹£”—;”C1$8¤BX‡Z:»Nž5£!åJÊE¥ãÌç¨ÓýÈ´ ¤Y>pêAE-Ò.¥¼C2»µ©‰<ÿð’ùo9jy¹C0&ˉb@“èíI±Õ“ì­;¥¶1 ý3Á@Éjô0—Tð8nE4c«œ¤Žc2ÃÕ÷9£¼&=~ù‚;•yˠ̓>žgn롃DÛ¾™±µ“õn-äÕBä¯Dý¸m)vq ceo_½ä‘ùoLË:4 ›¸kÍ£knì>Ô¹a2TÑñ–bL>>㿬–­;»Ï8cve§ÕV•[àÊðds!‘!!ÎóZJ)y²n5•£î737oZ½nm±ó–b àÔKH2³ÝÑr¨gÊi'צ¸³ÌòÖ;(üS¼qß¿ë®CŠÌÇõú'ØÍñ–Þ‰óŸùÏ'õxË¡bæ-Å ˜BøŒo5%RÝ=Œn»§þ了´èµ-Jä?i4Xb·` †+f».Ä”æßþç[‡ o)vÀÀ ’õü™€D{ëA§nd—7Úu®ëÀÒ–ã1ƒ _Z¦)Aà ÖC*P9n å“v¾|ÿK¿èKõ¶ Þ2T£Ë=²ËÞÖÒ}ÚY³FöÚ•J¾’JgηUC:aŽ›J&O%1Œ «q1ÁYÔTŽv­ï½iËúMë‡o €!Ä'‘+V€DëöÖCÓΚQŸe¡”Q£Ãû]òª Cþ3ú[“À’v9*Öß·ì¿–,j¼e(Ƥš(4vº·¢“º¦v{m•ëÓ Hýžò¬:Myü,þg"3Ÿñ~g! „‹Ñ<é¥ÅwÏÿ-39Þ2”cŽÑ©×q Í­Þè$ÇX ‚míÈ~„›6 9áTƒ)nNÑʺ4VLnÞ°dãÿkÛ`ÇPä-C 0&&ö¾æ=½Ó¦Ï¬H—÷Œ ¢ ÿy—¾!DVUÌžB‹EGçù:®ƒQÃz®é¼yÃê7Þª¼e¨† M€3Û›vÍ8{fC·Óž´í¤®'BKG^m6R•ò˜æR=]2Î@p]ev9†·×ýñ…Ç—.ʼe(ª$“©m$Áé¾4!•è©?©¾¡ÏIÙŠ'˜)j:˦¶.ªFRz¡ ©gB0»[>mõ“w>r'Âê¢GT翘#WQ&S;Ѷÿ€S;¼Ñ66Ùà¸Ù`’ØBŒ0 ¢hú'âg Hß;"‹Ñå¶½òàÊy©îžäò[†,oÊ€1©&“SÏÞónKjÆÌÓ‡÷%º«–!X˜…XÖ1ÇÊ:TWÖõìzqÏ/v¼½}³Ç[º†2oÊ€1=ïr>°’tµçíÝ3ΙÙÐív”Ù– ô3—úH›+\$ì2T´ÖÜóê’—ž?^xËPWI&>cTMN6kQ*ÙÓxZãØÞt7”ü™Áî 0†M{uÁo½ aœhÈó–ã0â3Mµ“Üd=Õ9®ò™AnY7ƒÆªÉï­ylÍ/µµËù-G´>Q 0ïŸ TÓÎwÞëž2yz2SÑ]mYöa¥gæ‹“ƨòºÎæå-×o{ëíMˆûáãAº uÀèñ&9éJç3‰;Z»¦Ÿ=³®Çí(÷ëÏ FsÜ,ÊË*ØWý»×žYñ"Ôe€Ž Þr<©¤‚ùL6“!+•H5žÒØÐ›í¶ƒÏáDkO]¶øîÇïšßRTó‰J€éŸÏDó÷Ì6ÖŒ‰ÑT¯øg[º8W5µùù{ž›—îíÛ£ù[Ž;°O€)Ô?“ص¥¹ç”™g ïKvWåfŒŸÉ:iTkho~a÷¼ÛÞ{Gò·È¼%À >ä™ä¿kcsû©çž^×#•[d4®ë ¼¬R$÷ޏ{ÕÓ/½(ù[Žjÿ`Þ?>£D¶]×µú¤»Æ>¾±ÏIYá3«ßàN\üÔ=óï÷xKÇñÌ[ŽgÀôÇg|sÛîjït뫚ÜÄhª êç?(Ãu³h>å½—xáÆ¾Tïn˜—ÊC 0C,~è€L$x÷ö]=S&ΰ³U½£(¦dª¬õ²Nj+;÷¯:øËí›¶lBXìç¸æ-Ç;`âêéé–S@bÏÖ–®“O›9¢×ê¬ÌçÔs…ƒŠò*TuÔýaùü¥K5ÞâϼåDPI&Ncä3ÂV¦-Ó;á´‰czî\þŒ‘·0ê3ã.¸û±{=ÞrèDá-'`âøŒ2)®«£Ó­­“Ö”¬Ïº²$O0ƒá¸4 ›²yÙ½ÏÝœI§}Þ"ç·œ`9‘$Lœå€fÏ»»R'Ÿ4³,;õ¹ÅÍânâ·hPAEVEYd²Ê3,³ï3÷Þî>ïÛKUu÷;ˆrnñ»Ì]º«ª»¾>õSçœÒ%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ò%]Ž@a)Ò¶b}¾æo×^·iïê‹3Ù "0î0‚ø9Q!ÙKê÷ŽÔíׯ:¬v¬¶µÃ#þsL‹R÷ìüÚóF_ö»».¹¥)8Ê`QM°¨f_Ã0Îf .e`öQÖV ¸@,ë/ùx~ÐøºÉ«=ùþ³_;^`±~s÷• %Ò¹Àq p@ ›¯`´5ªÈMŒ2oŸ}ÅcøÏñ¿ÌWªxŸãüïw¼ë3@d÷É«ç\±ïž×!}G ¨Á0Œ”™’Ž&`,°dÈ6_™ÑÖH6˜Çx3n0˜ûg²þcÂ7Âéä!âÈþ|E!ùÎßÖ JýãÎsþR[Œë&W!Y—Æ\+µõêñÆ&@€\Ý¢­ÑîJ€  cÂäç7NmÌ&‡¬Q sÂ`Ž"²ˆÙSqaÖÅ<ÐÉ×€,ÐH“@Îâ|Eš‚¸ïÈ:>þ_$I†L9zȵź"[À9O¥9 pX°'¯§Ô”€Y2œ:à!eˆ¹¥?µ8Ðu€*K ·hˆkŸ?P¸F§ÖÜØ¢xÉã0Š ˜ ]M S‹iYŽÎÄ=ÀÖ€˜O<óÑ·¼ ÿÆ( B ÔGÆM!òy^’ÌcJ$60Ü ›ÓSØQÕfS’ôZ<¦;FX!æ7 Iè묂WÉ4“L_\€j¯Í”EjÆM@ÐÔ’2É €K+aÜMüTÄ8²?ˆ$U5¨È¥jóG²á˜&aÚ!™Hsª³­Ù1×t'÷IÓ™MŽY\¤j1--a<¦'Å6à±ø1)#¾'inážTòx`¥ùŠ‘3Wñ™+ù`—¶F6ü¬ÇÁâLLb ÌKYm(¼Ôai Ó®ôg>º/Üšˆ§Î̃‰<æ(j§GäÓÏv|úŸþ2‰PyÕ![KKßñR‘ß±@²=±C¼ãß's ,õx’j€!jçF±vn,“^ðø-™Ano :ú{¢¶Y`§“„fÁ¸Þ1(îºôþ5î›Í$ƒž H’êRÜìjéýkÜ}áûàÕW¸˜–þï§ &ïÍæR®(HÕÂÈã³ÇwL2«‚ÜçZÇ*ÜËaR›ÉJ9«^×9äM¸\וàšSPʤ‡í¯ä-Æ=Á$3¢ïH Ì„ÝU%Ø´oƒ8p¬ýø}?¢ïIþõº@@>¬7h<ÀÅRˆô¦®„I¢ ïs"¦þv>ùãrüfüïìï¯ûîxøŠ'0ºø4<|Ÿvìõ€ÿ5yÙ8mà,½o-N8yÙ˜ùûOãSÚ}kñ³±×cÞŸaö qÁI íùÕk»ô¾µxÿ¶pöÐï&è_­û)6-R Ÿ'æXËîºø>¼½âMÌY÷!.ýû«Æü¿~ùZì­)C¿Üþøûõ¯ã¥/c{ùôÍë‡}ç§xcé\5æ§xëó×°ëÐ{`š#M˜ô× =àTÜséC˜·a–Xï”k±·Z¬ ûàh00Œ*>¼ä~,Ûþ™Ø¿S~Ð1µž¥&ïMa“€ðšï Äìõ3ÑÛ0kÝöo¡@ m #ª!€[Ë·àì!ßEßÜþøÇÂg1 ¿g ùìªÜi7ûÞêwÕ"X¹k9rºä m†A4´ºë½üôcúïæbñ½«ñÌÏ^B¯½Ýý[ûAû׿Òêâo ¢4`:Ü+.SZ¹žt B0.5ÉþyÑ–Oñð•Oàª1?ÅŸ®| 7Ïl?¸W޹³×Ï1Âìõ3p嘫QR±ÃaÌŸç¸êݯ÷¦ónÃc³Ày…»¦þ.ngc>ýc‡óÀ¤Óþœ@²Xòøìñ“3¯ÅÜ;¡¨Goû˜É³ÄÂ-óÑ;§/>Ùô&Ï~`À¶ƒ[ÀÌ^?0gÃL(LAIåN_ S˜Tï'è#ÕûÖòWñÐå“1ãöùÚëûÜÇg9ýë•ÓG¨“IׯX"­ˆ¥Üð î”  @ß0@ﱿ{n¤oÍ€p _È“ÜÓˆÈe)·ýy-§*Û!…ÌõIæ¼7] xåŠ8^Áóq×f¿wºÇ¤µ'ч×ë\q¥‘Ӣ̋Žé1tÍÈ«é=á”Wï}± )à“ºƼĜÁçeç¹úËKœû$ ®”Ü2£à{âáGa:àXÿ,°9«èLè 7Xl`@8Ö Ù+ÔLêFêLI)¨%™–&[&¬Aç}Öd;ãÎsùiJçXÇÛ·âïÌÝ/ò8^2Z¹üãûe×ÉÃÝveH覑–0ÒÓ%¼dÇY²&øØÂš¶â>»Œ1ï8ë;æc!û|/}XìŸß÷’©€‘Mb™,Ý\ךš–˜@Jâ…w˜J`Ÿ'›ˆXùÌ‘ægÞ•’1žï˜®ž¾.yL aa–d"y°eê#qFž¼‹›‘ìzK•–0nã1r½ÄiC\0ÀcÏr ÀrÀÉÈsu™)¢Z»ôîu6Ï`ŠS·U?SÈ“—’Zl÷‘›®ø~¥bIaã“m‰œ§•)n‚HƒFžJî 5÷˜}tà7 öÇA*þAœõZ«c”^|LF´X¼ƒW¡Évudžç1 ˆôv›\8ÊNÀºX[¶Ê“-d…²pÆÀ3Ñ#3`ÀŒµÓ„:Fô9 óawu 6íßpXF gâx9þÅ^Ü+=%%4øF;So…µìÃ>Ol”`Hj¹ˆLà%¡Í^ gd>niÃÝ–¾2ÅëKË¢j-æ‘7H]ƒ‘»N³ Z|l&‹ÜŠQÁõ‚ÙÅ'Ïš¦‘8“ LÖ‘^¹êl®Áœ8hйCWq¤’9Ödâ“û0oIGRn)+þÙ–X¦á¸u#b.iÉɇÛð×K)¨Zw^ ãõ03Ήq(òñ^n $$bt’DLô”dœ6#Ø2<òžÜ ´%¿Ïé)©C@HÌM|¿'ˆÎ4pçå°3=IuŸ "Çˉ˜™Á“#É))—›× uGÞ§s6ŒÄ4dGQ(žOØ (†hð‚ü ØÆî”Èj—ê€áòÝ2)”|SåßÈG椚‡ A7t膣Rë’z­0 S ‘æ« YõêÐM2³}\ȃÌËÓ/ãtëTä1)<%±„Ob{RÇßC_ËÔ¡c­¶â„™œTª a!Á]j&N:e·áÆr‹/LXuúzCt¼÷G™8°C'ÁK &2ÃI,0¿Úo¾øô«‚†Ì¾¾Õ]JàrÀÚɼf«ë$ðoçZÌë$é­ß #5à?0º”Z—Ü"ŒûIjm"À0s­( TƒöšRÒòA:ÞªO´Ý8œ'‹ÑIZ/…x%ÅZc‘Î4%1øÃk†»çäueŠfŒÑWÏ5õjɆmÙå%ûrjU4Ö5ôÐ"ÑnѶhV(3ÔDì¥k.zÑqp\eì#Æ<óÖYkO!5ÍÐ`Àè&B|d£eޱ4)iYÁ!fÄ`ïhc˜î†÷Ž_ƒÁHˆÎ4 =Ð{`ÿA}ð¼ La0Ž”7^0ŠßN2pçÄö.`ø%0;¹–F±‘{j6Üs¨aÏÄ` ¬Y7Ðo5ð_é¡È+³<êÍë­:)€ÂcÕj ¦ SA€T#èÐ8k«I$Íd|¤)—u×éK|R1HG›Þb÷Ï—ûxu›‰Ñ †í{'¶bª:ÈÜ#A8ͧ-_}'ݾ6•©ˆÍÝöDÖ|Rv@ÕÍ”¯ô°2)W¬A: °`-€~_EÂX{¬×[÷½¼ïâÛøv}[åÄÖXs¶ªà ¼’½ ™Çï²}AzXTENÚe1SâˆÁjb£HsbSm£š=¸àc¨I $³D3ŸJ»Ÿv^_§M&ÌøâÞ&î~Ç×ÐÅ”Ó dè8ذ'ÃÌLZÿjw±R ¢¸ÄÞgÌÉZ}Ô`±²sgÈn®oì²ö£U•gŒGÍJÍwT% ˜i£P Î{…©P˜"|ǘUQÌ¿ñãUEÂâïóNI$;R3´›“yï0Áæ;e¶ÖŤf˜+£„‡›“ óÞò_ïë rl@ñû¤@±ï£uÍ—}?Uóy TÛ7Ga Fè™õ­-=û]ûÅüÏ[“‘0~€ ÀÙ +€îˆï8’[²rçþQãNÞ UöT1Õc²©Ø\ª²4uY‹þÓ\Åp'(—7sÀIüÂ%Kt@܄¦†óAU¸ì´«páI“Ð?¯PV½s7ÎÄôÕSãñN$ZŠ+-1OÂW»¸ìTïºß[ý6tCKàGñ:†ylî$ßWKSìˆmœ÷ôœ¿uû»$z#î{[d‚¦+€ð„›¾Fc¯²ÁÖëVC*q¸eÉÝkþ®:^\ø4¦®|ݳmÛh ~“‡Ð†‚a<ùãgpJñéžõ¯-];¦ÞŒ¨rÿ0&[Ýd>¨†ñç?ƒS‹Ïð¬{MéjÜñ¯›3¢Þý†Üüw‰ƒû8¯C4#ŠÜP¿ºêm7­ühñ¿Ôhý*¤×R©y.cíËØÍü›Uµ³²eðÉ'äµj3°/L«šê)Þ’æsrG>zä¼bÞÆYxkÅ«ø¿EÏã…OcÊ’¿ã“MóÀŒè3g :[lÂÞš2ñ&sÊ”MΡ·å– ¿Çø磶¹κÎzÿüü”TìÄèþ§¢¸`²B]°b×r‡Gs×ßåMAÀ¼•æÚ7T¦âÖ wØu?6Û]÷@³î•%Ë=6ì’BƒÉ "yË7×Á­2]ÞSøÂ·ç,Р…›’[Â0SKÊ4Én¡)aú›Ò¦Ð”>™}è1üƒN«Ó©A%$ùzpÙ”lóºÂ½·Ä»åœdù¹1³ÿÌcO‘£üúÜ[pÍY¿ÀÚÒÕ¸å|m)LÚ’„@ÈïZ€i·ÎÜ8åZl?´U 7#úŒÄ ?†¡ãòg/BuS¥»~T¦ÚF<«­‚®…xçÖ™€_M¹;mNëþ>jšªmëqAzòмóÞ€kBéáãžA1ôi;qÉ»¼y?€rÕˆooI–Ã(>3%ÐÌŠšL±U Òl¤ÞDftßÎÒ†úú®Ì`w²Â3lâ)Ù8Idä¤ÿ²ŒUàüR,£U܈e=Á–Q‹¹ljÓVý 0¬èך“¼Dö ÿqÜð‰(,Þò)¶—ou==›öoÄÒí‹Pƒ?|¢˜àÛp nÐIçZ0pÎðñP•™uËýÙ¼¯ûü¸ÓO¬%rrô O¸I„­˜sùŸÍaLmÉ€ŽžÊÝóžŸõWs<´v„ð&ZK²nI̬´@ ˜Jó}ƒÕàÊ™Ÿ•);²(P`º¸²KÎJ/IëC‚{#‰¦u2e)³}j‰#ÙžqMmñ Q”ÂÒ»Œp*`éöÅÂB'¿øÙÖ€QýOB%i•¨n&׬ÏBÝVÕÖ½"Ç-ÝyïÄ”3ùX“GYï´݈!WéÓ°åƒí“ëê¨3A4Yu:™ÅG2+‹šÒ¤Þ”.T¦š ì0ë–&}»îì|¸V=<·ÆMâ>rdžU ¢kußyK¦ú)÷wx*J0ÖÔ¤™’Äâ3•*L‰SgJ Èþ’²†êem;3•n¤s®Œí‹Ÿï ve–›Î» #úŒDYÕL[5µÃ*{F(ÐmõÕZÌß2‚™0Ȉ¿`´+EÝu»ûÏ× Cº^JRoácˆœÍ 4hÇço/}Õ|Àmîi ‚¯b*IvI7é75Õ[¨]5gÙ>}kÖ^ƒa‰ŸŠdäõž€Ÿ|çgøñw®EK¤÷Lû¢ZÙ&ÍËìe‘Liç\Æ’X c)`(I©"¯é1ägôiÙ3ïsûËË8ÞÒÖQÞÒQÀðS“Ìg*$>Ó @[õþŠ’ìú¢Z4$\õ³ùZq³aèNl²ßÆåä-…®û_á×ão¦k¸ú±xË¿LïöÂ"Y 1LYböËò›>†fh8ç„ñv¦L#úŒÄØaç@34,Øü±ð#%"êŒaÁ—fÝÃÇÛRÊ6NR|OʱCϦkX°écÉKhŸß i²‚ÝÝœ²mÍÆM¼åˆdZ<Àð|¦ÍDpgŸøLkKKdÍ¿Ö}Ù])ÒtCó~JÈ_•üÅ97âWãn‚nèxð½ÿÁ¢ÍŸzôˆ¹,´ÖÔ´ìÁµXúÀÀp6¡µ¤PE}f¬žŽ€À_~ú<Æ Ÿˆ¬`t ecˆ 1ù'OCa f|1U•®Q\zïZ,½w­K:2•|ÝÏaÜð È wAv¸+&Œ¼“¯~ ŠbÖÝPÙ.Ñ÷59`:‚Jù­ƒ,û`á|é¡="SQôÁ„çZŽV]L·‡"}w(î ßt…È8ñ?F÷Ê=/xbTk…ªÜù[|ü}…½¨Û)“ž˜€šÆ!ØÒ‡âSÉØ{Ouüs¸¤>áP¾æŒ2MùrY_º·¿y“©¶[žxqà-¹/Þ·±Œ–èEü˜°šÑ~ݯߌ¨qûC'9DÍÐЋo˜÷—y÷EZÛÊ̇¶Á²Â'»Lù*‘<ŸQ̆÷¶^!³ õË%kŽx~Hß¶¾ (,îèMäµó›[u|ç:"&.ÜŠ?:~0œâÑà¶×nÂåc~„ N¾ò‹ãK Õ{0oý,Lû÷ThzÌñcoÏ4Ïœé*¢µá¶×ƒËÏø±XwÕÌ]7 Óÿ=ÕÎ L˜0ø@ý˜EAÆ€ú­ìz!ÒÚvДöÍ’éÿˆ•#àbùÍd"î+Sˆ¸ D?Ä]"zè K—®Ù™çþç¹£+B%Ýœ+„_ú /ç^•å÷âÁÅGF NO`‚¯¤HÉøFfŸ8M–É{„ö}o'y¯ ¹Ò•ð)ã9¿^9–\vuд(²3òŒPiþsó¦¼÷.€CætdiEÆ‘Œzë" DV˜JÐ|bÑ(«-mhpâÀüVÔU% ¸z.ÑË^º|:M‰Â ï2aIfÅaó{³ÅkQ|åŒI»~I™„¿ü‚¡fÛ‡—wçþŠå€}<†€@^SñÜYÏO{Íœ†ê¾N°iÀÈTÍ’<nj ´46áXv¤Çண•©, š(„(F^d0 ÜÌBp硳ÞÙKßhxšM’){S…I ¥Ecñ1S’Ëlnü¼Ï¥ŇSÁÂEDÐ ô­u³ÿúÁdÃ0,Éb¹,høš2˨_XøúU4Uû+Úõ4rZ»“Íg¤§R €î5 &IÞÊ$©Ã8x{áq^ûääÿFν§ =ÍØÇFBÌ»ß% ¤MP™çå˜þ£È ômØ6³ä‘ªòC%œ5·íHÙ[¾ Àx-Æ3ij²þªe›v7Œ=ºGK >SÍŸºâr”–ÂOM¼ºÍ›Ò½öý%ñ}œÏpÉ=v_³]º\Rнí4kïÖ1&IKiûbF ]3zPëzõ/ë¯\ÁYs[9ˆ:`d+?«È|&HDJ󡶦Ⓥ{¶uªÂnµ’ÏgHnggqΓfzƒ…Ÿò܉‰l^CL´ óŒ…_jà­Ç\ “:Üö ßw—©{d@QUä7 šýÑ+Nõà-:¾æ$gG:݇ez³)àí?Ó Z¾go㾕[2]I7bvÀ›Äà±§"Üñ6ÖM]öÈj,µr2CqîŒË&¯r[Z nYÁ``s.<b\x¯œÚYÏÖûü~Òã£{cÙŸ¾‚áÜS¥|í ‘Ž‚XñÚ_žó}«cßX¾ÀÈö™V45h¬EÊMŸ¯«`;³K% ¤m÷Óø‰‡à£l×`îõã f¹†ZkWd¯a1ÉÏ—ùÚõï½òAÔ6Õâ7ÿ¥¯¨qGm:ž¼šEaFqÝÆ¿|¶©¾á Ü®–ßHùºR–ÉNW£žÅi”Ï?X²û{7ŒëV›¹77¨*î¹[¶¿XZ²¹Çñ¼4ø×š–Œþb¢w‚Çn+^‹dÖ7×@¶E” nÜ>êšá§TÇ„‚j˜3¸‰ƒ›‡ëÇ߈ O¹-‘,üòS<;ç)D¢m"aaéc«0áÞspÛ¤ßã{#ÇAUX¿{žõ7ì*ß)Ø[TEÅ/'Ü€‹NŸ„œì”×À»K§búòw…Hs³óðˉ7àû§šíoüÏÍ}*¾÷’¸ç±;óÐèÈcSL3Â`P A5Œnu½f½?}êñËMµ)IV³-ÿ™F>c‡i,Ý×XþYÍöì@wC3¢fnkð2åæ7°©l#.|p<~ñÌO‘ê‚ß\ð[36‡[0 è_q6–nÀ¥_„I]€ÅàéŸGß¼~Â]¾ëŠ»‰Eð«§~†qwŃÿºWŒý&ñ;l¦üîulÚ³üïx\÷·kî‚ÿ<ÿ'Hžç;rÆz’U}Ÿ<¡Äs6D„ÞÁ¡;ç½üá+oùÆHî7 žÇ<øŒ+(ný’Õc;C¥‚®k‚=ÅZiþácßÇÜ5³‰EPY_‰?Ïx çžxžïmÛ¼w>\ùZÚšÑÜÖŒ+ßÇ¿ÿ¿œxƒÀ2Ê*Ëðú‚WPÕP]×±¹lžœþ8~xÖŽ•—€³ìÝE%ão<¿[C×yŠ¢ØYœˆ¡@7Lü5Îy º" Æ»o9›{mA3í<oùhÍ{|…³/ã"y ‰¬:.1—šA7tad×ÎødÞ;ËàDš¶ Þr4Ch,>#kN¶+DUù¡æ=óË·ŽëqRk¬‘Ô àÜ‘ãñ“'/C]s ¢¢½\jŽ5Û5UõU‚­Gv®]‡¬yªgf¤â¹'Ç‹·oUÔ£ÈÑÈLUÇ/dØtlLqS€I§™c*0˜|}Àê^™õ†¯Ó\xÚÅö{ø`Ž<’Ë›ûÄÂãñD…ýmûtû?Z›[¥o9Z€ñâ3õhdàØŠ™K÷dÕT†aŶÏqËE·£[fwd…³pù™W¢¸p { ŽÁðþ'â¢Ó'!+œ…¬pL:ãR\ý½kðòüÿ“Œ²í»­Øú9n½ävtÏŠ·ÅÙWa`ÏAÜò€´qh{n–RIL¢[(7RñyíS[¾Ø°%UxËÑâ0^|¦Égj ‘²~æÚ§]7º{Utøñi—ß÷ïž…¨Å’M‹ððÛà{#ǹ“ š÷Üzéíøí%·"cýîuøÝ?~‹ýÕû:ÜéÇÞýîºân¼O¼ýϾ\„‡ß~ß;iœ¸DÁMA–sԲɫ„º–=î|>û®Ó¡ëB Wä¼óïùï¯L%ÞÛæ7Ú®Ç8qà>pü ÷àË8iìi½sÏÊÞ¢5(Ÿ±Ÿd>ï› #Ζ?¹ gÝqº×üÐñÇc¶{Òàø—i÷8€ø*4ï—›­½¼ì3ÕœQ¯†_XÛ°tõÁÈV¶Geñ½Ÿ-S¿ì™'&FB>rø=7SØK¹lH^÷"‘Kñ‹BÚ"hz y¡Þ{W¼³ìo&Päè”)Gss 9(ÎM›Ï¬š»|OVC^¥¡ë0 Ãά$XQ“míïQäù=KyȘ/M±ƒ3nu›KÙªë1tÍÈ5­¬}¶b_y¸Tá-|Qrû̃zù ÃPê÷74=¬ E¯òI¥Ý)Vãåå_@ðU7´² €í¤°”3–ó+펵…`Bj¹-ý§-x{Þ 8þ--©Ä[R 0²†8~ãr"omn!¥9Øš÷íÜ¢H¬•)Š*”õH»SRºûíˆæ•š×€|&·éjße-ȉô]4óÙéÏšRµGq¨3>’F25‡ª¢½s‹ ùz.øÝBø|¨žÆ7ižðÙÃ3³7 d÷öß$Hu<ž¨ÿ¾5Ó×LnªoØ ·ËBJ–T Ÿ¬‹ù€FÙ¿soÓÈ‘§d5(5Ùñ ®<žlJ ÷`Ì÷¹öÚ @Î`Ù.XˆéädjM£OnYµ~-§µ¦"oIUÀøñhˆH­Û_ß^ˆ@—%™Ž,™Ãˆ@ºŽcàâϼóTgá-©xˆd>(Îr…ÔVVkyÝzQ¸HÍÓuÍÌÕËÚ‘_,[¦<¥07fÈc?¤$…¦GQ°wùKikiÝßYxKgŒ,,IÃóµ|×þ¦'îÖª6dñá§âWÌszaÇ‘ ³_(òyìÆE ºCNV¡V¿¡õ‰¶lèL¼¥3†ù€FL@ ²¤²~ÈÉÃò[Œ†#eäÈÃ$Å@Â)È+øÐ^ÆqÝÐTÃȪÎmá»óæt6ÞÒã551Ш‘Ö6 ¬©`HaaDoUELÒx3ñ{–`×i–ÀÎb}f̛Ϙ¿“aÀ0tÒ€%s^šñ"u:ÞÒ™ãO£^]Už×¥H öT Ò¤½#Ûfäo"oæ)íËãRŽSwÇô(Š2‹Ë6ÍÛü皊ªÒÎÈ[:`¼t`¨‡ÊÊ[‡ ž 7wµöjJÄaDIÂOcÔÎ9~Ó”ëªézd4W¯ixrÓªuë:+oél€aI€&„¸ÿŒZ]VÝ8lÔð‚&­6¨Ú®’S/I»Íº"ÈXÕœË7üv§¿t]CH £KmÞë‹ßŸ?¯3ó–Î8%y©Úž$8Òah 4ç+¿ MkQK0ŸA0°1o®g®#+¤t[ÉV“·4vfÞÒ™ãõ¼[ëMAžÏPË·¨vêð‚&½.¤**\»Øá¢:j™•9SVÌ[²àXá-}Jòâ3žS“‹)¬%Ø\4¢¨wk¤ ‚ÿÌ‘î ô˲bæ‹Ó_€³NÔéy˱˜ñ™^¹ô`>ËÓtÍsí#QbzEÙÅ{Ö¼·æÑúšZÞ¿å+íO”Ì7Çgì©iïö=M‹‡£™MÝE=,÷Ì„`Ñ"èÎk([´ÿ¡]_nÛoJ&uøŒìt%ó™@UieãÐQÃóšõº°ª¹p,M!ÊDàP÷üû㥟AÜè˜à-ÇÒ””4Ÿ‰E£Li ´}»¨ 5Ö¤ >c:Àz«ƒÎyéý)ý["Ç o9ÖãÇgÜþÀÕ±¢œ¾F å ö™Ã–.úd*[0åÓ‡#­mòNóÇXŽ%À$kŸ ìÛQÖüíá'wi 6eÇ#FÏÄ´ºgÔ–->ððÞ]{¶sö–”ŠTL&9>¸ým¼osYí §˜×lÔ‡¦v4º®!Ê2‚»¾´ò£%Ÿqö–£’w. ˜#Ïg„•m]ו¶ªHcŸûµi-JGøŒaîX ÷Ÿ3wÊŒ7LÞRw,ó–c0íñKÝVkôüì^z å†–Ÿ!t=†^]îYòæâÉm-­à½UÒ€éœ`±–˜ >P²¯y`ÿaj,»µóŠQ’f½˜Ö†ÜÌ¢†Š•Õ–lÙ±N’êcš·ë€aðv…5§€@ùÎýƒG ïÚª4d%2ê醆Ìp6²ëò^Y4cþ|‰·|í›B¤óÍsO>c膭‰¶öÑ¿g«Ö÷Ÿñä-„ühßY3_zïU“·Ô/¼åxŒŸ‚âëôܬž±Œ^Áü˜e g &4=Š^·.|õÓ'£‘ˆÅ[äÔíHæØ‘0~š“ šòÝûZkx(Ö¥¥;8ûLL¡ »OÓŽv=ppïþ]S‰i8Ίzœ\§ O'òòûNsjA£VR5Î[BY`¥á§W/Z±ßðfViÀ¤h,VËôâöM£X^UtB¯¢æHC@QôÔΚûÚŒ· nfu\ñ–ã02§‘I°À¨«®iè¦æ–gö ÉQzm˜óÜŒÉDtHâ-Ç%XŽW ã¥jÌÏ€æCeå¥Cœ¼³bÛ¡9Ëì€{Îã,Ç£„ñ ò·l7Õ5Û*÷ÜDA\'¢4`ŽŸÂ|œà¤€­PÕÒÔ\Dùu¢¯móðÎTÇ©„Ñál’¡˜@hA<¹n¤bFKýxËñ 4V~`Æq—“ü&˜šÍï:}ðÙ‘ÑÇëu3Iµ™S´5=EÍ×1íß’LÇA£š/…ŒgÿíôT”ŒëúåäxÒžôé’Lr÷! –tI—tI—tI—tI—tI—ã­ü?Æ=3ŽÛIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-dl.xcf000066400000000000000000000714721226750426600167540ustar00rootroot00000000000000gimp xcf fileŒšBBJgamma0.44999998807907104gimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) ½  ;Y8alpha 1ÿ     *Wgimp-text-layer(text "alpha 1") (font "Sans") (font-size 16.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "fr-fr") (base-direction ltr) (color (color-rgba 1.000000 1.000000 1.000000 1.000000)) (justify center) (box-mode dynamic) (box-unit pixels) ˆ8œ8¬(ÿ(ÿ(ÿ²þÿ þÿû2–ðÿ þÿ þÿûÕ€+ÿ þÿ þÿþÿí—öé• ÿÿ žñõ¹-øÿƒåúÚlù—öé• þÿâä_£’ÿÿ©dgé$ÿžz7Ùeùä_£’ þÿö æÿÿsùv£ÿxýCÏý æ þÿñ Šßûÿÿýÿÿùçÿô ÷ Šßûÿÿý þÿñ›±1 ÿÿÿúûÿõÿ›±1 ÿ þÿýïö#ÿÿÿúæÿúÿïý#ÿ þÿýööƒÿÿÿqút¢ÿúÿöýƒÿ þÿè® l­ÿÿÿ¨b eè$ÿõÿ® l­ÿ þÿì­õîžÿÿÿíõ¹.þÿõÿ­õîžÿÿ þÿ5þÿ5þÿ`=2.0.0ÿ     &=gimp-text-layer(text "2.0.0") (font "Sans") (font-size 24.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "fr-fr") (base-direction ltr) (color (color-rgba 1.000000 1.000000 1.000000 1.000000)) (justify center) (box-mode dynamic) (box-unit pixels) g={=‹éÿéÿéÿ3ö't²ßø÷Ü1÷pÏ÷÷Ïq ÷pÏ÷÷Ïqÿýüt ý ¾ÿÿý¿ ý ¾ÿÿý¿ôÙŽQ% )•ÿÿL õ’ÿéW[ìÿ‘ õ’ÿéW[ìÿ‘ ü‡ÿÀ ûûû2û8ýú ûûû2û8ýú üÿò üqÿ¨ü¯ÿp üqÿ¨ü¯ÿp ü ÿõ ü°ÿ[ü^ÿ¯ ü°ÿ[ü^ÿ¯ üIÿÎ üÙÿ+ü.ÿØ üÙÿ+ü.ÿØûÈÿv üòÿüÿñ üòÿüÿñûÿØ üýÿüÿü üýÿüÿüûtÿò- üýÿüÿü üýÿüÿüûpÿ÷A üòÿüÿñ üòÿüÿñûrÿùJ üÚÿ+ü.ÿØ üÚÿ+ü.ÿØûuÿúOü°ÿ[ü^ÿ¯ ü°ÿ[ü^ÿ¯ûyÿûRürÿ¨ü¯ÿq ürÿ¨ü¯ÿqû}ÿûTûûû1û8ýû ûûû1û8ýûûÿüV ÿõ”ÿéV[ìÿ”ÿõ”ÿéV[ìÿ” ÿþÿý Áÿÿý ÿý Áÿÿý  ÿþÿ÷rÐøøÑsÿ÷rÐøøÑsp1download ...ÿ     .*gimp-text-layer(text "download \nversion") (font "Sans") (font-size 10.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "fr-fr") (base-direction ltr) (color (color-rgba 1.000000 1.000000 1.000000 1.000000)) (justify center) (box-mode dynamic) (box-unit pixels) 1 +1 ;úÿúÿúÿfþÿþÿþÿþÿþÿþÿùÿ9c9ùÿ9c9 þÿÒ7Ûõ‰ÿ~ä£äzçDÿDéÿ{ðì^ÿ~ä£äzÿÿäM7Ûõ‰ÿÞÒj mÿî&&íµ>µ‡´?¼ÿl Hêÿî&&íöAÞÒj mÿÒû ÿõô‚ŠÚÜŠÿÿÿõômâýÿþû ÿêÒh kÿ¢ÀqŸPùx{ùbÿêÿÿ¢ÀqŸ÷E MÿÒh kÿê7Ûö‹ÿk“júü6ÿêÿÿk“jðïÿ7Ûö‹ÿþÿQü/bAû Sghü9c9Ü'æ æ&oÞŸÓˆÿ’ú×¹™˜ÿ~ä£äzÿ{ðì^ ݰno®ë€huñÿ_Ø¥aÿî&&íÿl Hê ÷:ã ä7ô ˜˜èÿ]¢ÔÿõôÿÿóÅÂÁ‘¿rhhÿhó‰éÿ¢ÀqŸÿþÿóOÿKT˜˜ÿñ˜—ƒ(ÿk“jÿþÿ™ŒšArrière-planÿ      Œš's"s.ŒšW"È6&8âP¤hkbnTr Cÿ zû\1:9::þ9::9:9ÿ z÷Z2;::;:;::;ü:;:;;:;:ÿ yýT2::ÿ výN2::;:þ;::;ÿ tôH4;;::<<;;:; ;<;ÿ søC4;;:;:;;:;þ:;;:;ÿ pö>4;;::;::;;ü:;;::;ÿ qú=4;;:;;ÿ põ<4;::;:;;:;;:þ;::ý;:ÿÿ pý<4;;ÿ pý<4;;ÿ pý=4;;ÿ pý<4;;ÿ pý=4;;ÿ pý=4;;ÿ pý<4;;ÿ qý<4;;ÿ pý<5;;ÿ qý<5;;ÿ oý<5;;ÿ pý<5;;þ<;;ü<;<;;þ<ÿÿ oû<5<;<<þ;<<ü;<;<<÷;<<;<;;<ÿÿ nø<5<;;<;<<þ;<<;þ<;;þ<;;ÿ ný<5;;ÿ nü<5<; ;þ<;;ý<;<<;<ÿ nü<5;<<;<û;<<;<<û;<;<ÿÿ þln nü<5<;;ü<;<;;þ:;;ú<;<<;<<ÿ ýwln ný<5;;<ü;<<; ;ÿ ü‹xmooï<6<;<<;;<<;<<;<=; ;ÿ ûŒ‹wmooý<6<<ý;<; ;þ<ÿÿ ú‹Œ‹xmooý<6<<;ÿ ‹ûŒ‹wmooý<6<<ý;<;;ÿ ‹ûŒ‹xmooû<6<;<<ú;<<;<;;ÿ ‹Œývjmmø=6<;<<;<<ý;<;;ÿ ‹ûŒ‹ujllü<6;<<;<ú;<=;<;;<û;==;ÿÿ ‹ûŒ‹ujllý<6<< ;ü<;;ÿÿ ‹ùŒ‹vjllý<6<< ;<;ÿ ‹Œüujlù<6<;<<;;û<;<<; ;<þ;ÿÿ ‹ûŒ‹ujù<6<;<<;;þ<;;<;<þ;ÿÿ ‹üŒ‹uý<6;;ü:;;ÿÿ ‹ýŒ‹õ<6;<<;;<;<;;þ<;;<;ÿ ‹þŒö<7<;<;;<;<<;þ<;;<ú;@?<;ÿÿ ‹ï<6<<;;<;<;<;;<;:;;þ<;;ÿ ‹ñ<6<<;;<<;<<;;<; ;ÿ ‹ý<6<<;< ;ÿ ‹ú;6<<;<<û;<<;<< ;ÿ Œü:6<;;<þ;<<ý;<;;ú<>?@=ÿÿûu„…†… …öxV=,@6<<ö;<<;;<;;<;;û;ÿÿøqdMRRQRQQþRQQPôQOOB:<<;?>;<<;ý<;::þ;ÿÿûc>588þ;<<ü;<<ÿÿõU::<<;;<;;<<;ö<;<;<;<<;<<þ;<<Cÿ ¨üszyyÿ ¨ýŽuzzÿ §ý…uzzû{zz{zzÿ ¤ý|v{ {þz{ {ÿ ¢ýsw{{|{÷|{{|{||{||þ{ÿÿ ¡ýkw||þ}||þ}||}|ÿ Ÿöfy}}||}||} }|}ÿ  ýdy}}ÿ  ýby}}ø~}~}}~}~~ }ÿ  ýbz~~þ~ ~þ~~ú~~ÿÿ Ÿùb{~~~þ~~þ~~ÿ  ýd{ÿ  üc|€€€þ€€÷€€€€ÿÿ ¡ûd}€€€ü€€€õ€€€€€€ÿ ¡õd}€€€€û€€þ€ü€ÿÿ ¡ýd}ÿ ¢ýd}ÿ ¡ýd~þ‚ ‚ÿ ¢ýd~‚‚ÿ ¡ýd€‚‚ûƒ‚‚ƒ‚‚ùƒ‚‚ƒ‚ƒ‚‚ƒÿ ¢ýe€ƒƒþ„ƒƒþ„ƒƒþ‚ƒƒþ„ÿÿ ¢úd€„„ƒ„„þƒ„„ƒ„öƒ„„ƒ„ƒ„„ƒÿÿ ¢üe€ƒ„„ƒ„þƒ„ „ÿ ¢ýe„„ÿ ¢üe…„„…„ý…„……„…ÿ £üf‚„……†…û†……„……ý„…ÿÿ þ¡£ £üf‚…††…†þ…††…†ÿ ý«¡£ £ýfƒ††ý…‡††þ‡† †ÿ ü»«£¤¤ïg„‡†‡‡††‡‡†‡††‡ˆ† †ÿ »ý«£¤¤ýg„‡‡ý†‡† †þ‡ÿÿ »ü¼«¢¤¤ýg„‡‡†ÿ »û¼»«¢¤¤ýh…‡‡ûˆ‡‡ˆ††ÿ »û¼»«£¤¤üh…‡ˆˆý†‡††ÿ »ý¬¤¥¥üj†‰ˆˆü‰†‡††ÿ »ý¬¤¥¥ûi‡ˆ‰ˆˆ‰‡†ù‡††‡‡†ÿÿ »û¼»¬£¥¥ýi‡‰‰üˆ‡‡††‡þ†ÿÿ »ù¼»«£¥¥ýi‡‰‰ˆ‡†ù‡ˆ‰‰ˆ‡ÿÿ »ü«£¤ýj‡‰ ‰ˆþ‡††ý‡ˆ‰‰ÿ »ý¬¤ýj‡‰ ‰ˆ‡þˆ‰‰ÿ »ü¼»¬ýj‡‰ ‰þˆ‡‡ˆÿ »ý¼»ýj‡‰ ‰òˆ†…„„……††‡‡…†ÿÿ »ýj‡‰ ‰üˆ†…„„…û‡†„„ÿÿ »ýi‡‰ ‰ýˆ†„„þ…„„ÿ »ýi‡‰ ‰ýˆ†„ „ÿ »ûi‡‰ˆ‰‰ˆü‰ˆ†„ „ÿ »ýi†ˆˆþ‰ˆˆý‡…„ „ÿ »úf†ˆˆ‡ˆˆþ‡ˆˆþ†„„†ý‡…ÿÿû¡²´µ´ ´ö¢tR;+$o†‡‡ˆô‡ˆ‡‡ˆˆ‡ˆˆ†…„„…û†‰‡…ÿÿ ú’––•–••þ–••”ú“”‘‘Œ‡‡þˆ‡‡þ†……†þ…††ÿû‡‚……û„…„„……„ü…„„……‡†‡ýˆ‡ÿÿ…ý†‡††ü‡††‡‡†ö‡†‡†‡†‡‡†‡‡þ†‡‡Cÿ û])2122þ122121ÿ ÷[)322323223ü23233232ÿ €ýU)22þ32232ÿ }ýN)22ÿ zýH*22û32232 2ø3223232ÿÿ yýC*22ÿ wý?*22ÿ wý=*22ÿ vü<*2112ý1211þ211ÿ vý<*11þ211ÿ vý<*11ÿ uý<*11ÿ vý<*11ÿ vý<*11ÿ vü<*011010101þ011ÿ vý<)00þ100ÿ vý<)00þ100ÿ vý<)00ÿ vý<)00ÿ vý<)00ÿ uý<)00þ100þ10 0þ1ÿÿ uü<*1001þ011ö01001100100ÿ uý<*00ý1011 0þ100ÿ tý;*00/0þ/00û/00/00ý/0ÿÿ uú<*00/00/0/ý0/00ÿ uý<*00/0þ/00þ/00ÿ þru uü<*0//ü0/0/ /0û/0/0ÿÿ ýqt tý;*//0ü/00/ /ÿ üŸruuï<*0/00//00/00/02/ /ÿ Ÿý‚ruuü<*/00/ü.00/ /þ0ÿÿ úžŸŸ‚ruuý<*00ú/0//0//ÿ žŸýruuò<*//0//0//.00/ /ÿ žŸýruuý<*//þ0//ÿ žŸýpttý<+//0/ÿ žûŸž€qttý<+//1ý/0//0û/11/ÿÿ žŸýqttý<+//0/þ0//ý0/ÿÿ žŸûqttý<+//ü.//ÿÿ žúŸž€psù<*/.//..þ/.././þ.ÿÿ žûŸžpù<*/.//..þ/../.ü/..ÿÿ žüŸž€ý<*. ./.ÿ žŸõ<*.//.././..û/../00ú/01/0ÿÿ žþŸö<+/./.././/.ý/1001ú05410ÿÿ žï<+./../././.././00þ100ÿ žð<+//..//.//../.0 0ÿ žü<+./ / 0ÿ žý;*/ / 0ÿ Ÿý;*/ /0ú13452ÿÿû‚•—˜— —öˆaE2$A*//ý10//0û2840ÿÿø}gGNNMNMMþNMMLöKM:-//.43//ü0/0//0/.þ/ÿÿøk2'+**++* +ö-0/00//00//0ø/00/0//00ü/0/ÿÿû[/-0//ú0//00//þ0//÷0//0//0/00û/00/00ü/0/00/^ûd°°ù Ÿÿÿ÷  ¡ÿÿ÷ ".7­ÿÿ÷ "5GU¼ÿÿ÷ -F^pÉÿÿ÷5Sp…Óÿÿ÷";\|”Úÿÿ÷$?aƒÞÿÿ÷$@c…Ÿßÿÿ÷%@c…Ÿßÿÿ÷%@c…Ÿßÿÿ÷%@c…Ÿßÿÿ÷%@c…Ÿßÿÿ÷%@c…Ÿßÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿàÿÿ÷%@c…Ÿáÿÿ÷%@c…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿáÿÿ÷%@d…Ÿàÿÿü÷*;Ut“©åÿÿø5±÷óóôùõöøúûþÿÿö Z÷ÿ1ÿö  '+ÿ1ÿ@ÿ:þ9: :þ9::þ9::9ý:9::;û6E‰‰ˆˆý;:;;:;:;þ:;;þ:;;:þ;::þ;::ú;6E‚‰ˆˆ&:û5E€‡††ý:;::ü;::;;:÷;:;:;:;:;;:;û5Es…„„;þ<;;< ;þ<;;þ<;;û6El€€:;þ:;;:;:;ø:;;::;:;;þ:;;û6Da||þ:;;þ:;;þ:;;þ:;;û:;::;;:;û7Cc}}&;û7Cc}};ú:;;::;;:;:ý;:;;ý:;::þ;::õ;::;:;6C_||&;û7C_||&;û7C_{{&;û7C_{{&;û7C_{{&;û7C_{{&;û7C_{{&;û7C`{{&;û7C`{{&;û7Da||&;û7D_zz&;û7D_zz;ü<;;<< ;ú<;;<<;;þ<;;û7D_zzþ<;;<ù;<<;<;<<ø;<<;<<;<<û7D`{{û<;<;<<;þ<;;<;÷<;<<;<;<;;<;<û8D_zz%;ú<7D^yyþx;;þ<;;þ<;;þ<;;þ<;;û<;;<;;ú<7D^yyýxz<<ý;<;;<;<þ;<<ü;<<;;<õ;<<;<<8D^yyúxy‡<;<<;<;<ý;<;;<þ;<<û8D^yyý‡Œ;;þ:;;û7D^yyúxy‡Œ‹;;<;<ù;<8E^y yñxz†Œ‹‹<;>=>@@=; ;þ<;;þ<;;<û8E^y yûxy‡Œ‹‹;< ;<;<û8E^y yûxy‡Œ‹‹;þ<;;<û8E^y yúzyz‡Œ‹‹;þ<;;<;ù<;8D]w wüx†Œ‹‹;þ<;;<ù;<9D]vvûuv†Œ‹‹;þ>;;þ<;;<;ü=@=;;<þ;<<û9D]v vý†Œ‹‹;þ<;;þ>;;ý@<;;<û9D]vvûuv†Œ‹‹;þ<;;:ý;<;;þ:;;<þ;<<;ú<9D]vvûuv†Œ‹‹û;<;<;;<;<;û<;<<;;õ<;;<<;8D]vvûuv†Œ‹ ‹ù;<;<;;<<ý;:;;÷<;;<;<;;<<õ;<<;<;;<<;<<û8D]vvûuv†Œ‹ ‹;þ:;;þ<;;û8D]vvûuv†Œ‹ ‹;û<;;<;;þ<; ;þ:;;þ<;;<ú;8D]vvûuv†Œ‹ ‹÷;<>B=<><;;þ<;;þ<;;<ý>=;;<ý;<;;ï<;<;<<8D]vvuv†Œ‹ ‹ ;ý=?;;ú<=;<<;;<;<ö9D]vuv†Œ‹‹ ;ý=>; ;÷<;<<;<<;<<÷9D]uv†Œ‹‹ ;< ;û<;<;<<ø9D]v…Œ‹‹ ;þ<;;þ<;;ú<;;<;<<ò;<;;<<;8D[„Œ‹‹ ;þ=;;ô<><;<;;=B;;<<;÷<;;8DV‹ŒŒ ;þ<;;<;þ=<<þ;<<ö=;<;8Bpƒƒ……ýŠ<; ;ü:;<;;þ:< <þ><<ü;=PRRQR<;<8þ7<<;<;<þ;<<þ;<<;<7@ÿ"yzüv‚³²²&züv‚©±±zü{z{zzû{zz{zzþ{zzüw‚§¯¯{þz{{þz{{üx–­­|ü{|{||þ{||þ{||{þ|{{|÷{||{|x‚ªª|þ}| |}|ûy‚ƒ¨¨þ|} }þ|}}þ|}}þ|}}þ|}}ûz‚„§§&}ûz‚„§§ }~}þ~}}þ~}}õ~}}~}~{‚§§~ú~~~ ~û~~~~÷~{ƒ§§~ý~~~~~~û{ƒ€¦¦þ€$û|„€¦¦þ€€þ€þ€€ú€€€û}…€§§ú€€€€€û€€€€€û~…€¦¦þ€€€ €û~†§§&û†‚¨¨&û‡‚¨¨û‚‚‚‚ö‚‚‚‚‚ü‚‚ø‚‚‡‚¨¨&‚û€‡§§‚ùƒ‚ƒ‚‚ƒ‚‚ƒ‚þƒ‚‚þƒ‚‚þƒ‚‚úƒˆ‚§§ƒþ„ƒƒþ„ƒƒ‚úƒ„ƒƒ„ƒƒü‚ƒ‚ƒƒûˆ‚¨¨øƒ„ƒƒ„ƒƒ„„üƒ„„ƒƒû„ƒ„ƒ„„øƒ„„ƒ„ƒ„ƒƒ„û‰ƒ©©þƒ„„ƒ„þƒ„„ƒ„þƒ„„üƒ„ƒ„„ƒ„û‚‰‚¨¨&„û‚Š‚¨¨þ§„„þ…„„þ…„„þ…„„…„þ…„„û‚Š‚¨¨ý§©……û„……†……„…þ„……†…õ„……„……ƒŠ‚¨¨ü§¨·††… †ý…†……†…†ûƒŠ‚¨¨û§¨·¼††…†…†þ…††û„‹ƒ©©ú¨©·¼»††‡†þ‡††û…Œƒ© ©÷¨ª·¼»»‡†ˆˆ‰þ‡† †þ‡††þ‡††‡û…Œƒ© ©û¨©·¼»»†þ‡††‡û…Œƒ© ©û¨©·¼»»†‡ùˆ‡…ƒª ªû©ª·¼»»†‡ˆû†ƒ© ©û¨©·¼»»†ó‡ˆ‡ˆˆ‰ˆˆ†ƒ¨¨û§¨¶¼»»†þˆ††þ‡††‡†ü‡‰‡††ý‡‰ˆˆþ‰ˆˆüŽ„©©û¨©¶¼»»†‡ †ýˆ‡††ø‡‰‡††‡ˆ‰‰ûˆŽ„©©û¨©·¼»»‡ýˆ‡††‡†‡üˆ‡ˆ‡‡†‡þˆ‰‰û‡„©©û¨ª¶¼»»þˆ‰‰þˆ‡‡ýˆ‡††þˆ‰‰ˆ‡ˆ ‰û‡„©©û¨©·¼» »‰ˆý‡…„„ý‡ˆ‰‰ˆ ‰û‡„©©ý¶¼» »ˆ‰úˆ‡†……„„þ…‡‡ˆ‰û‡„©©û¨©·¼» »÷†…†‡‡††…„„ü…„„……†ý‡ˆ‰ ‰û‡„©©û¨©¶¼» »„ú†ˆ……†„„þ…„„…ý‡ˆ‰ ‰õˆŽ„©©¨©·¼» » „ý…†„ „…þ‡‰ ‰ûˆŽ„©©ý¶¼»» „ý…†„ „ý†ˆ‰ ‰÷ˆŽ„¨©·¼»»„ú†ˆ‰ˆˆ‰‰þˆ‰‰øˆŽ„©¶¼»»„û†‰ˆ‰ˆˆú‡Ž‚´»» „þ…„„ý†…„„ø…ˆ…‡‰ˆ‰ˆˆù†yºº»»þ…„ „þ…„„…„ù…††‡‡ˆ‡‡óˆ‡‡ˆ‡ˆ†‹š°²³´´ý»†……„…ø†……„……†‡‡ú‰“–•–••–‡ý†…„„þ…††‡†‡…„…þ„… …þ„‡‡þ†……þ†‡‡þ†‡‡†‡þ†‡‡þ†‡‡†‡†@ÿ2þ12 2þ122þ1221ý21223û-A““’’ý32332323þ233þ2332þ322þ322ú3,AŒ“’’2þ32 2þ322þ322þ32 2û,@Š‘&2û,@{Ž2323 2þ322þ322û-@tЉ‰&2û-?j‡‡&2û-?j††&2û-?j††21ü211221ø212112211þ211û,>f††1þ211û,?f††&1û,?g……&1û,?g……&1û,?g……&1û,?g……1þ01 1þ011ø011010011þ011û,?g……0þ100û+?h……&0û+?h……&0û+?h……&0û,?g„„&0û,?fƒƒ0þ1001 0û100100û,?g„„0ü100110þ100þ100ê10110010010100101,?h……0û101100þ10010ó10010011,?g„„þ/00þ/00ü/00//0/ú0,?fƒƒû‚00/00/0þ/00/0þ/00/ò0//00//00,?fƒƒý‚„00/ 0ü/00//0û,?fƒƒú‚„˜0/00/ø0//00/0//0/0û,?fƒƒû‚„˜ /%/û+?fƒƒú‚ƒ˜ ž//ô0//00//,?fƒ ƒñ‚ƒ˜ žž0/212441/ /þ0//þ0//ý0/00û,?fƒ ƒû‚„˜ žž/0 /0 /ü0/0//û,?fƒ ƒû‚„— žž/þ0//û+?f„ „û‚„˜ žž/þ0//û,?eƒ ƒû‚ƒ˜ žž/þ0/ /û,?e‚‚û‚— žž/ý03//þ0//0/ü151/ /û,?e‚‚ûƒ— žž/þ0//þ0//ý20//ü041//þ.//û,?e‚‚û‚— žž /././þ.//.ú/,?eû€— žžü././/0þ/../þ.//ü.//..õ/..//.+?e‚‚û‚— ž žý./..û/.//00þ/..þ/../õ.//./..//.//û+?e‚‚û‚— ž ž./ý0200/.û+?e‚‚ûƒ— ž ž/ú010/100þ100ý10..þ/../ú.+?e‚‚û‚— ž ž÷0137213100þ1001ü321//ý./..ï/././.+?e‚‚ƒ— ž ž 0ý2400ú120//.././ö,?e‚‚— žž 0ý230 0÷/.//.//.//÷,?eƒ— žž 01 0 /ø,?e‚— žž0þ100 /ù,?d•Ÿžž 0þ200õ1310100270/ /ù+?_ŸžŸŸ 0þ10010ý12/ /þ0//ü+<}––—þ0 0/0ý/.//ô02/0/.1KNMNM MNù/00/0/00/÷0/00/0//00ð/0/0/00//00/00.++þ*+ +ô*+**)/00/0/00/0ý/0//0ú/0/0/00/ü0//00ú/0/00//ý0/+@"°¯ü® 'ÿýõ'ÿýç'ÿýé'ÿýê'ÿüë'ÿüì'ÿüì'ÿüì'ÿüì'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüí'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüî 'ÿüí'ÿûñ;þÿ'ÿü÷ôôóó€ÿœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû‹ŠÿÿûPTÿÿû5_ÿÿûMfÿÿœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû»ºÿÿû•–ÿÿû„ŸÿÿûŠÿÿœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû›ÿÿûKPÿÿû(_ÿÿûLrÿÿÐ ýôãüÿ—üÖÿ÷Q7<<;;<;;þ<;;þ<;;þ<;;þ<; ;þ<;;þ<ÿÿ ú#F7<;<<;<;þ<;;ó<;<;<;;<;;<<;;ú<;;<<;;þ<;;ÿ ü:A9<<;<þ;<<;ÿ üE8:<<;<;<;:;ÿ õG6;;<;;<<;;þ<;;ø<;;<;<<;;þ<;;<û=<;;ÿÿ úF6;<;;û<;;<;;û<;;<;;þ<;;<;<;ÿ ü7?8<<;<ù;<;<<;<<þ;<<;<;ÿüA::; ;þ<;;<ú;<<;;<<ý;<;;ÿû J7:;(;ÿüH7;(;ÿü5@8;';ÿü=89;$;ý<;ÿÿüD6;&;ÿüG7;%;ÿü5@8; ;þ<;;ü<;<; ;ÿüC99;;ü:;:;;ü<;;ÿÿû M7:; ;þ:;;:þ;::ü<;;ÿÿüF7;;þ:;;:ý;:;;þ:ÿÿü,>8;;ô:;:;;:;;::;::þ;ÿÿ÷C79;;:;:;;ú:;;:;::ù;::;;:;;ý:;::þ;ÿÿø L6:;:;::;:;ü:;:;;:ö;:;:;::;;ÿÿüD6; ;:;:;:;:ÿ þ„ ú)?6;:;;þ:;;ü:;:;;:;:ü;::ÿÿ ‚ üA99;;þ:;;:;:þ;::þ;ÿÿ … ÷H69:;;:;;þ<;;:ý;:;;:þ;::ÿ ˆ üG6::þ;::ö;:;;::;:;::ý9:ÿÿ Š ü+>7;;ü:;;::;þ:;;:9ÿ Š ü?99;;þ:;;û:;;:;;:9ÿ ‡ úF5::;;:;:ø;:;::99::ÿ † ùH5::;::;ý<;::;:ý9:ÿÿ † ö/A6;::;::;;:;:þ9::þ9ÿÿ ‡ ü<:8;;:;:9:þ9ÿÿ … ÷D6:;;::;;:þ;::9:ý9:ÿÿ … üJ6;;:;:þ9::9ÿ Š ü*@7;;:þ9::ü9::99ÿ ‰ 9û8::;::ü9:9::9:þ9ÿÿ ‰ ûC69::þ9::9ÿ Š üH4::ý9:99:9þ:99ÿ ‰ ü.@6::9ü:9:99ÿ ‰ 9ø7:9::99:: 9ÿ Œ ÷C58:9:9::9û:99:ÿÿ Œ ùG5:99::ý9:99:ü9::ÿÿ Œ ü%@699þ:99:û9:9:ÿÿ  û:88:9 9ÿ ‹ üJ399ÿ  üE59 9ÿ ‘ ü"?599:ý9:ÿÿ ‡ ü2:69 9ÿ ¾ üH689 9þ:ÿÿ Þ üG599þ:99ÿ Ÿ ü!@59 9ÿ  ü39799ÿ ‡ ûB5899ÿ ˆ üH499ÿ Œ ü$@499ÿ  ü2;699ÿ ‹ üD5899ÿ ‹ ü F399ÿ  ü$C599ÿ Œ ü:<699ÿ Œ ü?4899ÿ ‹ ü E399ÿ  ú$C599ÿÿ  ü9;69ÿû Š„‡††þ‡††þ‡††þ‡††þ‡††þ‡† †þ‡††þ‡ÿÿ ú0†ƒ…†……ö†……†……††…††…ø†……††……††þ…††…ý†…ÿÿ ýP‰……þ†……†…„ÿ üjƒ„……„…„…„ƒû„ƒ‚‚ÿÿ õy‚„„…„„……„„þ…„„…„ü…„…„„ü…„ƒ‚‚ƒ‚ÿ ü$…‚„„ƒ‚ÿ üM‡‚„„þƒ„„ƒú„ƒ„„ƒ„„øƒ„ƒ„ƒ„ƒ„„ƒ ‚ÿüb‚‚ƒ ƒþ„ƒƒú„ƒƒ„„ƒƒ„ƒ ‚ÿü y€ƒ ƒ÷‚ƒ‚ƒ‚‚ƒ‚ƒƒ ‚ÿü"…‚ ‚þƒ‚‚þƒ‚‚þƒ‚‚ÿüJƒ‚‚þ‚‚þ‚‚ÿû[€€‚‚ù‚‚‚ý‚‚ ‚ÿü qþ€ ‚ÿü$„ ø€€€û€€€‚ÿöI€€€þ€€û€€€€ø€€‚‚ÿÿþbü€€€þ€€þ€þ€þ~€þ‚ÿÿü {}ø€€€€ ~}þ~ÿü"}~~~ ~}þ|}}~ü€ÿÿû=}~~ô~~~~~~~}ý~}||ø}|}|}}~ÿÿú^z}~~}}~}þ~}}ô|{{||{{z{|}ÿÿü u{}}|ô{z{z{zzyyz{ÿÿüwz} }|þ}||{zùyxyyxyÿÿ þ¥ ÷6|z||}}|}}|þ{zzyþxwwþxÿÿ ¤ ü[{{||ü{|}||{zyxþwvvþwÿÿ ¥ ûoyz{{ü|{{zzy÷xwvvuuvvÿÿ § ú {xz{zzþ{zzþ{zzyùxwvvutuuÿ © ü9|xz zyxüwvuttÿ © üXzyz zyxwývusstÿ § úmvyyzzýyzyyxw÷vutssttsÿÿ ¦ ù{vyyzyyízyyxwwxwwvvuttstssÿÿ ¦ ù=zwyxxyyxúwxxwwvvutsÿ ¦ üVxvxxwxwvuûtsttssÿ ¤ ügtxxwxýwxwwvþuttsÿ £ ü|uwwvutýstssÿ ¨ ü7ytwwúvuvvuttsÿ ¨ ýNtvvówvuvvuvuttstssÿ ¨ üetvvøuvuvvuuttsþrssÿ ¨ õxruvvuututtsþrssÿ ¨ ü9,11010ø100110100ü100110ÿüE..0 0þ100ú1001100þ10010ÿû K+/00þ100ÿüC*0(0ÿü;8,0'0ÿüB-.00û100100þ100ÿû E*/0%0ÿüB*1101ý010 0ÿü<8,110ÿüH..110ü101ÿÿû N+/1 1þ011þ211þ011ÿüC+11ú21121221ÿü16-112û121122ÿûG./211þ21 12þ122ÿø M+121211þ2112þ12 23ü232ÿÿüB*2 21232ÿ þ– û-8,322þ12 23ü23433ÿ • ûF0/3223þ433þ4ÿÿ š ûJ-122þ322 34ÿ  üE+2 2ý32334ý34ÿÿ   ü08-33ü23322 3þ433ÿ   üD1033þ23 343ÿ œ ûI,233ú4343344ÿ › üF,33þ23343434ý34ÿÿ › û4;-433434þ344ÿ œ üA3033434ÿ š ùH.2443343434ÿ ˜ üH,44343ý4344þ344ÿ ü/30434434 4ÿ ž ÷F-2434344û5445ÿÿ Ÿ ûH.34 45ü455ÿÿ Ÿ ü)=/443ý43445û4545ÿÿ Ÿ ü>3244þ344ü544ÿÿ  ûL-344þ544þ5ÿÿ   üF.4 4ü544ÿÿ £ û&=/5445ÿ ™ ú76145445ÿ à õL03554455455ÿ Ý ûG/45 5ÿ « ü$?055454ÿ Ÿ ú7514544ÿ — öE034554544ÿ ˜ óI-554544545ÿÿ œ ü(>/55ÿ ž ü78155ÿ  üH0455ÿ  û G-455ÿ ž ü(B/55ÿ ž ü@8255ÿ ž üB.455ÿ š ü G-55ÿ › ú'B/55ÿÿ ž ü=715õ $1=FPÑÿ0ÿô0CUdm‡õÿ/ÿô 4Ldv…ºÿ/ÿó2Lg‘ž¥Ûÿ.ÿò +Da|”¥¯»ðÿ-ÿñ!7RpŠ ¯¸Èüÿ,ÿñ &>[w‘¥²ºÙþÿ+ÿò ,Fb—©µ»äÿ+ÿò3Mj…œ­·Àóÿ*ÿñ"9Uq‹¡°¹Èûÿ)ÿñ (@[x‘¦²º×þÿ(ÿò -Fc—©µ»áÿ(ÿñ3Mj…œ¬·¿îÿ'ÿ ñ"9Tp‹ ¯¸Èúÿ&ÿ ñ (?[w‘¥²ºØþÿ%ÿ ò -Fb~—©µ»äÿ%ÿ ñ2Li…œ¬·¿ôÿ$ÿ ñ"8Tp‹ ¯¸Èûÿ#ÿ ò '?[x‘¥²ºÓÿ#ÿò -Fb—©µ»ãÿ"ÿò3Mj…œ¬·Àñÿ!ÿñ"9Tp‹ ¯¸Æöÿ ÿñ '?[w‘¤²ºÑýÿÿò ,Fa}–¨µ»áÿÿñ2Lh„𬶽îÿÿñ"7Ro‰Ÿ¯¸Çúÿÿñ &=Yv£²ºÑþÿÿò +D`|•¨´»ßÿÿò1Kgƒš¬¶¾íÿÿñ!7Ro‰ ¯¸Çùÿÿñ &=Yv¤²ºÓýÿÿò +Da|•¨´»Þÿÿò1Kgƒš¬¶¼ìÿÿñ!7Ro‰Ÿ¯¸Åùÿÿñ %=Yv£²ºÐþÿÿò +C`|”§´»Üÿÿò1Jg‚š«¶¼éÿÿñ 7QnˆŸ¯¸Åøÿÿñ %=XuŽ£±¹Óýÿÿò *C_|”§´»Ýÿÿò 0If‚š«¶½êÿÿñ 6Qmˆž¯¸Äöÿÿñ %=XtŽ£±¹Îþÿÿ ò *C_{”§´»Ûÿÿ!ò 0If‚™«µ¼çÿÿ!ñ 6Pmˆž®¸Äóÿÿ"ñ %<<ú>??;<;;ù<;;<;<;;<;<;þ<;;ö<;<<8@L;;þ<; ;><ú=>@A:;;ó<;<;<<;;<;;<;;ù<;;9:U;ü<;<;;<;þ<;;ý<:;;ü<;;<<ø;<<;<<;<<ø;<<:7Q ;þ<;;<;ø<;;<<;<;;ù<;;7I( ;ü<=<;';ü7B= ;ú<>>=<;&;ü9:O ;<(;û:7Oþ‚; ;þ<;(;ü6K/þ„;;<(;ü7AJ‡ ;þ<;;þ<;!;ü9;Mˆ;þ<; ;þ:;;û:7M‡ ;þ<;";ü6H'„;ú:;;::;;ü7@B‡;þ<;;û9Rš321õ01100/0010112ü/1Wœ3ü43322121û212122û1,Q Ÿ3ö4334331121121 2ü12122ü+G* š4þ32212þ122þ322ü- 4þ34434þ344þ344ù34315V›434343434þ344û3/T 4þ34 43þ433 43ù434.M.ž 4þ344û34334 4ü.@<ž4þ3443 4ü06QŸ 4þ3443ñ4343344334420T› 4ý34334þ3443ü-J˜4þ5443 43ý4344û3.?9Ÿ 4þ544þ344û316Xœ4û54554454û343344ü21Oœ 454þ344ü-M˜þ544þ544þ54454ü-CB™4þ54 4þ544ü16ZŸþ544þ544ü3/S¢ö54454545544þ544þ544ü-M›5þ455û454455þ455ü/D?•5þ45 5þ455ü17Q›545þ455þ455ù453/Rö545445454554û545544ü-N& ý5455þ455454û50C:¢ý5455ü17P 5ü3/X!š5ü/L!›5ü/B."š5ü26M#—5ü32Y$›5ü.P"$¢5ü.A-%¢5ü08K&œ52þW'¡5ü/R(¢>ÿþøÿ=ÿþ’ÿ<ÿýÒ+ÿ;ÿüïY#ÿ;ÿüŽ4ÿ:ÿûÂB)ÿ9ÿúÞQ1 ÿ8ÿùñh7!ÿ7ÿøþ‰>& ÿ7ÿø¶F, ÿ6ÿ÷ÚV2ÿ5ÿöõo8"ÿ4ÿõü–>& ÿ4ÿø¶E+ 4ÿø×P13ÿ÷ïi8"3ÿø>& 2ÿø½H, 1ÿøÑO10ÿ÷ðh7!/ÿ÷ý’=& /ÿøµD+ .ÿøÏL1-ÿ÷ñf7!,ÿ÷þ…=&  ,ÿø³D+  +ÿøÎO1 *ÿ÷ïb7  )ÿ÷û†=%  )ÿø¯C+  (ÿøÛN0 'ÿ÷æb6 &ÿ÷ù~=% &ÿøªC+ %ÿøËM0 $ÿ÷èe6 #ÿ÷øy<% "ÿ÷þ¢B* "ÿøÉI/ !ÿ÷âY5 ÿ÷ýv;$ ÿøªA) ÿø¿H. ÿ÷ã[4ÿ÷û{:#ÿø®A( ÿøÀH. ÿ÷âW4ÿ÷ûy:#ÿøžA( ÿøÂH. ÿ÷á^4ÿ÷ôv:#ÿø›@( ÿøÊG.  ÿ÷ÜW4 ÿ÷ôn:#!ÿø—@( "ÿøÇF- #ÿ÷ßZ3#ÿ÷ñk9"$ÿø’@( %ÿø¾F- &ÿøáS3'þdÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ‹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüJüüüüü ýýþžÿ “ üE58ÿÿ “ üF4ÿÿ !’ ýBÿÿ "Ž þ5ÿÿ #“ ÿ #“ ÿ $ˆ ÿ %Ž ÿ &ÿ 'Žÿ '”ÿ (“ÿ )ˆÿ *†ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<Àÿÿ ¬ üblmÿÿ « ümkÿÿ !« ý"rÿÿ "¨ þEÿÿ #« ÿ #« ÿ $¤ ÿ %¨ ÿ &ªÿ '©ÿ '¬ÿ (¬ÿ )¦ÿ *¦ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<Àÿÿ £ üJ13ÿÿ £ üH.ÿÿ !¢ ýAÿÿ "› þ9ÿÿ #¢ ÿ #¢ ÿ $” ÿ %œ ÿ &Ÿÿ 'ÿ '£ÿ (¢ÿ )—ÿ *•ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<Àÿ0ð .Gd—©µ»èÿÿ/ð4Nj…­·¾ñÿ0ñ#:UqŒ¡°¹Èû1ò (@\y‘¦²º×2ó .Fc—©µ»2ó3Mj…œ¬·3ô"9Tp‹ ¯4õ '?[w‘¤5ö ,Ea}–6÷1Lh„6÷"7Sp7ø &>Z8ù ,E9ú29ú":û ;ü ;ü<ý=þ 9ü4C+(þ89 9ü6& +ü¸Èúÿÿø³E+ ,û²ºÕþÿÿø×Q1-û¨µ»âÿÿ÷óf8"-ú›¬¶¾óÿÿø‹>' .ð‹ ¯µÀ÷ÿÿ³E, /ñv¡©¦µÿÑL10ña|˜”…žm7!0òKdx}n_B% 1ó6L]fbT@+ 2ô$4BIF;+3ô */-%3õ 4ö 5ýü7yÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+ÿ8FM#&ivy-2.4.0-rc1/doc/images/ivy-forum.png000066400000000000000000000243111226750426600174770ustar00rootroot00000000000000‰PNG  IHDR³‡]ÿhHgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<([IDATxÚì Õ™ç¿<ê>û¾O©uKèæ qÉæôŒÙ°‡5cf±Ã³Ä¬7Ö³1ï31Þ1;»6ƒ™ÀÌ|À`@c!a:ÐŽ–Ô÷Ý]Ý]wû^Ö¡W¯^fUWWŸÊ×ñ¢²ª²²«2ùÏÿ÷½#9UUÁ,fY …7wYL˜Íbf³˜Å„Ù,f1,"ýÂ`llÌÜ3fY¥¤¤6oÞœx‚³d]¿~½¹‡Ì²`ʦM›Òìf)³Óé4÷ÐÔ 7CÛ5ó¦9 É«h€ÊnÕ¾HžÙ×ðuޱ^>ËS…2×2ùÈ™›0ç.gðùœË¿Þÿ35µÌX5€[Õùª óâ˜Ë0ÇÖ赩¨¸È,˜UÆs£÷XÐ/z¸Å+ ^È«QMåäyƒuôÀÎ×fä‚6õ¾B<ªÄ£šð,¸Uæ…°Äè=ÜÇxc=;A*°¨Îù–/+Û\³¡òN7‚8¡>JB7Ì’רz¡*X…Z0~½lYéÝÈzü¦çPß+¡¡pœ“Ç!FùhŽHï‘­’Úf#cQ8ñëS\˶&-/=Sé»YƒY°âV¼ˆö£¢ã1=[Aúb ÃÛ¨ª^Òâ[[·¥öd'¶âíh;ËLT8ÔJ"ž@âSU}UÕ£em¥;û ¼Øs°ïµ¤§¶Ç)–<~d&(¨5 O½r†k¼®^m¼¡~á¦æxrp „@>MƒÌS9cA'°³1*ï(µ7Ô_SwwÅòÒ[8‘·j—Kuá¤ÒB6Û3dÝð~þ¯êÛ»ö=;plðý¤º¦Ž[œ8–´åÂKk>7þµÞÒ\ôC4ã0ck É_¦=^ÇVÁ ¯=¥¼…wU¯«Ü^·µö 6µZA…bv3®Ôv¿}Ý’[›Pº´äõ޽?ìž'Tšî^+Q öÒûº8Ñ&¨8vZ00ãŒî táK¹@&[çhOŒw–#¥Æ®JWkóM _ö7û®Iíd³ÌVDÁX ¥-þ{¼5îÍèùIß‘þ7’Á5«8™QKêvÄòæê‚Ÿ‡§_=˪©—rc©±÷<³U¯¯ÜÞx]݃—¥\Kó˜¾xN²^tu¬kÞÞø¿üÍÞ-ío_z ]};“ÇËh8YÐHˆÈ‰óf¤œÑÀdRíDÅ3|ðÞŠÖí_*_Qvû¼ë'q[ ¾ï^û¥+.¾ßùäÀ‰¡½ÉãF«3è)4dv±·0³úóT¶‚Tc{òÑ‘¬ø¹è©u·µÞÚôˆ§Ú½+¼ÖÒ îæMÁ*mq‰Ë–ÞÑòG¹ãG]öü‰šG^t ÅY™×™å© ¢rUÙuÍÛ›F;«ÂTãùì¥Uܪëj¸¦ö¿¹ÊMgß¼ðÃxPëgã.EEz¦§´ÍäÄ®dÅËÖÚMUŸ[zGë·,±ÂÌT,Û‘´¥KK\u_Ûߨ|¶šäq·CfWÖH–Î ˜9é–¬Æé@Ϭ ²âÖX«×ºrÙç[ÿÎטÚ¦c9xÈžHgÞØ R‘ì…+ ³­ñúú{k6UÝ›Ñ$m–…b =ÖåmŸk}ÂUálLò`c(4ÝzXÐ|‘UY¯uO$@ÎPdü^í¦êÛ믭¹?1Þ΄`Q‚w»Ïº¦íÎÖ¿¶º-I&¬ÄÕZ4gf£|2 2+è³T¬*»¶y[ÃCȦG^œí®rmYv×Ò¿¢²ÇgŠÅPçb{fdÒ+Ó>YôÔ¸ÛZnnü*ZÛj‚¼Ø–ÁßìÝÙ²£ñB­Àž·¤  Å"ld/H3: YœbYëmMbõXJµ©žÌV½+èÊ5åLöLží=4ðF’ Ö„™³*ͺgæ {Ô4Ùï‚TfkÓ ÷â¦êÄœef¹"JbKÓM ÿû¥ÉWY)©3?M€YÙ ÚbÐ>Y(_U¶µrmù-fËÞÈ3–ej›onx=º ³Î´rÏÅ zÑ=á,ÈVT7]_÷ÇÏñª™º¸23’þïŽÚMUw'íD>)9Á‹2«Ùšî—lm¸®ög¹£·q¦O¾r–¨¿ºúÑ‘ócûCnRcSÓ‚å݉ŸÄ`2k´ˆà©s/¯\S±­èšeáÙ EÑa©i¸¶ö+™{&R¦d7¦ë™õòÊ"3žpÛ‰¾øm¢M°™i8³hêŒb¦²e%÷–´ú®Jª/ÉÏ”óÎ|ëÁ,@öüš*û›½+Ñ—Þ`}fI«3Š™ðÝê¶VOÌ®ã›óVçb(3k8r,þ’ŽšM•Ûx '¨ ˜qÌJtH’Á×ä½Å×àYCÄq¬F”œEœÈúSž{å%H™×^öʦÍ0KJñtœ½fCŽcÇ&_ŽSÊL‚º¡X Ä¬É éæëtW¿ªuå[+o™/ $øò“bG5sfz^»Õ<Ç›¤ÍZªN«o‡»ÒùÜä@:³‘H™Òsu&”YoºYhÑê±V`ƒ¯Î“!|Ñxxìú– °ªq5XE[ú=Y‘¡¬ž?ã¡qèÙÌlØ…²²•%×#˜Û «!Qê\t›A«³ÞüÖDàçYn÷[Kµy.æ8¯І`ÓÒÍðèíß„­A,ÌõþÓ¿Î} v‹}f”HQ²îU‚OŽ‘xWT%ë?x½Åv¢áŸX²Äsׇ}/É19¤Ή2§'þ.m󯙈"±0¬k¾ ž|ä‡àuøæì{`6GòÆR—‹¤H ÉÙÓ½âŠ_Aâr|qY YW¥c-ª­ã]“Ç€ÝH ©Z ˜õnÉKÏÜ)XÝ–ROkÉ\[ ¬l/ŸÞöd¬”d?œ6§öûæÔç´ ÅQF X鯆øÓ§ ÔS–ñÞ/?ø9üÓ›OÃêÌXŸ|ËêVd¬û»C¿…¿ýõÿ·Ý½ˆ¤ÏöÃ9ý­Þ Ìôt_P¬0פ.tzŽGgYÕg-™ëÖXõªKkàêe×d½÷Á©÷áûCèíÓ”ûª–õÐ;Ú«yk 5Ÿ—OŒøá MaEüÞf|àyÊÈ~WIÆë.»‹y¿@¿«J¨u=,Ö~-Þ:÷Fôð"#£ÁåòÎ…f3Xªœu=O½»™xNNÜn`n._¾¸ƒ* ö¬ïMF&áû/?çûÎiо{ümxý“ß@¥¯ îÚz/l[³VÔ¯ŸÓOQ¸4xö¡“`Ïñw c°©©ƒéwõöËNà«CVF•Ö"{]l3fânMó!tV8VÚü¶ÒèXt²où,35`<Ó= µÍ]íªŸËA}ØØDRV*š³Þ  BMI­ösbR¶,Ý ßõmXݸVw»øÄØÚv |eû×à™·~¿Ø÷spXòÚ,± ·µ ßD ÁܯrÅ9Ërpg³y­•sy5 "åýÚ÷_û%°PªŒKµ¿^þήôsœwvÙ\È>8óÚ~¹§¾óÇ…”ÛÿüûŸh m–iúfÌÏŠ§Ö? Sl,Äf°ÎZ9»ßæ·z­¾¹œèÿol|.¿®Å æ*ûO';CCy#ܸz{´íüœí=ƒ,Ê+`³82v– iøÿ`Ž…5k£ëw6#×µoK³(tpʱ÷GÖº‘l+xœÞ4!d±pî=oÏ?ãyKíËb«Q™dSìÖf®X©9½Œ}o| 3/òÂ\f2l;RÕ½0¥5Ë`; èè,Çk¿¢e'¸îË BÆûŸý^Øû{OîÑØ=[¿ 3:ØÏ¾ý´–xðúÿõùÝŸþNSg¤/ËøÙsümxä–G™ ‘«Þ7wþg¸ Y“B¥ÊÂh¥,q•Âÿxà{ðÕmÿ1ë½µMë´ŠÓŒù¯ß†¦ŠxüÎoÃöµ;²ÖÝŒ‚]\kKêàŸ~ÿcpZ0 'ð^¯\ô0gç>ô…¬œ0·é#-›€ö¡?½ _Žñg]f‡'ÑY™é?±z‡Ðå}"<ž•+¦ öëù‚¬5Ì0\¡Êði7¬¾ n„m†ÛÛ¹ñNˆ£“uCËäõ› ×}ô¶oÀöáHû!MæÚj nœÝâWÔþÌÜTÀFl !Šaq;Ø-i19†vÇøŒ¢Y”©ìYñ €}* P/ DÉ&j|EÀ©BE‘;<¿ýz÷–{s‚œ „ïÙò…Ä÷š1gã‘&\1m†ÞF¹Lû3åyz ŽuCí‘w… o<õèÓè±2ó’¿d+´T¶Â…ó ¸QP·ªa ”{+˜Û™ÑìÎ@ Y…«µÏë•î‘.Í2án¯Û‘w^ZÝÆ°'kÁ‡‚C@òœ0×ÇJ™‚˜NÛfä^Á‘ÇhqÅ *úÛ™ïá~2µ_ý<„¼.ÇQ¤¬Ï¿÷,œè<”׫íç}Ê‚§ý~úÍç5èpCÎ5Ë®ƒõ«˜žùÈ…Cðíçþ\ÛNLŠ#;ã€ï>ðܹùž¬uòÖàçïÿL;‘dEÛû3øÇ?{V֭μ28üZæ'„þæ: T5ZhŠm:2§2ÞK,ÈjL™os,³vŠâ/¶3/ç«×=ÌKRâZ‹¡ËæÎkO9í.p;Ý`- Š":9d¸4x‘¹:nFèÆ¯Â×o} )åULqéî€îÑ.mÛ~·41Ø{jsÝÎì‡ñȸ–’Ãëâ8à½ïf«/‚°Ïƒã„`Bv u&`Îç:ÎÉ19‚€Vç{/>ˆÝ#Ýpøâ¡¬÷>·ñ.M1ÇÃ-ã}/ÞÛ÷_û`áWd]~¹ÿ¦ofV?€$èø9ö÷zéI2ë‚î_ @çC&´IbÆ ñ§üeÁ«ÏÓßI)¨`›ç1 .†ô¥?ü2ë=l¾ÿ•€îÔº[®m\O<ô}­]ŽuÍ  ×tâüð' ×Ã^ø»¿øïÐÞ^Ç˦€žÏE Ëøfó2dO¦¨©t!ž™Ü BÁšÍ¢Øx<,…í>«uÎdÎø=—Ý ¿?ú&ܰò& \²¬ª_£ŒNj‰xFnùD×qxö§áÿ<ü#ã\Oh<·ç§pq î»ú~Xݰ6ÝÍtdrHë½÷«_€®áNøÊMgm2K™Oâ*ß™'òêÊ3 ±²:¡PÀEiBL+³J¡èXlØ^bó<¿#ÁT†¿yù{ZJìóïÎZGÏ#ŸD ?þ/ß@>ºfJÿç·÷œ|öŸÙ§õßH)+î4í´¹˜*:_œ=ô´ä‘ªLö†.QŒ©ùر€Y–#uI uŽ…G£ƒþ%ÞÖ…°5ß)Eá{¿ú+m@+nÞÆ),½q‚=£ÝðÛïà <½£=ÐZ9õŸ‰³%8;‚{÷‘v!5â…å—õlÆb(øü”¢òD<$õ§ìóT€.Ôf–Ba€Œ—¥ñK5+®žë”èp” ¥ Ž0¸®WüÞ<² VÖ¯‚e5+2†ZE¥tuÀ'í´F¼]¼B(­uiNóºófž‡ðPèbh(ÒGÀÌš ¶X È, eªB°?ÜJ1Aä­s9Ì0ù¬çüø­ÿ—•)ï×:Ù¤|bbÀ©S³Ÿ^:¢A«fäš9MÅq§­+h2]—ӳ⠦ëƒõÖÍw»³ì—ñ9 ŸTâJ„Á׌(3P^™ZJV54 „{½î&5>w0ãÆÜXq¢ëXÖÑsicüæ¥j¸š!ÀJoŽ>™Š_uäLà!ˆÊT¬Ætl†ªqºª²\˜8çkv7Íå~Â@ÔúýZf,€Äý*p3Y°ÇêÏMCêD!û±:Ôë4¬×Yž[/6˜=‹ÁAt<Ö3Ñ<—ÇûÑ@-Tu|³¬4¾öZGÎŒ©»¶ò&NàÅÅ:•-Îã‘&_|òά÷p«Xøá‰aðؽ¯#Á Hñ2þ?#“ÃYŸKñ¬uq¯?zÝòÿsiyƒñŽÉɬ*#›QeÖóË)5«1Ùêžè ]ò·z–ȱÅ;a¢Œþ¤X<ËÆð<_°ÅÍßñü·²zîá{Nb´ î'räÒ!t2Ý• 3ºbVÉíðÀë‡^AîëYW/|B°®³rõTA<1ú~’'‰yN`Ž0ãöÕ8RãÐàÑá£æE‰ã?¾øY <}ø°ºÒö÷ùbóò5{²>X±éào®R~¼ÈãdÁ©±óã'ÒÚ ³¡í†i-S#–„9´2tjìTh02Œ¿´Y¦x `XÝÉÊòÁ\ò*µ.ã²ÈšQç0wÍ!‹1pdè·rTP,É: «Å‚Ù(”)q•¤4Òdø“¹yb–yx²" G/ù I 2Ý?£¨©9r²gÕÀfĨj8Òþ»®ÝrL‰ã³Ô,W½° 0|:°»÷£Á·’ÜD ³m‚Îbäú*†4Ò½çd`üÂ0zfü|Ç»½ûðYjf7®¨ìŹs¯v<‹ìE˜Á…ú­~3î™9b™Õ§™„š^†žýý‡]Uöʪå«ä˜éŸmÁ}•EPŒ4z~WçSÑ@¬/É@„ZÏfÌš2ÓgÂé&Jí TdU:¿«kÿÈgN^4åy1|VòGÏŽKòf€,ªÊÅ‚9Ÿà<õœ“ÂRðâîîƒè²#›ýØ!ȸ£“À)ßê~ºÿÐð{ÈQ2Ž¢®è*Ì𼌸tÚEl¼½ù–ÚÍÈO ªyKíErB•;ßïûY×Þþ]DÀ¡@–¿¬¢ÊÅRfÖ3z¶sÖ­#TtÖòm÷6m/[é¯Ç÷O6ËbSdº?èþÒîž—’V"B¨2+ð#³S.Ó™lt ¥o©&ãž'ø /¹³áæÊeˤˆlf4ŸµP;÷ô>wiwïËɉiõI RåB`Î2ymò^ÚVb¯£6ßV{síµ›•¨Ùƒn1œjEv1Ö¾«ó§Ýûހ˭ÀaÂbªLwõ,ä©Âl2}SËÀtÅïq;jnmØV»}‹öN£W$ÈÏ7r~Wç3‰`ONBLƒL}Sn ™Ìù€LŒÙ©Š_švÔîlÚQ³߸Çy±ø ܲ‡D"íç_ë|zôìøñ$¤! f²EØ({1+ž™²À™„Ù‘Rå–õ÷5ÜXõ9ì-Ö‘ÚW¢?æ-Œœ |pîÕŽç"£±ä#{ãQ$ƒ!æ 0½¬ç‘Y0kï·ÝÓøPÍu•·*±¤"›ß‚/¸§SB—v÷ýºëý¾7ÐòDÖ0Q£È´½( È…xæ\AŸ…ZDQ­½í M_«ÙR¶MÂ]>Mk±HÔ˜‡É®ÐgÞêù·ÑÏG“F)[‘îË®ðõ¦7…€´Åu<3¾±¥sùýMU¬+ù£È& Ýcˆ•¨îú°ÿÎ=}¯ÇƒéQ"t g”‚Ë{ÄõL{fŽüÑP«·è]ñ@óã¥+|[µ<²Yv¦÷á8\˜8ÒñvßËcç&NjK{cV£ˆQæ¢(2'æ/ 1«„„Y¶—X«V<Øòo³{½ òcKL0éêÚ;ðúÀ¡á}Io,3”˜e+èÖ=¥ØŠ\ e¦í®qg•½nÅ—[¾ë®q¬ÖºuÎD ÇSѦŸã;â{v›¶fz¾A ÷~»÷ÃÁ=Ñ@¼. ‰@fd æÀTw­¯.LÂlÜ«ÿ…6y‡§ÑµlŃÍO8ÊlËÐÙ› _‚¸$ˆÉeúŸdÌ7L¬ ÉÛª‰”ZVå¸EÅqíyD–Ð{èU¬¼ÅQa/Ã)#ô®™ÏžŠ@JŒûÇñ‘Á££{{þ0ø^x0Ú™„2FL*1 ²núÍQnƒuÖ¦¶¿Ös³ܸÈH‘«×<¼ä¯ídœ~íB"q‘PÅS¡)qEBG‘õÐ:²š¸¿­ŒþÐ;¸*Q9*‡¤ŽMÆ'ˆrd4Â7ãCÀÊh[2^-+RX©Š¢H%†oц fíxXx[ÉroKõÖò ¾÷ˆ Zk£™ÛÖì c5Ž Eúíïÿdx_h0ÒMX…2©Â´76šôPyÍ#KU[‰õgL§oFÆë±ñøäg¿¸ø÷(ÚmÀÛÅ72¬¢*pX-„ ó‡@ƃñ8^†Ë½öXSüÓg4™£[X)B­¢:>vxøÄØIO“»¡zKÙúÒ徕V¯è ¯Í¨drôèH&»BçÞ?t"p0ˆ `F©£ÔX"Rn¬ÞoiQ ËïoR¥6PbÅï“3ôd@‡”22òÙø´Œg>·):º“‘HÙ€ì&¬ÿà Xi:»‚;¼Œ_œ<…êYd;*ËWûW¢ºÆUë¨ç­N2ä­Õ+ ì„Nìv$@c£ç&Ž~:úQ }â ˜ñäñÔ›û$FLg*tç†kºµVmºµFlAE‡0§0È–’Y)XSä&‹áuÞ^½ûÀ±š•ûÖÑÎÎ=}]Ýû>ôÔ;*Ö–¬ö-ñ´9Ëí•Ø#b°µºØü5—89 >’ƒcç'Ï Ÿ|:v~âDx(ÚŸTì9ó±¤Ó·Ò‹K„ºë+Õ¦[j`¦ÛÄ)€Ìš01+G­K.PÊ©·}5ef£Ì Ù*™nnG—7)Ð>9Žêi¤>v}Ù*ÿ2O“k‰©7аÅD6$ÙD]€ðrZbm¤¶U±‰xÛˆÑ3ã'QÀu:ØîMz_…ìb p f©q†¡ø Ö"Œ®Š0f…ÞmŠ™åävãÈf=XõZ‡Œl†^wTêtEÖ(>zvbÕã‚•w;«U¾Vw«¯ÉÝèªqÔ#íE1¯…© $2)êü\ËöðIx¹Ä÷”"R(Üí ö„ÛÀg‚½áKááè`RiÊJ° ¥óÄ$ÈŠ¥Hï™ú›ªÔº?ª›ß 陫¸<¢¯YRf–Íà’? {f#ò³ùØ ½×ô’ëz 9¹€éeNtGQ=Ûý›Ïâ·—ÚʽM®W³ÖYn«A¸O´ <(ÕÇ$™*LdmŠÚÀÈ«'-Ç]¾NâïGÁ7²Q½¡¡hºâ\Š FºC‘tu 6Oa€Júß°§…Ý9HW—Ü]¯–­ði'¾›½ÁbsԲѷS˜8F Ç1À̯ZÌ4Ð.=†×X4ãFtYÆÍ¶"Rh§£ÌVbq‹~w½³ Y’ «ÇRŠ”§ùB˜‹ÖÓB2¼·jð+8æ/Ãód¢ URU<'›‘#Ñ@,—†¢cÑ¡‰®Pot46€¾çHt,6J€˜Ú—´²æz” ü°á­Ì°×\]®Ö\S®¥ßÐUOû8×Ï*¸ÿs±'ÏœN6C¡–êrϺE"Ç8œFÐæ£Ì` Î¬¾#zÕÂ8R8OE^cç&ÒÛRÛ<q‡àâ­¼ÃêµúeV·Å):ñ{è5;/òȉstðìès\úž ˆR<'ª–kGnU­UÂRX át'²9"O¢Ku0”&¸ã|zóýUV'Aö\'ŠPI0[vÖª¸U/2ƒÐ`$§m< ß3çÙ ,m;x*Ã`䎦5ë3\ŽÏ i¨ƒeúd` Ðåh¡PD6ðñ¬{¤ª"z"V^öD;2°'Ü¡_‹€«§Âz7ÉQ±•8ýÂÅ9 Ufj½ C¡Ûj'.O Y`ë̪<ã‘g\ô Îe³âÑ踊|F•»¼¬ ¾ñ™7EÌ4Ž rŒƒ“o¼ªNñõ\6ƒåŸòŸú@tŽÈ›³ Îä|c†|€¦{ ‘y|VÊL68 ô6º½ï¼MVŠSTNN'ÃÁåPÍ|A妱ÃÈF…VIÐd*…g¤¶c™# ò9×É­—Ž4‚Y5Q6PqÒ¶ÈÔvÕ… q±l†^P—ï(Ö#¿ƒLÁ¤èä£%KbT9ENÁ­êÄ ¹®R,¨U/­§ØFUe,³N¢ðt`.ØÙ(,egùxô§ã €ÍÇNð:q—#ÇyÀ¬×ùŠVk½uXFàq1ažOEÕ ¶TF 9ÀÔ{®g'Œ¬E>•‘12‚tTVÉñy0h+XÐSÌF`ëõíP ‚6^g™3øÌT,†Ð,Õ)VÖ6ÀW Ìù*6ä‘ËñòTd.Ï”$ î©ö*¼"à½Ra6:˜zp磴F‹|Ò”¹Žô ȯ‘iQÃkœ†Fð|•—Ë#u©æÈåjâ¿bÁ5a.N††ƒÂ¦“⊟9àË„yV@7!œÃ’5ò#›{Å, ¦¼f)ó3Ï<@ÀÜKfYÅçó]öqæ)fY,åÿ 0U&›ÆÏ ÉIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-lierre.png000066400000000000000000000356371226750426600176460ustar00rootroot00000000000000‰PNG  IHDRÌ»üõgAMA± üa pHYsttÞfxtIMEÕ#2¡¹yçtEXtCommentCreated with The GIMPïd%n;IDATx^í}‡[gúöïûc¾ï·}“ÝMɦm²›lÊn6Ù{Á%jŒ± PQ¤( bEDQ+ Š€"" ˆXQ)bÉó=÷; §ÌÌ™™s¼s]çÚ¬L½ßwîyÞ§ÜÏÿ!ÞþGn‰€DÀ ¹I$#ü‘ƒä1‰€D@¬^$ ‰€DÀ(’@Œ"'“H¤"ç€D@"`iÇN)èóHéóS@ 0Ž€$ãØÉ#%}I }~ H$Æb;y¤D Ï# ¤ÏO €DÀ8’@Œc'”ôy$ôù) G@ˆqìä‘>€$>?$ãH1ަ±+Þ¦ñ+ߣQoÒÞ“[tƒ HŒ!´KcYÊ$¶<Þä1aÕû4.ò¯4)êTS_a y”D@"   %Cgv²åñWún廂<ÔßÈðWi]Ö"] È%c% ê2)ê±tq$ü÷x&”áK^¡æÖfcˆÈ£$Í%„&NSgòp´B6ç¬Ò ‚ÜQ" 0†@ÐÈ‘³Y42âÕN¿‡+/dZìôüésc¨È£$MÜØ@³vF]ÜY ð‹Œ_ù>•×”hAî$C ¨dÝžP¾ôeÖ‡J*!¯Ñš]?CE%hB h¤òZ\úºp’º³<ÿ}Ìò~±e<µHgª¦‰ w’A hd^Ò0½üMM䡿„L‹ý]»]cyŒD@"   ƒ…^§®¬’!‹ÿD…h€Aî"A à ¤©ù!ÍY7€Æ¬xK³õáÎÍ8’`yŒD@" €'…Û)$¾%]]ÏieVª†y w‘B   ¤±é>MYý׸ôÌ8ÕB$ÈT¹¶¿!`äA‰€wš@’³ÃiDøËº¬GbÕ2dÑ_¼£ ÷H !°ÒÖÞNc–s±\ä;† d2(ìº×$ÕÊ ÍyDÀ K ‰Y¡ÝJõµ,YÜEbênÉP®|$V ‚~:ײ ¦Å(q¨Ç [ò*«*²;yN‰@ŸG $ãH¼áÈ‹3á _ú-Îéó-X@ÀHSËú!úsS¬ 䨹}V`'Ï)èódÛDXvøºtQœ,=ØçZ °€# ‘°õá[äÅ‘|P•»57Ú ìä9%}€"§w˜æûPIÊeI{Âûü@K$V 0òìÙs Û8‚s?ú™¶|‰€@ÖgGX<§D Ï#0rñJ1M\õ‘ωcξI }~ŽK,D 0„›É%f-%ûf9O—0Ò±pÉS÷i‚@î?ºCß­xßtë$'êÆœHÓ¹±ém=Imí-¦SžH"¬˜J 5e”z –Â6§%[Bh1ÿÂ·Ž£”Ü**?JOݨ¤çžÚAÖšºu´bF°†êá¢,SÆgû)݇L ­¦œSžD"ÌøL ›ïSî©tºè²øEñųü-‡_?ñoÈíöš¹¦?!×ãþû¸M‰Fɾïië®–?È9^²ßð=nLûOo£Ño‹¤´vʆ%¦gÏeËàÊ{ >H;¿\‘©Ó˜8þÌ-&½çn ¼ “)«?¥]ÇÖq–è~½ìMC‚AZü%¾d¢]Ìgaæ 4xÑ‹Ë+ˆmÙoÞ’¨×Ì$ù }Ÿä—_~açç|þŠnç',ŽÑËúÑĨ„ÒºÅ1­¢·æÆÝë´lëD&w…³ã½¡­DnaJŸœ,ò¡%ÎøD 8Ù¥Ú2š¼úCP¼˜V’ÖNéåÓšF¾ŽÜ×e-a¢? «HiPÕ%¥ˆ{»â]:_]¨é|r'‰@oGÀg!Á.eG)üVé×-ÕbEø²ÏP^^]©¿äq¯Ô_¦Íû—Ñ„•±5å¾m&–_s× ¦;·zû¼Ï'Є€ï—AÅ[¿Z_HÀ—caI¬Ü>Í%å5çhEêšýO‘BïMýLœ+m²&`åN¾€€) BÂß&¿//»ÇbÙ?Föñºßt›N]8@k2æ‰.w胿¡xÏ›‡••sr[_˜ò%š0@Öï‰áZ+HÀ×s‚ØÆ±ï"$üuö‰¼$¤õ’8;~»ÂÏš–;Iz1¦HMýE¶þƒÀ³B@@ŠÃÖ¸f,7¶ú9^¶ˆèÅï‚|4˜F ¨¦]þ£øºûj1âñˆæ)ÞkbyˆD ÷"`¢ã¥Ùì'x;`­£Ä„$¹ÑËþJ›{ïLO&0€€©ÒÒÒL³Öõç\ ý}l¾ÜvßNÂî…à•‡Hz7¦ :xz'w“{Å'ƒ¤ õŠóô=N“­!z÷« ŸÎ¦ËeUqœÖ߬ýæ]ºe,=yòľò‰@¯FÀ|a¸òŠ2¸í… w¦"¢4fÙ[täìž^= äÃIŒ"`  Ô}ñ¦±A‘Ç©ëSc?7Š­ a,#Ü*[G†¿¬Ù¡ªTæF"Ôáç& ¡_~‘ÂA†g—<°×#`)½¹ë†hJqqLŒú;Ȧ·vÐkà^FqáÜÙÊü^?äJ|AÀr¹ÝPO3ÖþÇ+)Œä\‹œ‚-¬šOóÖô›ÿË.Qu»íBv­Ü$÷XN ¸4}Æ­x§C3ä}—Ñ™¡‹ÿBWnžwzíf;/?ò‡z­_÷GÞtO«¯]”óF" ð‚€-‚{¨­¯¢I«?–…«¢6È"æœì’ ¬¸RÆ#¯iöŸøJêñ¨yÉ8œ$'ŽD@" Û÷Rs½‚&ckä¯=ˆéïs× ívË¡É#=Z-f‘†z8NZó·lhÓÜE" °•@wyu MûWð.¬h‘Þºw³sTÐŽÙDáê|7Yö­8&g…D@" [äÖ½:‚àÐçÿJôVq—‚´ñEÇtÞúƒG÷Du¯^ñ½„òBÁ\JÞ*°ÉÝ$ `9ääÞ‰€õÈ’Mßë² @4H!Ï;›!†'óHg³Z«µ ùƒ§•ëÉM" ÐŽ€åHdêºÖ–áLz@Å—×±o9ì=±U éYb •|Ø’—Åí:šh¹2ŠÇàä•›D xöŒ(lãHù7ªº^H·Öy/–HÍ‹„,S->G’ACë; 7)ëøzÑ-NéÝ9(ó×È’7Õ7xØü€æ% ß\º>{I@a9´µ·Ò‚äá^kaœ_zä\®-§#ç2iÄR}Œ^Ac©‰«? È’7Õ7HÚ³”ƒJÖöhÎÞ^»s^@a9à©÷ŸÞÎVÄëºJõö=wé4VärøeK-Ȥè¿äÉ›ê{Üj¸Á=–^îÌBMº²Žo¡¬cøm¦ÝG7Q^á.ºtåƒöžÚ@ÙÉÝ~9§7ÒÖÜ,äü7Ãêg"£?Õu¶‚//&P؞ǙÚÿ+,õ±ÜƒYë‡V]®£Hõ'–͸÷ð¶­ ÚG üXOž>¡Mû–Óà°?ñúŽbV…z;,4oÂã߯ýfÁ¯8¹+î6Þ™©Ož>õÌþ‚4fá?Šõ¢–fÙŽ~¥qöÛ”{:ÍVðåÅ$*SbþÙYdª‡<ðññ*MŽþ˜êï\µP[ D}ºöÇOhÍι4+ñfͯèûUñïCšûýœð5-Ú4š×y›¨½ý±.@°vŒH™HS¢?æX“³T" ÿ>.òm±,žÅ›B¨í±¬ÄÕºÜÙæ¬ûVW óó:;á[&Ðsÿ¸@¬ÏDõ„n+¿¬wîÝ¢s— è[µ7ª¨±é^·CPƒŸž­še2ÆÓÚ̹4?i“Ô7l™¼Å®/ŠŠ_üïð%¯Ð̵ýù÷ ï3œ"·M¡˜ôYÌâµz.%÷•ø„@;÷œ?uþÏÑ~^}yøB1sxUÚt*8¿ß§ëûz°_,=7m„@ÔóC’ñôûM t³á*ÕݹÜù«¿[Ã× ~M¼Ïc¶vZÛšÙ™åy©¤çÞå¾OdßL“Ydkù–i"‘ñ»å±óô-±œw•ŠòøŽ»$®Ü6]t=x†L3?oO ÀG%‘_~aO¬Ü$AŽ".á['ë÷ñãönOs¢$—¸ 4À7¸zÇô€zú  ‡/–H@!.o¦Ï#p¼4‡F,yƒn;ˆg© œ(ÝÏV†ëö&6ÀYzøìî€Á0(Ä-i„ÌÜ‘7bå)?PLÆL—GoÚ¿TÜEbÐ-q,K‚îæ C l~#ë·«iÓÞ´í@¬æß…š"´U·åÆÒ¦œå”²?†Òó)í`ÿÿ”š-ηý`mΉ¤ðÍ“),y,-Ú0ŽÂ6Œ¥ÅÇÓÖýQâïz®­w_\ã蹿ñ>k§ì_­ûˆ½ËiáúÑ3=?à¾y"ç嬦íŒá›šËãy(Þo¸Á¶!{™nÜ´Ì`‹y10ì÷Á‘“´¼µâ:[ö­¢ü³Ùâ™ .³°8iÁ‰”êÅŸþŽ¥A¿¤ú»ö‡nÇorîòqê¿à×B,HËYwã#?àðîFqÿ[÷¯¤©1_Ð!Ö )¼˜O'Ï e)ßståUöG®É~ÌŠ~]?^Gj¹ž¯û ,m?¦Å}ÊŽs{¡CN^h_êªôbù9+á[ZÉÂ[YÇ7Òåº2‡0X¶ !LªéqŸ³:Ó‰NlÉÃù¿±Sæ±u,à[%/ˆCh2,}Ró¢è8›šžŠîš[›Å„PÒòYg$y(=hên)Y99êo×qW¿OM·¾ô¾¾ì/^`e]mt|t·çd2êБ0>±]·µë|"M›ýW[®Ôýü†`ƒ6*mšpTj'¾áñž°v~Šÿ¯p+Nøõ¾¤o¸¨ó¶øÒqs¡º˜­ñª½ÕµÔ1üü xCÏdÏWk&•@Z·Rüî¹\có9ÈûÂâÌÂAˆl?6' þ?È"Î?pqS^Q†¸æóç¿Ð¥Ú1Ð ’FðÿŠ íÂß¡þà AøÍ¹Ÿ/–=ö†}‡¡ŽgYêDÝ´¾½Öx¹Ö|ÍÅ”]Æô¡¡oo|ñÑð –£xà㲺u·¾ÇÞ{ÐÀuYãèÛ¿§Êk¥ÝþþŒ3¥Q²?nÅì{{A ¾_ù}kâÞO P#Ë/îJœñ´lqµŒyöô^B< ³—ŽRÖ‰õ, ·ˆÛF|G"?ŽF´œš ìtÅÏKBGÖRÓ£&sÞ™º!„FGôžqŒž &ÔÎ8ÓÒúÈÄas}ªêúólý¼­I.AÏ3øc_ùð¥¯RQÅ!ËqÃ̓֌=Ö ‡cyËuZn7¶ˆ¶æ®¤q_uÛeuúOB/X%:µ)Ú®cI¶àä|‘€'¼Üe5J£)½ä(MLÆO´qo]¿ÙU$‡™ûMw©¢¶˜ /äQÍrº~§šÎTäw¾è)V³Nê QæhŠs5¯ž— QšóÕ…–pÖ± º¬õ<‡ÝûÂZLÞcõ—1Gä[ØõŒh]Rtñ¨×9±`}[ßgÄ~gËsôtº/ÅA&¨©¹v«ÚëùÌÞ!  /í¨ˆ7éÒµ³†¤¡ñÍI(Jõ‡,~‘-—8~>ƒS3éÚí*&‹f.Hz.:Ò=jyDÍl%”Uæ!œ¯0£}!u2ÂTL™föØõ8ߨpŽ ˜u²ëEòväH´·w¯1ȇÍ÷yn@-·ì»²ú§,ϾÑTeþ?‚ó“‹Gžóq%²z¯ [8_o4\3ç h¯ 4óËmĹv«†Cª_;˜{ʺË"˜Ç(çØò=­fµ³YñDbÚþw³×ÁXïÂÒÖf]ì¾úÚEÑËêÉo÷ùAþeÖ.cìlâë>¶œ‚­š_ô½Ç·Ñ¶>à—óô‰LZõ ­Û³Ž—dSãÃîÒš/¨cÇ€&˜”p‚òxM¨w ST‘ÇŽSˆ9+&¾00õVmŸÞ¡\¦,O@*ª:šk`Eñ¬>“¥chôí“1ËVÜ."ÁG$lÃ}`èÜ;2eªmŽg|œ~Œý‡i]/7®\¿LÑ;fÒѳ]e5×/RdêOô}Ô‡^­$ŒÐæèßÌø¯(*}]p@è„ÆëîM "õÊÓCj¦à‚Ò—Wì÷Ç5_°xQÿ›q U#/D`"RÆy#;Üp¯>3Ýr2òœfƒ1ƒbþÕzkò"ZÙ*a~N:4ûÞϧ¨ˆ½IIÙ¡=†¹òÚ9šõ¹(À%!ñœBÆZ©PÚ›¿~˜.>>–ȼCŽ t…SöÇÒ£æ‡F¦˜Ûcž@¶\n˜@Î\ÊãÚ˜®D2LF¬#¡Á½c†1ÿ÷ÅË+„)»¼§l£Õ/„çWú¢ô£]œhÅv¤8»Ã×¥-GÈ—gÆK K´öfM磴´="8챬vŽð)Ùϯrbâb6š! ‘ ‰zøüÌÜš@°„QÙeüZ­ ¤=‹º™õŠž‚RàVVU$Ì.Ç™2ˆ¯ÒÁ3& 73.‰»ç ³Õ—É­çX+–yž®%ærÎo±B¯6n×,ñ•¶ã™0ß~äÇíȹÝl!üÙ-9¨IÆÉã]D˜ÌÖMûóÑM ðKÌI@ ÷oé°B”á Û0¦G±žJ СÄAgçÄ/=/’Þ}ñõY²é;S›]ã,Äï8jdWôE)DQ¡õ_l_%÷UÖuOªòõK ý[̘úzÇRïþÀ ËéRŽò9n©¢;ú%™¿„Rå’³­ …4ˆ$v‚fŸPÄS´X ØͰ^œ­ •@w„QW3hÑ-Ÿ<Ž/BHøtë^¯s¿óøƒ…éâ £wBÙ_ñ!ý›Ó®×0¾¯ÙJ"HâÛ‘o®NÈÉóû:ÛGÁCÏ1Pÿÿ1ö+®¦í‰»Ã²+¹<"Af’2tUÑc&·p›isÍÕ‰Ÿ@8ü±e’&ÁN­Ü].4y¤ÈôsgyÎZøs†ØZ¹ŠÂ©=ܞЬíçµl³¢°ŽNf lC½dxM®çÅS÷¡õHsS¶“²Û¶ôƒõ±ëh¢ËaGþÑ„U˜V‰ìç¡‹þB‡2¸ÍšoÎç XQêRÞ‰dç*•¢"W©êŽ„¥ÎÏk¿9®ØÜ™@pì™ÊÃâvùB”FZ˜2ž·¹ü|@èïl±>pßÓ¹¦%ïØžÎÐÕªÔi8ƒ<—Ê«çMÁÎËQËx,Ü( ›q¿äÇÖÅŒ5ÿá‚L÷–羓銈‰lxžñ¬Ü^Xžo NÞN°"&,K¶©8Úé9vÖþ@D£âÊ9þ•pïö— ¢Å'WáŠ@à˜[¼y´mVˆèëÁNÁ«7|O;Þ¸w™m_P„³ºÂY¢`æÚÿÚfý`<±,Û9ÇÛœÖôwHØ!º$¢HìûŠß5Ïã}^8âóRTX­Ý5_fìä7)f«bpØ n×}ƒÙ7q±¦¸ó]YO¹Ufdê ®Fü›ˆ¯{+tsE ¸À¨µË¯N¨ÔƒÑ>ÒïÑÅÏ.'0ä'UÄwIY•f®Ý=}ñQA6f› ©íËS¦Ø’<&ò1ø¾kê+=Ž7Ú9@> D‘Axƒ%&Îù4·ôì7ixp‹ËìÿÕJu*µý•çð¾ÅŸ/T‰:ÇIŒAsµ$qG 8ÚjB:À—Ôz,ˆnÞúÁ=$õ ÜÉó¹¢ÉÑðžÖ{Å~XF§÷TVkni¦9ëìóÁ¨•Ž•ø&Vä1Xv`‡k|ÏI‹g+ŽÑ®¹q·EnS´HôŒ‹ó¾J¢ÚTTî½HOÏ\ó´¯íâ(?Xu½œ&­þ{0@X·[qÖySkji–Œ£³ ½vÇ,{§Ç€x"CE»Ø¤ý“O¨uðÅí÷X×ø@'í /¶ÖkÝkêïV¼GWê/ºœG{¸»š§6F¯ëî8 Åfþ$>,F·ü³{lUÃxú˜ÍJu;4fïý9Ësþó‰Ï™Äªu‹„1»6Û  ¢I>¤í:Z˜$¹eƒin{Èé¿ ÀœÃ=p¡pjÛ©Sºù6<rC¦Å° ŒMVfi‡ã sÃ;¢«™÷:’I*.s–¨Xvµ¡©óüÊÖe $þ4ºÅeδeÉŠ99§ŠW‰º+Ϊåž0íí]º§5uü!ýÈ”\ñqâ:˜‚ ŒÂ£ë8¿ˆZ³’Ì}H=Ð 9Ë4r* „eÁD¶V7î(Q™­"ÅßÝù’ô&îÁá§âÌ~"â´ä–Î p«áºmªÙ”zäpQË 2,‡×~ÝCWÑ;~_urz#Û÷êùËn_v*|7FôR—nš`KÔHD=2¼«Êßm¼A“¢>6-Á™ ÇgáúQ†¤ðâAžÖ—0ˆÚ'Nº+»\HUuåüqÚÀÒÜ·ˆk^”ŠÙ×8_)„ž>yN‰{æ÷¨¤ÆÒø#Iõ\¸g­!g|L¬ÁÍâ»Þ1C`i8ÈVQ{Ü⾮߾ ÙÕ]<‰¥–âI~’ö,ñh¨Ï¯ü(–êÎt_°yÿŠŽ¼ëSµ!¾“>GÃ0uíÂò¬.U©¼½tFþŽÈ *Aµl›s#l³B0žCÿ… ÙI=Û¶¼há³1‚‡ÖcÔªÛ5N-=P‹rºµeDKk«æqÛq(ÑÙBLîè´Yšï«¡ñ6'K}iK] ° ¥^ÏÖú¸™³YÿnНÁ™(«·¹okµôû¼Œš8XtMœ¼ú³úFhw¬Ü>…±EÝpÿ®ÛÇŠIŸ%0†æî@ ³±âž~‚Õƒ§_ ¤´ª€[[þ†bwÎæòúÇâ¾!'8vù»ôíÂßò:_ Õ¹$þ÷ nÙþ&í験Q|#÷ÇÃŽ*µ¬š…lÎù\K„éùcèi»~û*;Nÿ!,Šð-Y=L{ï ¥9BiÏ]NÁf+ù™«ýáêyüf”TaÓN|Y¸a8›ÊŠ|ÿ•ú Z¶e27Þv/$„ýÎrôfç‘õÝž)r'a­ÈkL âPŽî¬Íœ/ôN·çRP—S®H_ˆ!\ëauz»J QéÚÂnU×à­ÿ‡å_P¬½Q>¯× w…ZoGbÆx"+tUÖ–kæµ;Ú¢Ú†y}¨¨«“€»IJéù(¥hnÕ÷²ßãHÜüuÃ…3ÝyI+>œ›w£ ¦Õ›ßeèCýYù C§tÉë”~xm·ø¾ú¢»³BbèhÀ3)úca5¨%Ìhð–ãv‹k&p‹tS­Çe•ã¾P‚²#"£Ô˜|Aµ}PÝ ú†œE–[FŠåö>—š{xIíÈOQ–1¯±þ§Æ´m^Ú‚­VChݹƒ' ±Ô€ÏãôùÆðÞsb3/gþÊKî®$HEGg1‡Þ}H–Ñx7¶^Xl¨@Dã Õ×€‰‹¨:W\íJÅu—H†sTÔžN(ôlŰò@àq6 /p[…©1ŸÓøUïu:Qq/êÏÙ¹z³’÷·^& âË9åYd-*niùòšá[Çkœ>=w»v»Zø›ìÐ'Á˜‡qÏž½ÞÇyylŽÊ¾§%–Ì™nªn]Ýd~ñ.ê¿ð×´eß*¯ÏànœcÜ V½ëÈa‚#6ëdwëÜðɽè7yŒ!&l×Ú[ñ L‰þ„f¬ý7W~*ËWu0˜4H£Æ€)¬ß`/õKl:îââ»§ÝûXñ>q 8¡H¦FaÔóª$âŒUÂî…¶$ᙣÓ~¢çð»Ùʯ Åx+— WtÜ+w¨A22ñvϳÜRR}Hм(­VúyÚâ³Ð÷ÅZå1Ìé1Ÿò2üR[)(Í£Ì#h÷ÑT[ßUH‰Õ8ÎôNó.÷ô|çóøãÉÎU!þ.^4fÑxÃÑùï~#³œÆ=0ô÷=Zjöú¨ï“»%ÌåÚ "®ŽFÌáÜžÁ¹mB·¶ŒÝ1G8Δ2zEÒÐ]WµŽTj¹bB/ÞÂf¾:åàkA·±;÷{¶9Tï%fÇlË×ï˜|óx]íëV{£Êë ¸Ãi›¸{‘Ç[¾Ë¢¹ëZš<¦ú³ÐRÁq«ãfOÓcÿ#|H–DÙ· É^“D•ùŽúElýŽñú—Ëgháˆá†«Twç2gWWR‹"»û΀øQÆ1“‹,‘­lÇf+8æ”VôT_D¼ì“8¼¥˜î#1É\Ξ¸{•qóju½§.EÚÚZEOÛœ‚-¢Ý£é&Ða ÄÚÔ.k¡ÜmðYIdj䥼Fiâåë“ñ³-¢ÕH®BÝ“'±àSå,O‚ɼ¤ºÈÒêV}ý‚¨õR›­;~hP¾”vlësB™`þØ r8þ÷lâT‡qBÎõ^(Ù@‚XbÖ|:wÙµÕ`(/uíÚl%<”ú•wG `r¬á¶åÅ*üÁtëîwÿá]AꦒÇ-^úÌKÌÉjJ;ËBÎ9¸ðfÿ—EͧD2G¿޽ÙPGßpB•¯V†·ãAp£Ágç Õ•hâíí¾üKÀ©“uG^ÜMÔKl:WIûržŽEÔãl…ûNö©yQ–/©:E}’ã¶iß ·Éuê!*çj»ûÀž†ä¸¶í¢¾ä΢$|õ !T¹ïTŠWQvèN2ø'4£Â²É9 Ђ֣–&JÜFcÙ[­7¼µŽMd«# jní.ÉurÌe2ô”8äë‹)"/\JPRyÂú÷ÐäÑ>—¨ky6Ì›E»^@Ç›r‘æªyºåًǺá´2Õs‰¾—✥…ŒÓ¦ʼnšœ!¢“J[U÷ÙÐÈ\]ºÅX:¿¡Átsí¢Þ_•Q¡9/i(AæÞ1}Z‹²cu/ªjÃyM‰I¦^Ö±ÖT¯‹”ù‡Íº0¼x¥ˆ_0Ž,XØ;U]C§ˆêvou·j…SÙʨH¹8zó>¼x©¶”B–ö·ÖB zöQ›OÝv‘v©¶Äò–Ÿ°§pÁ®·øLïy'ŠÆÉ»´!;’ÐbBIð®Ð®ÔÚ@&ÑÞ^¸Îcî7)¼xˆþ;ÿ7,j<”ÒÅsj=ét! å „.adxXÆ8’ö…"ûV(ëÊD}…Sž»ÊæÛŸ<Ö]#€ôöð-ãºæé™àZ÷Å‹Œçv´2%t(Ì[S›âB1âÉRóË¿Ÿ={ÆéÙJ‡V Œì§ï[lµ¦öà´´¼Ë­G”Md驟‘Ÿ@#¹1”·g‚åJ'm㬊­ÏVjÆüµÙB Žà.q ”UÒ7ó%²ë¡9vn¿&QÁÛu4‰ÓãÝÍRõ&þܜم±üÜ›ÕBp¨ÂÖÂÕ”ÈÉ€5åmý;LåiÑ®#fLÊ 5g„"—•ž]m>åìßRüÞ¿èFñCîzË ¢Üy;|6SsÝ’«ÃùA"9 -·p»Ceè–ˆyqLØrNÚª¹^A÷Ep<\_PÐ|¨¬U¸½©’at;ÆÎWW ®xêߦ”Ü®å»:O(»måˬdW¾J©•õpe]‰¥Ñ`…0øéó‡ M­-å%¥’ï£íëjäe¥îìÇAäCÝ*Ù‘keò˜ºìŒÏZЊgœ¤G¾ÕšµøèŒäeâ¥Ú2­Ãaê~–ˆ3y8&l55? ÝG6‰¥Áœ|ƒ$ǯü#ÈÃpG * ªÎ±^çÏ" ÏÓWNÑ`xƒÒ:*8Hë¯"ÑÊÈ×zŒÒ½ý?âñvÝ ù ¦õüŽûá«Ê™œVëFœb‚‚K«ynäYp ’ ÷Ÿîj¤ÙG+Ų‹ñ-Ñ&Õy[ÏÎP;~)‘NŸ_ó÷Üõ]é_/»XB žjWÔD"–+ø¢#]\j"êvå+y®2Q¯rí¼ëý9)qv-& ^NüÔê_OË)w@Îä¾3VWÂío:8ZžîÌ9Œ+ªgY$f0ËBÝ*:}=ì¨qpGH¨Ü]´qL§‘·/—s&ª§Š\w÷~¼t¯°òk ’›ÍÙ­|á”ÈËSûôzo¨’[òŠ¥¸aüá¸Ë¡û 9³ZµD_褀^S_®èÉØ¤­ë8ç1_¾çΕž%(}b §ƒM%Gòð¶Dp$˜ÒóסÊkçèú*‘Ò­Šø¢ˆ áEw$ÒÌ{k3ç òñæ¨s•ÊX¤/Hf¹/ÄJA#–VD^Üaø˜x!WÃ×ÖÞ>¨wÚ~ ž—2[-]þ)­6¹,âI÷^·s‡X^rà5—êǸÿpã²*-ÓÙç}L!WŽRow¦ˆx©£þÑC¸¦Ë¶N¡ü³Š®‚;GªzS\öž^ –S£¿Ð¬!ªw D)—ì9±±„1Ü;Ç¿‡§ûí\Î,.øX©e~˜B ª/AOA%ȳ͈ÿwç½^¨>#·& ¨´iÉ£[í ïy p‡lÝ«ª{*¦sÎ'ñž¥þz'¶Öýazd¬ìÞž=}ÎÖ¤ü¬õ…?š…=o•ªÛÏš6êvøìN‘ï(±ü]ùG¥\÷ó1kì}&=ËÇ›V á½ÕéÜ(ˆ7L0$a‚ý—«qï=hÐE Øú îÒÎõVãzyGHP¥õ¥ ”ý0±P³Ñ¤ACìIæxž}'SmmDeîHøŠÜ>±ó± mS-![›•þ3/x¹;² ùg²|¨«B½Ë‚¤Ž¾Lß.ø-‹ýNüðoFÜ7ÂV9)T{ëR§fÉÝû7™ÈõåÅ€„Vm›AwÔ q!碕M÷¸e¦õBÊŽsÇ0ø:;} ÌÐ \fíqÛca9` 3›ÃaF ä|u±0‘¿ Z D}6-VÒέ–Ê3ãEJõËÿêë°™v|þ98­Í§17Çs(š-›‚¢‹J¥÷d3,}–²Êz n~'Da¦Ç}Ê_|â »ÂäÃzyž$ =…u¯r ¼P s½¢ÅÏñfÔxxËA1{2ë=ŸÒj`gÀÌÁGÍÄ=¬7k!˜|$Ñ Û· µ2ˆ§±R,4U~¥{‡Sn„“øŸ@øEÿ!æÑ­¼âJiç×|¯ë®ßºÚa…¸W%såHmiifýÖYð‘@ÔåŒs¸Ø÷ \÷`dM«—ŒîÈˬøþÔÔÒh”1ïÛÆrV¯=ÍÌb§‡Ò´˜/8A«§`²QDbYTÖ…§{ƒE¾xsˆÑKX~œß ™ƒ[÷ňÍ៪‰€Pìæ÷Í¥äà4EˆºÀäOØ£˜ZùØ7ãp¼Oa\£ànÈYPÑæ“»öú¶—»òé‘óÓC¢fì \É%ïÍ«Œà·c®Û$4<žâ†Q¼ù@²ø•Vžb Ô{/ ²ôP„c¿ä¤¥²Ð›‚}žq¯Üe©ã»u¼ë4 ½4–òu ®± ‹ªgbÆÄõõˆ¤³Þl o7ï^çeÖ—¼Lpý%ö_ŽWê^>9Vlùñ.ðjÅô­û=¥­¸£ç Ïå Z… ©ìª"$ãØG¾¹«îÀ‰àx,% Ç`4•Ý(êq«Ófzõ¬û2¡µ+šsE}ÊÊÓ÷áŒ3ú¢2œe2w é»EÛ©ò\—Y¹XÚÏZ;€Úœä,º ç AkÊÓ‹‡˜1‡5¡R:ý2-Þ8ŽZ·t>¨;‡æÖ«Ü:3}u¢jAùúí«"‡ÅÌZ­¤¡î§F^²Oºït§åYìܧó"XH‘,ÌÃÉ«ÿÉY¤Ö ôÔß©åÖ—l}9ùA…Ü’»ÂÎ!0t-¿2ñƯ|Ÿ¥õ”µÞÜuCz$)âµýXth(•+ŠåbsHsÇÿmlj ‰«þá69ÇÁ},O™äW+KHíjäÅÝLEFrˆ†6z ÕÈþª`òšLßš^{{+¡¼ÁÊûÎMæ¡ß{¼4ÛÛá~ÿ{bìoÐÎcÊZZ¨®¾BêrF4ÒÞ:–.]íRßVQ<Í¢BPsw7aì"Rîqç¥?¾¦JÎÂë\¸eíÄ·bæÞ¾WÏù4ÀÍsv¦BÐ{Œª[T~ÄŠGívδÃqÝÄŸaLû’®uøþ,¿.àwÁÀŠœøo„j^áNùx)Ql‡œ /4TÃ7O₦Q¢©§¥ƒ]‚ñX»kŽ¥Šàî^µN×ãCˆæ±®„2Q“¿¶ÂF g³*.ŽHdL†¢‘è[@–ÃÁ¢tzò¬]ôµÕ2ÈØGéŠÞO{›tv:ä)ÊXÞ‹¥´>«–ý°v^›Ù³OI ODõþªëÊ9ç¹þµB†ñê„ÝúÜ’)a9*¹;¯R±Eac³çAÀ¢-±onk¢Áa/h&-/•]a\çÁAïR+•ÕŸ¦ÿ¨ˆ·üÞ/Õ×Iº<•õ\ø+<ÞÂFTžæè!þ‡nÛ}}ÍÇ?xx-ê8¤û -\ïÿ¦ÙZo<`ƒ6~å‡Üäè‘h¥¥ÌYy`_;- @ÅÕRÑýÙ«e¤÷9\í/Lÿ´<¥®(˜7(Ó…„ûG_T‰ú½ÊuY[l‡°¤ò¸È‰ºûà¦í×6zA¿HIÕIÑÃËõ÷Í‚_ ѕ٠ƒ…7Þñofü·Rùø^·æÕFÓzܼuC…IjÆý{:ÌßÉÑŸ˜Z-ªõ­Ø/2uªå- \1–N?pÚzM½µbÄî0 6ß•ßäâÕš?„m×ù›¹f =}ö”â23Îñofüw(Ë$")í±ªMÅ—ŽÑœ„a¦?‹3óÙ‰¼í@œï²_ÎyãòiÜGÔ̰Ú\‰Œ«Ò§øå™ƒñ¢~#`KÞ³}dßd»Æ Þã#ß㥧UÛ‡®yW H” Üú6Pn·[åMT†s¹iG@ˆv¬äž6!ι £8í-,oö2F&³&Ü´#¢ýöåž½ âʼŒ°ßú‚É«>îìÉÜÛpµêy$X…¬<¯n Ð5/iˆ_¢/ÈbÞy$ð¥tƒjñ’@,Xž^;¡Cü’þ/ªn£>¡+& &kêàÞSHpŸ=w¯ö×°èjÕ×˹_oÑÓØn¿‡Zu›¼w‘EO×»O+ ¤w¯iO—u"‰ïÝÞ¡zoÆv«¡ž5/–Ñ$–`@)ƒ?R×Eè–³OkêÌk×`6ÁrI Á2R~¾Ï¹ëûÓˆ¥¯±¼ßgÜ5°?…nJ‰{Âh÷ÑM,­PÆMœk¨¥µ•Ú<$éµ´µŠý²§p¯“1,Wùo‘ëáÏÂ9TvÏIìgtƒ÷ò’@‚wìl½ó-ûW‰ò¼ìÈ—³ü-¡ã‚â/dŒáÎwƒ¸rPØ…Ì‚Ú#¶«WìïÅß°ZàÅUÚú¯lõV×¼Bu¬"'7cH1†[Ÿ;*¯p[ è{ã¿Þì¼ø\â2çô¹±4ó%˜‰f/>Wie‹8½ÔkDïù*¯É´u_¦­$_ÐëCÇ>|ÔDCÂ^ô‹£ÓlËC‘}|ƒR*­SåfI ƱësG‡áOŸ…YD¢¨­B­ìô•›oHñ ¿>u4ôZ‚@pÿ¹íɲÜ>5vV=¬$«í…ç·n¤­fYŽýrà8ß¼š±6­$Úˆðý@¬YQuëÙ:þ ¡ãŸ¸_N°të à©Ðyk’@‚a”ä¡x†/x0EÁiŽºŒdÕVË—›yH1Ë^¦ÂòCœx…PnpY &Î9,E¬oÕë'ÓJék#îÃó^¼zÆ/:¥¾È]SDûðäòPwH‘sC3õwªE×Ú®cmAOžœª¾¯ Mó3Êõ! D^}zo´Í…g¨…±‹Œ\Vš±Oý”ªêüÓž¡¯LI }e¤MxΖ¶fZºy¼(„3òb[}ŒÚ\kìòw(õÀjzØüЄ§–§ð„€$9?4#ðäéŠÙ1S¨†YMZÎ/zwT£*xPè‹´rÛtývæg’;ú†€$ßðësGoÊ%ù°B°”%ù6Vè*¾·;¤^¸ç$õ§ŒüõÜËöiŸ?°$@]ÿle>­Ü>•–§L¦Y éǸ¯„Î4AâEÉ?rEÐj­8áÈ4Úçja8~´Ðy•†ñù‡.~‰;ý ¦5™s *i—jËÈbÅÅ !{oWˆ½x÷Š«=yò„Ú·ÒƒG÷èþûtýÎe*çoÁù\:X˜Î-6c()k …%奣…hOÿ¿BC o¿¡ûXòÍ[7‚V§ýL™GÖ‹ó×ß­æë6råg½Ë`I Á>‚Avÿ· éCȺüµ¶H‹"ˆÆTH –¼U‰@ ! $ÐFDÞD ˆDƒ%oU"hH ´‘÷#"$Ñ`É[•’@mDäýH‚I A4XòV%†€$@y? B@H –¼U‰@ ! $ÐFDÞD ˆDƒ%oU"hH ´‘÷#"$Ñ`É[•’@mDäýH‚ÿ{c¬öŠéÂIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-publish-fc.odg000066400000000000000000000255661226750426600204050ustar00rootroot00000000000000PK<Ø8Ÿ.Ä++mimetypeapplication/vnd.oasis.opendocument.graphicsPK<Ø8Configurations2/statusbar/PK<Ø8'Configurations2/accelerator/current.xmlPKPK<Ø8Configurations2/floater/PK<Ø8Configurations2/popupmenu/PK<Ø8Configurations2/progressbar/PK<Ø8Configurations2/menubar/PK<Ø8Configurations2/toolbar/PK<Ø8Configurations2/images/Bitmaps/PK<Ø8 content.xmlí\ÛŽÛ8}߯Ðj°û&ëêëÄÌ"˜§Î`€ôÁ¼±%ÚæFR¾ÍOÌãþß~ÉII¦,«-·•iw'Ý€ÛbU‘ÅSE&ïÞï’ØØ`Æ Mç¦;pL§!Hºœ›¿=ülMÌ÷wÿxG âYDÃu‚ÓÜ išÃ_¤S>SÔ¹¹féŒ"Nø,E æ³<œÑ §¥ÔLçžÉ±T Ï÷qgqɬKçx—w¼5YôØ}dɬKG m» ^U_ЮÂ;[ ¨'ÊÉ‘»˜¤_ææ*ϳ™mo·ÛÁÖP¶´ÝétjKj¥pXñekK®(´qŒÅ`Üv®]ò&8G]õ¼ºJé:yĬ34(G «f s`é ÇìÖ‘.Só¯Í²³wm–-0‡+Ä:û™d®»Šuw?Òe”¯Zì;±?Q~|¼?øKºŽ%xkP…Œd§©¸uyJi¥ªPÁ.Õõ'°Õ³Æ½}’}ËHŽ™Æ>É¢8¬§É)ЀϵÃÂáòU x‹€g+rÅÌ£Ö®?¼ÿ®p‚Ìä<³ERž£ô€ OHÜÙ ÀÛâ´(%]Aðj¡S¤éÚÚpW.ÊðÜ®Ð:§B:´d$ó»w*¢å§¡¾‹Áçf”¹fѰ@ ùšTn´2´Ä¦Ý.ºd Ñ%CÙŠ„es†˜Xžäƒ¥„®b‘Yö[ˆXXN07 êa8F¿`À1¦¹~˜8â×4„n³‰ÁœÆ$ÒZ*^, ŠXb@ d­(#À:‰b Åd þwÍs²Ø3n„á-!Q—Ý `­%£[k…Ér¡¹@1—0ÙNOæ}­ÍXP˜m$ª+§ÙÜt¾&—€é¿ ˜ b_0³ hçæO fÖh·¶$ëL fÔ« b¼ÈÏáp6ᵜÁh,´Ñ¢3¡¥7¼ øà;ðÝwŽw J¼ ~ƒÀ3‘5ž‰¼{ùÂãuS¹ lâ\h“Ñw›¼PƒÈ‡0#Q…wZ;cùk£˜ìĦBªjѱ+´—$-X˜¶h,¢ªlúO¤l&i-Š·»Þzê¥õVcJJ}¸ÒÐ ù#å`Y«Tüß(£üÇûuH"d|B)W Õü¼Ö§˜Ø~ñ-á¼Æ‘‘<ÇÛ FÄ’Ã0œüx¹Î`˜å5 A°`C‚ľ"8EÛ™ï rwÛ4ʳ›µÍK!Ô¨£º#tbڗͰ»–¢ãfíxS1V¶n‹mÏ#£î~¥¤JòiÙºÛ®¤|w‹7JšWkñŸÀFñßcß”²äh¬ ,Ü&ÝÝÆE­üÐXó¾æí¥É‡Æ"ÿ E_o4>4ÖÑNÓxE˜6VÞ[ÅôÕe•FµpkÈJɹI`S%¶Š×®v—µì´Gƒ¨þ+zûgM&\c‹>kf»wM!ÆC?®ãç†"ŠvPÒTŠd‰¶¹ùÿÿýÙÙÌŸ`ÛúiŸ@Ж3Ys »æ4¢[Kr {ÎÖ ƒÃÉÉ=¥î“ñÎMFëD›’”á ¡S¼  ‹íþH”6’’ˆ"=‚Lõ.`Ôer‹ù½!ä¼7‰PÐ#B“7‰Ð°7„¼Að&õ†ÿ&ñ÷‡ÏÍÓ“Þ ÞhžžöˆÐÛÌÓ®ÓDÃו¨5rQ0Û­j Â#öÕCqsæî<š÷gÔ!*°Å³[Û¨qµ+8ÅñÏ1“o Ú¼@ë8?\õ‘7Ÿ yOì Ó‚†k®ÝªÄ,ƒ-S„9Y¦VB#¬ÝT‘cˆ[|…2ÜÔIÞí©˜jçgâÀERH{‘¨ä‹Ñ^Ü1„?t-¶/›å¬°³7'­¢¥¼ÿ¡5íŠÅJ|߫f…GécW{ð³´IúÏ”…¸0¥à*Íš]×m„c²Áìýéž%8]‰KcìTi‚s¶—“Ú¼ý…i:†cxîÈ)>K›Æ(ÓŽù*;êäòt¯N\Ækle”¤9a;qÄŽ¡¾©Om@Õ¢›U‚ä0¢üpG^ùYòí3á:1ÝÊK”àQ!7Ð r5åLÞŠüX~o”úhc×t*Ÿ~7~‘¡ÙðÊŽŽêutTïzGhŽ:¼ÚQ?`uo²þ½ï ‰ñÞõÛp8š¦8³œò6¿ÕÛüvÿÚ¹r)œN+ÿqeT ;*½aï)+uPH%õœ«šF‘rSt`÷´F9¸Òe*:íbvÉ.Èg‘Uq<|ç¬ûcàÎÁ1ÎãËqÂÙoÁyx%΢ é æásxz ìø,°Óâ’Õ)l½Ë° Z°un ÛÑs±è¸ŽŽC׊ã2`‡§€~%`ûMãVdƒZr.Lm}?…´ë´Áì·Â<9óèln°¿0]¡ðžÂoÃa|Y»g×¢vž½cÖ|dÜL{!è¶ìWÜëÊ@ϼûuý;ÎÕ–j®3r ߟ›áN¯­Tƒ½+lòX¬­Xóƒq9àçJÙ( ¸‰ë‹oŸë%œlU-×îºnj'½ºˆâ½r³@SüÏï>Ò‡ü=éÔuÏ--… Jª£Ë—ÉK$ÕQ-bž(pŠˆˆ˜ÚîÚÕbf|]Àø]Cq‚Y½ÿSñsFþƒzßÓY°6Á0§ñGFg¹¡xµô•^€N ðó|…L¬2¡ü… äFn©·û.Ë›Ž™H RÚ›ƒêF8f†zpP=@qP!N“6Ð@Ïs@ÃÆ÷"嫸÷Žt;’¥¤7ôB×HÕ²,6Jñ­®»ªÜÞÞˆ*ùÀ>c6’ÿ,¬wŒÑ5‚äß¼ù…>,,wäŽ|w4qÕ8d_âÁ˜í‰±µï~±œÛµíB¡".‹úHE¢Ü.¬CÙš–ÖÍCrÌÎÅ8c@‰DqµQÁiž!qS¥Šâl¬R-+Ò€2r{â…•“$‹±–CÁÂö’aE-çŒ\KD6@ µÂãcfó¥E%’†Xà,(ùáˆ<È"縊 9ÄJ³pºÃªÔE\{Ñ9¶¡¢‡tcËÉS(yœID•GÅŸPFóŸ?Ȇџx3ú›&(Uƒ”¾½Â)†Àz ŒðªÁ=bDGõT9ù øÓŒË±¥«­`("r  EÊøòÛïmSBº¢T;ú>¦^ðèîý£žjó|›sœì;¬åµÛ††ð\+(ÿËD(Cв/ZT£%)Mq›wb“Æ6ô$P©v†PitQ©´†QI[©d2”:/'¤¹OUÈ9JCÄBë‘Ý[~6³Y–Øgô³xI¨ †‚ÅéãIc¸Ìö]ùÇ… |…ï2O„é¾<€]*ÞÔÖl(À>`.¤mƉã*‚j¤òt6 ‚(’[!C¡x¿µ¡ˆ<ÿJÌa–”sq|´Ébq!Ù0²Z…ë…òˆ#!T¥Æ  ¥=ÇÜ~hÙn[…:¤kWü…Å•¯µ1É›%|'5LµN¿X)ÛË"Ž1)¡‡³ÇR•Èo3 ë¿ÿ±ºJân½{Kü~›,ilS.U ›^½’;à»Gã?Œñ#$i#O2{‰á5 ‹¥x-–BJ’Ú1Z‚M•©Bè|MN†7ö/¡é º¾H„®N†?ž^$B¯O†Ðä"ñys:|.´N_Ÿ ¡é…ÖéÙ ºÌ:í¹'ƒèêû*Ô†¸ì¦œ®¦è ÙsC'²«V ìÊAÝ4GU«Ñ«ºŒrXRk¬ì=×}Ub‹SÑmÚŠT5è a#q%’òPêD¼ª†!-¸p§šÊI7ùšÑbµ¶Kê^5໋*i„ÓòÞuÉo¨1=;KÄDÝu™´€SÌP›ß›{ý¼r?`½¦ ­g*Á7±z ŠBÈÊ]P1%fhFÔÎM¦tDdP&]1u¨È\ÀI¶F*©öè#†c‚£=2æ†.?á€o‡’ªøØV.FÓ ˆU?H³÷Zõo¥kÆÞÕ±ŒME#àrÞærÔÖ8Hå|šj;?%œe½¸'9‘©ø$4ÍWDUXpXOº"ÍŽËs±}ž!¹Õ®ü&/—4ÜžÓÓÃï>å‰öªÛÑQ}*rH ÜIø>_t]ïHê§A1YÁ¡"¼%Ñöø0Õ›ÍÙ‚<̬î8yJ~õHJò%½f¼ìÀ˼ì‹Ahàe^vàe^ö¼ ¼ìÀ˾,^¶IœjPzv'„„Õ í+§Ó£úJ’wŽ˜:/츊69’¢ñQ4{Â}ЦS«H¯¾Ëá¿þÓ,G[èÖW–kEA0›=ë<Òs+`†»LCÏ<ôÌCÏ<ôÌCÏüñzæ¡gzæ¡g¾žYí°ÝÛLc¯ã>S%hi—Ž»´ÔÄfrÔJ×…â®ÏùõG /Ñœú]pú^ŒŽë35FgéüÏRó™¾ö6<º'êÒ_*tnËý;Âaß h‚Q^°çØ®&åtì ¨š¾¨o8µÚ5n>ÕVÆúiN…"%¼<ú¦°ß¶Ïï —Å—rÅw[ 4˜+ GÝ–¼±ݹV‹Îôê8 v†Õ!ãµ2zTÎWç7õÕX¦î¡•þ1 PFêßQÆ"&>FÝf{u°üµ ¶°¯ 1÷’l‰‚Ï+F X~µRKÊBqð=z“Éé\­R œËŒÜÖ_‡˜Äx)¨?›ß WA‹ÙÚ嵿}tÔÝ´¼[5€e4> QîsQ;¥–³‡¥ V`ÜX¤_Õ7bëzP§g¼z¿×EB¬­Sc¼¥ÓþûMnÿPK“ß§×¹EPK<Ø8meta.xml”ÁŽ›0†ï} „öJ & X©‡ª•ºÚJ›ž+¯=IÝÙ¦Iß¾¶ P+qdæûg~—O·¶‰~ƒ6BÉ*ÎvidŠ y©âï§OÉ1~ª?”ê| W¬oAÚ¤K#'•† ©*îµ$Šaˆ¤-bQÈQBæ4 †È­ò½ŠZÛ„®×ëîšï”¾ ¬( ²#ÊÙÄu½nÅ‚|ƒ²]†FÖ;ÜjʳsKã²Ô†¡l«1×Ìk)¥&Ó^6 XÇiºGÃ÷H›V4[;z6aªí\Ï·f1S*E»µŒgg®ï´X‰z¼?¨º 㺀M­Òõ‹«ù2;Õ.ø*d‹–‰V¿€Yt8¦íãÃÇ^4<)0ÎJ´*84RXAÝ 5„è+}§ZDÏ”j*AÞUkjІ/g?áÔBíæ|LÒC‚ñ)MIZŒïê%WrFþÛm–óܺ0Î >p¨:wþä%aX¦Îö÷Ϋøæ½¶êo'üù1{ί+ÙD ÂÞ€N8œ……ˆ¿ñ*þ"Ï*Êb´ÃÛ°|¶Ÿ°éÍ0þç0V°Vo~Ü÷Òº5 uÑbÏп^ú/PK¨6fgdzPK<Ø8Thumbnails/thumbnail.pngíWi7êÖÓ¢´†VÑ¢TRs‡ô˜“š›ÆmI¥¤hÍ5”ˆƒ„¶D©Ò 5O©Mp"U:Q-bˆ¡ˆ9hB AäfÝiÝ÷Ü÷Ó»×»Ÿµß½×zÖ~ž7ÑÁÎZLTNT@@@ |Å‘ö âGë*z#‡Á¦×#rièÇ×û•ÚV¦Íge¼îúZHüå…»‹w~= <%ó–<–¬=°{s;£G)-ælÃ=Q‚Í Åä,v%×Ô X&ì\Ρ;(o”wš²Ì eµ˜N@„fwez­¨çÊÜÅ¡Ÿаb¡åf%/u´–Odp‘¸¹xY·ùŒYöGlG=•b̶ѠԄýräV8öCËO¦fm îvlÔ=c·-777ðãCÁ½ÅÅúqÖððp¤¢fÉœãÐåê[œréµ2hqtCo?=]>Ûe´dÌùéOJÓtnüœ AölKÁÕÅ' IV´áaF^$C3õD·ñã#a#1cp©¹)ÑŸ@jE¢Päôôt^º€dÕ<ÙTÅ$áóâ*Yå¼pgVßòñ•(ùÈC™O)raÁJÄðÔB„…41®Êóé#±•Œ’µJQøYÕ¬ `mŠÇj}_Âk¼lM‹WÇ¢Ù¶z(ÖhG›Ñ aá©NÁi("Ó ½òU–›-õ˱ՒÖ17÷0q{›{Ì©Òm‘Õ0ò—nÕ˜Pç€!kâ?ð.±: Ê£§²žç8·ŸÉØ”º›áê´!806æÖ]Pq³E—5.—æcVu]”v,P° vA÷Ãjù5_=•¨ ð1ëüÒc¢xé8ä³;‚{à¼ôžb<«”÷Z– fé0üÎÌ9ø5fÆeêg 0¤Rhi~®”ê…yôb¯OýÕOÓq¹M>Å]Q6–C ˜Õvµ(Ũ…ê¶8Í£ñÕ}•Ã"Fð«\”@“‰þ;À?fe,¥‘cð¹7¡b©ÚÈ`˜ã„©·nE™§ü÷› áúÔR‹ð%yÐ:zu¬µòT3XO.`¹A={RüÒ!‚AUi)»¨è|+$1`ª”Pî} 7¾(åž¿öWøÂ}á¤}¦sšëe}¢˜Ui÷aŽ“õî9¤Ê^oTÍ ¼j@]ïDÛi*üÔRšùæ(ÓÎ'gSÔÞÖ ¢Û4£Ä\XXãæÝ»wï’‰7ŒT>êÉçX5™I wmžP%£–ÂU¬S´¶vÐ"U=^¿ÙÔ:ê +*t± ú¨‹+Ø ½~E1á4Ø·¾˜¬u›³>K€ÂžÈê†3+9y—®d¦ž4¸Xb¶fÖ]~†áÁºr®X<¶1fÈáã7ô:#ÐD.›¢É"¢'ItÄkR³ÛœÛÜfVÒ°bò£¡“9¬„RÞ¨ÞßJ1Ðú$¦šä¾CÚO„ùù@ à—ª[lRäBIvà}Y×°ç#Í1ÍäÕïš»ÿ为2w›¯WrdžÉå¬\»Vè°¬Y²·Ã¦Èä^O¨_So«ö‚¾¤s7 ;+ì¡j¼Czšs×fN¸‰Œlb|ðMìòkãݵ>D)-± ®Ð"qŸïŒª¤Oñ^Ë^.w•*Ÿs"öxoÀ ¡ÔóJÇgÔþî½ñÏ[—Õ}Œâ’2ˆ ~w|Š~©Æí¥_wiuöÔ¨5ºö¾6¨úœÊ{mµ'»c3yümé”»ý I¥×u˱Ÿ½ÿ `ܶkž_©çŒÎzl­ÒYXùÀåæÔ8zp %¡h<"¸ŠÒ —…ŸÇì¬$€¾õ `½™ZX{EØ/í…ºœ¿r¦àêÛ+3މϼ¸õ,ŸÚ…™o±N8*ôÍŸù6âe=©»!³»½U}4 ê}Ö‚ûqû–þcjºN´·Ó'SÕGÝXfeóX~«QÄry­BÙÜž9hHu³tõ5R#¦RRRj€¥F!ñ©J赞š ?!É™½Ów èâZÉ08»ÜQ+~˜BÜ Ë:ØhpCyüÖ›+r"¦z¥E]†â:>ºEòöbkÒÿVꢔ¬ýVÔÓÃeŸ}¿ ©NžÆôXuÊÈ“4üê¾_1¿mk˜–³ÿQk¬ì~£n+'k2eÁ Õ]–hM>Úê™u¼Ùì8”ectçÛ³¼z߉j ]ëׯzP€ÃÑy åñ–KUˆ¼Ï‹X§Cý/DðxÔŒ”RµYfFÍGA:É=¬S'Jg}·=uÞ5£%+¢'¥¡fyÊ`Gm#žò!9ØÖàC’Ö‘xrA„­ :Õ+ßÿÄo‹u>¸á9Ñ¡«#éâ¶`"YK4~è…ÓtÐV/Yg‡9lÒ3Û»Ú%»Þ4’S Y?,¬ÝÝ «õÊÿ°Ä÷%Z\”ª—ñ—Ù5¼?-ž~ä“)²?dÍ`Õº(XÁ}MJâýë~NÅäÕ D*6ÁÖB¿+ÏÏ>ûç{·<í»ç^ï¼ß.‹+ȶöÓ¬[‘ˆ,F|A6DÕäçªfNÿúMì­V¡ž#¼°üh®HORÁ0 ½Ü.8Xodv°:ˆnwH³Bïð•œk©Jæ~=W´gÜ´ëz;Õ^Jg…’Ÿø®Ý@¸xbÒk}òj1ˆ­>¹íâj˜ŠÁôÃ1í2 Ýoh"Ъö¹Þò†à¼›ðTJÿÍ”å×v<_-0‘O·j3©ŽÉ Ê~¯Í©çÔ*Ê2[ãÒ—ØRϱeEB½’®Ô|s¦-övË¥ënñ+¾ô¥qvþtå‘ã…'£CGÄüzWEäú WW—)ý>zNfÜ/Xx}Õ±È`¬ª¬¯9sEóOG‹N”o=íí;Ócbr˜c3—«ù×& Bg×ÞçÓm-Ü!,>}h1‚÷ :k”.«g•÷%?ïûó왾²DÉ›·óÿîVÿÑö±±ÿOüo%¶”:2yñðcASüÿØÒ΂`vûáßPK±ñ­oŸ & PK<Ø8 settings.xmlÝZßsâ6~ï_‘ñô¡} †$w“0 ¡aŽ$4k¯oÂ^ŒYòHrÿýI¤lâȨÓi’‰-}ßjwµ¿àòËKLŽž ÌhËk×½#  1ZÞã¤_;÷¾´ºd³ ² Êš)Õq¤¶SÑ\½ny)§M†MŠbM4Yt½­¹¹ºiÈVO^¦O-o.eÒôýÅbq¼8=f<ò¾y»^šp I#p9ÂÍ=›´£3•EY­ÞÜÏ{ZoXÌ~R¯Ÿù«ÿ׫EŒIY.½¶°8Q2OÉ]!Šã²0zíÆ©3Å¿1w{mÛµIÛ—ÙAWjXB¬í}”=Ö|-O½ùŒañê ^Þ¾·{¾a¡Óá€&,ñÖ/å2Q/1•^»Öh|>¹ôw>>„™ÌG?i\4*ÃÿC9ÏÃ?=«ªW†¿ÍsåoœŸŸ•ÖN-FI Ó^ Üæ‚E¾¹Ìå=|YFbX Â-1…äʼ¶ö KEÿÆq8™>¶à§Œ@ÔkKžBø>gt[ůà3D„%ú@Œ)J&L³^ö5úEp‹x„©pG¢1…BЍé~ú7²ÏÕCç,#¦î›ÃŒH*n ˆY å{Þ[‰Ìh늣h¬n)6½\cŠ$ŒYµ ÕÙÑt¹aéSÝ2ê Ä.— eö¢¥Ê|ÛøHÀç³®‚/½¶_úç¼e'ËHEH‰þ+Ò Yðáû¢øïCݱŽTáê€w¬ÇÛ±º³?¤¸Ã|£cõW•†·åœquu,ï͈Šhjðƒ„q…[:PÅ@tq”ÅI'¡ñŠ¥Ê†=‚ƒ§ ¼Èëæø*§0½9¢<°USáà8c‚C#àl‘oã3Ëð®Ô¢ <–ʈo{¦ é–¾crÇćÀÕÎÃÒüÚ¸rÝý¿mIªÃïoINí+ñC\@¡ôºmeñøÙ+¡÷Um\(¸uE´F.–º´.ˆÐÞ¥1p$wÈq”™ê.Ÿ¥BƒøÊñý_8Çw7çSQkškª ÂÂŽ±JQè ÷¿‹ïiNùQF朇›ƒ‡¢×Ù,#Y~nµzr“º?2Àê$ Y> àWH¢Ã—],ÕA'Ú†£•ŸI•¿f¾È²ø±`S;VUÉp¤ªIÞc±”êÑàDQ´°4å»õÉ;Ò+$æÖœ¡%'ÌPJ¤¢Ëü‚¢qR~HX<Äë3>ÅaôÕ|ÕGzCUÒ¦9-E¦«¶µ}ªù PûËòqŒv†xj‰vµ ¦zÀepMýû«Æ¹÷“ ±³vñÈNó7Hö÷jn›-¿§¡l>Ji SW}×@˜ M—±'nfÄ›]<¹hR79öN»+“¨\èfÒiÐûXZ–% nLÕN†é†C£ß¹r† &àVOìD~AU µ'¶´ …€BFÉvb:Ä©n‰”Ã#Ý™@ee”eÏl)§ÀUþQnƒh9©2"â(™Ó8v\'ýž"‚å¶Ú«Ì‡ ,ðÊœú3p•‡h¹;(Z{a‹š*tIõ1+QæÜêòD†1™nWоÑ3|[}¬O{„ wu nša½·—·~LB•ŸTŒ''dO®*Žò… §¿óÕ ¿è‹2íPK#\,j#PK<Ø8META-INF/manifest.xmlµ•KjÃ0@÷=…ÑÞVÛU1q-ôé&òØè‡f’ÛWäÓ6”¦X; HïFi±Ú[Sí0’ö®OÍ£¨Ð)ßk7vâcý^¿ˆÕòaaÁé‰ÛÓ ÊëÃN¤èZ¤©u`‘ZV­èz¯’EÇí×ùídZ>Tð  Öybì„`´ÎyÊ뛣«¹V4c„°ÕŠÄ…0$cê¼í„ò.ámÊ›wƒS<&BÏ’8Ñb<(…sè£T)Æi›¹’Å]EƒñÀX|H!_ƒTý‘Êô”z18{oŠÁµ…I¾j¶¨¨ãNö÷7ƒ’›º§IºQׂ¿åp§œqÏrêÕ›ðìçÿ5óï\âƒAšk‘a¶‡g½Mvã@’|6ÁsÃç-,2çOñ\Ú…üñ'.?PK³„ANPK<Ø8Ÿ.Ä++mimetypePK<Ø8QConfigurations2/statusbar/PK<Ø8'‰Configurations2/accelerator/current.xmlPK<Ø8àConfigurations2/floater/PK<Ø8Configurations2/popupmenu/PK<Ø8NConfigurations2/progressbar/PK<Ø8ˆConfigurations2/menubar/PK<Ø8¾Configurations2/toolbar/PK<Ø8ôConfigurations2/images/Bitmaps/PK<Ø8 GuÎC 1content.xmlPK<Ø8“ß§×¹E ß styles.xmlPK<Ø8¨6fgdzÐmeta.xmlPK<Ø8±ñ­oŸ & ÍThumbnails/thumbnail.pngPK<Ø8#\,j# ² settings.xmlPK<Ø8³„ANî%META-INF/manifest.xmlPKîr'ivy-2.4.0-rc1/doc/images/ivy-publish-fc.png000066400000000000000000000472171226750426600204150ustar00rootroot00000000000000‰PNG  IHDRhÙSÄ pHYsÍÇ™ NAIDATxÚí}=oãH¶vÐXæ4¼^X(xC&(ð4r´ õ8¸XáJ0º±/–Ù…†µÐ‹7ðt¤Yô8Z €€¼€±ž†™³‚ÞúàG‘"%J¢$’zfÜY*‹Ÿ:uêÔ9µù|N–Êßÿþ÷´Sÿó?ÿCr’ÚòÓß¾}ûïÿþï%gÿð‡?ì£؆¢™cEi».ûÛ%ÄtÝ›’µšÉ®êºáß|eE;þñ,y.Töô\rDb>ÏíHá’=©õÚ±;¸¬×މkóvÐFì®)µµ±»^©­Ûˆ´¦|wGÎùńξµ ÌK§«©ã>Å ~´Åi´&M·é1ð›>àÅ\~ 3ÓÿWþ_3ÒŽÅ1ж _˜wÃõÈQu•vͩҙ í~i+†ëš´oê­IoÒ¥Ÿ×ƒÎøR$ÂÂk„ß ”E×Ú¡ÆlfÐ7zR‡¯¡äˆÍ_ìZîšìiÇ3æ^ÛQûÇQÚaö0Ô­nGdv¯(ݱ[?%œÎ5E1ZƒëIï!ƒèY×]6Ë]‹–jËf÷á€ÇéœS8Ñé_“¬²*¯Ë‹ãmØâbtX?­·T] §¡ `Ødød»¦fŒF×äñáÜ &àtêxÜ®ÖUzUSc_M]½”¦[¬ÑŽl:\Á÷4 £ýcE¡¸{&wÖãÔé¿4h™å&öÄ&ÖÞ.o7…é^ ֱň/ùõ‰OÞzeVÒ]F_—­«wF¶¥kˆ´HèXÀ—ø•‡îØí ý7s#/aæ§w錥FðÛ¯÷hrý·~#¢Ïå «q í(ÂbìÛÛr¹êâ‹]Î}Gi‡YÂ(tÌÎ7›¯«Ç1rH¯Át'úù¥Ï”¶ôÑVüÅ}wÔQȈ7]-󯻚¼l}Ÿ[º¯;›)m£*®?¼m‹èZb#:†a™fGéÁÝŹ:|²…–K‡ø±k¾²~býtÏöŸ¼®nñ1?pŸëøÁð¦±~råîÙ~”Yº®ÎÜùL …A‹ô&´³À Õ rêjËR-ôóˆ­‡åÛÖŽ½íÔÃx[ýñå`ãíòÑdc¯×õÚ!¿Òb@Ÿ ŠãòCÖçÂÆ6a5¸Åví¼±õJÏj éÀGÖ÷·òîæ]E¤Ó-§¤¹l>+Jw,ª |§NUÖÀ/bäØÂvÂɇ*/ª½Í¦Ì"wÇ¢+„ 7¡9ûj¶50Åû¢hïËV/‹¸™Í^™ÇÇb©b›=áöE4ÓêwGâBññvíˆmÖ)ëËR.hì°;r 5PîîHôd*K§ÔvÚtŠˆéRîîÈ®‰-“™~<ùõÇù¿žüç¯ó÷g¥êŽ´Ž s“'E1]7q’’Ö)sßM¤ÉþŸ7+3£ÕøNw²t¶gNÉbUÌsÎÒQ:ÖìjÄ>F[&é(!Ï–kñin>+嘳ÐN±üMûÄÛÛO¬Àó!Ú…erY2În >Üæ¬w,é”Ãv„Ø=´Ò)s'Zi¬SÞÙù{‡s–ƒ¿KÞÜ´NÙª;>½;¡ÿý¹ýòáÝ÷ÿú¼cm’;ôRUíWªž°ˆY_>œ|ÿsâJ@Fµp±S¶ê9ü×çùΟ¶pnžÏÅß¹¬¶m 'vÊ>¬aû±IÁ6ž°½Žwžë‡¿pÈüŸ ¥mºãQ§ý8éZî%ý ”ñó}tÇ~¬’/-ëyÍRÚ£š¾£Œ¾ í0 9„q06¢yš1óÖ}£³CQê-vÿ,—OJâ6™ ƒNñ4cöûø ™|B•8üm¸7-£¬åÛ–ï@¾RK^á’øÝm›ÜƒF“Ø)K~^[¥ØþÂÜ;ŒqwøtéÛ;ѽ“v{È–G£Ž®[ÿý0î’SÓm(£á˜Nkiyz–Ÿv”—IËt­Ž¢LH«E&–ï¨(×í+ÆS÷¹>¼8'ö;t¦Í»óÕý¶ÙÚ]Ð)+û±¶êíÜÑÙg†~é~Ø"8(X‚}ðþr·ØÔÖ’<þü¼*áFB¼ý||0ƒ»Ú†˜³tåê}% ³Y ]w¦(7®{§o­a;x¤"®"KO0î²Bä¢Kžë3K8\ ßC¾ Ï¢ úô_n ç/C •oâžšZI½5iZîÔ‰b»Ô÷¿ú›äë'rö>¡;ƒF¸n·J<=•˜n""ü8F dE@×CïY9n‰.yílâsþ={GÇü¯2s³wsÝðPËwµÒ­–ɆîÈ:) kÕæ‚uÛw—}uGeÝ]¶¹«ÝõÈ.p—)èKâ¤Váa»+K gä\œ«æÔ´Ý©gµÍ<„¹òLºWâèTugá`è¬7è©I¯q1vÅløõÚ ƒj ýüØP,w,Ê×O½eDŽ { Uµ¶–™Ãà> Á×è>4„ÑçÃ=[¦? #tI—~¾9¦¦ê)>Éû×Ùkë¼lÇ»2f[eÒèK!´‡tên|a•y—ñ€øÊ`æ•P 0s‰É,wâHƒ…êý®AÌÅ÷ë0çV½r®?æo/šmùq b;'e?ô4ƒˆT¡]c}#Eþݱ¾P%þ&( {bŽ5¢ 'ŠÖ°uåZM¥3_ô<‚x`»ME?v… x^—UoÇžÕ–Ys%^ ½°ty”Ú8¼ž:ßôºh +ÈÔ>ìŽù}bF[•îÀœå8æ,+µø´SKVá*¸Ûi›Ç,žZeêŽU…ùVP]þÒuŸ¨r1f wƒ™ùÒèÔ“ôŒ¢õHž;%õLÌe´pÎÂ4êsGZ@ÏŒR@úØvÓùÆž î”ô±™‚_@Ý•®WCá^–mFÊ-¯]@GšµRfÙc¦ ]mwx>‘Vg!-2ì»n›9FD" 9+é^DM.ã‹^{"’i’¶Ò!Ìõc¸`ß©,:´àß•#p ºÀ,øø²ywP­¡€/Ñ´Òõ´¸ªi¥·Å4ÁmËó–qÝî@w©;‚Y?,é^/”ÎŒNìÜq î(£†¶Ãî(QÈŸwGZ>¥cìŽ%iŽ®;–g—:®îX¡ø=²¿¸aË{$-ZY»#{ŒˆtŒL³£(Aw¬e%Lë‘““ï?°y –#ïçR¢#’ËÄ ˆÅÜD èQ§}~ÁNÉ!{DäÚó>{±9æåëŽd\8S¢òµû‰ö‹'¶àÐPµ5Úľð6Q«‘ØVŠsG¥¼ö– ½Ý‘èëâïm± åþÒµžøÞ‡ŸR¥­.A •zYzäm䱆‘’ø¹—i™[ç.:•ÆzÄß>/':õD;h_dôùÍ'ãZw,lfÖ–Ì$ªé9˜‘GòWÒ ++w%njÞaœôIÞÖ´IÛà]ÛQ_ìúÉgy ÓzdÉÏkUí‹´YþóZ¹úbz–{deWÖ–(´ =p̆kŸ+2mÍtƒ´HoÒrgWJ£Ç"êw:äŽEHŸ ZÓ¦EnôÜŸ „áèÜ0.! )Ç ‹°ƒŽm¼if›§Eg[“{ „ßõÕéEoµ(˜fÒ> RÐ@‡°¾']×2hëÇbûðD3DÁžbÌ\–B€Ü¹6±5û‰õ‚mH}qÍÿ²¯/¶mL¥jqÄgëœvëbײ¶é‹µ0UKü»5EÈ›ÅU6)JÄ(§~åý#Ñ4¯g¥³AòTÊ6Þâ¶&jÈ¡/åëׯggg™ºã°”!/ôoFŸYä¿&ä·~úð·÷?ÿ‘|ø‘üë?óÏïº#ÖüUŸ±ôW/ºnŠ “CÒw'"CÂÈk,Œž;)².çÕQõE¹`±X,JN cEióŽ¢ÜÐ7‹¾aôæ ¥3$“ ‡TlW}!„ö…øðË_›ïÏš èXÄm1í ×j6›Pî|™w|ak–78Õ_;ŠæG–(z³®E&ôŽÛFk0§:£Q…r|A4öPÞ!¤åŠ<­³Ø±È–»è‹Ï~žÛÛhî°ÚòwDó‰A¼Þ;ÈÓ qP ‹i®%²HDîÊÒu‰|Ìïh!³hkiŸùÊÆ:ã–¥ƒhâ»êŽRg,ʹ; ¨},^)’Dº IŽÂüƒî@w ;ªÐÈÞãõBâçÂÞ{Zg: ¡V¥;Ý%Dw)ë;½c‹îØö;}_Š•ùë°²#ƒÈ&k´Ñ„W6O1ß1½½Ã“‘CÈÛŽ²Õ&Úª¿FÞíÈùÌÆñ¢¶¡´‡|ÉRÑû]úyÜ%m2\kÞjCç•YꕆÉØ+ºcÉ;â/‹ðÜä<™ÓB•£CØÇ‡Þ1þYXçGŽ_OÕ=4.VtǪ&튤9×ã›4¹ïäÌO„›àƒò"ÔÁû‚dHüž—¬NØ9Krí'!CÖ5ZtâNQôólÐâ®™‰e,gÔg½4ycÊ—é?%žAöƒH™çºî¡ú‚¬\£ Äš]F7" k´ÎÙ”“½«Foâº3‹òˆAQÐ÷o¨+XÃuÍÎhdé-9w,ñ¤ãŒnW3ÂŽÜ7/h\»­eJˆªS/¸ÍqOŸ°ë½øª#?HHüIZ’%Ôä_±×Cã?ãyã܃PFBw¬µ.¹ü=_?NTŒݱ®êIÊ)¿I‘ºHó©xëõ¬¿è_áÐÄNuFÜ@½|¢d2v3$ª=ØíºC ½Éé#iò>äã†pï¡dòzíÊn`Jo^µ\ë}]3Ý,89HnŸ ×heþ—?éfcÃ3µ¹ Ú¬;ªá-™[w ¿&Ì?ètº£¨Ýu–øH‰u–¢¨àŽbtÇ’yðò½pŒ9¸Í Rl– GrN±©x;,©¶‘e ¥jTÚfoÿ;·ž‹Ï§õ4ˆU9Ŧ„ëð«Ø ¯ê¤ ’swp‹_ðR¬6ÿ!ÅfEѱ|“{©ZègõJe:?Hìþ•—Í^sl[)ô NÀâ \,æR0™!ŒÅù(¤pàÈ€ [Q‚hî©'?®ƒø|)â(ÊCôÈSPÈᇕŒÂœ o”sËÕ(˜»å9w0;ŠÒ—6Lƒ2®¶ © ²£5ž´}Á‚‚ˆƒâˆð§‰[—&=…ù‘t]÷š{¤‘ <ÞÒƒ¾©«ÜI¼ØÞ—HÈ¡˜&ýÕ¥ãÜë.ƒh£pÌQ›´Ñ‚‚#x*‡òH£óX £è:G`lØÓQJ… à€€p@Žòˆ<µ& p`ŽpdÆD7ƒà €ãÐ’1M9ä¸À!/Ç"G,À"Ç X"G Žu×ô‘£Ç6®€HeÁ‘—Ðf9ù8ß’Óæm“œœ|ü@þu;ÿL?Ìç·'ï>Í?¿çšâ3ÀQ>Xl ‘é¯m6åsž3ïÃo?‘¯ä—¿2LTG,6ŽW¹1D(+Ò<“0È-ß:Z}Pk°…m8,G/C áñ¢Q‡è^BO±_‘  ‹”k"š9í(½ ñ2?ó ÀE™°½*¦‚JHkeèW@¤ÐàȋؘđŽ[)¡b1£)+8è#Ɇ{ähRHíØW²DM¡#Λni«šQɇš×σ +âÁ¤ADQ o›ÛÔPzCŸØæX‘ëE1ì1ik¦+«õ{ N*vã¥ï,*¥¦A„"ƒ>õÖ`pÕ4ÇÝa{H3—Çó \¿ol¤¬jŒî͵M•cƒÅbFÊ-ù£SÙDˆ„ D¸W–)">Ÿª›j¼d ˆh¦{„lóÚ~d)lù@³}ÍÇ ùúÈÎ|ž/DŽP·ø(·Bºkˆ@å¬,8¶È‘ÃBDÚÎ%"^ œ}²C°XüºMŸ”ÆMp9D‹å§6럒9/B°È^lݾ*åÖ(››iëëBä`àøôîäýç9žñ~`±DÌ"ON˜Í”ùæ}r"N}øÂÝnÊ);ò5ÌÑB˜"Gë/?Ðú…¾999ùåË/bÎWó†Ê‹ Orõ5ÜQd½å98μAEŒ,M9yÃa9ä"9úî!àbD¼¥º…cØ*óp³ ƒ˜²œ'Ër‡ÜEˆT ÕˆežÊšI…Œ»J;ðq™)JC¸Í*‘\€‰ùF½4˜û =Ò‘+~Î/Æ<6bp‘!R+5Ö:^ I ì aìn\‘Í`±8üqdevàÅŒÀ¹ËêÝÕb{­|d­˜0‘cÉpFŽºr;wÎãÈÙ‚c¡]ñìEqg‘ù×P”k9#03Åܸ®%6=Ï\W儤÷x5‹ô»mØš·èè=?g4":-Bð\x8sF¶ªkì©Ó¼Ø]ͦòlûõ¬”7gWâósNïbL||(†M†mîÈEßX¬zÈÒ-±XåŒ:t~Èï‘­ZÑ–³#ç"¤ÌÆ‘ìÙ›€#i*|I¨5˜U%…gþ%Q®PÝÙ=1˜¹çJCì‹ïŽéCëûÈÛê;íáÕÌÔäžVõ^g¤[ú0x•ŽåÞµ Û5µakàÏöÙvjñ€ƒò¦÷ÛæÄÿíËDIc캯³ÎøúêéÒÀ$¼€Òx¡5unê–F”—¾ëŒZWMZ¶Á?ît¾¥ûTi=¾.𣫑}²¶æ8-6š¤eׄ"„åÂ쨉% }± íúã‚Å?¸ü]§À‚KËåc¿†BñWãõ«}~%VâSb'ë¯Bàõ¾§e|¬aâˆàwAõ¾„]"G®CÍ1l†ÇÒO8†šÓP#qûüJârugQ­çP¶qäì·ŸNÈûßùç&aÎÜ?ü@¾#ÍÛ/~¦ðøå÷y&æXË®uÕbC¼m´¯ÍÙI%"èãáýÈÔtª=Pý”‘Íýðœ?-‡7V¡û¨¾„ý޹«\>±‡åŒH¨kÆš1~°ã¿8W£ Ю_;L¥ÐÈ“„ ŠÞÔfL­9ø|$Ä œ·o%ïÖæmÌÕ5kÙµ¼%+\þ‘=ý¥—czT  Âõ;q\«â?QE…¼0÷[q…@Ïk’ëä“Ë…fH/ºê‘8¿ˆKˆ:EkbjÍBmåGòPH,ök×Ú\Q8¸¹³òë;5˜; eî,8°>²aÏýÖ’é­i<.p@ à€€pl!Ç³Í à€eÊ]C_@ÀãG¾‰# Õd àHÀÄqî•8ÀÕý3J¹ýsÇþ½„ÇQÕò9•ÎKh+p¬EÁ…noˤÒu'bB¯aˆ#®uœ â(ÞL‰¥Ûòq…;eF¥i¹*ßÍ&Ž“É -,.«_DKñqNM÷AQ.i;ùgõ( c[plãmÊ!ñ ã.EFpD¸òv'=U‘Ÿ¥O7VOxÜ ®/eOØs·ÑèÒ¿´\?ýð8éê<šßÓÀ=/»6!jN°(©†´ 86G¢ûš4ÙŸ[|ö.ÇÞµ?rán.×£×ò¼Ê…+ypE]øÅk±úéWÝ«<ÜôF´ã—xÙ Ò’G4[YC½pFÆ›nÒA»MZdh¹n¸žå™6Ü1šÍi‡¾à7ŠÂöÇò  ¾Zf{×fuVÆw¢Ž”‡s×{™í@_é’a ¼±ˆz,î"¹s=n #É©©«vgtj5§¢±+®ÓYw„ERÊLz<UDîÛîæ]yEàÎj¨›ƒc­q¤Óxá/É`\?×üMM¶1cÔí´×Jûx™hÄî µñbº¶ÖüLE싱Ùi×ZWM£Ñ0]]¹¯»=NtýXÆ‘õÀ±Á8b‰ñ›ñ$¢c¨º ›Äß—¦yc¿É•FüMô|ì7…ÞÀ~)o5óƒapmà ôÍOc®GµZo½¬Uð sšeÅÊxíç:H ÞfŒñRÉÌbµ=ÛµÒLºeÁ®UpìÌ®%LŽb¼Éf ¡g؆B9$ë3TÐig ^L;¡Y¢¡$X,FaY£3e†^l­hOG8ެÇ>æ#ÎtÌÇnf`ÄNv«i† Cé1ܘã‘1KÄ,BäݾØ9}Íìù!ã2TÖv=ŽDE˜(t-jùðŒW’i!ÉPÑ ¬³DÔb!6Ú[ h]Ϥ™KàºãÙYÛñ8’›ÄÂn Vûùgu¤ñ…lnƒÀ8 Çl~8R®çGV à €œpªå¡lö°‡]Í¡W?¶ ¢¥G•)4EF#€ @àXg4q ÛÛ‚ <ƒF–«]$Ù¯½vo0cîÄ"»;;.Ü›5àã˜ÒÖ䑨/MžË‰;t_Ëš (†>–@©ç—*ëQ€C 8@8‹çîeê65IL¡­µ ´Q,p+E|‹ “‘9è#9¸NzT>]%V„¥á ÂÈ 9à¡do¶p`¢L 鞇ÁöUpÄH ÛF Àq@…ø(48>UAx»è‡Ô°6[8p'.%—Âc%2 Eòݱ3x¨?Múü$2ê(ç–«áÙVuXáë®Da¡fŠò ¢D^óÝÒ¯£N»7™¹ÑýòÎHiô(œüõ7[QÚcwD y” Eáÿ¶O½PZ˜x@°P:žÀ“ûÑ©;ˆ˜xÆÕdÁ ±S—Œ tŠù Å Àð$‹õÙ†ús $<àjÏVèc %äšo RéŽÉp"3‡øp®’W<Õ ƒ#Ζ¸ÒWS'DÈ97ü+DóÂ÷h«T¬Àô‘@8’¥Î jè;Ä(Áñ‡?üá°äÚ(4sP|ÊŽd”`X9ˆ§1QC<§ý¸ Šk%SH7x`XPÅlp@À8 à€@À9Fp¶vñvR€p¬)  €#>8 Æ€# À8 G1E¸%ÃSàHFAÜ7€# B€€#ÀÀ± ÀÀ±:!ðq¤àȸeø8:p¬µ™ø8"pl°Íø8 pl¼ø¨88¶ Í|T¹íØ Ó'Í[9uÕôÓ׿û3€£BÈØ’?>žœÜÎç(äö‹€Ì´y{öéyÿù+G=uv;?8JŠŒmðA‘Aññ3!_nù÷æ_¿?9ùðeN¿ý‘ýù„ûð#¹m¥EÆÆø8y÷i>ŸßRÂðœñ4‰Œ@~ ?|žưRdl†/ßýtròÓ—ù—_§äÏ|ð89alÁ 2ÿÌ?ÿ0?ˆÔŠ §3"–®î B¥ç|@iú‡œ`µÉVÙ9cÔQt˵ åÔœ5:S×Ò žEH1l×ԔΈÇü¶ àXk4é‘}ìšIÑðÖí3 [“¨ ¶A†C/ÁÑaÿ(=8ÖÕ3Z‘?åíâüÔ;4ñ3ªœÖ37Ëø|”h –{Í2î´®ujØìˆ;«Ó#,]—ªŸóÔpY |™‘¡Fõ5Ƚâ%Tu×õJhæ9»€‚‚£ ©CÒØ9 “ìñð ¥cºVÚ×qãÍiW¥†D„ü‚2ÇJ|p£Å)™^ U&¸mChöÈÑz Cdš¥j†dÞh*ÜøášL#íúkÈ(å°² ¶16Mþ€I{È’C²Ï—áùq—=øawlFÌ3aüà£Ä²%Ó9RñqZuˆ¦’g–u¸eùC‰áŸ×̱1M8¯ÒÜ5Ì@û<˜¥WH“ñá-º¤E• žM¸åF´ í¹×6u¬cÞ¨<2ba)¶¿ÓÃÏVñ!-BÛLJå”Jª¦ŸG6q­œQÊ©ìòy2riS+ÔíàŒrƒcwø8Ndär˵¢ÝR¾ø86dä;²ÔŠy{¹à£IÕÀ‘>ŽyÝx­°·· >€Œ*ƒc|ùh’c2‰ZÁ_‚uñdˆîÊÅU¥èþkáÈ:*W¦8ûdÄë¢íñQO°•ø2;gK|”ÆMp >€Œ%¯Í6ø(“i">€Œ•îÆø(™ƒq @FFU}3|”5½[ c­Iþø(q2 cÝ_­‹ƒãëׯggg²/dl€CãëMÈç÷xÐ{Eƺø8ì°òõäÝdþùO,[“œœ|œÏoO>Nç·Mx©´ØÙ]H¼œ2âãÀ:LJ¿QLå~%?ÿÌBµ1)7±ä’0_7¨,ø(˜Bzöç_~ŸW#îg¾! wá@¹‡ÇÙo?÷¿‹n#´ÛÈ?ïÈÙû?ñ­Dr I¸;×ëåø8sˆ°kâ½ñã³q¤È_Ê,y…$Üõ¦%ø@†ü%Ç„û‰e’†€£Ê³Ö˜8Ž£ªjv|%@†ˆ±I?(Šâ¦GX‰›)±ô5øà(g¸³ÁÈ!çaÌ’QÃÓœ¶V¿g0¢`jZî‹uÓW”'¿€Þüà6RD“4|Ô*Ö§$W÷ëÂ&êù‹MzRÌ’Ak¨(CJ'Ψs­kªæñJ0x fl›ù€ôáa)쇙 "š$â£VLƒžáŒî)ž¥˜%DcÑY°šq×–0ÈË;ú2iyßOëü=²z|©U¥ÆJ2x†„…Ÿc–ÐÁ¥=$ݱK4r¯(mÒEB«¿²3®©Lz qÝ׎Ҟ~ÄYŽƒCPß"J=¬$2U#bìï&„' c–핇3±I3,!~%ÕF4‰‰ð•)ý°@¡ƒKÞ[ɵ RN^TÕQH+ãû“>–X5² SÙ ã#fÕÈž5æy p”¶›õÎSfGÕ™Uc|akæé¨CÕ ÕSc+Èêð¬‹>¹%‡¬XTê±>䨬¦;ã” Œë¶¢Ð™Kðð+ˆøº$QWUzêÒuŸø_m—’!M5ËS]rr:£ä$‹âŒ:ª©¿ÓYK6މøØ~,Û2gŒù³W|HKÆ¡›øè‡q×[D65GQЬŸE™D@æŒF½Þ³+–§[×Ò¥¢ô· qøžQÄËc­åE±Ö`pÕÔ‚G­4zãq÷ªiŠÏ­ÁŒ¢$¬™»ú‹&ÑpÒë’®©Ûöè¾Ý›Ð»u” Ûñ¡‹Ó#¢Xâ.Åýø|ä¢å¬ ŽÄ±m6h=Øä¾­Ì\W%¶Òu¥³ƒ9DcIƒÛÏ×Õ)¯8îŒ"#èSËCaúkÌäšVÖQ:Âe42Æ> u”ß«…}e9ˆmb–Ç:,ïÇÆ ûLaÆ´)°n]wFM±QŒØ>*Î+½(«Dw­!ö‘ãŒnN¹Û _¿Û´LZƒ×`Þ‚DdìT Ýò[ÛTÞ^&äœÐ7©Á™ƒ9+I¢[c ——ɾ²ívOQzô`m¨ d+J;ÖÅçŒö'ä‚Ót]ó¸Çu'­:?xúüêðÓÚ°M‘7¤ÀjåUÒŸÕsoóŽýÐ×}ïÿ³2(è½»â ÷³rwŒ{®šêô†èþ0b? 5ÍìMºþW^¬(ÈÈWÖG²?£‡æTrɇ ®ƒôÉPÞn§µ&ôLËÔh×{‰çùà °ñ4æ¯8aÊ#2îbª¶1z%çº)vó}žºm4îL÷¡'¨ë¹ñ26åò§¦ø<í´É‡vyÏ´7öh­ë¶7-2¤4ÐåžlrúÚyÓ-Í™6UbH×ÌÎd¢ó­î®åv”½ á¦ËŽÜ õÀªÆáÁ‘ˆ 3êå.ï¾"\ Т£‰»*™Á/5þ»áÎ.o3–P&è?ºç%Éßa¾£KœÚ¨*6yÉåý6øgØQ®¢¨btÞØ¼ ¦¸öWc¥T^£Êëáãâ,¨G8ošnX³ZQddÇqO\í¾žu¾Upd|zwòþó/gPˆ´>Ïÿ/„)`’”З«Á±Ü4Kõ81L´psÂ[à)Ÿýe•,ìóK#Õ˜!¢Þd°vd7„,ÚEö=MصœE¿~Ÿú²¶ 2lƒi£}]¥O¨ÇwõO;Þd"ì£Nƒ™ô1y)íž8(!<Ö3¡¥º®{)0Ä7i]’©¡ô†ã¨™Äo¹‰‚k 3zÝžï˜4ãÁ«VEÄ)¯a½†o5á )·‘Œ…±«ÑóZ.˜RŒ…Ú*6=I }YÛFÕàÚŸ­ÑYW8 E©·B•S·fÌÂðF§TÓ¤Oý‘<FÿL,ÉbÈË9Sni…š;ØŽP]ÙÔA‹è¦f ïéã=÷›á©À¼V^Ì„%[AºÃ6U,ÛîP‹½ ùÙGM)“…ÚJ©„¶þòÃÉÇé/üóíüËÉÉÉ/_~ù!ŸSB_ÖrPBß^Nù“®·VœHFˆ ÁÂbÁ0$Iý4^¡óú|ª…¶ùg:–§6#-lM¤,ŽÝeó_aÈ2¹u”q+7¥”U Œ&ž:*tÒæÊЗµ¦'ÚuƒSt ’ñbQd#DÀ}¬FãÚœÑJLíTíÝŒtK§†S[½OßÜëW¶Ò1¤Ã®v”áÕÌLlF7¥‘hf[ ÎLJ3·5ìÂÀ±hJ);2ò™Ê®… Ç·0MB6ªÂ® ´ÑÀ¢à!|æPY 7jx Ui~…|Ön„Êx¶“0ŠÍB3$=X—L#A|d0"ÑÝÀ6ʯ1¥¸±ÚŽÉàÀZ|•&®y‚cÏÎ][Ì?,ÕX=Ypû2’Á箌r~šºìÚ 9‘‚ã,wØÃï^e¸ÛgÏU:n {LÚ¦é õûaf²<¤õ˜GC§ˆ}9N%4pl±t1÷¬/"ŠýÛU3ˆt¯ú 2¥ii‘–•ì6r¼Ý¾']ÍLªÿ´þÆ‘—Nÿ8‘A¶L:¼±˜îXQ”ÁxÀáÐò“°œ¯@ŸÖXømóª¥ø V„X"÷ìB>ù¸9oá0©_Õ_;J›'jƒÕ‘«›ƒcSdÄÂÊkAº>9ÿh?8»”ÞËõgFŽGÓŽªAéð¸ªó¨ù~ý°~ ß 2jRÿ£FÆÚàÀÄõxA¶Ï+ ©*2ÖǚȰ×ÏûJgäXäà‹XMVÔìŒ:"uRÓ/3Ë1M\7GöéIGayÞ¥=¦: ­³{ÌšaÓ›nµY¢5‹îˆòpNç0ÎÈê¿t^¯-ý­3:µšÓ¾®‹z„±K|–Íb,÷ 9nK6 žÐïtè%üZ'»P¤gDk¦U¿y¼²t©Ì¸;:5›Sfü¸²y ÏÝdŠ¿G2=ÙkL\ÑÕŒ=ÅA‹Ü7XæÆ!ŸÅš¦é™œÑ`ÆUBK§ï®k²Ï}Ý~R,flP'/¶Cµ&yåõ\xž7ž:PQ鳤ՎMÚ$lcÌmò,f6ðf%¦_ƒ3}ÔtÝ~è±\MWM¹Ìsû™)ºœK&ÝK~êY‘ò|22c]U㜽I«E.‚w޽ܮ;ê(¤ß=× T5ÕF-¿éÉ6¢n45)ŠTÕÕ¹–ƒZ$qGU÷ ´ ç{«íÂc§Ø¸™’üVÚdû¤ÃCDr¿ðÌe’EaÁ!Ã7B“F3t¿è¿Ä<3¼Ÿû¤×´\Õ÷42luc»Üñ¨©à؃\$!ט‡˜%Òçf³Œd¤XpÈ ƒ™ïrawC÷ mñÌð&±²÷¡3ÞÕïMÝ26Ç~VOZžÍÛ…°x؆Ãf.7HDK†ܬ¡’—I‹ÜÉîIž’FÝŸØžÛ7Ãn^#Αd¬ísz"\1\÷Úwà~_&·(t»D¶}‹Ioàѯ¿J{È].ˆä~óüP'=…~ L;Š7‰½¼¼é[.šT~z’ Ž=LOT_™ü¯22lÒ í’ûEÜ3C| ú¯3}4uh9 ãHÒQ‡à(üÄUÛÒ¢æ¤m2’CÕX ÈHòÊB Íjç€@À8 à€€p@ŽÃŠ^)5Žˆ v1À±VðÀ8 ÇnG(à€1óŽ œXéO6ð˜ÿÇ?þ p9À±ßfq9è+EÇó÷ÀÛ¾Ðà8ø~ Í£ÚžT&páÝÅàRDpd—"‚#ûSu”9˜¹÷Ê®9äQè©ìJOÚuÝR‰£( »A7”Î3™Lü4~L½ò8pQõ>‹Ú~ðCµÐcK$#äž…¨vyŠ8BH õ¸ÀAœ×ú©6lÕù—ÓçWçB:9!â ÓðB.ðP J£Ç#ÈöÑm£qgº½ðì¸;tˆ©ÚÆèÔ4·N¢)8‚¸º¼1ˆ#ã*e¡n@@°ı½JXâØ|ÎBŽ2й  °ı9}c²z€2 Ž0HÅtû+¸GPıCÙƒìg{˜â€@ â€@ q@ q@ q@ ˆcß’˜o]>Oˆ±—ýq@rã¨zÄÙ=›  ”ˆ²Kq@0I€8 ˜°@ Žâˆ¼Ÿèˆ£"”!â!Ó¿ß¾}C~ˆ’‰2d}@@5(ôq@6¤ ÐÄÙ2@(ã¿·Oú€€8@ ˆ²{Ê}@@  ÐÄÙ/e€> PF écúñäûŸé¿?üòûç÷gI§ÿ÷ωg H(cÿôá“•£ÜðõÓ»?þô›ö×ùm3R^:á™°žú€8@Õ¡æíü 9ùžø qöþóü½Dœÿ(ÓÌúîËüs3Î%ÿüËïóùmð³wÐP@ ŒcÑ>½!Ui 43—õ ®‘|ý÷o仿Ʌš€ˆ”q4ô1ýõç`vBõÎ!ÿùúc”X¸rB ä¯LÑøÏWÒlÞ~ùpò} d°2ÿÂtÄqä”áŒ:Þ$~´;vM­"ôá«ò§èœ%Ð R ȇ£_ Ž#Ö2Zƒ™¥«+hÅ+DÜ«‹^oè"~‘h-¶¡´‡+j/Àäâel:1™ôJoGi¼ô]× ©@!ãYLÉëš>=±ëZq¶y¼šyEx¡N}ò}@@E¶e$ëo/“Vý.ü~Zo‘Ç×·:!ç^açõ™´®NH.úa}šén5í}@@Å¢Œe¢]î ã\X;l£Ñ#ƒ™~:} ‹¨z¿Ûk?Ø:-â)(ô“fŽ»J;P2˜Vò<ØHã}@@Ť U·\=Ã)ª6ˆ9 =(³‹˜—^<ÿ²­€> Žâi%ÐÄÊØ–>Ðe‘B}íxz\ÐG~µÚ†rŸ¾Þœ]^,ûµ¼õÙ¼ÜD„Æ¥£Dƒ4ŽòÒGèšÑ ._ët· oíÕåå¯I?—=>Yøë³ì”òÔßœ<@Çé#ð°Pý¯„Ôß²º]ˆÕã’¿ð¶ÑR.ЖzmH1Õƒÿ”q”>bê9Ó8^³»]Ôqù¼ûK½6q™  ˆ£4ôñ° o1^´ÍuÜ.4s6è4”! T†u¼6–¬ý‚2 ŽâÒ‡äT!½ÅÉnîQ"_þ¯ 5êñ‰ÉÑÉ¢5T>rðÇ âØÚöQ<eTE[IqT–>@ǃRè”ɪtäƒ8JO  LX@ P¤Ð“G‰é”¥Äúe@Vs6¹>@r ˆ£ôÊ8f ‚B*Š ˆ£ÐôÊeÈÐ*}€8 J  PFœŠ@ ŽÂÑ(”‘B‡¥Gè”ÊX6‡¢G!è”ÊØFQÝ?}€8L  PF^¦±}Òˆã`ôÊeìb1n?ôâ8}€2@»vÿÙ5}€8öMEó†TŒ2öCÇF_?½ûã?ÿòûç÷gÀ1¤Â”±kú8*â`¬ñÓo„üöÇ“™ßž}z÷_ä/ßýôÓÏâôz¬É?M?ž|O"ßD‘~åLüÇòèéÿýsñOq²æKGEgï?ÿNBã+¥’ÿ7ŸßzT‘ª ð":ßýäq0Ò`ôþ7Úûþgüøç™}ŽÅL<š}»ã»?-Ï×ÿF¾û[X¤y;oâ5Þ¿Ð~ÿB$-ó÷|üqþ£L3üé»/óÏÍÅÏU¼=}À8ê)#þüôëô¶Ùdû_:*}€ýòáäû` £ÿÂt¥ úGªÒ@if.ë\#ÙËP®ôæÛÐDZ‡Òü8ØÇËn»Ý¦s sÁ|±àâ¡e.gªü(ı?xÁÆyìô¡¥øqÏ­Óä:È«l¸°“\<ÔØÌ'µ@d 6WÊqsc d?øR:HÜ©t‚/iòŸ˜€8 ¤t€5`û8¬l“ßÄ äèècû”` LR GDyeq@é€ìü¡„;rÌÉâ8Œ n@õ(©¢Q\â8†1zÇN E;Êp^+ÔëT±Ð¯Êhæe¤QF±ˆ;—!•g½ÑÇN)£(ÄERº×¦°ô±·{?$q€2 ÇI» =ßûÁˆsÈñÌMvJ¡Ë \èã€7¾Wâe@@¹ÐÇÁo|ıÐr€³PV¥Í¿Ú6 Z‘de¨¸¼* ¶a—ò+67Ù˜> •µ½QF }F(€A»ç¥€Xä•¶HD| YÇûÞjM&“ÅJ¢i>£¿ ^-?|RìEã¿%ƒH^?ÿ7^˜…þKÃ?”N*)¿L _ê—cÄyá7ëZù‚^ovÇYl«†DªóÎK׋ºýä¼!wô8¿„Á.øåý°ÛwÕx“‚KŸJµ±¢±’> u×µÃQF‚°$Sd"^œEmdØ6.ÝËä_jælðÜèy¹iį»Ý‹áp’TÉuŠr#Â$$«Böéû¿óÚÙVÂôú³A«!uƒL~ö£ÿÝ`íí4xk˳X/´uì…õ#¾%Öoëô=—b©º5~ s¬Á"@ù)7®­áãÕuÀ™¹Ê'Û4yƒÅk³+è(ä69àƒ3}¤·"ª¦·uÁYÁ~’Y–]¯ñòFG Oº}k±I¢Ì“}]ke¤ÑGÑv*Ô Bâ%äî^²QSH¼Å~Jùµx{Ú”:ÈE+fsú É#þ¥ß¢^ë—7,0/o(£ÊÈŸ ?ý:½m6™šñ¿tfòAÅ—'ßJÓKþõKîGþs“d7‡ñ•ì4±TºcïÇÚe— _ÞÒ< âZI+¸ªÑ…Še…›‹š[bhñµÈˆi0«“Hzo°†Åo3\ß•º¢ïeýIé$‡‘@¸wEÜ eEüNÈÒ6ÌMö8[™¿—>§/és’ø%âØ•4ÙÍát« = â"_•^´uuwþ²Fáˆ#†g*<¿ˆŒ*™œD’{ã<¯Hp‘š/‘ÝÂ0ƒ7 æ&Ç µÃSF×E7:x§þ yÕêõXÎîäEÝ4ˆ%¢þê+ì¢+âŽ}¯†Ö`|Õ"/Ë /Šó€àï]ª“HÒ$÷†m¬Ý¥i=°à0²0óõ¸èlJÍâ’Õüʨ>qìhÝ$’/Ám Ái"±t¤©ÒÕ¾"L+[á¢G“ôéúbáhò>’É#p‰Þˆ–ÞZÚm.é±ÔˆW6>ÅÍcIÃÒۖIʼn£Ò«Ü ;('øtA@õˆ¡ý »` ôCe‰ŠŠd âe@@õˆsæ&5ˆŠŠdmâÀÞ§C¶z ꈦ*â€@ â€@ â€@ q@ q@ ä`ò÷¿ÿÀƒ‬¤ ÄM@@ü„N@Àìhq@–¡lÆ)ýØ€8 ˆ€8ª'‰ ù &&$.X:€8 9sÔ ˆ½â€ìžMÐ JÄÙ%w@Ý€€8 ˜¤@@LX ‡H]í§7øíÛ7 o?"Ò_£*K‚2*Ï=SX£ÊÄq ŠŠˆ£ÈІm(íaäHk0³tuùOîëñ2ÁÁij‘Ë‘±kjKêwFÆã•¨"Kù|eeû—œ…¢)qìtnÒ¼™ôÝP v$úÒÆ^á©¡ô† ¿Ž@o’@F¯£N[œX$)ÿG“†òB+^V>ä¼®£õÜ«‹k¤w:Vþ-zCþýehÿ²óœYÆW©7ÊqTqnâŒî‡” VŒð“—sËõ^2F4OãñâØÜè]Œ]+¡¦sÝruï§ ã<Â;ªn͈¤q$—÷”¿ ìDgA˜<’;¯-¯,–wmã’_Þ6ÚCÊ€šwÅåí÷Hã¥ïº®Ä¶> M^ˆ•~ƒ˜›€8J®h$Šê¿¤K¥U? >ŸÖ[äe±ˆfŠ·Êç»yN8Þ^&䢯ÊK¨ûâ\]Q~ÜUu\>ù´‘µý´ÂVýŽD:áñÕ!ZÑ E£âÄQ€uö2ôžlSÓu#±› Ú,ߠ̉õèçÝÞbwIU%v2 GQ(CÒ¤µsMr:çɾa ‘’Vô"š÷~‘P/ªKv܈°2ÜÜÂÕ)^¯iþ(±6ÄÜG´ø§´z’»+ñŠyûu€2ªOUÜ ÏF㾫ÌM*NÕuÐHÞ!Ùe€5*K¥¢Œ]¹{ìAññ}7Ê{   G)µŒX m­`$yëëêˆjýö–üK®Y\ Ý#~ââ\E×B@’¡¬"Ê–« ÕC·\:[QÚÿŒë.{ýYyÎPüêZþæ¡7vmSƒâ¨Æ´D÷YbšéºË¾™‹ÅÍݼ9 Že"ö¤b9¬q€;À¸¬q€;ÀG¥¸C|86”Ö€€8r`Œ«Â BùBÜ,(’£ücaôW—˜qIEND®B`‚ivy-2.4.0-rc1/doc/images/ivy-terminology.odg000066400000000000000000000505501226750426600207100ustar00rootroot00000000000000PKi©á8Ÿ.Ä++mimetypeapplication/vnd.oasis.opendocument.graphicsPKi©á8Configurations2/statusbar/PKi©á8'Configurations2/accelerator/current.xmlPKPKi©á8Configurations2/floater/PKi©á8Configurations2/popupmenu/PKi©á8Configurations2/progressbar/PKi©á8Configurations2/menubar/PKi©á8Configurations2/toolbar/PKi©á8Configurations2/images/Bitmaps/PKi©á8 content.xmlí]ënã8–þ¿Oax{™nH©«ƒN ½}¨šitgžý3PdÙÖ”,y%Ù‰ë%öç¾ß<ÉÔE]lÉqR '&y$òÓ¹ñˆ<üþÃËΟÝ(öÂà~de>s'\yÁæ~þß¿HÖüÃÿ}®×žãÞ­Bç°sƒDr Agˆ:ˆïÒÚûù! îB;öâ»ÀÞ¹ñ]âÜ…{7È©îèÖwä^iIœœüÎä¤1M¸/IWbÜ–¡µŸºß™4¦©W‘ýÜ•·E Òäë°+ñKìK롾ÛÛ‰WéÅ‹ïŸïçÛ$Ùß-ÏÏÏò³*‡Ñf–Ëå‚ÔvŠvûCä“V+gáú.¾Y¼2XämwnbwínKw)8ìžÜ¨34vbsOu¹1j‚†‹³Û…h†¿Ž›ÎÜuÜ`v¶vÔ™ÏHc–UÔUwVQW4íÎN¶‚çk->¡JòñécÉWÑ®ë½p[*'òö‡™¶¦éÃ0,ºŠ Ra'Ý…Š¢-ÒïTëçÆæÏ‘—¸ÕÜilîØ¾S îê@CíÀµÜ#fùBˆ0±€.Òê¢q¼^úOw¶îÎ.{í%/ˆ;(‘‰wžßù) ¶¦µ¯3+à¶”èdjš² `þ‚ôÁÇ‹¢À>$!¦v$"ÉñÃ÷©D“ÏYú?¾ùý|µó¬`m£žŸPQª¥½½qç 1é&âH7‘½ßzN^¼·#lžÈ)%¸®ìh5ϯ›‘Hû%žÏpîÖžaôC¤¸þ}é>­5sžÖ`«.lKÛ0ò¾ Ógû’í{„Šƒn‡”mwÄ×uÊVI¸ÇãZPk%¼Ö(ô£(í£üÇ!N¼õ©Ë0Ó&˜¤M>K[×Ûl‘BYÛ~ìöA„8‰ÂϘíx;§‹$\‚?‰ìµ¸‡ÊßBEîj(VØy«•ß íÝrÃl¢Þ¯°³)¡Ö÷sI‘éìú £_ ×p ÍR# &*Æ­aБC2Y óZ8¬Ñs»8XWPA #w9ל96 ù™—¨åmëa\¯ÛaôÝu"D'‰~^ÞƒIñ¿y} 9ûxD×oz@éŠâ{T›ôxˆ¼Ú÷nò®èµ8´šTjme‰ ÕOvðšo ~|Y…­_ ¨ÏæË+ºþÂ^•ÎFÁ¯‘쑵 æøªWà#ç‹ãžµªe!«·póeìúÈyÔ:û:â#çF÷éì¾=rÞñŃosžš‡ßîµÐ×íyä\×>P2NZ–Œ|/pK3pß²KôÈ9…gȲÀïο>Ó}îŽçž­Ñ†c“[›>r¾áЬÒ»¯s÷È9нµÙÖU|DøâÑ·±QóøÛ™¤ Þ ÀGmû`ðÆ'J|0÷Lk>Œ;O6ÿû^œ‰>Ó×xskÙÀw®Ÿiˆ§ƒï»É,­ÄåèúóôkZ%áÝÞ÷óþÿÿµ-Çá÷ÄŽ~?ížù(±+=£i]ø,‘–Ù—b …Œ¦ÿ\Sw{ ¶ †º5$Bïm]Ô]‡‘‹XxîJjðº+ß~B4Åê+£ËdõRC¤ËÚßBÚ€Yï!}0„ ¬½K„ŒÁRß%>æpø¼S=m †öNõôr@„Þ§žÆ³– Òß–¢¦ª3‡y!Lî’U<…«Sñ%Ëâòð=Y_Œs¹¤+SÅâæS±Hš¤ƒÉ¶¿Å‰‘$0YÝOîÚ>øI™v†dᙑœEeŸÖ¡sˆ©Uí¸r¿÷OÒʽM í•Kmè ÷Š\'áûBòË«£™µÜ¿æ5Þê~î­ð›7òÕ·O8ÑúðŒä¸¹Ëwã’=6¸ _w¯ËEÑKº[—üž.^vŸõlã\izARÞO+ˆ$¢’²½:B:½ «##{Ÿ1.;Ô¬±sÀ×?¢úOáêà»ËàfEb?-v'yV·G\T žu=.ôì¤xkïݺ‡…¶£®ÉîF]†ùvpþ€.øÌ QŒœôÕ ¶8±ÓJÚ¸áÎM¢¹ùÑsŸÿ3DRfÊ CÉ>ó¡Ÿöèò3;Øû_ŠKíIF°O3Lü1#g.3+ÿ*³ÿ™ý…ˆ?~þ< @w £º‡¡ †Zÿ0¨þã¸`†<À^GÉ…èë’’ˆÅ…ª†EuÖ#;JÒ.ácŠKÆ'µ ¨UÙR…tcÞ ÉÉNÕTKô±ïûoà“‚2Ç­#_kðµÑÄÔ¦LË7Pàê§qÚvh¶.áG ûÃÚ˜ÅBMÒÏ´ù‡µÎ”Òùˆ$¼a…Pª³ôWÿ Ï%BÿKèå[©*òÖž!2UQÐìr¹4,Uµ ÐM¨>¬Ëžì?,P9 ÿ{ 9ÓhS·.G [tðmô°0™ô2+Ôu-¨ÒµRÀŠo²@ö©‘N­Ò}XÃÙwÀÔ•f:­~døa4ê5]ÀfCt3½¼zv+?“¶ôÄ_±—fD÷x $“s¦bmäb¼HÈ'óv‡bVA½ý’ÖN,åžcý&ÝÚ¢t¡NЇCëào𖈠ʣûh– ‡t;ÔùÃoîÑÃÙyÇCLC9&É´ù”UYZÿí¼( #jk^á¶ÒÕùŽ<¶’V€MNƒ³uQðêXºjÉKSQtâ5LM꫽ü©".!­ÓºÞ ±¿*Ìe_é.ûåØs?EwÁ7„‚o´Š:ääœñpiy]6{z»'€á ¼/A0`Ñtbÿ[cÈØ=p™0¨#|²71ô×ÃЂYsW†Ökº¯w^ØHi¡2šÆK&££øb“Ô}ERÚçObgoGäÁª‰£¿ Ž>“…—#°ðä M,̳°ÙQ)·¿C«y™ÃheŠ¡! êMÞ\IIú±Dœùv4rÜ$Afƒ°a¼ôk·ZZ”ÍÃ6˜¥¶‘›8[r-é%SŠœØ¬¨á»g7ƒ¬¤ž\^Ìt­IÊðE åW…é ÿS†îQ3$_³Œ†È&Ó˜´Éš‹ŠêE¯ «Hð¾c$µ[Xï÷ë@Ç…åÓðµÔNÉæÉf„\`>'„-„\tÇåÛBú&Ogßa~o¦³„À€Ê%G«µ›€ã|#ÔÏe¿p Càl!âØ%{kÑÉ`Öš}SQ÷ñ³‡äÞ]1™ÅSpj1§›2 =ÔÇVäo?.·ÄJH«Ð‘;’7_&c1‹ÉXLÆb2¯a,†±ÚÖá‹·ŸLÃd&Ó0™†É4¼]Ó`dJMCM¦a2 “i˜LÃd^;ÄÔ¾2£¥b~j)¼ÝÞŸÞFL¦b2“©˜LÅ%¦b¡!ÖÙKh#ÚßQ+ò¨U³ È†Ál;²fÑö,3ûPÞ÷)|iÜwÖj.„ÖaQ¹É¢Dãö),ç„Lðþ‘²ºý‘a¶3 ƒLÓû¼ ÀY ÁYvG;‡m´áÁÆ,ÞÛà ÔHls™¶±ÊawŽ S/É{(sx¶C €"„¦¨jÀ¦FžLÕb6×h´Gc ŒŠ>ø1 ÖÞæ/µóîÍbñj¿MŸˆì‡(ñÖ¶“\áV³¬AZëàÜ‹‡Ÿ_7À\¹Z@”É;žä—?j`)Ëå0Sj2>P+±kƒAÔšlÀpÞ=€ü8SfŸó²m xu±wÝð<Γÿ˜EŠ”Ù3u¥×Y0Þ-ðƒãß"œ•E‘Ò@LÍ…òÛ¶Åb¸è¾m[ƒ‹ü"­wÔ™½£>ˆ=c>˜¾crQtø(]bL|Ð'‡_ëõÉniœ6ƒÙ¶Œä×Ôñ«Ž d›Ô¦ êØ¤ù³f?¹±y{d[Ʊ뽓7‰ÌøR6iCn2†|)[P™r]hÊA)7¦Ü¨šrœÇbkêà ¶5µå¹Æ|XüÒ2’ÿ³û|?—êå;"YØ4X ²¨²Y³²VGd!Ày°ÐïQEÈ‚ Òa5B+N†Õ×åÔd³) (S ‹ðbOD•:Du¢°DT3uŒ(ñ(Y#!y&m`QUVÅ,º¬ƒ (]9}¤œ(Ã4ÆãÅ×EPë‚`G! ?¶ïZ£Iö…V”GP -°.Ô -mhÏ(ÔceCñæê’9gº²ÁÞ{ì41æÓ"ˆiÄ´¢ÏtxZ1-‚è·^ˆSR¶¯¥Vx;¢Rv@¹§)¼ÂȤqËn±J¬ò€ŽfP³j^ÚT†Ÿ"Ûùì&¼öVsÌòÇ<navT*UÅÇâˆZ–vгæûëãVѬÓÈýS×fú£•ÓÈÝ §Žëy£X“GÈÉuoÙ1›,gé°¼µŸðï‡/ÞUèLÂ; ï$¼HxÅÓ¹ó„6¯1„åÃCä^IOò;ÉïW&¿â5Zl8FofЎцÇÄ{wp3ºÁì׿~ºêÙ.qú:Íì^r{I 1(<Öüáf¶¤eƒmPÜþP ¦ûþ‡‹WF_|h–™¬Oþ±X/¨%¤Ùõôªo§CAkü ÓÁA7xöáP\Y¿úyøJ‰Œ¦D VeSÛy¹`¤r&E΄„ú¨9ºžãx©þ<`m:™tÒUv>Ïq®SV“ t„yÆž:PLô:* ÚÚª”ÚÁ*µÈ?FÙB(Nð¤2ºÞü ±eƒ€õHº¥Šoú½aCˆ°Z‹05í Ï;Æp8fl ö¬çfk Ê jܘ·µï»l¶VÊ8·ÁOm&nïÝØ •c}ØÓ8Ú±÷?c:ÆoÚ`\¡˜6OŒ§ Æ×7gåò‹öíŠíÆâ·ŸøéÓϲ0íd &1ˆÉ@L¢É@l: (~7Ö~X…]FÇÐó•cmƒ|¾ÀKE Ò|bJ¾KÓØU_Y ù¤ç±i &ªQà*Ä„i³üsˆ);±®ï{{T¶hxÒ8|tfLO˜Òñ'HŸ y‚éÃíÿÁ½­Ã ²àAfó•U"fYõ ô›š’èc{­v’ktš[eÓ—rÈ‚Ñ^·¡ÅTŠŸ&-öV´˜ZQ 4—ªUp+šLmÒcÚmj±*Ð=¦Þ¤ÓtØåÜQÑbôŒ*ó›PjÚäš½A¥&Vi7ªÐ´f×L¿U׬Q¥i7êšé®Ù°JíŒS´:¼«ÕdË0xÅÅ(½¥Ê¦1ì‘HËùÃ_£xq¿‘€R8´xØ×Þµ£ Š×Àö³Ê,Þ6ЖÁbÌBÛÛ¿68˜?üæ’¨I®°¥Ë(ws·»Ë í¬¼"_ûᳳū)vö&p‘yV^üY’U±éù[%¹)üHߤh’¿1OKó -sªƒ¤ü/Fo{®å!ñ®ÀÂóÈ^´oIWÛÜ v}u ÒºX)dà%k&9 \°öêr†í]{òp{f…>Œå„»]ÅØˆ9ë8z_¼ÃEbìhвûbïö¾»eùÖF_Éí8øðÃh#Û{ÛÙö}£V—¬CtÑQ¼*VoóÜźE|Dí²M¨t µ ‘,ŒÕ¡®8Y6¯H¦®H¨X×àÿÆXç9"ÀZe’ÑàB· 0>Y‡ÃqÒ. Í¢ÅB{ž]¬=%Sh©- 7‹3é¹f1-ØÛ<1 ×kÏqïp‘lÊ‚§pu¢ªCç°sƒDB—IÐ߇PKÉöãK°™PKi©á8 styles.xmlí\ÝŽÛ6¾ïSZtïhëÏ3¶7“¢‹"@f±Ø$×-Q6I(j<ÎKô²ï×'ÙCR?”-y䯓™”3ãó#žóñðç˜ö›Òĺ'¼ ,»³Ý™c[$ YD³íýéã;´´xûÝÇ4$눅eJ2 qHHarV¬5óÎ.y¶f¸ Å:Ã))Ö"\³œdµÒÚ”^«¡4E=l¬º6µyc•¥lGoƬ„MíˆãýXe) ˜šê1«üP$(f(diŽ=²â!¡Ùç;{'D¾žÏ÷ûýlïÏßÎÝÕj5WÜÆà°‘ËKž(©(œ“„ÈÁй;sçµlJkŸ”5MÊÊtCøhh°À'³šsR€¸+ãr܃LN|ÝoGG×ývæp‡ùè8SÂÝPñ£ñ¡âG¦nŠÅn`~—ó÷ÀT?ÞÿÒÆOÇŽ%e;P…œæ£ÝÔÒ¦>c¬1U*èÅ®Ìõ'˜ë׆ôþ¬øžSA¸!žq6ˆ³´4sç Ƚ ùÆï”&£½Ù Á ½”5BµJ‹F*ví·uÞÕéöí™E øgÂ-õ·àÎþ‘s¶·-Þõ=%û³‡;Û±Ës,ßÑtˆ¾Ôr%mç9_ìùàó~¡ùÕs~­ž«8-òP+a 뺞gy^à·Cƒ-®³¼wo-÷6q=+ðÀ Ë, +ð­ÀòVh T¯½òn,×GR"ð‘»ðAÁ_Yî|r}©ï­”þJéÃá‚'ûòåh(ðî‘¿R‚€‡‚|‡ƒVÀA0ðü¥üž¿šµDÒ5²/M ¼£Bpö™ ;¨wP?D½HI«Ã¯¶;NBQk0Q¸0åæK”l+¾3[8Ë05x^WÔ¥…À™Ü˜kú#Þ|JÇqå’§ü‚ÇËß~ãdÑëd£iy–Ô±|«#=è²7ಳp]ö\öA¯Ë®w{¡Ëgf±uð릲ǯ¡©ìˆ~i:ø¥÷̈ĸLª™¥i1†u¸³·ç;ÚµlŽ9V4”sÈH\P8Ãi–<!\ VäXŽC#´(Nò¶+±¼ÌBQª´…öÀ¾³ šæ ©ùpÚ hà † @N%.š#S9€PÊ"x|‘ØÔ¬˜Á‰’f‘IRž.ÕS¤!ê㤠p _Y^óa·qé׉·eAÇ"¶Gjð% Î+‚—àIÌ´E5ŠÿÄ9+þõ‘B*·þCöÖÿXŠ3Mìx åÑ–d‡¨r‰œŠæös*Ï’íPý xA.-ÁÙ¶Ä[ ÅTBVf‚ƒ-ï~îöœÕ†þO¬O…S<±ÞxÔÒZ½8‚¤§×üÖlCBZ^ hû«@¨\¨y_jVåLÍÉXFú¬“;lB`Kùˆw€ä9ÑA‰a'‘^7n# O¹ÒÆegiÖi®S[äÒŽ0ìGVoõÚŒf#µÁsXB#½åVÙnO#•Kd1ÈU´ÿÃQÿª£O`+œ\řߤ ?„U*øziv` ŸQ—Ü>å˜&IãACi,]­Â0ŽÕRÈq$‹S)@gù…Ã`l˜òì×ÇKH,ôžqÄàt»38׎Ôù”F•:D粂ôÐu²Ë<ô2k—–Žü“«jÒ<:¦XG×D £M™$DXš)éj?Q/5 ÉRäÎþóßí¡”xœï>À8¤–Ø—¤KÂÅ÷jœ3÷g¼Çœ1b¸¤tÔN†6jµqÞÈ©Pœ”f(ÁÐi"õÆÜSÿNùWCÈy¯¡àŠ-_%B‹«!äÍ‚W‰ÐÍÕò_%>·×Ãç•æéåÕ ^iž^]¡×™§]çj-þ^‰Ú`WÕÔ|¨(:Û쀱¡ÙJ‡u)PÕ±.ºT]jtiM•Q‘UËbG´¾ë8ßWØ’LV›H¿#b´3¤ŽÂ•ª–‡~Ð â#P5Y)¤9ÍPK™)vœ•ÛªºWº?žTÕF¸nÃ]Vý M«G穨ƣ®ºÌ¶€b”ס>»÷öõóªõ@ÔšJÏLobõ;(!“©VAÓ)1]3¼>#ðÜÍ”Œ–ÉO"*Hšï°ª“ö' %ñI3æ‘& ÛüFB±§Rª~W£·S·A1oÞG'¥ú×¶kfîâÒŽMóЙ^Îíù^Ž^g[9M½œŸÎ*_ÜÓ‚ªP|’6Í_ð²°ìa=¡ëºivYœËåó ‚[¯Ê¯²râÃsZzþìSíh7Ý.öê·²€Ð ƒ ßoçÝÐI¿”Ð-l*ÒZ.wSŸlžÍÉóÕ##¯Ù_½°%ù’ŽÙS_vêËN}ÙƒÐÔ—ú²S_vêË>/BS_vê˾¬¾l·qZƒ2²:¡ÂhX½Ðº2.ª+¥Kîsø4xaÇÑm“ [4Þ¹Í ó´E3¾¨ÕM¯±Óá]>ÞÓLG_·Ði¯,uæ ŽÃpµú¦sðHÍ­™î2M5óT3O5óT3O5óKÄgª™§šyª™§šù•ÔÌz…ßfš¹÷™FO¹tÙ¥¥.6þEo•îŽä]Ÿç/Ô¾B3ð†àôÜñ]VgÖ=Kåÿ| uo‘Õ×¾`ÁF—C÷DUúK…Îé¹G¬ñðkM .Jþ-–«ÙrºôTÛ¾ho8õêun>µZÆüÕ]ØÊŒŠj?Â^ß:Ÿ}Ø¿z)?”+¿( D5£sK`«;°Rt¦â¿ï»GæLx lGd½É¸½›LMUãUÀyb}5Ö[é{h•}œ(ŒÓö«>rÆÇÔÄÇðb8£ü$Vß¹‚¤~‰I< ² ?o9+aúõLmäÆ÷èM¦ùàlUŒBEä¡ý&ðI’ä¡ }m~<];Ý|ˆý„ßÚ;FFßM+†ECQÎ’3Õ:—¹SIÍýРTÎJŒ;“ô“þDl›Úðlƒ×øh=jçvÞb|å¼ÿˉÞþPKûÐÆÝÜHPKi©á8ˆ+2²²meta.xml OpenOffice.org/2.4$Win32 OpenOffice.org_project/680m17$Build-9310Sakari Maaranen2008-06-22T00:09:22Sakari Maaranen2008-07-02T00:10:3121PT6H8M1SPKi©á8Thumbnails/thumbnail.png}yUT^ø-!-HH7ˆt %C‡¤¤HÒ‚4ÌP¢¤äÐÒ1t§t !]‚0tJ_kÝû_÷¾ÜóröÓwÎÚß·öÚûœ˜·ZÊ„ø´øhhh„ª*Šºÿv:.ö?tÉ"¶„†ÆÄ§ª(¯ï›y˜õ飾MÇ`§¦(*y`°­/d¡ïõ¬°Â±Â¢{ÍZèàøŸ0èâg]u<èp"ƒnÿ_HƒÃ™Õ¿{~¨1ú’|ó‹”_:QµiÃUÜeжÞ\Bì1á3Ëœö÷B×€I^*94ÓØÎPìGòL0å( ð»£=¢P.?¸žJÝ #pÕþæ¯mÄýÐ#÷ýamí%}øuåë´Á ‹ã÷Ôêô¿E«Ás‚N¥qföÓiýÜ‚F°Ôq¯„ï5O_ `%·\'Z¾r}’¸pß`êÐU­ÀZ†QÑUŠÚ‚œÒÜ —ƒ3ŒŒ£É‚w}ÃÂ&àg,º‚wÓí^W‚,C§È–kƒë:O~^+#$cˆ=3°P5jüEö‘0ç8œØ°~á‰|÷Ö¶¦á(žnûЙW€³ö 2í0ZÈKìU³}°Ñç FMË¿Ä åkÝ]ª´ûÝÙuɬ÷,tÅw¦LÞMZ=z›1(Ö„¹ˆ®ì…{¾cC+>@=5•»e¹w‹púûwr8\*³q⊘ƒdôº0â»Ü™è ÅޘϿ·‡}9AÊý¬«ñ»À8•Õ<ò´oW÷Õ•Ò©€-{wÃÂTâù—Gƒ×ë‰@%^n›½ÌGJmi³˜äƒÇðäöηu“T| $ëÔN8± q“Ý´s¼×7gA• u‡:nìFøJnIêè‘4°¥qšEª˜¬…ù%ÿym/D.µ‰Ñ*ìHQÅ”ýë5µÕ N9u¾µäÌybë÷LSŸßÍ0Žà*=³J6„¯gäuqÔ"BÜÑ·šû¾âÿT¤Áz×DŠR¶¾v>XýôR4V©þFAü³$X¹ï ,!ºQÀ“ÓZJ¡\[LÍ”"1Mö97&‘îˆ<œžÂ3iÓx.«?N’‹RXRu¼uJ,öùéEï-µ”S•Ùßãö§ƒæ÷añDŒT*Xs‰fœ‡F?’é}³)´¶Ä rŒ<œÔ_¼ïÑjʵ 榵îAA\k9Ñ[yO¸O,¦p6›tW¡ŸU=Øð• –ªºŸkÓ1Z%[Sèø|ö^öè|–|)õNºzX `»rÎ-§¢ ÄÅ.ëôÂ\z=ûí>7›Ã(2¾Ð¬èƒGP$¯îæý±LhéZP8Q^dˆ¨›@÷VÑ¥q—Yû^àHkaÓ"E%C¶‘6áu—QLÈ–‰N±h]1Ô˜A•ßÔ!¯H~ ai¶Íâ¨ä]ס¸Ò·ÆÖß$93™kÎ×k}-lrñÑîŸé]/ÍúöG¼±*)EØôžHoìÀT¢¹"DÌO}9×hÄž‰¡ aêßg„ù=¢šdõfZ˜u5Ÿ ¾ª¤92é NmÌû6린a„ò¼þ:#Öç¥ñ7I»ÂÅðF<èZ³…‰€¸mÌ„ù»¶fzK+µï'4íR *YTGf^µQÌ´Äží+ ™Ø-Õˆ>Å[ ÝñèBŠ_¸àyjëѯ‹ð´9ß¡"“(Ú€žV“Eå ×Dƒâ«ôxx´šÓP*ŠúWlÓ>*þ2»çøfH U Þ,‚ˆß~œ•”^E¡y‹Ö┡†øé—ÎX•äˆl_¼>—¨±u³8ŽˆúhKb²¸!r¯ÏñbÃ>KV ¬ ¥;ÿÇíßB„Žc?ð*yŽÛS­²¯RdÍ3¨z«<²B±â÷,"H%ý÷Ðu3'×ŧ! è"d> ßë("(]Þp04ˆ»~} ÷†S6ðŒS—I¤¶Å,–ŠMŽÌ JýþeÄ á#¤¥»r]¬›bÛ÷„{-~'­Ay̲î#É<[È/Ô»œ7ç>–£è„#Ó¹eyBäÙãú¢‘Å-ê“S_$ãæÖ\÷½ÖcìŽTT}}RócÈž"=>õ™^·èHDº•—ìÙ“YPé‘Ë‘ÕÞÚP< ŒNðËÔ£q?e€™û("Ì Ñ?¿>Òfû-xˆ2üº¦ùÕXíEûΕ1»*ÿîÏú’q[Û®äðÓ[8.Kσ{(mÂŒô#'ƒÇË5å¦m>¬åÙï­ùSQs+ZF ÒùOiÀp½Ü”V ÆŽlþCÞq/åpÄÚµA‡éœvôŸ5¾n»wܧâ=C~ÝŠL£on’ȤOB_”y¼7]—˜ÞR4Ö6ªü-å¹iòöÙ²Ð!G¯ä–÷„S Ú}fëÝ´OÒä©ÁI™”¦–+É+VO{šÖ#û9ÍkÑL¸ä“°yÔžÝuV—S§‘øð¡·iöÝýÍ|•„YcGShÿéqlpx1•¹¼i¤s—MjwsTy*ò ™“a‰‚~e—!M([.r‹i=u·\[TL鳂»—·ó°’¨mišß`ü.3ìSþÊÓK5‰÷‚rP£ÜÃ=æ(K€ ÉÇ!€Y5dljßZ‡ïˆý&y!RN·òÞx¾¡ÞKÊ÷ƒû܆åœ4Ôa­ŒÜmgåõµXFš©»C³Ó’–7g¡™TÊ,fHn_¬á‘?nëâÆÁHü gåÀÅø¯u¸a^ž¼™.l9wa‚¯ø?G½b…äZÙâñøU{ò—o[ú<ÉXEó?w^Y,áYƒì6Å’¥$†gÕR‘+Äþ˜â&=Îí—‘8 îiÙÒÛ†9<~?-ýÏg–hôd.—q^Á²9ÂÄÍå|ôù¤ÂX Å=ýظ[ù?”ûFF‰‹%X¼D;ÞE§¿Æ =aÄ'q¤ÐS8—ØVV[Œ³¯ÒÿÊÌ(КKæà]x/w6çL¯T]¶“NˆÃ}Ö_hÂpvYØÚ8•Mú¼¢TI¯¹)gõ]ËÚ‘á’§¼à :E~-mI%kOLü‡ái}{yÆžb¶+£÷$»;‚›Y!ï~â,pExñœ½½ý"ðcɇ{f6¬ rÈÛÉ& Û ã •Ì¡ÒßæÏ~Þé‡%‰¿;ÞÕ7-ßpJ$|Of+iSýÀ¶Æˆð¨!/eíwÎ6¸(VT†9Ÿˆ¹R®&.ׄOÕë «?׫SºáLÈñçÇ«ÍRŸ¾ò‹V@ú÷ŽÕ#n¤7¯A+ãž.Ž#¿Û‡®•ÇŒðôà p9+ àMÉM¯91Ïu_<5•ˆ:ñ4I†g·GÁ{@ˆxß©>–D!Iœ2‘,}¿á©K “‘æó³±Éð.“—ýk^‹â˜I·<êÆÈkµÜ\V™þÝh¡²ò¡µd0målÃC'ÅÅýÁ}yy%}F-К¶Ã*BÔÒ‘òâ8ëÊü™¨Kä$MBxÒB¢éâCî}ASûHÏQ¹Ù$s%‰ÿ¤uML.0¿ ‡¡ö"“ÿ“\Ãjß®†ñß1Öô‡ .÷-Å–¿„UìØÔDÂöoÕ-Èœ É_ñìÆüzÎ{7çi¬³«;ú ?Þß²ýäh¥^¨!¹·$@QÝ Û$3Ðku·Rùu%â½ïî§€îØ’ o¼Ú/GF{åˆôøë惶‰Š 3|~ˆ®M-± 1ÝÀÊûª.ÍÚ ?gJÌÒ—ãwég¹˜$ÜQJ$ÒôÞ»:ouv—$ÙL/³ÔFéc_3¤/4›ÑªäÎíÉ0È9鉼¢ÅÖÅ&ã¼K¨ó}Â×”9Íã$½R8[Gÿ6‘#”+ï£õ°Ü9§Ö½BL5y ³¬ß·å€›Jf÷C«çürZö†ÊJŒ¯ò„²^·¹œ±C ±²ðÚä_[Š7'k¼Wt‘·“”•ïz¿ B–H’{Ëø4ö@é»e­ûÜè2éaýÐú>nn¨C܈¤V U£eú݆0餣ۢH3Öˆâ£L¥¯¼ æ=Áa†¤´4B.¯mWCuôgØÂQž1‹cs¿ÆæÅ¤Ü¦Ð¥qBOÜAâ×öTˆ¯÷±-ìÎE¯”Œ­À¦‰ø7>0fùƒ„sçR‰ø0XÆ–¸',£õåx×´#Âàáe}DzáUë:6›Ð?+õUÕ)šü8.u<Š:¥›‰k2AÒÙY© —«¼±µ.Ë< ¥ý çÏÖtò6>^›u¤€)–KO=Ô*—ñÊ*OЇÓ#vKŒ{¦¶ó ± I¬Å·òìUeE@ÚÀp/ÛŸŠœ½õ¦É¬óWx‰->Óι¹ôñöÚ-¦çÕîS6ψVâ{9A>3Ò\ãÂD9ØÞÞÅB‡åð†ìhg·©Çêa6˜¤{ï{Äe}ß<=°ùj¤ý¹¼9ߺuÉÜmòAò6ãIß»‚Íà@j“-&ŽÄ3²b:TŸv6Îû âÇî‹_üî|R};ø7ÒÛ[,ױעŲìvü‘ Š1¬æï50/ÙºJ>Í€³pÛ%”z(V$Ä&Õ$Ê94;³î”|%à@½íß$[ïæ1atYßÞ1›˜3‡£zµ)¤•ÞÆ R¹ô_î¢No&*7krž«—t¹ØªËÂòf,3ÙÖdz²cdIÎA±ÝO„!ïúRU~'Fû¥n6ÃŽ ‰ÜàIzêš­~E2fÍK¶Nõ¥æ–qáGy”M³B²¥R…™_—‰l|&‘•y¿J_R¥ñ2ÑÌ?Àx~^€{U>GJC§í:35UO;b¡…«ñ5\ÖB¿8ŽIîªSÞx$U:ŒZ–]¤å®¾Iý^§,{½:r*¸wÛ(°RC¶A&hÄǪvR_Þ8ÿÚâ‹YÜ€‹~æ­V¸W8÷¤Q!²ÌI„æ&~^f šÛµÜåÍKÏÈO yþM×`óï>Qlð†*0–kœ’Ô©ê j眞8_`§f~Ó9§Ï¡)Rt'®´… ›NÆ}6‘KJ¼‘Ð]eÈEiS_® hÔÎÌ…‰$ ý¡ýu5¬Ê yFDO6c»¿nCUüwvY—œin.ÄꥒTÄJžÞ=¦–€'¯ŽüÚ9µ´QQàâë½xåz´ÜƵ³²Uø`Ý€ê¾oE[]§€× zKT y¸âñ¼k~zîÌÜØÃç<ëŸ9þôn~ùj£yr!Í6+‘;äãrÙ³Ña(S•é@2îUÔ‘×\HA¯<å­¡_¥ š)8š^ò7"é8z@cnt)ÐÅG~Ü(+@¸éÿí¡ªÍþ÷ûö6å–¯Rk…ƒf¡Z rƒK•‚ žw ×ÛÏ3ZÉõøps|hÚ¡Srg„JÅ–oÚj£ÞbŸöX\9°ÆZÙu¶|Nñ§z“ï³uV‘¼½1†V{À0,ô¡!ò+žõ`xB§Ș4²1Ð=›54§(’-»¿ÐÚ©lU_TH2Li2@}JN!þ-´x#à§›Ïð ˜[ÿlrÿ&LÚ$bõ¯W DZ2s`Ø‚Ë1s<ÉZ j"~£¸<ŒÊ dÄðÿ q¥v;XÒâßÊ)Yâãㆥ®,ÚêÉé>úU¿²ˆ{=`¤ˆ_Ê'j%ËÍE8P†s‘ØöÿÍ·^2 -à"›9ò_ôswg\ùul8Jª•wò’J 3ʦJiÚ° ÒoÙp§‡¨mûÀ˜Ñ3 Ñ»ÌA”n|4»þiQE]¬Ùt,×.¡5‚§ \Å®,¤C@xÐT‹ë¥OîïÐâdÎ1 žå­¾¯]öRÄ­ø{$Ó'VŒaŸiãŽúî7ÈÆÎNàwôõâU²Ã9ù÷Þ]-,t®Og—£óÚ+‰.o×ä16«âµy,±¼½ä?ê¼¥ÙÝUõP³.l‚ìé“^ PÁw\/ºþ› rÄvöºÃïñî¶Á&£ÇˆøÜ1ÐzíG.«€¥ï—8ÂíÎÈoØéá<ä.Ÿt^pVÃÊk/åÐñQÂ\ê>úõ^³`%Z°gnÞi¿P¤Œüœ¿HQsHÈ»DúW}×¶þšÝQ¸êWžeŒïFïí ä5† òþgæ¿xèÔmû»Æ~̇mš¨AâB²K/‹<þe¢)áR/Âuà=Y“òÀǾæ•îc‡Ç-HÜÝã"]Ä2_—½— Í0Î8$Ò<_¯@'ƒ\íäþ|È3;ÜÖÖ3³+E0y+úû¯3•ƒƒI1E”Ýz}èª Ú9cI‚ý?Çã®…Ÿ©ã"A®-är(>É•ã½ó;ò”_¬ÖB8½/` õz±ì·…|7ަÎg£C±[ŠN³®K4ËöÒ1‡í€!C Ræ?-'ªS]— :%¸ ×qV@ã°qÒ˜žy¢ƒ7ŒªÇŽáZòå/íàü¨/{M‹ŠÚRR_"‚·¦ÞlÞ_d}òé^ëøáÐ jð"TT6ó'a+fÄÐ-^„yÍL—éœ[a‰ñÁ¤âƬû\"¹N J~ÓñAù…’êN þû4¾eUVú‚'Twã¹§¸*Ý^,‹7¹ý±ÿX¤¸B•Ú}ž†4N¹™áò†=ýœ ÍÊÏr-,ùÅ®£Eí«ÞÐÊŸÿx6»8hµXN½ª/¢uŒT /\6á‡P=ì5Ïú–² …`¢òм<ñ×,>dz‚C¼p#µ‡§"Ó^Ô˜GQáDÊ›…¿ÛÚ3•ÎIº«!¬°#gù)?ÍxBúp,¾h/³X™×ðÉf®”l@‰ %ã)©ñüWÍ•ç“@Ì#6]ëí …²É¾FûÂvõö—í øÎX~I™šÆÆdÑÓ¬„ ð©`ùVLŒôW¢p/ ß!8,CáVÓO1B¼×Òᙄª¬‘…Sn]®‰v IDÑ·Â 5¤’ æleí“nAë^×.ªŒÍ±q¼eVãJù¤Y‚YïbFKøï¯EÝcQЇ!ý1xNœÐ¡Ç¡š8gºm©°ûçm^?þQšUhÛyʆÎèëøü?—à½EðR™Ã½³Q–m¤E|õ‚Â~pR[Æl™&—UÈtíþ“·K:Ï«–"^¼{Ëú.©5¤QËÈYYT‹éI,iÊ"{e˜Å¼8új+ÓN!k¨é(åçV˺›Öý.:…»Õ™ds5³=µ£ð¸ xÙ–2ôe[K¡®$k׿ ¥”vÁ2ÄuC«yäùOïÔÔǬ¶`éSÛ㢢·nY%YÌhÅfÊü®Y%ãÊ_K²Žµ[1ÅþÎPŒ¥d6°4áÞ½KcnDËÅÿ;UýO¼ú@üÿ·+¡ÆÛ´K¤¥X©`ú¿PKàbÁR!f!PKi©á8 settings.xmlåZßSã6~ï_ÁxúÐ>„$ÜÁA†ä&R2 %áÚë›boYë‘dBþû“‡æŒu:S`°¥ïÛ_Ú]mrþù9bO $EÞöš‡ ï¸åaÛ{˜ôk§ÞçÎOç8›QZúI\Õ$(¥—ȽËÖêuÛKo!‘T¶8‰@¶”ßÂøz[ksu+%[=yf”?¶½¹Rq«^_,‡‹‡(Âzóì쬞¾]/H ET*p9ÂÍ=›´>ò Ë¢¬VoîGġ͆•b©àGÆÇúêÿõjQV–ˬ­ùÅZæ)ûÁV„Ó¨,ŒY»¡ufø w7½ÎÚ·k—vÎ3EWjTAdü}=6|mO«Þz¢°x‰/oß{¾Ri”é Œ½õKµŒõKʕש5OÎ>×wÞ>„™ÊE?>mžTFÿƒjžtzr|\þh8Ïÿ¨ñ©YÚ8µˆÄ5Êx†`› ùÞJ÷èàË2Ãbl‰)•СàuL`4í,ñ› Á@föØ‚Ÿ"2 Üë(‘@ø¾@¾mâðaÒ} ÇœÄ4,û—}>"!ÜR.Ý‘˜ßCÊ¡bfº›þ ¾ê ýÐ9Ëõr£Ìˆ%òšð€ì²Y¾½•ÈRk] ŽõIcÅî±€+F#ʉ‚²ej¶¡~ º†./-5 [mv¹\¸(óÇ,uáÛÆ'N>ö´béuê¥NÛv²Œt†Tä¿"ÍýGÞ¥þ6Ô-v•NÿS¼Å d¸+bõ`¿O‡õÆäê/º oÊ9 }t,Ï͘Îhð½d 780Å@öh˜åI'©ñíà FýÇ <««€Öø*Z¤sÂC¸ÇÕÂ:cF#÷¸È÷ñGËô®ÍbH—D‘ýw=ª´¢ ÷ÂÉÊÏ¿$Z€_3‚ºÌŠø¡Ä©«ndÑͤ¸ÀÈŒIÍ`p¢)÷ÚW¦Ý»µf¾é%‘skÎÀ’f$aJÓŽU~?Ñ<:.mÄâ^Å”ð÷UŸè uG›äÜ(2[ͨ­ïÃ_€ÚX¶'DP²3ÃËPKÜV{Rnæ[ÖWN¢ÈUrM#é÷„0ª¶Í^e<”‚èÊi>×5qH–»s¢u41\Ôt£‹,1jV¢Ì9Õåˆ c *Ùîß;{“'øºúPÿŽ_0”.ÎêØ' Ü\†SèWïò–Àq ë“®€Ñ¢˜½R«Š³|á…³¾óʼnzÑ×d:ßPKæ) ðh#PKi©á8META-INF/manifest.xmlµ•KjÃ0@÷=…ÑÞVÛU1q-ôé&òØè‡f’ÛWäÓ6”¦X; HïFi±Ú[Sí0’ö®OÍ£¨Ð)ßk7vâcý^¿ˆÕòaaÁé‰ÛÓ ÊëÃN¤èZ¤©u`‘ZV­èz¯’EÇí×ùídZ>Tð  Öybì„`´ÎyÊ뛣«¹V4c„°ÕŠÄ…0$cê¼í„ò.ámÊ›wƒS<&BÏ’8Ñb<(…sè£T)Æi›¹’Å]EƒñÀX|H!_ƒTý‘Êô”z18{oŠÁµ…I¾j¶¨¨ãNö÷7ƒ’›º§IºQׂ¿åp§œqÏrêÕ›ðìçÿ5óï\âƒAšk‘a¶‡g½Mvã@’|6ÁsÃç-,2çOñ\Ú…üñ'.?PK³„ANPKi©á8Ÿ.Ä++mimetypePKi©á8QConfigurations2/statusbar/PKi©á8'‰Configurations2/accelerator/current.xmlPKi©á8àConfigurations2/floater/PKi©á8Configurations2/popupmenu/PKi©á8NConfigurations2/progressbar/PKi©á8ˆConfigurations2/menubar/PKi©á8¾Configurations2/toolbar/PKi©á8ôConfigurations2/images/Bitmaps/PKi©á8ÉöãK°™ 1content.xmlPKi©á8ûÐÆÝÜH styles.xmlPKi©á8ˆ+2²²/ meta.xmlPKi©á8àbÁR!f!%Thumbnails/thumbnail.pngPKi©á8æ) ðh# ŸFsettings.xmlPKi©á8³„ANàKMETA-INF/manifest.xmlPKîdMivy-2.4.0-rc1/doc/images/ivy-terminology.png000066400000000000000000002116551226750426600207300ustar00rootroot00000000000000‰PNG  IHDRK A¸Í pHYsËÆVKÞL_IDATxÚì½lWž/úm©õOÂÛ‡ÍÓn' fx¯wÉ=8Ò^GÂ~8kÄ8cGŒM¼ ²6“ѾŽ~«dhH„Ȭó›hQì„XùâÜ6ÒpÝa&&ãmK!Ë^“;nèÄvc8o_rã¼÷O½ó£ªºº»ººººªºªû|åêªsNs¾çóý~Ïϯ“ã8°*9ñ^[>Ìz4U# pãÆ …555²å7µxÒ,¦— eñýht[†Ü?û~ôåmJ!M|Ó¦M¹UvzõÈ>ÌZ0zzïy¸‚­Ñ³‹U¯ÕÔ¼,TÄg(ÀkŸ)•2ùs¨j‹'[ }q‹øóîÓ5Ñ˯BU|öZÕ¶—Ó[^û ¿E¯DžÓçj é”ű˜uõó'Ä‘Q°íe±0IÏ34ìì¢E=ò,ʺ×%åHNÙ²i(sz”ô ¦Ô”9ÿ(yO½ä¤ôÉ×ÿSúûš.Ò2äññþ9µxD¿•-í¢%z½é"ºšlXCŸ\ÇÖÛ °¾êü玉—"Ï|àœ\8t¼Jçâ™C‡&w¦<Ù *ºéx˜ë˜¬GUºC§²YH´¨eþÇ?Úµ Ý VÿÝbd­·’V ê[ß X“±x}aúx•Íq“Gß>ožqlÜóL‹ÇÂÁŽ Ç¡`äɯ|¯Z6¦1Ÿ”²®—¾J/[Rñ‚¾$°IQÇqþD0òÜúB¥ó“ÿÒ o!·ßˆ¢Eb° öÞr¾éb‡Dº u<¼LnË.ß.[ºEÞ²šÂ[®xûˆV˜ W‘&Ò‚Mdˆ¨´¦ohr'e×Ýo ¡wþ–?}iâ'OÁÖô‡® /Mú î2¸ßûå„f“­0ŠK='2PÒ—o;v¬çÒŸgN­KcYÌ•ÐVðÀª×›.^G )ëâldP'öJ­[²PAo*FºÆç^lƒÝr‚qa¾ÿëê@ã½®‘…_RÉR ž=uiD„g…˜ÔÀ¥{0pE½lwfúXzÃä •o¼§Bo˜ÜÈ~Ò]Àr¯b¸…kS_ë ó]>sW4ÌB÷ºœô–|ñ²ª‡‚tíãqUjRõö¤M(k9Óë5@d”bˆ<—ºº&~ô–ëè9ñ{šãNkËÓÜÜçƒÆ/“zð¾³€ÿ<ô×{ªW÷¸R¾—gΙ6÷5¿¬R³zÈY1Džs}í÷glTîqÜQñy«ã`ÞÏÿ‹}Žç¼…àÍ'ÀÓ>Øêõ‡"™Ì4pçÛ¶µè=ٲɎVP %ZieK*L¦²™a”¥«Y˜e_Gü´åióæŠ[·Œ/ž‚zÈÚo" U£äüË_~ß}{º¡QkÁ¨zpæÙ¸3WMD…8u¦å\zûœ››GWŲ­dZämxAÊØÁ4_:èñãVðà?càA£žTAO_oIi\ ù+cK~O¥˜Ž"ßÊthœéêi9™ò$RÊX?*ŸG ‡ÿÓ. LOQAe#ù²ÝwŸ>JåܨƒÃá帛ùóßX«%ƒh–¯VÄÞ=Í¢µë‘Ó ^ ²ZØH™‹§Ùæ$Ì?˜Â ]Åâå9¸aÃQÍŠeÈæìYIž¸Í,‰3#Lk'ô;€%G럹P;¨]ëLô˨)e³:ö¨ý…º|¨lâOrßn6öÒU‚™”§b΢8 ¨Ò¾¼ïþO?*áŠÛ]fÙÆ™ïPÒ‘?Bøðl<^‹ŒOÝæ÷tìï¡ÎÞõ=cè -!ìQs´uã6O^_bЉtü¢¥³VÎø\™ê¿´ä׊*!cñòT bÃFv–£{,’JŽJ±¨!®]®¥fd©¬1ÐϦ´pOMwVÌ«pÓŸS/Q?ðkmœÞ?yd5|wolq¥}‹;C-ÞÔœ'G©Õ¨\6D÷W´o1P´ oÏI§¯»r „¤ËèÆS!îgþ(ѹnøG^xÄÆ süÖ#(w#”S®3Dª‡qEé⧂ч‡Æ<>I:»àÎgÏC>ý=dOkkÌéKÆ:ª„ÂRá}¡Ow6Ÿ¾,R ÈæLïïåU<½[æ½ü“p¹¦ãñ56§áKÅÅ™tÉôå @=Ò ˜º½×'¶ɰŸÃqJ°3© ºäp´sl†Î=HlÎÈoÀS·âIÕ”p_âŸdHbCWò\ÞÔ¬7 {º÷_Mš¾$«)ö¸90V@éKÀŠF™»º0’S]×&“䜷ºb(!]®oô^ƒí¤ÿzºÏáM^C°Ôçø'<¾”º¦BM3QØaê4ØX‘HIy‚©¼­”ìÇ?þ¹†!MÛØœ: ‚b7Ê,{f„]'f=õ^½ßDÈà:Ñi™ò|VSó´æSï¥~År:Íi]9e;‡|ž~ßïxõòÙŽ*TòÅóoWuü_55;.¿ºcÇo.+$(–ÓŒ²©,˜è ]ŸþòÕh´ƒÿÙžo«êØVS³=©ê8KÞäbd¦k}%ªð§·M¶"¤?£Ñ³Zd‰ÑŽ rލ\ƒN}q¥­äºxIL¯A§ŽÅЬ*­å"QC1rus‚ß3Í*y¢¾½åsh޾^ œº‹…¯Y½¢bTn€ëW^oúDê+QÿÝ•µl ¥îþ¬’úJÔ×!e3ÈþÞ×434¹éüçå¨ ö½õMˇ7:&©¯¢5ûš¾šÜ"S¶0;x‚Æâ8GëàÍÝ£Ôý!ºçBÈJð‰|è ɦ¾ÞÉà‰&ÇäÍ3>_Xƒ¢ßùÐöwù åm˶ò‰Äô‚ñeCyóáÙâé0äG=f¾úCþ> b¹ nÔL?Z£¾õ·x³Z <Í¢Ür]oNÎß%õ¤·ïÈ÷CÇ„8€~ÂKO5ˆ.6ÏŸ€“S·ˆ?`“aÞ "/yñáô¾“BN4}Âßý}"bŽV‹Ye£¶õ€ˆE<Ðð:%.,¬ëH>ÓÒÅÌñÞ o/Šžƒ¨CDzkëÐï¤Q3Ê–êûð0ç£æ¹vÔ6¾k?HêyÐìq®É©¾¨²Ád‡· V6}­³|GÎ-îOO!{N£«¶€œwBqy:L*ÛÙpK1¹9¤´×7z»9œ©ûéÝCÇwŠFVAŽü6DNï…µUÞü{ª!ñâó/©3ô»Ïü·wQ•¶¼Ñòw‹zOÊÿuhݲQ_Ò‰nâi¼—w ct`–^ï˜äïéÈ‚Õù–Kz‹ÍÚ¤åä$ú¯£Y:8§ÉBر%h¯4¶<ÄÆNóøv¥Nõ¼ ž*Óùf4ÊÙ¥SdeÑúSCY‘Ýi˜Õ³ ÕÜÊ·É”âQW…ÆÔ%>5o¤k¼s8'‡üYÄ—¡LÄ.×tØ·¾Êˆ7)ßD?…)-AºAHÖOa ÌÒ‹Ý9Ü&ï§0£ƒC~éo|¸Z6âp¼!‹,)>÷¡Ne8*¼* ‡B•žÇpÙ4xîRiæa(çVê I»~Ó¥ÿBR7MjÔ …¼2fuêG½¤Ü‹ÝV6uyJ¿\å‚SGÉ‘•dý¦(k©#CR³?F§™’ƒRŠ3BHvÕ(õbHCjcšIx›¥²'B Æ—M“½øe´ü‚îõ#-êbæ2ƒò+½/ê>´hþX¥“Á2ýÆÊÆÊÆÊ–_ÙLvF¨/e™6â|!é˜ù¡×ô0Ò«þ|3©ø¤wß„hª|÷o.ú$ã?š V/v)9îžã³fÏMÃz0ªt]Ø9¡¸×äØÔ*QÏuF•-W'‚9y(Ì­lEéÏT‘oäQÒt¬„_XpG B<6w¹. ËãôiyùÅ ËÇ8GöÞ'ûL:dà•òòËË7H°žw?%‘òÒŠe#çˆ1Éy©© u P–YY=º¼ÌgQÎ;bJ]4£ ’`{TLÞ´i¤ŽõjZÇ–?2J–Ÿ&(€ÈIî•——k¶+œV(€Bø| ¦¸†4MÚ&ïŒÜÇjáÈø\fm|àÓèꑯ ³³VTH7î}hÁ]­æ ¤tZ¶ŠÎN"å‡ÛT䌜öÔ˜¤¨vëÒ&‹¬O`¼;ÈÂiÖ(š²ÉhÁ‹ª«ÿÞ(\AG°œ>¹ÎÝÙ@ñ‰=xœO±¿º\ãH0Š#\äg³¬·äü°ñ(q[È'ÛçT±'p‰»:áÐ/²à §Û=ÚænLH^<]ÈàtP’ Ň]V%õYH ¯ÁÊæ\‡6h´-Þ2(êÝæã;dÖ­å ™´xŸ‹½•î;0é{*³êë%ç6é ñGjFZ3î–§‰L¼ÊÕ¨pf6ðä+I¡H¢×@éÃ0,}ìø§-OÀD à7¹|O çlÒàÃGèU%NJÏ»¥l ÙÜø ÒÇò¿z„Ä#’rÚfþÎwrö8gš³À¹9¿.¾…´è£=&L†<:YÊ–Iäï&°Ïq0È=C›bŠ£Né9›nM5+jíÉäÅŠØ;C´:Þ qõØ#MÝÛþ¼Q-,7ý–„©“ˆŠAÌ« Ç ÙëõòhH?À¶²ä»{pÿÿ¢ìAOÝ-YfiZÙî¯P‰7ìµ£÷íÉ]òùzô.Å`ÿFïM.âÁ¯r“›=<ؽ{У.>¤B(Ï‚¡œ8•5`>6®ôlïT!"¼uúOÓƒ{ò9Â8“íaˆîΓdÁ¦aÊ(Y’GÁòýªÊVX·]yROŽy,ç Õoºè€ôeR.[Äóžÿ¨3XdL^ƒÍ!®‡* .(ß—×\°,5-ghɼÛ?ê V<Ã\w¹/JÛ¤:€Ù“ÙÊ–ÿ\‡.²D[ÇÔÀ¹:ÄqGiç­Æ|‚S÷„‘ÙÀðü½·.ýÚ_é#ý=i·(SÁüœ «²6u.›Ôá¡öŒ]rÁÙ»èÃP,˜²“õò3—q¼ýÄÉX6esÄûÎ T{Þ.=ÿÌ4ÌŒÉÓ.ÑÅÛ_nmR(LEäÃe ]>¦Û }‰ ^fà¶Ú7C­‰Sb<@Ôêð†¸·SF`e—©1Gä˦,ý5xøK'¢y%ñH\I안Ý­Ü…3ÉïƒAîý,Ñ7µ9‹©3š±lúŒõM•tÀÙm‰²I]úá?Ä\Œ ¾w©ùt³bÂQ=ìߘðª<ØêÝ?±GêOr)X&×[N½lÿÔ&MÌE¿žÎcxÒÔƒ_"÷ý¡ˆ?þ›ö³5Íï¿9Jz ¯ {ÆÉ.Ã1¼lyÎ-’éÅŒ¬#K[*ÔâM÷…wfúðËîÑ"â¤Õñ§Ý7{j<ØEµÂÂD®Ä’A¨Þ5ìÛâmHŸPŸœt‘L›=)S6#ÌÓìI… í¥µŠ=Y”§çJâFpüfQGiÊš9_iBË£&õœB¦xò0‡1Ê,1ÇÑYú·”½-j9‹žÖ¬_MYY"ë§Äh&åȘÏ^ûlÛËÛD¯¼3HÞ[â—¯FÏòNEgƒ¯^ŽvT%À„žï­©¹ ;¢Ñ³Ò‡¯ÕÔ¼œKN¤Ž$ÓÙéÌT¿"²2C}HC‰R7ô,žx–ÔT‡綗£ï¿V³;Û(óèM Eï?Û¶x~ïóØ‹âbÍkŸA›äkϾÕ²YüeŠ<ÈÊ õ!mBp”©M1O|(¾’þÄq·%‡.WE_®þüÞòêe›XÍ% ž*Õë§\IµsV;sN/‘«\ѺóÕü¦æ´o̹Vc›†,9ó·;rµPråJûLæÔµ _TëaØ:ІdM8!2Å¿`Τ´‹VÓ¢ÿn/Þ,­Ýµ >¿¯#Ö\¾ v¬ç°÷"¸ëý)¼uG6][[½‡,Ý‚…ÅwUÙÄKìÐu¢ÿA‹m¼Âiôúªµ»Hu?œðk‹x& „*ÞA,øÔëQ¬U€½BÖƒ%©˜çø EûÞúfè@N®¼¿Irý-¸õRË9:ÇFšp°Ïï¶ÆB~’Q79n#?,9)z‹Ÿ§<”‚£Ïár“­ƒœñ-ÍMö¶F_ É¢ˆGS¯Ä!³Ž”¿7jöBf-K؆¤qË^â³vèiÝ !ü+ø÷#'îzˆ OãñÃ[rÃÜ ÑVGÓª÷hsPb££]ožIuú‡ž§û”C,AüªÛï€æ3\Ðï8Nìÿ] ®¹‰Šý…›îDÛ "Ò˜÷È+zëÆ7X×í’†]“—´ôøCYK@ç>CäOºv‘2Î4ŽŒY’lyÒ_ä;¾DF%«çR¦>ùú²©«.ƒŸ³ðGpû{|% ü:8¶GàÖw‚àž!‘y‰ì”×?þ½…ÞÇ…D*ÄW(îÄK…íÎ ç S&Dxa—ÐÍZŸH[± °^|¹J4/íÞîÚ™by¢¸ sÆõ¯¿uqëJVœ&¢°3ß&*6Î)ôóÛXƒ—&:&Ãô;´+©öÑÔצÎ^Ní@j"aH‡EøÞðÈÛ szqðø/À¢[ É“¿O<‘‰%¹—ÆE:®€›6m²ç2‰GT‚YžèÔ¥‹šÜ(¥wÚˆ7ê‡Á2…1‡£úr(S¡œ6åîJQ9·jЖ>Ñ“ò9}gÁœÆñF!öZ±¢2·ê§Ã l¡Xaj›¡haãM9‡x£0Ÿ‹^ ·°j²¥øedósE*- Et•ÇÐuw#KÿÝë}ï—xDƒ:k%׆}MÓu‡&w¾Þtñÿðñ}GîµüëµA„Üýxfí®úD<²Ýï]+}~ä)<ÚB‡Êî‚c-Œçeçr&žI Á3?%¼üiÀ×itýUïZôP"ÊWÁ¿^C%eMjâ|Â6”,â¨ô9bßPÀ‘&,‘ZÞha˜ÓÎ6ñº88¾sGò+þ~—Lx‘°ÐµCòŠ^3=—ÜpŒsŒ æ‘« +ñì¾³˜1wp 6ÝuîyØó6¾‚ij=³-­K§…“›z"‰+ë0²ç`U¤A<ž8ñÄåRËå—Ê1"Jói¯ˆ9pU ŠœÂ¿~×xs¼­1õ˜áš!ú1zMÉb†ˆ8˜È†”ˆ)®®¤7âOÙˆR§Dü¤‚)VŠúˆ´TG\qõOüW­x·£õ_ìrMcg+½Ÿ4w–eå_Fi‰ªFz²Êæé6zDÕÜ‹m®®ùéájigeHšEiþd#ŠlbHŒ(|tEr³=¹UÊG”HNA&Ÿª".Ì ŒTŒ(麱 B¼QQ$±6 ÐÙ–Q-焆–xÒ)p)Јþ‰®†Ë² Ì y܈µ/'LÊ$7e¹DLO! p9Dä=4g‹(ø¤… ½Q°¹†LUq.g)9uU¯OÄâSrIœóz¤ÉØÉ!–×kvDÍY-tÄlœ3Ë¥.ô“ÕóLal Ú+ÍäßR·öîÏ¡JÉ“yýÿýÈ;]‹=ïå_ty1ˆm&qŽÎ­7¬—OEG„ÃEë…¡²;°Í$ÎéȶôF@~^”3g lMÊ6ûIKÙF +33õ|3ñ8k—9kÄI04 ŒsÚž” Ôí¸d(g%¹›˜‘ É«Tþeš—aœËyRèP§ê’¸²ôÎb®Ñ«”ˆ¦êöæ\ŠÚ“Z+æ ˜£ÞŠ„sâ‚°tkEý`DJÕkŽh&ÛŠAZ¦ˆ&3ë®°ÄNà¶-粆(쿌´sÎ^l+vVlëPJG<8™`,Î1¶ÙŒsº{Šb¤²#Ÿ¯w—\}0¬¨]óñájtí_ «}ú§`ïWÓ¼p§s¸LåלôE…{í†Ý(¬‹“%éIÑ{꘰ß5ˆ·u¬`®¦Pžuî¤BÒN° 'Þ`v䱸 Žz|›^;)‹3‡07¡ÆåšŽÇÑõÊt¼mdñfó[0ªveg^Ùõœ-`çWüÕÔè£ÆÚNtnKi™î1³ãm´†O¨•ÙËå™S´M˜¶+i†]¶Dñól4zÀv„X@ h’ÒIœ³ìV­úmøáW…M\_™éLïd±oÒ¢CQcªPÖ¦0XòóžÔY4µÈ•g“^?E}MçDŸ<šéݹyØS]´¦ŠŒžË*3GFfï&=!¾?Û?Þày° ÙæCØ< ¾û©My<ýÝ AãÒˆôžö±H¼ŠœŠ=îÕ{>úEù+õ˜šð#]ãÖÂ¥æ¶Lmå•òò/“pfoœz}}ˆÚRK1×TÉÙBá;@µô'ݪә@®qwr`Ò“ÑÆ8®ðß»Qg«!ÇìðՈ؆®-S.R@ø±ået]–|"é{0Uä9ÇzÖï!8•õYqTÇ7¼^¯AÅ)//D".—Ù°Sò?gMØi°¿Qµª¬ ‰“”šoª8³š‘L‚Ù£W` ØñÝ©;ÐXK:x‡®ï'ýf2¿£¡ÙLÍwÂw®7¿…ðøh J½‡P nv¹.MÇÛܤÛÓ5²r¼³Ì—©#ûR€¼2vYlK ›*ÐXA„U3].NÍE±whI´“ìdKŒNdôvÆ¥sø£Â¾#–²š*E0nYÅHYFvα‚5GUTaŽ™*6³Plbª”(ìÔê9•2³ fw§(m馼E—|°”:ZAÆžpò=mýÏJNZ0ó0z.´0/=ŸÆ8SEg e`7Y®35ëÚÅcÍý÷`àÊh7Ð9ébr T…¸H ßs_óÑÑOeNãjíºK×~m~¬EÑïuº+@œ­á3€‡°rbÞÉé¶ \ _¸Kۜػ eA7¨41}ò0Á⌠KÐ4«›Lsàœ؉Ÿ¡£Ìx·g M!âl‡»6}öò™~¤?À-†×™œ\Ø&f¦§ƒÒ¯–ö.ÒÊ"S@LÍòé¢(Ã.7Ì1SÅ:=„Ü8§ÞT‰½¥¶5ÝSÓḛ©¾¹¹Ïï»o°PM<ÝTÉYÏv6帣DešÌ³ù${ ©äþÐNÍýh“zyöN½3mõ0>çéÚÜ~?>§©^†âpxI~ðníVÇ)8ó`7èàhý3z¤uðÏ!;ÄÆû{aû ØÜ sAîtàcÇAt3ƒýÝc\ÿðirܸÃñOw:S–¤Âì!85µýÜFUzž#œzn3ýYŸË·/åe[ˆëI<'ÌÀlCäiç¸ö>ÇANàCÿWüð‡øS»=Éi*°­°$5U ¬½Dê ú·±1¢Çè¬g}±MpôV¯?„TÚR *=ÄBév B5 K>¨T²Prd›Ë5{ôš¢°ËKÏ)ËL5§ «a§l¿`T8ºÇ‚¾ö$­æ—üôˆ÷3R…G؆¨Ò#X(ˆm±ÁƒÿibÅTê«ê¤ëõ2UŒ²PPO<ò\½š`ê{â´ ÷¼_·|ï÷!6Œ0UL±-¿»ÿÏ á_¬&;KWkÑ@q86þå/¿§BÚ"œCò,/ΩÕs÷WÀýôŽîÖ̶HA,m åpÃx÷h[ p& 22òò'ž»ôX­¹‰‘ìMØÔèˆ-ôÅÚ· :¯Ù—ˆéÇG6z[ÎŒø+é“ÖÁ¥¿Rv¡?I¤%¤í­cÜVŠ(â襥_û+}™3#®)*åÛ+Pf[NãÈ9K´;<õAO²åBL<>"Œ°Ð'”Oâ°‹À6l¤ˆÃ.|D¥.q£x5r® ‹PO¼ mü¾ûôoÙyØnc{™äÊsl5Q íÒR“a¢£¬(Ì(þÜÜ碪SyN‘îz.ߙՂ²í¨Æ-Ç/ÑÕ.ô4üBU”Ój€K30&zò´D ž0}ÐçðžÀâ¥VÙê8Xð÷ÝŽë&{‚Ää'C—oÔKz¹µ]¶g˜häœ €Ëô ŸækŸ2&ÈE‚ q(Y:“' ]‚J¶pŠGj˜há\Á Ú+0_ÕmÞ\Ad¦¿PÌËk¥la “dA:nòwSF¿…Rû`ÙÀîÙéx­›DñÇè—6+ÈÉÜ8g…arqD]SóÒðÂÍRë (S1)«º …–aâÆÍÏØe`Y¬Þåšޝs¹îè8Ýã´8àDƒEÌ€8§Ú|é §ù aÖ´JÐsÄN‰ l^¢7ƒ­muH¹EÂ}Þè5ü¢¦>>'zßæ‚õbÊâ´__ßÁ`P±L€8Ì/¸®Ð pj9§mz­”Mÿ´X¹à?ÑNIL¨V¦Ø#¾`Ä'¼ó!(1R)#'™mÑp²†Iœ³Îˆ ²P ²Æ™X(§sZãlœa¢½'ž îÀåö¾³yÎîOûÜøL bóÐÓ¶ýìqÉtàðm‘5Î #ÓîΆ”ÎL\vÎå8Ö@˜mä¾G\2K¨'?Û'>……ž'ãh=W¨ CíÞ* Ÿ¢È|–Ÿ¨KšÜÌǢ˙[ÿÌ @ÌÓîIØ23Çó ÖaÊ6PáÀYXÃDóJYŸO`=2FB§SìO¾ÞÅ0‚Ú qi!ÉÌœ'ÙvÍɈ5³' –sù°MåÌjþ œ%ƈ^TŸçŠ9›fœÖ7LRÆP̧\gVód›ÊS.Ù̪µ(«a’…sVž;-à ½‚¼N&µÂe¦^ù[à^Y% Îù¡,| î ÇKh”“9g÷àtó@ëàÒÄþ9®ÇÑ7Ó²µJq*g ‡ù9:n)²·G†Í®4§]— q±%Ô÷…A\l ÝÞæP$ÖçØŽ~MìÇ¥h|ê̵盃ҡg¾'‡—YòO*ÉÃSgZÎÕÔ/8Þ^<Ñô¼Êî^Õ•ï©÷6œ¤@'Qy"#“ž`ÄLî“ùS{i²ý6²©µGH¶2˜Ì³|4ÜÀdJaî¹qÿž¯“tÊŽzÃDžs_ÔeÓâv7?ìR&¹æl˜Ø²W`‘DÂÂ!ÝÆ-5.‰s6[E‰´],Æßûžrô-¢¿g^¨ßÿ»¸¶un8ñݨß*li§OÃØ)ÃC_¼…B€ÍÐâ׫Ë(6~ánã–Ú\”òÏ™g›,ú²òL¢°C•µ—0€gafä«;žÇX¬yí3¸œ¦5¶ÑëåßüŸôþå÷Ÿ½¬•m²ü3s†2XG¶Ñ e¦2‚Ñ«Ï^«yúËW£g±£]žE­áéw£Ñ—õÊ^–s¿,kt˜c,ˆÐy?݆Ÿ=+ÊÀs55Oi‰Ùö. Üôzþê,T0èåhôÝš×XÎ$«ÞH Þ¿,Àg›xÄ<9‹y˜”ÈÙ*~u7kÊÒŸ)¨Ò²€ãùqôåü[Cþ XLÊ©P•Ê2P[HÓȈf^(Ë"-QÑJË$KÝò}på–'›yËqNwc'½Øäez–²fÏrœ3A´ÊVŠ9ìÌô ßušÜW³lOÃêø§ùRÉ’œF±K -Mv‘Ž€˜ƒó¿˜/ç¬)ý†&wšÜÍÿ¢SM+TºæŒôç\z|XY^_?²xèx>3f߬Ñ))+é9ëGÿê¸ûòmˆDVÜUeŸ-Ç7îï]»v—ÌNðË·ïý2Bü·w;>¨ƒõ?’&…še‘pÎL jKa-p;ÖÃŽ]«P /M»ßh—&ÖîÚ„ßÝ^„õCçßú²ãÀt³t ZÞðòNÜ%o¿ƒ­ˉúR™+8„-D;b=/ú(ÛðÍÄ7I†ÆX¿†õ ìD¦ŠŒs¶¤óŸ;xÄ3Î’>ÿòòplÇñÔ4}ýã~ÿŽl¢óM3T«gÍupl1laqåЮUèúúKŸ¸sÄ:Ϲ>‡#HF›zñ²€ Œ?…û¾ ð¶w’ úÐý™Ø?pܤÃñ[Ž Ñ`b‚'ÈÍd/ ‡­ÇÇm”¬Ìì ‡¯E=û7av>þÀ?Šqû>[÷ Þ•'1”ª°;© ¸¿ãÖwÔ^]›™¾RÆÃÃ[ràªå @/oÈ…ÂMÇ`+?—ÙÖ¦ÁàDÓ 9ÙÓºébÃñ1ÇýZ Æ ›·Gé^5ÄѺ÷9Ø\¸úêö“ç÷êÌL9€Œš¼Cû‚ošÜ"ôyKKȇWñ7"ÚÔ±-Á¹Èʃ&rmÞÝr3ôkihŒ38Ó¼{”ùúr2¾÷½õ ÑOö0‚ŠŠsr+½øñbÄ0t­$Çm"ýPÕWç_úN4ÐiÄ6üj×*!@ŒŒ[VIÁ|Ò+†9=(•mض^'þªž@¬ó·Ôx›€/E=#)¼UŽÈ8—Ilk$!ï.®•Z႞ÀüuKG"ÀšD˜‡S^1Îi%…îݾ¦‹©N\ÔåÙ¾¨¿\)Î)tï2­-P0RÔ ó>YÄ5Ü^FÊÄgËÇ”óÚ°€j¡dh²A €Ø†m™—&:&®¿5}üF]Ë¿^ë`ë¦é¢÷ƒ–¬W`´‘rý­‹[4ˆ?WßX k¸vâßòÔÝÿúáµ–ÌIm=°s±³éš‘מj¸öËHbœ3PíKm}ÕC»èXT=y éFŠ8~ˆàuhr§tä½êxx ¨g=qiÓ¦Mt._z79úA.½l:«°{…Tí6¶óÌ´ Å6q“¿Í8§r£ž¾ÛÆó0‘ôoš9œÍ`—ž@z!!ù`Û¡PãI6––fNËeÁ¾˜çÂùŸ3Xù'[X^Êݦù_¶€”9M$ý„…½“ é§Ü~gíÙnQ‚Ê g FèÕpE¬bÕN,›[‡bW‹ÚiPºŒŒ–RjOlcl³ á·¬ŒBçÙ0?Q54¹S¼gdAÚë›` ³-1Î%ÑíÅ}'—†Ž×¿ÞtñšÜr ËG.’ j"}sùvùŽõúhe² ‚íYÕJuÿç˷׌„#›®}±­e⥠ÄÈ÷þvà…r_Mn!W¼(–¬ÚI¯4Þ¾¦™¡Éz²xýZµïÈâ9Cöù¾·¾§QÜãÂІ9­ä®*{ï—‘ºÞǯøäúï¯ a„U?²@ß>óSú÷»ôˆI} ÏÒý»ÊèÏÀµóM×ðê’”ç‡É‰Þ¡‘Ž<ŤeD¶Ü=´kÕ¾x-]‡J¸ò#t_÷S «çî’çåxïZüª÷qºZ9€EÀêH{þÞ/'Þã_‡Rxæ)ØÊ8§‘ÖWínAÏäJhx/…Vr»ê‡v%ãlÏÙš8ʄ߰“ò\6qÆ9KÑšb* ë0Î1bœc”ç~²ú"« kÒßîd˜cÒÒ&4¶핌s6!¯"þ¾ˆÙV„œÙƤ%#Æ9F†rÎåjS3·cD¤ãqS#ªÏ§Ë5®^Ú;Ó?©òK(˜4v‰ˆªUJèQ}>Qâê™ç”m/ŒyÖgž3ØS¾$æÝtú@{Ð?Æ,U)ñžËu=Ì‘¾­éïÆOÄÕÌKMA5R#ö»Æ›ãmÙ"òÁ’ ‹n¤]Yæ‰SªK óœ ’Zú¥x¼Yòò*$@…šª”xÒw 6CDþmçpó€à±á¶.×ôp¼A5óRSPͼԈT‰ý÷â åˆb°“>þ ½IáA:óĈ# Ð鿣 {5ÌSg[.̃»šÜ­ DQK™ê¿ÒhÓñÍuÙaiïSeoÎLJ«úïùNþ­z£+=Íq%*²Fƒ!¤R–‹7j#J‚vºµê9‹È-¾Œ¶¾É4f3ùä"6”lE[(ñ@#Žž^wÊFfz *mÅôˆb%*G”Öµ[r“‚›ti™‰IÚ¥%ëèQ™myö œŒm6íÒ±žxõĵ ÆhˆHf…ˆR«Z—/R frDõ±r.wŠuTÊúÝBeÌ:44©È9­3É+0PË3¨nÙ\<šžz]c$l̹/¾Ý© ìÆBûi媬e N s„fªÈê‡=ˆg§`ÏÏôi[ŒsZŒO•$¢žô7V&{sŽh‘‹–mUC“Œs„¤»mÒªç2×…¬¢yØÂ ñ&-ÕÂNó´^“׆Ú&¶äœ,Ûd픂3qN»"å0‹½âêÿžNøõOìž µ ÌSˆ˜iåѶIQõç2uD‹*Ê`ö®¸Õ~Vä)D¤¯Ò™gŽ¥ç køeé‹*0¼^¬ÉJ†÷  5 3ÔâÔµî,G¼ÐªXº, ,¹¢å'ÿ" ¯R"š`›•´”˜æOö2 EY¶™c›äË9+Œh¤äA:Ì  éf¡¶ˆæ« §}Ù–^S"ì4› 6Ú~çÔ¥Ê,¥í,5JÀôœí›ã#s)§3b˜cÄ8Ǩè9WRŽLŠŠs%åƒIKÆ9FŒsŒçç1α‚nœKw¹\LÌ+â>ŒSýÞgFÖœúƒ¬ K#]ã‡ÃèoM\²ÔŽ’«+q\ô^–ú]㾇h”æ…'›‡;ËèýÜ‹mFûpaöÖ­'m‘WÔ¦úÇɱSèZ%k§Á·<áÏN@avÀt¼­AòP¤@¼-+ô¾s¸m…éÄn뜚E‰›VTí6\( ±ñpýa]¨Ú€pÖ 0 Cl£«W @×ÉÀw¡L<ü' K†‰©{;j ›}и0ÏÏqÃ:õlCF#²6Ëß…åcðè± „…›ÔDÜ«ˆuÔÜžÝã㈠".>ù_À˜‰ó\U3›ÄK¡ h¬ ~uQíJç·êc‰œµÔXë먱6Z‰‹DåÀ¥„£R€õ¹G¢rê$ÌŸ[>¶‡K ¸‡Ïòo¾4o c‰áLšÑnÒJH‚\€N·––‚÷MzÀy²à9í¦Æå¹B eó©”ÒH×øƒd`½ÅÅi§‹ƒ -U ÌÑî¨Ë=9ÝFò ÍÉoŸ\'®QÇ#ñ¨F¦fÃäÕÀîqTíã54Àál™Y™nìl‡€Qtþ… ÊÀa¨ÑV#¨ÞŸÈGx*Àwòoérz€áO é§P¤Îa~JA,JDw©§´DM,NÖ?w&ËJ|*Ú=8|'!ÈÙ8ïjV óàÆ;¤OúøÕ(…’Õæpî[€ÕâýXè´·Öƒmiª|4¾ý«®+¶±-‘¥uæw÷àþ ˆÿGV¶©Ñ¦­ŽSpæ)t3q}ñæÖ÷6î¿B„yÄáðÒë™›¿èÏV‡7ÄOááSàëÁ7±1ð´“t†&7£‡èàJÝddkô”ßß“y º1€Ge‡Íî ¥L¥åýd<×¥juûÿ ý Ý|¢/vZ,æÓàºÆ0ÛZÎŒ‡Q.Ò†¢7^¦%ºòWR¶aÆ·<>îú×tªw²ÇšXOiÍæpnuþöwÊÃÄ z’BbÆ Àù)Îh€ïtúðj—Ø_‘âì‰÷`JH±³ñãÿÜjEÖ¹¬}×Ñ ¨¯¦K÷Ö tß}ƒɧTÕ6†rtƒîH½uë(Ñv7M®/Ú¼uë ¥TFÎJ`šÏ6±3~ß}ö×sP Ñgbp`Ðò/ù½´'Þßpµ¹¾š5µ'ž.0&Vz¾H-”í777/ý9à{(ÐüÝW³Ñ L§iß3SÀö9¹Óô*×l½´¤Üà^¹Šál~#V£ª ÷.×ôp¼ÆåºÓ=Z«¯s;g>02‡2Šá«‡têc ­ÿ€þÖ\ƒÍ!îgƒ±úkB@Ô§tÝ4yƒ„O)Ø Lz>Õ}Šv eÇPrÏÿ²¸IçÝbÎôqBÇÙWO×âø%]¯@æKú¢l£¯H0üÖïë±r#¦s«9—UɥϬA!N×*Îܯ·NO<ß9ñ’ÚÔ“ÛLˆ·Óç[·ŽZ?“†²M•9gòÐ £tQ©‘sŒm¥2†Âˆq®¤Iªä´p®°Ž 5èìpl,¸Ž°ñþ¹Î…{´oÀŸM4Ò5ÞYÐ0¶óÑ–¢2gαþÜT?^MóØ“ë (*s朕ÙÖÇ'Vqq\ð}37·¾çñ?Cß,9ú¹`Õ`k›?”Û\£¨±¥´”]1–a磬HÀ¯sŽVOï¯ù¡Hî……A8íÇ|¥TÉ+Iøq›b?Ι *ãJçieù4ÂVP2º”ÝÓîÇ’×÷q=¶`’¬/A§.ÕZôT$;K¬³óÑ®œ+ÍéýÜ8g‘þ@ î|Ì÷g+°Í;ñÊ÷t õíèÈMç—Š´´ÈÎG˜ºü’Ñ7Ö OoP ëwM´îèÉ$*ÕrÎFC'žGï..‚ºàtíH69ÙT—¼´kI²¯'û =”Uµpgêì¶!,RÇ‚·W•j9W@¶‰ç™ó¿“÷<ßÑ®ñÀÇïÖ›ºç1ÈE}3\°Þ‘åxôT")ÃÄážÂ§ðb½PóþæàyD ;Ùjæð¯{u®ö ${ϼÀ?kê›–t‰¨¢[ªú•'~;FîQ¶Å„d^ð% ¾´À¹Ý-ø~Wï•Áî+5¡ˆO—±Á/¤îJÐêœK…{ÊžGü˜Ot|$Á$~`Å—´Ï#¼•À¯’ ¦ðã)¾]{š®y8 ”]Aɩ✆©T•;!Ÿe™ª÷<æL¾Î'Ó·NÀ@Ì©ßù˜ÓêD¶óÑ®z®¤v>*‹ÊìœË§?0š‰Íÿõ9ø ÿ_ïŸÿ?¸ú?"ÏÕyß™ä¸#«¤v>æë >án­½3GÙ6ßV}y»íÿ^ydõÁÿ­nKÔÍR»_Ýç,±šaà¬kzót)äR¥%¶ööÔÃjزšö„Ooù++ëeé?†nXœ}̲+ˆ¬;t"ìvœì_0"n„lõ6‡"—Z½×'¶¹Óaa‡#êÞíïæ{u´c>HÂнtx%6xpãþ+½°}ëä5¾öL9²NãË';•š笌~·#Ô#À@„n„¤lCè뎃ÉGÒë§]=Ĺï$‡Ãˆ‡>ã^†ÿ4çǃg¨¿mõúBV?Ø;:s)ƒt”1,ù (— ù„‘kÊÔ”ó½(@ý!èlÞ™²Fõ›õNPvŸ±™«²ö²pŽ-­” äTyãÉå…9 ²Í;M«:¶‚ÈZ¤RTfä•…³™¹¼0ÇØVº¶%#ƹ”Á{ì|Ôf^ªWròœ³¬’³ÔÎG#ÌKõJNžsVrÚùHWêáyÓ4¨Îô\!hjàO lî¾3räÎáðwñx¾‡Úç$*e8W,ýɆ+¼œ’Lð²¥PëàRFï2$®·$g%6×ìž½?×s9‰JΖmjv>ŠÎ#öÿn†{a_Äþ>YOtÆIæ„cÌ•ý [èó¾0ˆ«ù(§Ž?‰Û餳BY¨±6ÞX˜º²–´Ìiç#f›H¾ÑÃ*lÛ?~^Šx'{ ·BÈ5ux,Ž>€(ýíàÒÄþ6Ç~èÅÏzhø37Ça‚Ÿ²G¯À¢R2–ßž,mž[èd›ô9à Ââ 8+„§O}HNú#ééø“åªÑsj¦R•8džNd)/¶MÍ.|õí/Üy°.5· ìžßýÝ᫳'›ÃsßÃì÷Ô?S‘Û–t®Àü^Ý´§qçcc­»ñޅ뇇×]šÂº_¬@¶hgÙÈBY§[ó1òl Eug<ÃqÌ¡@#Hç^Åýv¹öR9g}%gØ¥ªøXäžfY—O •sÖWrÖØù¸2oèwMwÖÂîiºO‡õ lAeDÜ5àíÅzø–Ó&*œ³ÝЉ£Ÿ&tæ…z¼çqp,XCúç¾§„íŠéÛPñì»`/s8NA‹ç ô_Ÿ€kgÆ%c(3)§Ýd"½v…k• ÎÙ®?€xFo¢­Þà@<äШ؟ñ‚¾ØXê-al¥e"F—Êâ#Á^h°‡#l£{\mTv•–b<¶{{‚ORõé[ëÏRÿ¼S ±íÛŠmÅ ç<~}û òü3hç£f%ÇsŽ­R&õlK=À0%ÇsÎ.l³þzK3k’õ 9°äÀÉDeáò:ÂÉØfSræÉyF¥FHH§?ŒF£&g£¦¦Fw1Æ FF3HÌG—úlܸq#O›Z¹âU&`X0V#±Z@Ka™?&ºð8Ï|䟂Ê4øÕ”•¡°LÇd®PÔrù7âL)hFH¦ˆè¡Q‡òœ$sqõYMÍÓ)ÞF·ù¹W/G;ªðͳïG_Þf?("æ{à}Ѩ»A 3+(.±éŸß[ó›Ëðõ"l«Bèx­æéwÅ0'éÏF£/§x BѤR¢KZ-Æù»O×¼K¾=)ÍgßGA¥ßÚñêå³ÒäLÇ¡„›6mÒ9ašeXd¸R@š%íÃEÔ’¥y“â Ñovì툞•ÂŒbò3xùë½5I1½½üêovüFŒþ@UJ«}_Ôrçe£ÓOìx5z¶ß¼|eïµÏ^†§QàÄ[¦qªúœÚ𲨗 Oti↦iZ»'VEU"Š„èûÏ&k¹³Âí»55âóg‘vÜv6úII_~-Yq½}~q[N°–à’‰.“=œ γÖd.jûrFtŠ J“õûó¦mRAÐq6Ú‘xó²\Ó—h9Ei’!²ø¹¤ïÊ #Ù‡HX³©È`“`YöØtì±ÙÎ(,ÁJtE÷ röh¸T@² »ˆK)³R¸Æ gWÕÁ@hAt©Ñó rI”2„c_ûMi`˜ÔT9u&•‰A.‰&åÁVƒ1jšB‰Ã2yü3jZ×”A.g(ͪ1mIv ¿Evä”B £ÍN߯gDšfjÂ’íU–r6̃œŽ³ÕÆ¥™‚^ƒÀ\4J‘¥!g}JG‚A*”&hð>ùúŠ€/ûš.*(¨â(ããü³>SnUÚÚœi*˜Æ¡‚):Fúk9åV¥;Þ J“YƒŒ¬¹\[§úðê“Õ=Í"ÀÛùϰߜÿ¼<=…Εý!§AØeų9Hƒèú[;ì|½éâ¡Éô‰xOn(Î7]ìÀ%ð¸½xþ–ß 7¨s5$$BûZ-o´t<¼œž¼4AîQ˜™¡ÉMé©ýä³ ”+ª¼ §­Ñìl¡—LËäÛZ¶÷«Þµ—o;v¬_Ù÷ÖÊТa–¯=¥xvûúª‰_F:&ë¯ÿþZåÏÝç Þö5}94¹…‚¶`aq–? -ox–ÓS£¹b Ò­/ÇH½¢3ZÝQ•µvWýÜÄW X°¦߯:ÐÁ«¯5RcohJ½õÀN á ]©’¢¬JOá<ÀŽõèaU¾òi&¥¶žñŸA®Š®XÇf:&™ÑÈ WÚæeÉЗo—!‹ú™D¯â¾ååï¼wëç»Ï9q·å dN'†s¤!Ï/M×õ>~hתäW@ãÂS È48ÿñ÷'®‘~,—ìò‘™Çëƒ\ÌáØÈß¶œáB~MɆŽ&Å–‡¿Bd ™ó§û¾ ¯Ûm%H—ü;jñ¯ Ãþ‰È mÐòJuδÅ@uÿòá-óqdÒr½uPU†‡‘¬¡oî€{â¥HÇ䦥ÈÂ>A}ÝMzUOãR-'¥!á[G&[.‰÷Müò‘‹;Žï¤W} 7Ù iW$Ü·PCíÃÝ$M2Æ3þÀ —F'vÓ'¨…Çv·Àu1$º»†þöö|Ÿ^žZ¶Ê§–Bžšº ¯:ü÷õ· œŒ(¼&¨ òùÁ$‰ˆÓÁ^ç GaFaÞ´ŠŒÙ€hæ¥ ­ÝU?´KUZ%yÂí C;»Öt쪢j*åUr\ép‘ø-n+oRÒ1* HÓŒ7Èù &Ý…v³µá ©¼¤‹?Äù%?=è·ä'JSðË…GŸ‘®föKIMJBÞz¤?›w·p~¿ä¹OjóEòƒiÅŸ¬GÇÈrÃ'"Z,HœŒ—ŒŠ rŒ K¥°“€AŽ‘á”k— Xo¾Ý'>™ ëo]ÜJ[í{뛺§QúødËÚϯï{)&7>þMz âX¼dè| |þ¥˜ÂynØ×D‡ÝWäÒ ±Ø´ƒœ ¥Œ·´Ó,éðÝ2ø¦ ;0~ðº­#Oņðà5–o(εŸœ¯jù»EÉø8^Ï•šBå0‹‡Û‹‰¡óÛ‹ça+Y›‚”Ñј »dr²a!C,¶â™AÎDÒ6š’bƒÑªL‡>¸ÿ2ÐUŽk&^šø»É–¡7€ ÎƒÇÇqqè<-ö ?û´¾J2t^Õqëú¾&ª¯ð‚/U´^S,9F$okä—P®¯ÚÒñtÞB×OBúÐyj ÎöJ‡Î¥)¤|Žþ”ÏIæXŒäìI·ï®w¯Í¶$B›-÷ú‘ÅCÇ«tÌêep‹skʤ|„ƒ£‚£¼~_Þ×tch²~_ÓÅg>hù›HõÁvܺ~ýá­[au¢:Æ]>à··ÕÓ½9t”åîÇ38ðz¹`áWÇݨ»˜þê½_^Gº‹.¼@·Jòü^èXO?Ÿ‰zqè»ûÞ‚¡køïþòš÷7ã/ƒœ;{·)*Ⱦ5®…î©ÙµiéslÑ}Ñù›sõbàg>àL¡_ÿõCØzÖz+—n!CÒSx}ç$ýÕÐäºË·¿Ã-Ô¥Ï[ªÊI0¼”êõ—b‡°=¹¦îËðó:þ»Ô]fÜe³7­¯"&¥|®ãƒJdsB"@¢ƒ¦8<±>C Weî.®‰œD6çšLý:q‹:½á¿»>)Œä¬E:ø¸âiéÙÇ+U[†AÎZÝ9 ~¥¥ŽÂ‹lh¡4WžP—ÅLËYnŒD|•rÈ4óžcw˜IÊ g”²ÒëìÚô(4ýRÀ¡\ÉR·$Rfeâ5ƒœÊʸþ€Ô‹ Šé®d [ºt\i`:ƒœIÊÊœ®yÖâØ“&ä\ô¡eß N…RV–¤2JMn÷ùFsÁM`z‰BŽmÙ.ÊZÊÔïµÙr¶ó'̈I '«PFŒJrLM1*5£©Àc`cdY£É c6Œ>pZ9sŒYß͵ñ;™šbÄÈL[Ô‰ M ·°JdÄH3!!íõMnX2bÄÈÔ¾\IÐíÅ}¿Ä^Mø3U‰ÃîãâÏ|Тæ8ËG.¾÷¯ '¨~³¯iZeR&*éÛZØ] r ºÞǯøȹÈoÇ{×⃅vIˆé§uCtµT÷§üË×›.^=vNz/^2!ÑÉ`j€ùJøOùÈSÀš|—žD¡‹p¾Ô…ÏUÉÎëx¡ ÉyËSŒó r…£g~Š!?Ó¨½,Éj0Ô‚÷¡ã¨ÕŠç“£0×Ô|àó/E¼!šxiâ'“²nï$º8„-CDߟUØ=ÚÄôöó/߃º!þÜØŒáÏ“c¼xíŠÖôåÐäƒ(çbq°–cŒg+¹«Êvox¯iú8ö÷ç^ûùw@·Úq¸î½_^Ûwd) Ô@±fè¢gþàóÉav€0)¡À >ü yë¡'Ø¡X[s?Ëdèƒ:„”ŽO?AJïä¢î.Ÿ¼†,g,#®ƒƒ~©Ä–mŒù r&Óúª¡IêpèïO8–¤EÞbÚz`'ñÊÉA²¡ä°º¶HLÊ5ü˰J ¹ãøÎryÁ* ÷|,HúÜúª:¸ø«É–„+ÃÌáq†…·â‡Rƒ±Žƒ£ D»‚ ' rŒL¢$§Œä1bcĈQ! ·¯éb$Âê„£ÈëÍÍA,Ór–£¥%¨¬dÕÀ KFfÑ?ýN·ƒ÷ DNéè©ÇrYü•<[‚?´Áif’0È1Ò‹ö<“öämòç ÿó‰í¬’äéAHÅ!ê©O\i[zߎ,ÏÓ¬ªä1bÄ Çˆƒ#F r™Éë…x¼M÷Çãã™^¹\úÎåW˜r,Ž/*T©ùL,…fcäÐ'Q9u¯AZA²5Hê[ƒ4ó™j°8¾¨P¥æ3±š±†%ž¥¾h&Û—ËRƒS³Sµý®é@¼?Y˜êN7¸ºæ»Ã·à@M<^»02Ýpau÷‹µÆü€§ú‹.×,ºÜY¨ÈÒ¸(eé'âÃÕ)åŸè ¼ìy éwû 0ܦ ²1¹òóýb+»\ÓÃñÔT ³ÁM‚HŸè ËÒ*åÈô‘Ã0,ü¤_D!kõž–ᓌ5ˆ °0ßõǵbŽÁ]ÝIþž„«s°Ž„_韂ª²N|#+,“[+-§L ªþ"j=]®ñáx[§;´DiM05®ä¤ñ}ýÝcDvøÂß©–ôC´Ï“þE¹¸Ùò@ÒéO¯RéSjUÌ•–/¦W¾"ÅÚ–ÿbZjôÆÝù·¸Á4Ê?I¯RUÍ&ûºæ‡‡àð´$ìÛ€ÿ|D?Y}‘µ<é‹ow¶-1-grïÌuLÇêk°äÚè-¤åiF]®á½^Kœì46ýýðvBÿŒãó®è=õ06ýÏã‡í¨e·Áx*NÁ¹~ò°Ò"xÛi¯Ö W0”Zu`};v01TÐ/L”÷D°czß¿]¢–ÝüÃöÜýtc;uTSµKÎt®Þý ’ìC[ r:“†a +ôûÙPŠæª³iÎE6›Ê<†º’Â[‘@Φ`“öIÔØi(˜¤ði󿨺  rŒòj†R„ý/æ7`þÕáÍÞ–AÎLõC)¥°Y¾ˆñfÈÙqh$W»7§N]i¯ðfÈG]ë‹:¨8Ë@zÝô É'8ä" íXÚµÇQÔ®UÑñ(¥Wh¬§œÐ)hÒ[~§&¿/S&åLÂIÜô™þªQ¸§Û4§.%O"~«3)}ô9ã$¨Þó¨µû9lj-ZÈñ„Æ4`d–¢ËÁ [xɨ¤È …—¹yÞaÓtŒJ u…ÔrÀÖ£0bæ¥ÉcŠÎšT^^‰D¼^oœ?'ÏNtãÆ šóQt9CŽ): x0¥YÕ½q˜“s— ,.&ôUtZ¼¨2EWØÎ˼­ëA äØÂKF¥F:.¼Ôè+œ™—ŒJô2/šc2óRÝs¹îH—פ“Ôq­á~×x³éNpP6T?>ÜæN,†®ÖTÞ+ôîät['Ì»®&~ºWðâXvôCKM]·y©rLÑåCT`¡ëI<6¼½¡d|Üto§`£/j”A«=y¼­¡kþ$\ž~¨áˆ€‚=1ÿñÑq5ùh¼y·ëßâñ9±®ÓŠp5.)Ng¼Ǫ½ºkÃC>¸Z ŠÎ™»aøÑ&2ÅÚK¯Fq‹Sÿ@jrSkZ>ð6 â9á­{´m`÷lJþ‰ç-, HžÓüIÔ# Ïëpôìi²àŽ&Õåºj}®RË1E§‰Ë£Eþ¥0Rô}ÂÂëÆ ! %>üÔŠø0ºV“,Õ¦dFºèœŠ‰[±"%YÉró2Á—?lñ¿¢sæ™¶ð’Q©™'y¢Î™&˜yɨÔPWH-ÇÌKF%Hù(:§.9`ŠŽSt¦BŽ):FLÑ™ 9`ã(ŒJOÑiCSÇL0ó’3/M…3/1óÒTÈé®èº\ãau«ûÈZ¤îˆjÎ@ÿˆ‡[wt,)”ÌŠ-òuñ<\Zœí2«Àšêo dS$F‚Üi¿¹~Zs•J֏ާVÑé 9Ýrk[ò“«b9ñ ³b±›i9¹wÝá¼Þoadºáð10øá\M<40>WSà(Iáº4*~N{CGywo?9{¥ª–§ê«p”|•»"§Â•ÈaLÍò«}„«xÙÔÀ¬q‹¿¤ÅÄşŽðdó“.ÑOóë¼0ˆY%?ÖgR:¹W)~.œá‹Óï¤Â(:Ú}GWLª °ÌUÑ9uÏ>ŠÎ½ÄE®S³Sµo6\=)œñ<²ø$átÙh7¼¹¹¹Óý==‚öÈá;4°TL~=‡@XCnÉ‘ÏS‰µ‚ PvÒs/bqN[J—Òç4Ó wp&ÃãtUýÊHW”|ý &çëÙÉ‘ÝÑ“‰c­×v]2m±%Öi.|¼o|¸ :›é§QÓOYø/ȵïé)£´®PíUŸ~ÈåB,‹RŒÑ¸4©Ã…Ü‚kk×r:m`-K¤ÐXÛ˜vÞ«°ö/q¶l£$VÊj½Äù³üÏ š,m²ô­¸²‘O_ñs:JšxâëÉÅIÊar¡ÊŒ©R>–·,é àäø àô(ùT©»:¯¦7>Àgé§W`g¡írÚÀê4"ÖGa#¨ÅDÃÒ…Ô¶Gq”6aÀ¨¤H}k7 rl€Q©‘JEç4.LÑ1bŠÎTÈ¡èŒ#ÏÕ땚÷£…Ê0ÇÝ,©–77÷ù}÷ –¦øV£èœ†æ@ß…—ñ£·tÄ"”š¡¼Ü°á4Ç.)°™ @¬ ?5 /Fg¢4ÍKa®i¼DÊû—¿ü>ã»…ù¨žkÀóx>-ÐöU×øcÃÚ§Ñ,Þœ²fÏpÈ•æ8 ÇEJ̘œW0à{(@\äN‘Ÿî¢® eEç4!†*º±ÐLÿ<ƒóÛ±ïV·ßŸ´?´Þ;~›ü¯aËæÊâaèÌ`¬ÞïQ Ñç8 Ú>‡÷À$ñ o[½û'¤BaÉáhk93òó•Ôê8ÒÕ~Ð-øL¦«†‹ÜêQníf@ÎPEç.˜‡Sqèq,.x?¹=Nú{o?tûù«誯¼¾3sÖGžsë.8R+©‘,´AÓ+ÅBE‹´:N!m‘ò = q=f}áúkM ±€ämøTØ×ó1I„†”¾DƒT}3\îïw´Å(l­Æð‹ ÆÚÓ‘ìpœâ¸§ZAdîªn„’#Eç4'Æ)ºúGê#ÐÛÕí[Ð?wÚs8­Ç ‹¾ù¯KF…Ãáå0ꦼÚÝr 'Ü÷ü ÁH¬÷ ÂÉ¥î~h—à¡§µéÜî›–€ÞÆHÈ߉ñ©’ Š€Yê W¢o9ZǸNç ô´÷mìrí)0öÅÆÀYª©F:µ“ W¬žC4”ˆÚlAɵÕá½I̼ôWþ~î ⫇\é¡V{H,ü¤¶{„0¢U žvê÷+ƒÄĤx vflðàDï3à«÷‘èÁaЗCü㟳ùXȼðÒiZò7/½ïÌè;I` é1ÖÔ©÷åñŸÖ|D#ŽcxS6/fæ OóR@NRùªk¼s¸„,ÏEç,Ds4éÄK¶•Á:4ÕOñ¶ýÒlÖ5å.×ôp¼¦ª"Ј8>{\]w5yŸ4PÑIQç,H&ŒC&m–(Hl,‹55ã&÷8Е‹„û¼tÀÑ7ÓrâOp®åÌøÄ~q-^-.ÔN—ŒôÂvɲ’ƒÁ›O¤$ˆ×¦„ö7õOr‘%kPè ^bå ?_âì\ú~ Jḻ±Ÿ˜'ッîß?—³µì®ÆÞ­‡Xxù‰Þ¬™º³·1qZ÷‹ÕV“8ÒFRÈÙeá¥35uÊ Œzz8îg¨Ý“+øƒxÑÉî–s\(Òzâ=„™>ÜÐñü§ùu!°ÔÚzðסG`<¸qÿè}»W6A?™† °] ŒgÌ^”2¿¾D˜¯£óàr±fþÛ2“f¸oc?Æ͇a€ë5=zøÊÖVCc­›oÙÄ»%W»ˆŠÎYÀÖl}«OC•¢ð ®ä×I†nzÂùypa¶º2â ÿœÂ…,àJO’8cÎ sá²³‰‰u_‡Ö# L‘÷ <ú|VäѰ‰>euiKƒœ6E§r‹* ?z+k0¶¨f'O»®-9ËŠgõ¤me³î›S‹oÅYÀäªèl·Eµ¤ˆM¥¢s²Š0‚nÝ:*Š•R˜ ß¼¹€×ŠFÄPLä,8èM!~+É:­tfÃŽJ{ÃñM¢pÓqcÁ©wæzºÖŒAEûýZÒ+Ù±Úú¿›\º ŽrÜÑÒ™ Ÿ››Ïˆ7½b°/xÄÒ —رú-±…¥’:ˆAAÅ rúîëy¯g êÔz®‰«f[•ôü…%…mÚÒS’Ÿ§œÈ@æÙ{ßw‹§žÈ LŽçO¥vƒ‚Š+äŠoNš+•‹¶` íãçúFþü…ÐMOÊ+t&“'×`»üù 1i˜=ây øÝÓüý´*Ï´Àþk‰d•Nd F[½Ò ²j©$bȤâ 9ÍëN,¸E5Éÿ›ò¸ñy èù €Ï;HzžGš6N´&ëúcÉç/¤‡!‹HøóÒNaÞ'Nd$øñ‡OÅ„CPdOdH9ë‘V¼nYs>&¥·¨æP–´¥'âù r«Rxl(Éê¥2D"¤„ñINaðAò) i'2ð ‹N íDÇÆ~Žk÷KÎzu*ÎèÛM¥x¿\þ•U4FiÈÚg]j8ŠÓ°Ù«HMÊ@®(OÊPÒÒ:ˆÁ¶¦wíØx |öIé,­b‹ÈXʪ8S!W:*Ž£L*Î<È1¼1*5Êä=Ü$È1¼1*)’5)̓\‰«¸ N—TyŽº³ÛîfC®dñVj`£çê‘õÍI³ +nwYé4!gäJSÅ1—ŽZ9òGî¼×?U1ûæüðpõH±ªWH/ª%kR2—ŽiT1ûÕ <¹¶L› ÊŒ…5ÑDd?¡›\Ä3Çóô'Ý<ø»šÓÄŽr;Ý Ûçðîâ÷  WrÜÏRâ‚°ºRú¹¼ÜÇe§²a|ªRt¼mYÄ*NÙ¤4r¥ â4¸tTC½“‚¨™ÖÁ¥dq$~»Ô|ú…KþӾDHèã]:n‡>/#­}‹-ÉiúR¾>þø]–ÉÈ“ÒpÈ1—?M\_” ²ß¹¹ €ÿô¥V¯/4.â&yð ñ"Oü)%®”Z› ĽÍ}ÉÈ,g äJ¤gL+Ôct%{T”øŽ$^ùzH@á KÞAdÈyc¤é[ºk!ä×3÷%ëÒ‘Sw°®ÓVm‘‘¥©”]:ªTqFA·ŸJÌ¥céáMíÙñNZÉ\:–Ö9–\.¾œµ6FÌ¥£@+]#‰‚R6) SqÞŽ2—ŽitÏåºPsÒ§æˆG¸Zôjd¡¢Ó ®®yK¹†Ó]Åé9†7FiT><moÝ¥O§úÇmØ£k¼{tûæV\®K„WsjE#]ã‡ÃÐ ëñ¿Å)ø ]˜w5\Ž~@m®*NgÈ• ŠË¾Â]ÁcëÁÉ_oNvÈÔu#Yt©n…£ò'UfòÃ>Kœ#DO§ ìnF!>"©¯Fú!ñ»ÜÍ€àÀ12ØzpÿÄ•37©K:>‘ºë8qâ 丢V‘PQ¼o*„7 H±;54ž©Ù‡Ûâý®iì<§€ìØ•ð“¤?—»Ç='Û2¢rEBNGç)£ÇLÒ«Ø©f⺯ÉúõžÁ#ÿD­Ük½ôH UšgƉ–'ÈsO `#?jº‡÷®ƒ„ÈÁ¥‰Ñ$ØøC㣃з±MtàpE @ÖŽÑDN·œðZè $r-¢@¼! (U¼¾¬Ó ë4ërJc!W”úM—ŽŠnS_yxÕDg«}ä)´ $5Ùië„Gê’)›¬ˆpú~ÑG$JÄŸ|*&ÿPâÀQ²“£~c 5žúÇÖˆi4)õ„œi*N¥KG•T0—Ž:»q´P¶Kgé §Õ‰³>³#Þ€¹tÔ•Jjé‰f§äLSqV;]˜KG¦â „\ö,GÜîd"â\®`@e³áLÅé¹Â,§üîqàsß™;Q‡8Ɔgzž«÷¾³yNn>&¾0ãúOï} §·ü• \!ÙA V}¸TW÷öx ¢àMÑ §rLÅå. ÙNž:‡›/Œ ¿÷Â-.×ìIß±9¹\1rodâÓõ]h´9ƒRV9†·¢§XlÉã1È«#uéX&­W+ž«'üXøþA7ÒlÕk¬x6NÅ©‚óé¡Â€T”J±1ìnןÿìÿgïíc£¸ò´Ñ_Kè.d­‚¹@ÚMh0óbv¼’;Npfœö8öâä1±#¢“+A~ƒ“è½â]ÍÆ6ÉEä}ì A±A¡8k#…u‡Ì@Ʊ%˜ñä `:€€Ü½‰BöþÓ÷œ:UÕÕß_UÕUÕÏ3S]ç£ê<çùýNúöwÈÛÑ)¯íúÓÀ…èCÞk®=WÃý•bv²4Õ¸Ôåú—˜¯Ëåx•D&þËÓšƒò‡’‘Â?ö?È?/ß"}0¦ùVàZûI¶-1ÀÎ?X¸n\qØãóöOŸlðÑà´˜*>GОÕVz¦ÆI\zÊÁ¤ÌDÿÙCJ=ýïàó•䥃^þ—+àï˜kð½6±mü²·¼.úPðO“ý|öp×D/ûyðy¾]õDv1úEø&Ç“]^±Ã'BâÕO…ly½ªÔ!'Hc]/ñh[ü²r?<ï|¨¡rêµãýÔÆ£nÊ‹·9ú™Ê·ô”ßt0¼…²¬kÚØ6.-ª{H–&1»_4n­ ÅS‘â7“拱V#E¢5Ë'È_Ä~'è'_"œPA<PãXÉÛp5V§Ëµêoû½¹q,y`•Á¦±Æù‘%Ü©–ßée6-õÓ= éã¤:j¬®^w¬}®iöN5š,qI)¾å"žzR@_:²Žc ²0Éïú<+B!9¦_g«'æy}hNiÀ¤4†o¿Á’Ž*æG§¨¥Ê#-IÕ*«7޶ީ ;èI*ÊAâ!&|Qç˜oü üÓóîι)+µ±°i„KH9ðÍÊЖœi*o[.ÞtËÝ¥ôê\}Ç-^£é /G0)k‰üà±+[ZJZZÖYç–š)q (‰3Á¨ –Ò_ΓË凼uÆ Ê‹¡ŠÊ+8•ãmüv>§ˆÒ5±cµqî ž6"3Hâ} 6¼¬ ¤„/RÆ¡]$ù’èý”(¤8Ù‘ÏÄL‰K@9ð­üùù=Áýýt<ö€¿ã¤²Ž±$p>×_ÇX%ƪü%õg]ÃÐ5¦lêºÇbyd>ÃËå“6ËI–U0FÒž€üNœç>ȃ#‰¨Ï,‘¦c,ÚÁ¯ªgœÜçÚqø²C'j›,q±”ÃtJÑh& ÛÙÏ7ÒήâÒ„nõ¶íkf^ KR=ß+¿¹^óMƒ6Yµ¼[ÂJlYžH›f>—ô¾¾­­²­­#ÃúÙkê‰ÑÓ)ÓP&%Lx®{KóùE9ðMG¨¯Â‹?ú‘íGß,Ì7)£(‰ŠÎ….áTÊo@Q¡P'S£&@ññ-\¨ÜÀ¤`RšJ¹Âf XÏnJ˜áÈ@>Ì™››K}UÚ´¸téRêÊÊÊlÊRð ÈŽEY1Ç $,CB–Z™à[‘ò*¦ÉZE…b¦ÊÉ_œÇ.§òJNª<4Žà› vÄÀüé· ·'*2fÛzuj²Úô-˜¦Å9‚Ê@A¿|¸—õêÚltlÁjR:29&Mp (8÷äL6C!D)çì’]kfñ-+{'jÇ3ss/œ]ÍÜÜ»lûêѧK›ßu÷èÕrkÇ).̇F¤YX¦ÍI°FqÞaíÊPÊiy>×l?ÝcÄKÖÒä߈m×víRA3²Ø+¯§ËÊN#ÂËQêWóÛ¹w%f|ö¯eO¼sjn®FêìÙF©šÄÕ£e5¯°{j®YÞ{µ¬¬FÚMKæe BÎ:îr¦~5¯œ:õÛö7ºŸ••=¡É¥÷JU¼˜Æ†ñIZV¸*5mAÍÛäS¯”•«œ©Qö³÷ææ’i(ŸûJMÙ+ϼ7÷ò …lüú²²§c(C¿¸Ë’³È6÷Þ3ìŒÏˆ¤¼ž`{ E¶xâiYgQÿ͸ì¬/nì YiÚ‰§1®¨Dˆ«D¢‘«t`W=ñôQ&}[dÇïèÓe¯¼ó½ü^ŒrjñÐËsϼ#Ù“ÒÑD—ËWitì'þõ3–1?¹æ·–²3Ù3]½zµnödÎ8ŸH>İïx‰jCZÐ9á ýkɧäæ}å’¬6Ê9¼JÂÛò?¤¹ò;íªdrn;šŸ{æ•SL‹bêv*ÂäÃ0 /'QùaEÇ~[C*ûÏ–sûå oO$bñÔÙòDó»sãÌy{¥æ³fn"ÒŠÕZ)“!Åb02©;kV Ù;õÊaj–êW+vü!¥²å˜<¾œÄL|ùÕØâ½÷JÙG°ˆ1™ðù.Èí2#Ø¢&«Kšê{<õ'¾<ÊïÎ1G«æ 1†QÊ4„)Šú¶ 2æ¡ÙIïIã(ï=ÃlÂw"ožyOŒjIJ*‘{jn.Ñå ŒP®·L‚µ„° ç¦l_¡ò@©Ôôéé£Wßm.e H®Œµß››{"z|’ùcs/ËS=.v¹êÆ ûËs§ÞQT^Q¶÷¢×Z>0Æ'-÷H¬fR¾íW=ýûÝ$¥MT‹‡âw&¢™š|iôÑØËK™í¦‰1̇,üdÁ7Ë™¤œ ¿Êcþ¤•»QðÍŠ”³¦Ðe„ù3ÑеæíÏQ-Û‚ ÇEtôÄrK6Ÿ4Sµ¬kgoÖqLKÏ7{‹¤ ›}ÇKTÖ¾°ÍÄÃJø¼`OÚ†u1ž`#šo¶÷î x6¢øæÅ#ÍäF0Ð4‚åvÃÁ·XgÏPßô³#»H¿0à[â§\’ ?ü‹o``AؾåB?›Š^† ,N&¬¾ ÷|ËZôé&lˆv§bŠºª^à@Y,a„p“›o†e°`g‘#ߌpl r–ŒP§bþæÀ²ëØ ¬Óˆ#†îôÀg>€y|S›š¾ñ•uOSåpqÆAœÀ7-ôêæHœÀ·&èû@ß4͉_bZ×p„Àaî_1ÔqAþÍ+Ï6gDš Ikw«rxr“ã»Ôq{í }ô-Eàº|èaDšæ60 ³=iDüI#¤#uÓ·µU ÿfñfš6Mƒ^ %ºñ-Úm;.TšÑ*è÷ ›QÁ­ÊÌ[¼Ü0•lׯÞ\æYB£÷ÑÚÍñc….ìI‹:QFX•f~¼sá÷³å;-³Ûš¥²ßrh”™\b…4m­oÿv©¢œ=Ï OV ©Ù^{bxr“Øf—¿_ÿÓÓÝÄN§‰ o~4óWŸ¯†æ_Ÿ.Ù½™^ÿˆž¤ÿ Í>&JÛßúfxç½jšq)¬Þ^;Ųx½öÄnEÙ¢S[(JäηÚPÚKrà°i’Ç*=­º>_ÿ†Ýn×]¿ZÿF=ß~¿âèY.³5Ë´yu}éb¶³žnªþnàæîÉ0Õ?p‚6oú§+'º©jX²Ùè줜—Âj‘Åî7¼§®»¦ÆKcÒjö¤u^ØõÅÀõ«¿ØÀø–ÛÅKÄ?B£n\"úü1¦]¿zôkOó†µÌ15Q*À‚þ›Saªó¶¬tâñéæÉÊSÝ'jú6M<>Á-ÉÇg›'K&¿öÉ.bêÄ´K˜ˆ×Zë‡[/\ —b~3›üÚ‰yv¯¿Ü=¹öh\jÝ[oÂyß2¤EùNÙ}^#)3¡š5‰îmÞÖü”ôhse°¥k¥Ö–³=ËJ›™I÷'Máa¾îÖœ“¾9Våð pð[oYëðÍr↹&ø‰³'Î~AÖšCâé2 Ä›Ið ( œù®fgÝöƒ]ìÞ¼ðhíÌÝ재/§°øÞ¬^3,tá­}G¨þzf•ŽN(ãIÚC¤|«&½^{bVýO“ÑOýr±^ïÁ7£LJ@/Z½º†~xýêÊáɵŒ §®—Ý”ˆÁé$˜£,-üÍ_Öï ¿^;AÊPj3?á‹áÉ¥ÚCêµââѳ®æ ·Õ¼.PyùÙ/kôS×X¾ 5¸vLÈÛ—ÃaoN‰îq¹h2ÜïOzËåÂKü„´gæu¿C›{ê‡í‚ì#ÙIòr}ÞS*M^Ù°ôÚÙȱ Z"hVÙwï¡Ç'‘·Bþ)¿‘¯ ïˆÖjÍ+‡"Xv}ÍÄíÆì@pû€”ìå7„º÷#›Ü=XÓÝov¹^cõ:x9\w²aÕŽ‰ËëWI\aÇkY™ê†ÇÛø6MÒ@-uiÙp±ÝJ¯9¿ŽSzµYC –;ÈrióR’Ôä4÷Ø‘Úúƒ—+v¬3÷ØiÁ¡o]Û3Ð0ÄŠ¤=,²‰í‘öKN²â±tÆÛ¼º·*Ý]¸âû/ËKÉüôÚ°‘aù}‹¯)Õ©j¬A5+Ξbg¥ßò ³,9äÑLs‹Â†¥]+%K’· íŸ­®1j¼$ðーížhÑfV©é˜ð± Þ^»^b?kºÂá~Ö°‚ÔÆÏx-¾ìr­¢~¹5¸j'™B2-ã| ÍùáƒõÄ8˘ô‘"woÙÑ2ÑLãRS1;çeÅht¬?8Äè×ŘÙnßAãá¶.ÚÑ?Þ¶']wsϳSYy\$í6 ÉéPÌ?Ë;o´pwéŒ'ܧb^™rTLÔ–ä‹Ä<Ú°¶™‹´¤{+‰yžZÇL{H½6.hʽ"/"ïðäJá¼É‰ÓÛߺ3¼s‘ô÷Þ¼ùÆ;Š ÊV0J¥ƒ¬íbÿ>°~€ŸÂ4a@Ò$œ„QB1È”P¬t!Š>_ƒcÌœsÒ² > pŠÇ§¦¢¢Ì+î/‡·Œ³²+À¶ªç H™)¿úw¬rí ®zm*Þ²¨tàÂY5}ÊÌ• k¹O¥ÐLW”ØÂi°[!€Ê&eG•™¢ñ‡´?cæÓhóâó¶•I<ŒöÃ;¹î‰¿yóÍßÏ$aO ŸÙ]ÂÖŠ°ŽµlÚÁÚn;³»^ µ ËKP0ãS²™UùZ°œbΟ ’_fTS=ÕJF ãÉe??ʲþç_khp_1Õe2ëçZ7€æë0(™ð(Ÿ$!æ¼Wm¯ÓØo~4³Ä·œÏ–ë¾:ÜWª?‘dÖ|$e&GÔ¬yÍö7GÏÒÄ‹üdÏÀ'bÆ}Ât^¥NÉßK+2!&…ñÉ„GÅœ÷ëW_ÿh‘I›7Õ™¢›~7@»'Këi¶¹¯T3w>vj<%JAš†OÚYó§ºÕxp¡ù«òÉâZx/>$WÉù‚o€U¸O9æ¶ig*ŸÒÎU_v—§t»NÄ k~Ã{\Ôõõd®r‘O ÖFÏšOAþÊK;k~úsSuEüImvòTúD%Iuø†[`Ù1Šû,@HPblXùoÝÓOöùÔ/#µŸ`ÆÍšO¬œ=kÞ÷€JÝ%Í—9·«À7@ùÊï•@êÒç$ÖÊøéVÚÎü7eþ;gZܬù¨Ê©5_Ó§AÿM†¥Ìí*ð °åйêIÃK*ÆdùÎMÃÒ†â‰EÍ…çS㓨¤èïS4Û1'K?“¤“ü*ð (ЉîP>‘À7 ow®â)8£Žà›lK­™÷z÷ÕÝ}é‚õçöþZï5_¯ÙY´óbˆ¾ÙÒ¶Ìdå§£/›'³æÖL߀X úÅOÂE¥WÛk•`1K"¦[T±R¬™˜àÐw_ØP^NwŽž]Ô¼áööÚKÒþOI§ñ,ø*9‘5Õ|gñ¼À7Ë¢¬¬,­e¥JPü¢ŠÝ[ƒüÕ6U¨¯éb–DL·¨bD9cm¨ì{ëvߊK¿Øì#(Î'í—O“bÔE­ù8Ïgºð|+è+øfÙá„ô>LŠe{ËwVºþÍSZk3jIÄ4‹*¦\3±þÈ¥'jÞŒià[1!¥óvï¡Ç£ÂG-°øþri_ÒES;o¿è¢ßÑO’‹¯ÿYóñ¦Èö$øfw$xï¬y¡\ñ€aÿ2"=¹ ý x%šl_×’îÞâÿ:ÂEC°¥yò‘‰ÚO2ÉA¨c¬üûÈ JÄ7nÓ2,»KÕŸ¥«iúêÚ°°{+u¿u›åËŠÑ7¹ˆ¤R%?ÿÓÞ%ŠÀ2ƒù¹nŒë[ëÅ…´a-QO|+øhÇ©ëßHbX»3+ܸNåˈ¾þ.ÉqïðäÚÜExç#ĸ½³Š¥³„0;|³3X·èñ©¯†ÉÂì‘©›;¹UÆTE°±¦Õ{èó 0F‹Û!É T½&-$G+xÊËéó¾„9šm§ÀÊsô­)æŒQz¾EìO!Ô»)\ÞêÝþâ…fÁù³_ࡃoóøéVbn[E×J™fÒÝ“0n¨F s‡xCß°¶ž‚G¦¶¡È`æ²R~‘عÕKGb)WÓ·éPí‰>%©ìÉ&•ç F˜àðÎŒÄm˜¬d'S”—üÄöZ©lTàÁƒofc·2NX¾sÓðÎØLR¢å†Þ<¹©9¾}kÏܹVœ¬=3íË.Í ÷OÞ«¬\=ã¾»µ …ôÏ1KvÈ9¦¸¥æ?Äbh6Fñe©û½c·&Ù½c;Ù!šcc²{çŒSÜRób14íIP”åLõß@9P”3u¼”å@9óøÊr–ÊÑ:Ñ(¾epïn¹ÝgˆÊB¡uÊž;n÷Ijßê¡Ñù’ÍD÷ÑÖ±–‘Ƽ)—i޽î±A¢c¡Æêì  ½6:‹m¦þ½u#-‹ ¢\eà;{O/ê©Ö‡ä¹ùzäû(Y é D _jìámhª:T•ÝÓŠ»V“E‰x.b;sžÖyŒP¹ ÊÀ¶«>¼§ý…uúhN9ÆÜüÅü•ê™øÞešãü•ÖO—D[_ò½cYˆÇ“4Ǹk•,¨§:ª0+=¹ñSµŒËKÖNÚHI¹ rŒ¿ùÉrL_Á©-ý²Ê‡D{ø-Í¡Ù$ÈqþÊÏGª¸¦)ð¬¼g^Þ¼G/_.G¾%!ÛTÌÝ—oÍéàÓÕK«Z¯´Œ¬`dKÒ4å®1þ¯x¹ç(å#- z m‰sŒ»V“…l¼í¥s¬ÿë­:×Z‘¶ŸJXAÑDR-mRßÒøÚI­?ÙÒæóSä(þ¦lú1©É¾¨¦ÁÄï‘oi¶Í&qŽž±½eµ·ª÷Vˆéû^oüC4oÉžÓˆdèÇH0NXMB#¼§”mqõP¢çƒ 1ó[’4ýô9r3&iÚ==éôÜ'yePÑýkµ.¯)WäóóÉ1.5¹.jƒI´'¯ysñ嫸¢PÓö;fûo˜Qi‹‹aF¥¥¢!|Ù@6Í$¾l ›õs´ø· @6 d3‡l™ò dÙ@6“ø²l ›I|Ù@6Í<¾‘eŠçÄ‘cЦŸsŽê †ª¯{S—Ää‡èøfcÆx‰#‘Ï3Yž&g’à›ía~ë×Î lÏ71sÈŠrE’) Ó¹òmxr“³oÍöÚ¯#+JßÞÇFí¶¸ìI#L¶–N>_ÎÊÏ|Ãó†/ç8ÿ 0GâôâIž‰ìóñ%T¾Äxc|ƒÄ™bRêÒ^o§Þ^š#_£¼‡Që"Ñi{—Îl¤iiEU¾MVÑUÛ8€okè:6Ù|^¾sÕšáÔŠ|=ÃþDZ_lÏÐSÓ¤®^¼_9¡Ò÷Ð^â¾¶cÖMâò÷åÖxdsñbíþh|~ž¬´ì=߀BH\nI]#ºº¶vÐIѳt¶p‹ñQÍì(Ï~të<-ßÏ |Ëo袘!F>–wHÛ•ÒîÔ+¹ÝXY)›š@±óÍ^d3hÔ¤H^Ø´W]€gà“2ÃÒv÷ÍŽÆ$ü7gJÄ |+.2óRgþ9Õ°´¯¸Ùžo–uجP*LøߊȮȰ/ÈФÌùœÔ¦`£A_ýäÏ[?Ã+|_‰ ¥Y` ¤X_Æ‚qAlmL‚ov’¸bXðÕÙâ¾ÙIâ@9»‹øf?3å0s|³„U™Õ‹8–ào¯œÕØ}RÎƤ øV<ó³k’ˆ·Üî3Debej’%í ÄŽ1*ëñÞ:M%ÊòŒòÒ¡ÙS.·£®ÊrÎh @6ë Û×Ó1p»oHÛ·Fç©ÅÃצ¾Æ‡Ü­WÔ5AÙùí~ikþû“_•TWÓüèTÕ‡÷´¿°.•Ë-ÇØ«2 œ3ÄÍÒ|+Â/kr˜N©%€‹ÑÖ3òÚ¿|iÜ;n÷É)ÚˆõæÅÑ©­{ZªB-Lßr1,sË1öª KÇ´„ ›“Ðê‹^u~‘hî1«¥<Ǹ«0^b‡1˜”Ú) ­î©èF,{e´¾%Ëbd¸¾On9Æ]•>Gg“„ñI[›”1ó­FBUÑÇå!Õ•H¤<ò™Y‘-çã®J3ÃËI/øfW‰+†µò&nà›]%®HÈæ<Ï|+ò *²a¼ÐKÁr4)‹Šl3&Á7›™”ŦlΦ.ßð†-õˆ—¸b#›óÄ­`|ÙÒvÞ1'¢¸Ý:;”¶vÎ7˜”ºCÖÊç‰<ŠÈÈŠÇZsS„{§ê:«x+§Ñ©ªÎaŒè;MNÚ¿>4²"ò“hïTc‹'“e.íõ“T’ø6wV YúüœjÆ4–Å:§> B™”°' A•†¬ùöºÏø÷Ö´,šgŒ’ucî4kÕóWØ Œ-ҙݜleñª2Ú:&h&øyšV¨4ëuu¾{«¥§$­UÙ( Eï:Ý;Ö4È Ù5ÿ½ÿ±%b³OÑ8¾Á¤4 IX«¦Î“îÎȦ6M½·ŽÑ9jߨî md2È,@ÞÜ5ö(žß‡òï]¢žvò4ÿ»2s¯nþŠ»êk­Ñ(PÝÓêádfVÌÀÅï™*²óŽ~2…jíÐ7íIÖ‹¹{ï õ”0­lßÒ¨PËÈÆN÷\·ÙÎ;Êjqåi:ßòнù©óÛԲBü¬«–œ!ט¢~x_Ùn¹[¿}A¼}ûaº²xñzªÛwûƒmÉJ¸øW‡oà_üë¯n?sé_ýí±ÇÞ¼ýá ‹Ù_s§­Xʤ4|¼dÝ eoŽÞ¹Ÿæ^xáÁ·V÷X@C˜ÈRíe*½…ܵk8Ÿô^T¯óÓÜè<­|WZ=1œ¯lHê"Úüi=QéØúÐÈ]ÊzÖ«$}Ó`ãÞóg¤ì·¦îvWSSåTYÏM/<üꇌh¯Ò¯?|õÕ‹Ó«·ww¬û`1Ê1¾ðßE»<Ïè¯ÿŠýeÊÆx˜cfóWVŽ4†$Ó`?ÇVõ7Úvûö¶_/^üÓ mþ(u‰Kxû¿ÿí¿î¸Í:”+—.Ýÿêís?>Ì/ßtø ¡²eÊ·¼]¸’À‡W>¥-/Ü#žz€–J«±ð•£{¦î#é§D°$ œŽ,ýÇxß% µI±/¡–2-?[›æ4}ù-eÿ­è.•g®%ÄW~bFo+_æW^@”eJÑ êȸ7û5Ñ›¯2i;·ïte݇¯Š/¼ùئWoÇÔ1/|õÝýÒ`dË?¾_ú[GoÒ¥÷Ÿ¿t%i ÞôØcL´•Ÿ+VÓ•bwá2Ò·|G)_wµ¼MÛ¸ÈWÖ•ûå/¿M-,ŒhǤ–¤®š-(Ä—;”hwÅÒ*±æ~Cí¹}ç×ÿM"ÙŠm-^,ÛZWoº}ûÄâ_=¬£ŸVí­ê½Å<äNZ¿—Îå–FÇîÃÛ>ØÖAûöQѶ?þzýë\“Ÿü«Å'd5³› gRšñþm¯ÿ{ÆDßñF›s„ã+úq~È?…=±kÒÓREcbq@ílR†Lüë™ðk—WÍŽ±'î¡–ceîª1iòPhiÂE\(–Òå‹F.¡S9n‹ó`¦£ªbu¤ôI+¶=ÌäA:áéï«q³Ç¢P¯ÔsåhÏí{s‡ùl$‘H8Ÿ$)Û’´I¦ã6‰rb€Dûö¤®&e Gµ¼„_(” óHõS'Œïoâ׫Q'N§zv\4*‰/Ñž¬Ù¹.¶"FâW‹¿ní„¢‚A&%æ—XØ€lí8‡Ù|sðDL LkÐ7°ž¾abÎT}ÃÜe&%ìIpœ= “€I }‡ê\8.œ©|ƒIiM,^¼xzzšmø|>Ûuˆ—.]²rÉõ5)aO:Œl¢½ÚŽl¢§°c7aß`RZ°É’mgÉ0²¹Ý¿±ráõ-ôÍ 2ØËÇpFá¢opኤ=ÁŠ1Â…ƒ¾€…õ .#ÅT¾Á¤`Rž'Ú“0)˜”Ð7p¨¾Á…Ë ½î±ºPcÊ0–wÔÈbJÄË[n÷dqà +Æ_È_hd…•Ù“S}•° <ʨêWüd)HÔ7ÂR–j­w8] ºp¹ëLÊ|nÔ|ùŒTu'Ǿ|ZZ\]eA0m©z•¾¶MZøçˆV0²ù‰ºªˆÀžJù玵ß‘vYEּə)]aŽ */üü•€²Ÿ1MDÑ}ì…õ ¶ï]?ø¡óMJØ“ÀÔޥݣw^¸ÈÈV7øæ POTp¿9ÖŽ¥¼1²OdZZÁ ¼ÐNót‡‘‡çúBïJb5UþƦ&¹l:¿×ORPjÞM¨‰ˆ  <êîWçiÜw¬\G'¿¢5lëþƒÝWÖÐÜÓ}Vç[ý7˜”9ÃÓRpO1%õ,:ßtn–FÇÒŒè[dßýw›onU?½¾·7¸·o݇Uçª$sfP"¦üĺ>ÅÔm[gtF Q—šNŠ˜¢L§zèÓ7eídæ¥\þ&%ô­0àfmP"·§äèŠcë¤ ÓícVí2²cX188êYÇ„go;· µÓWăb«åQ<ÉÀÜZ Õ‰“µÞ r¾Çx \8¡ÆiæÑ ¥/ÏÓ±‘’èF©”ˆPÐâoLiƒ±HZSEfшô·E“»Z~-ÓZFµÅ¦q©iŒ|¾œTIhÄê/ÿÖ}+0”6 òâ\8 Ø§ —¯¾Á¤Š y¶vØ“`{&%“úÕ7¸p\8Sù“€I {œhO¤`RBßÀ¡ú€ gª¾Á¤`RžÇÙ“0)˜”Ð7p¨¾Á…àÂAßÀ¡ú¦³ 7Å]uŽ(£È‡"Îa;Û’c6fÓ½cÕ<” Qg JK•:‚RäÎj!Ê/ª“º½§©Ç˜0]𠑤 ^”sÖ9ÞRvOšó ºp:ë›n&åéóî¦9žk r´ÃTÌ÷yÜaVŠRbèsí>×Þ¾´©÷VtÌ9w5ÚGÚꌶŽÑ –³=y·•}Ö9ÞR¯¥Õ=öØ”68§½MJ‹Ú“­MsJíÑ™&â1­D_ wÞþõÇÖ“»Ïö{ÏŸ‘R8 -qŠìFZå\¯Î…FþqÐ-ÂÂñŽŸgá]Õùvš#)jª¨ŽJUÄäRË0ªãaUiC5ëÙ²L«Ü'Cš¬›4ñgµZÄ~ŠÌÊíú>ÿ[:?:Uu±ŒÝöøÖL5vVEž¯öÎXø@g¾éhRFE2œ¿"`KmtªG %=†ïGF;9—ªzÅ}Ÿ¿"ÂeKGStÞ+BOK&ëùï[Fê:ycZ'‡|L™Q®|ã+c—û51[¥&rgPʽW óÚ¢T‡UJHóß“\$޽~ºø‚dl’MJA†Ð±2·û$»o‘¬5ñgGçietÓ¿(k£D¤ï󿥞–$©“âÊï¡Nù¾ñÏTwC[ó•0+“Ò¢úö˜ŸÞ½S-u{\v¦îÖ1ñ5÷Ë}6k@S{¿®2+¬/3&¥|9©ܤdÿ.M­*&—0™=9ÿå·ìïù/ïPõ¢ÈMüÙÓÑ—3ø‡{g܃Œcez”Hê¤ÉÛ7ÆvbÑ%).}ÓË…}¼»SüZJ¦<çDß)zÙ”á q²ß¿”ÖQu]ñŸ¼÷ß'úWÖïÊCI!£ì²1&GT²${Ô¦³H±‡“—PS¤c¡Æ•먳‰[Vu窾I¢úU7IJó-‘¬©SŠ?›ÈŠSíIéÞ’.·t„ilÓÜ”2x#’bòëarò’XÍ…ÓŸoz™”1ÕHøÓÓRÒüTÇÄOæTðÀ½Õë´#l1çħ/6Rg—wJ”\JR&Õ02ö+W§D%—o‚’u‹¦£Ë|ß}ûÃáýÅdS­Ò½íÚ‘{à›î.œ^L3Zµd+2fÕßþöûÿø—é†õáÒºpÆê›Ž7Hˆ›¾ÅÓ=Á˜›²1²YÜL-¸I‰ñãÈvd³Ñ¸€ííI*Ö·ÂßÐË“±R­Õ=5*ë=]"}Ó}>òº[oÚås5ÝMJè›AÍt1‰›/Ý)Œl"xÿ¼°ý…EÛ0 ç&štúü<ÿ ±‘é›ã뚺µÛ\ßBó3nOéiíš#oÏüìÙJúÓL郕Wÿ4Sù`匴Íöw<[±ë Ú¿öïÐò ƒêuUÜÆ.ã‘È[ÌwÂp¾ë¹ÿÏçÞžÙÖXÙÁü=m|Që¿Îœ#:7Ã~m[A‡Wx;èïö¯uÈÛãÚÕŸfØsf(XÙ&·ê—ë9vÂáåè5—«‘º„ûå±Ù¡ߎ <>D[Úô$Å=š^ŸhßSípR¥páÌÐ7#MÊ¿“Æô¿Ýbõ?¥=ÿߣ¥lûï÷?»Fœqx쎅Eðx ¬­=žÜæbÃÓ=>?o뮆]“/­ÑRÉp9<íU¶»(0§Áå› êšœî÷Ï æwÔöN†§ýQþR:Œ$(Ôàú¶'8´+H•^©<48ö²Ü‡Ç·hËéZÕ+Ñ¡†];&μ< GâÂųIiûñßÛ\ÇëöÑßóíÞéÚòìiÿßO?»fºuÛ>ðle¥1]Iæ¶»Àœ·#|ÙË4$þ§Aÿ=ê÷Ÿ|tŽíÔ¢ãeãÓa®i¾þË=‚ ®]jRã']®}ýáŸ]àWmagúÃ4ÆE‡DÚçÚÆ§•KösÞRO¸M¢ÕÉëÚ8Íê'>&ÒðÍËS£À¾ÿq¦¨†ìmOmRjßY'Þ¾»dúÙÝ©•c™N•ôz(¨þ¨œ­Ý7T¸m°g.æP0è•$¥¼žo—IÊUÁ6‡v­Úq†º¶ÑÀa• å꙲²ù„:1 f ã^]ã$÷“·l’Ûšh«Õ7{pl¼ ÑÙ¤tÎû€Žgטo$0‚i9&ÎÉv‚òàÁ‹«.h£ùØþ­«öÌ0G‹ÉQ›K-7ù êoÛÏÕ‰‰3D™AH‰~¶£ýxÛø~¦ÜÇMKÖ㮲1qãZ8ò¼¿C“ÑÁ­ÚÓ˜Ë×¶¼Áu¸érÈc3}#ç¾ȺRÞ-Äx†<ªá­{t²­’ÿŒ=´<Ü¿œ“Gò¬ä¿ê`‰¿Ã¯~4sp0rŽêhǬȆ¥¿C9EÎb¼-Æ$éPíU‡1©[Ã0‰oøü4ÅŠ«ñÄ2†Ðª^‰À&öAÅdRb~I¡ÁJ²Uê5‚ŸçÐÈ~4„GZx{2“’]úÍ×x`–ÅüK([Z·“¾ùÞžÑ÷ –`è7h" ›õ-N,¡c÷cÙ2˜Âë4ÄÓñ.œÍü7[ñNB¾ÓßÿîžGfö?[)TúÞ¾8ýìš}šåN¡l& t²´¾é-nÏþÛ&ÿ•÷¨Ëš,mRð’ß“éC<…ÌZEøfŠ1Yî4ˆ~µÀ@<rü÷8‘åN÷¡ÁÅO¡ðö¤®âvÏ–»ù¤,¹¨¨¯³Í,¢`\<[“NÖ7‡qlk—:7Rþš&1’ÅYà_²ÿî»CMdÇDÔ<ɘ=ÒÚ¨ºŒúOúVpçÍrˆ‰}ðÒ…F¿ôÕŒkÏLýÀbÂ"ÈñEê{Âã[ ºäI®±Ÿ;ø§q¥1çH‘8ÄßÚØ.×$"Í ‰Ï·ƒÇù§t^rñ5Š¥ïâ÷ÈÅ–ã)ôû¯ Ù±ãb¶A£Mˆ§`ç𽩎C:;9*ö?|€[í=>Ù¿åµC1a\G=ö /—hÀŽ*é,?XOmý•ŒÀê9›•È ýÒwß«v¬‰a…µ¡†çdaä_ÄqJ_VÔ,xòãº6N³ú‰Åçvj<…þðÖc´5^Žgm3}³‹¸eUN±VVÚoó4±*gk÷ ÕnßòZì!š¨ÂT:{ìÐf‰ŠjQ׃q罊xõ·íá}†bÎS#/´É7™K_ýÀ.¯r‰äŒiÉvmO`y¿ŸÔK”ð ,Ý­‘³¬OÁVÆ$a}Ó<—\̼à­{t²­2á!¡9ÂÁÞ”Ö>G£Î‰D^ )ÎB‡š¬6w­¸‰0AWMß  sO!&²`{2Ï%¼í²¾iz»ÚYs·h³`¶ëD×S9\ˆáR“„õM &ã.3D­J6[·SùVœoŠP¶´Î›Ù|ÃóÙr3ÉlÚrbŒIÂû7Ô¼¸â)è·ø(ºÎÀ›`±“qÜÄÆ$ô ªoèõ¢B¼ó}'êÞņxçÍ<¾lŒIØ“à8{Æ$cúNÔ·b7ÉŽ¿\TUv¹VéûÄ3øvÞΛ|+fc²ÉfD eíªè¶hKÉŒIØ“ ›ž²–áúóów<žE9³ßãÀ˜Ù’’m´u¬eDÛîtJ#-¹7'‹S.…1 }3êŽS‘­„–VÙzÝc=Sëç=+<ÅÝ6Œå[Ñ:o¹­7o[qKÿñQO¨ÎÝû}¨§}¸`|Ãk7@öÙFÿ2Åí•QPÿ (rüü±¥îÞ[De¡ž¶Áþ:Ǩ¥H;bù†i%¹A'çb•ïqùä#rôf¿ {U=S ]>#Å-¡”}eãÓÅ]Kt­aˆ¤é‘ì’¯F <-U!ÕÞé)q¶Õ“Ú˜„¾YÛý ì Æ{ƒ}“—{äe”CÁ¡]Á¶ýlÇÁƒòYšzÊy’C ¤Ô¶ÿ$gÚ˜²A%n»½õ­Ä-&¦¾UÞS{¸_4þ[„%¯½8î¨uíkSVº!¾î)¾Ÿ¨®C,KÐ_Gí`†t-ñ(±cdžØùË]{fº^âT«€ &8oз,¸”I·¢c8ÚÀßfEš453Ag…‚áç˽2gf_;>D· >J‰ôME×Às›û§ñ”¢oÎpÞÒV!fíÌ£<áïŸfž›?š-=êêÌ »Ö¤ÞíU½"ä8Ã`ÓÇíô?ÚèO©Rgdþˆ/Ó³0Íy3oÅ•3ÔÑ‹~‰ZýÊù#Š´œúo‹@i¥Å¶ýRàæ-̺ô'7éBùè~mv€ÑÆ$ìI]­ýíI¼ (ZüèGC0&¡o€áÀúãî;ÈçÍ$¾Á˜¤â[?€¢Ge‹­dhLž4|Àà¾ûŠkÀ½¨¾B²„= q+f²ýío¿g¶%ŒIè[AÃþb#ž»©|ƒó¦!â)pÄÅS(^çM¾l„x ‰Àã)„O÷ŽQO]SëÍÐÈ ù^µ^ ,q»ÿ U±Ÿ­î©iÑÆ$ìIãú<ÄSˆ#£Ü ѱjA&>ldû·]ú5?:Õg+²Øž„1 $Õ¦c¡ÆžÓçOk÷Þ÷—óTí¡óüǪ‹e¡“¿5:_ÒRˆPDY“Ð7Àpˆx ÇÖs»Ï m<©®uôÎHË js˜¾-m=Ir’oÝHKæÑ)ï¸Ý'ý{×?öóæ(vh*ÔèávéXÀ¿^µZ©o703¬ŸrKážÓDF`¸ær5ªß’’a!ÞšÝãÚÕŸr°Ô¸¨ J<…Fœ«ºZÞ/‘êÖÅC#$Å5©Ê!&e+wüiþÊèWWVŽ4†„£x¬ì…Pãˆõœ7è›áhpí› ÃõÇ&v4²¿ãÒ‡ÕŒÁ¡]í;ÖÄ’ù#…-Ûõ{šê*sý‘fÔ` ®a{x0ªä;‚Çip:ì%WÃq)…»h£º}9<íå×ú&äŒ8oET…úç&ˆº&§ûý׆†ŽìØqQ¼ÒP 3üt ÃóCID?×$è‰Ówѧ7î—’Zã§ù/¿½¿Úéþ[q:oÄS`MvºÁµ‹ýe"Cmû»ž£þiF¶øC ®#‚Q{4[˹Ä(4qD  çT!ïçL ž0ÿ¤‚'?®kãü©Ÿø˜H"’Â@– Û.Ÿs­óõOn{)<=)är9ª‚ô}˵¯?¼õm ‡EX¡5V$®„–‰¿p¬}nžÖ}Úz†úꪤà_´>ÔrWïizúË)&­–rÞôä›#É–É—Ú™ÄS¨Ðl÷_î еŠÉŽÙÚ]1‡&ê…áX:;wm‚x¸Fòz.ìÙå8#/qùÆ£mEƽ6º&‚—xËÖåÝk˜è­ÚÁµhRúî›ç z¥äËë)8wÑëO`»2{UµE+Ê”^?”ù+•DŽ_xÉBC¯Õ=üæ‹÷{-=Üë>—Íê*£ÛFötƒ=™_'’K<ï–Z) ]CÜ‘ƒÔËt)°§q°:xáp:N6|3͘d•œ~V·‘1–”Ýﳊêïp®^¬mìI}ɦR<ÙlfOâF'sxŠ ÅO!gc’0^bˆ“‰x €A|Ã7)€x pÞœ¤oßÿîž-w§8á¿v}Aû×þ]á¬ÄStå[Äí¿|oÏn|Äûh)Íüiæ¹s4ölåÕ?ÍT>ÈÇ?|úvúA>õøøì™+Dk+w½=s†h[c¥÷ÜÅÞ+ÿÙÓZ™’¥z‘ ñà¼éÊ·B“»Þ¾Â‡¿»uüÿ½5ÿ“ÊéißÛ;žýoûBÔAó”?<ÜÒPññ|c¿4é{{¾gÅš0&‰x ±˜¿2J+Z<ü«Ð‹Ucu¬ÍôŽÝßÓè±aMÃùÍg³¥=y†òîþ?èêzÜ|³ãY>»÷ðØ<ÑõŽg=¾·gˆ÷‹ÉÀßúÞþßÉh¦ãŠmÑOñ47¹›B‘ÏÑ–òoezê¤ïMQ‘!/¾j¤äÀúë×Èó§ñÿM?¯|nüÖtC‰ïí‹ÓÏ®{䇯ÿç¿uD^¬ý—TÊÿ< ‰!ÑYUÁ *F[ÇBQñ¹nH¿ìç%¶«KžÆ¤]õMøi[ÄßIʸ¾-_»&ZVþnÿZö×ÃÏ»»dúÙ´~Óq§3@RÏ múÆ;2ì Gî|ÛӡOl…èt2Ï17,Ò6’ÿâȾÍ&œ÷ÇH¹ó dË­ M'ylÅãÔåÿîq횥3QÜÎ=¶x—¿1I˜_b. [Aá$O'UlÒM˜ãSãJI´Åæñ ÆdÎÈ'¶eñ‘È™el…®¤¦sò"žBâØ ±A„ßUZä.¬Ç—í¶Ñ7Fo?~³ ²Œ­ÀMD‰c¹ÅVÐsJ:c)b+¸bƒ&œaÔ îi|¾š€‚ð­ âæ{{Fß·Õü“ÓߘW‘‚ÇVðkÒiK[Aã§ñÁ’=´Ñ«”¡h¡‹ó–#ß eL²Lõ}'Vp“ØŽ±¬W-kLÚo¼ÄaÏÒ±ú³™umB<[·hô€.0áïBÅ¿Ð˘$¼lA6Á4tôYó o2»KÅOA÷&¡:ê"åÂ6¹°~1n¡op0p-¬ohL@QAGç-k¾Á˜Š a]L€= Vµ'!nŒIè8Nßà¼pÞÌãÈÀ˜„= ޳'aLæÑG^.ª*»\«ôm*n9ÜÙÍ/lÀÒÉÐ7MO\¼xV÷4µL³û’} r¨3²%”5Bš‹o MhF8oÐ7Íp²¶ŽµŒ ³Î†opÞrð7°~€)Þkï­ÐÓß»«ÎIU7:ììü6$Æcld'´ÓÒ§÷RUç ëXRF8o™ò dËþiaýE{ýÔÒSBT ­ ÓçO}HÞPH¬p‹úCjuOyZªB-wZG­cžÔ€|Ðë;¿·nd%ß^·RY¦ãô•Õ<ªù:éW«ûäˆÓ{öô|ƒ1 äA* µ,juÏ=6åì­^×ÄLÍž»‰žzÁ2ÍÌ cú1X q “åK³î[ˆ›šä§{<-ëi¹6…µLï`j39½ù#nm†5ç3IoÛ2×à«^fQ]RgHäçïxÍå«•Ösî_]ÓFמ™ÉŠ^—«w2|à#…p"Ajð¹&¸54Ò¹HY¡ЕopÞtAÂe:èàX’C˵T‰yoõS6#ç H«RQ«4‹ÅM+J+9„mû¥>}Z˜©~?iœ¹ðÒtxœ¤¥!÷·ÙÓ%³ˆó–†o ›$´>TŠ5ÕeŠSÄõìkLžô„­ÉV`{Æ$` ²¹ÝçC¡uîÖ+¡‘%îÞïC=%l»=p®‡µÞÓçOW¯û²uìç#ºÕ{ºdÍ›üc…Ó½cÕ=üïý=Iè`{eÛëŸs»çB»¦zø,–½tîbô9ŒTó£sO·”xª¹„4  rÿ¹½Žzª­¡o·œÁnÝ×_ÿFã8üC¸˜ êO!5˜^µHó¡{¦Ö%Qëb Áiž•÷œVf’ùiéˆô5ÉÎôÍÿñŒ3 ™^µkddb¦cS€ÏcÖ#»ù{­_©žW½îM÷X•1ã“‘MzGº4ǺÂð ÎÈ–-̉§扅z¢´NB‰Ú€«•¯ËµûÄ7oœ·¤|Ù@6[M×çUPÿ Èçáâ)h1e”V´xnΗ\¬«c½yÜØ`‘`ŒIc†OAÓuShDýµ”öÔµŽÞiYd™ç.ß@GŒ¶Ž…¢âsÝþ~ÿØÏKŠðn,€ó )>— y£Ð7noûׇF¬Â7Óœ·|ƒ1 èŠEÚæÔâ¡^ëu覓°'mÃc+Ó_yYÚž„¸ ëÄVð26ò  ž±‚LJhK›—sûÂ*ßf–‘T¯Ÿˆ™Æ$ôÍ|X(¶B×K[˜<ÆÇVpµSxÕ/âÆ EÂÏ5—j~'~7óÂ03dš{f÷î½Kꈭb `Öf–:Ç:C3F)cºZÕ·°Zœ¬œ(*è­rÚ#±C…IæRH³0bßóEŸ«M5~ð3rndÜ0Áiú©ùŸ¡wÞÑø|â’LsÏL/_~ï™w"sV o¹q) )ÊÊÊ0J™Qo;Ÿ>Fåš³<’þ—ç^~9#UmÖé¬dµK^áLÓÍ༈ŽBßr#/Ò t@çs÷¹AìT #«”ýeÛP8ÈTçŸ †c…2Ï“ŠýÛ·ì=¶ø©aP8ÈBçbè„Ûb8RŽ€:ÙŽÝBÕR}¥ …Ô‚Q5(¢v=ÐWÌ(¿µ¥ p`†ìa`²Ò3]È…€Bj^ÎÆ)ØWÆòwΠp@Fˆ î¿J>!7Mó €ƒ5¬ m Wìˆ0Dv¶¯B3Õ+a{³Z „Ây©#|>+K Tp°zAá³]@*ôò @n½R|Et’\¥}šN}ÊP8ÀpÍ#Œg:E3ïI!IT&7÷ @at1Ÿn½Hn$Ê® 'lyë[ôv)§]Šª–ÍF7°µ^€© ':5íÊpÖìæìRN{U+u7¥p ;5 vvv)§½ŠšÌŸKQ{(\Š.ÌR=²]Êi¯¢Â«À™ §FKmѼK[K•ÓEÍöÎ;CçÊÊʆ'7¡g±¶×žÈyš(ž£Ý¢± —U‡U@C>ͰˆÃa—[š­gÛøpYiFa{är,`9mQT]ÔÀŠ —O—jòhUÎÙ¥œdÛKË)œ.=” žGn.QA<$»ÜRøp8VátÑ s<“5¡œ¶(*ü9«puFFxFÕ.å´‘3çØÐ'g¿ØþÙÒá÷k‡óÍÑÚ)z£¾yC÷ °‡ÂÚ éÛÍWT»”“l5ýÄq"÷é‘ïžê,g5c?n~4Ó=pS>²µ*Ò•³žýŠجèzd÷æ…m¨¢§&"‡î°±g&’Џ¥Üïîž,/ç…á‰ÏkR¸ðÖ‰¾#òÕõAʰ OË¢lñ÷  pú£¥èæòïôM(ª]ÊIv±t¨÷å¡Õ«‡—Eexra¬v2ýÛ¿6"µß=õ¾¯fÿ5uÑîÉMÍlëúÕ×ÿäuzDûóhi¼o¤f¤M¸°m®.eÛº'—þ¹öÒò÷ë›—©2Æï”~ò”'Žj¼® ÊÀO›øŒ†Å~IM·× 5ͬlLÕ"÷ ¤pfv@yvy¦Õ.å´¾Š8Ù»þý<-ñùÅ:(×oMNžVÍþ Kë)xík"Iá<¥Ê¡ewyØß˜Ÿ 4õ÷¢>Ù>µûÏgËË™mX;ü•)æ¥ÕD´äÞ_tQ÷ã‡ø¶·ûý»c’̬ KžúåbµK|Ë+èÚëT¾,òÁ, pæwy(gQÕQ>œÖ)ábpszúNMÌØÝ²ß4}õmX¨‘%OÝ—k¦’@Î'$T†I?YÞ7ùÈ_»'^¿ªœsö iôÒW.Ôåì}LÕ²Î8ªv7§¯Í>°üÉe— P„ -ìïÌÅ8%÷6On’ÆîbÞÃ-¬éÛTÃë‚bw…<’Î.¯îO­ òŒH“ wˤa@þ¦íRE_Ÿg …kú¡îO¶_‘.Ù°¶¯k¦»vBvÅÞ÷uo ö½8½\)ͺõzí쬴Í|Äá¾p\-’•íNô½ÒV'ægÌ!€Â6„ýG,™tUÆtñK6WoNèx­¼šŠÑƒH )~J2™*A~ZùÎMÃÊvÌ%Ñ ;s§83ó2•zvO–jsLtI²ÅÜ«˜êhÆÕ p€8D­´âd  p…Šª÷7°.®_}}/=)½×´m²ùß&Õ‡Â69Ü À‚¸ðûYOký’b›µlõ¡p€mD7°¬÷o—*žÜ)mKQZ”@0Ü+š'ÊJÛÈóWÅuRd’¾èKŸÌóÙ§õq^ŸøJò”ѨKDšê%R ¤|€‘üª‰HŸmð¼&äy³áT—DgU};*\p¨aÕŽ õg×d¸ßo~Q{\µyçÎRùh³š‚>i]ï=ÔoÝ⮬èÁ°®?"oÄ'ݼ_1ÿøÔчäP/õ­šq¼ëW§‘ZVºû}âÊeâ«øZ‘a¢ ­"²Þønû‹ÿqÊÇÓLzÏ÷¦æ313ˆáŽ”š\ž%›W×L%¾D.ªFÇÊþë‚ µ-¢\\Lê^oóšXT8ÜŸW rmº6똦ñúÆ$x²HŒªYVÞæææð¤¬ô8ÌuàŒIŸÉžGÈØ†µÃïßPõ¹*–,×F`"Ç¿ [ÙK§p=’¼E{8\6s×gGûPÓ8Ù RÌ ®{íóŸ~Ѥ;‘R­¿ŒÏAUÜ$é{ÕK¸B‹,£}¸©F*Ÿ²li]OùD%íOâÛAv)YñÝ^JàVFÎ÷Æü²Qˆ?’¾^ôV˜iXÚ‹xQ¤ŽR>>;»µjw¹ËJŸìºÖýø4ER¦Œ #%ÈþÕ¾QÇURÚN~•ÈW½*òá|òlcŠ*Çææ–Zûd£”õåq½Ÿ·¼žÝ׉ A¶«¼×Ôô¡'²ß¤Ý;;$¿7NUÄ)QÙ(]ý…‰D*”2ý¶ñË$|¸„c’òùZÍ’´¡¶¡\+éË–]“r Þ¶—ºX&Q?kyþþÉ.WížÍ’z·sÑITÂö,¹0^Q¡U{Êx‰x­£ìŠ~:é àµkÿÍ ‹ò›Ê|Ãl–$øLPù¸^;ôwmù}±ê"{K± *=ôšqNõÌ”WEå«ùp>Å'üÑ—H§"@Lõí¤pþÍ]400!;kÑ=-ï67ûSÉ`*—FRŠñp[0¡·—Êè¢HMrÊdM ê’~ iÜkCÏÓ®oÉ|ªèûÌD.ܦÊs…_vo.—s×̉ˆwã o€¡øm2¶V OVâcyÓ|8¥³Ü±Êµ#ãá9oÛàÁcLWÔ‹êëëãÏ’U)G$R®ú¦:>v—"}oYs=Å¡¸ 0µ˜¼À_£ëªz?&hÜó_[µª–•¬?:GÙÅ7vU)%—ô]Œ GâÞD;Æ9°+dO+g |L^ §uÒ¹SɯañÄDŠÓ“¦Žö`òRe“~ìŽÜË–æþdøÓ[×T_ß4¥¨Ñ'Dgª)’ö@LI³(€D.~'d€l.7ÄN˰ôt|+@8¥õv™óa]ÙƒÎ`´ÂY¾Å±K¤vÚ s­p`’Ó( 4eee¸ó–¾Á‡Â€]‘•£ÆN6Aù†åHtŒ¹~ö‹£TžKÜ÷à„HùÛkO€#P8( GM=Ù©#=c®sôÅ ½QnÎ]-òHùœ©‹z¾½‹„ì1à—<‰Ú~“¢~*xydzêž,—âDðpJ×Z¬×•"Ð{º8ô”!:Ò`’8ô ÓÑOŸÑíLËC”M^š«(nàè"N1)hß«eûF'ÆŠŽÚ~“qß°¶{뉾·–²îûæGÿqˆ*ú6$ÎÞÓÅ¡O_†¨b'‹CŸ6ˆ~&•Íð´ìòšÒր€s<3ÝçOæ>O!טëå;«êk/úåêkÜIö&,i ÷|#Ê[;T<@ဢ9²Æwy¼Êº÷]ÔýøTE×#ÍÑ£móÚØð‰½×D¥“ }ÖÅN‡>› úyb™‰yP8€ÎeàŠic®ß›"j{|tÁ%¾å,ró¢¸s”’z§å3+ÆØPñÉâÐgD?ÙÏlîIŽyP8p´ÎÙ "Øü}öŸ©P80 öq 6y(déÒ!šˆ„b¥g…€,¥Î´¾#8ûÅöÏ–Š/ÕòÿŒÞ¨7)¾‰nÅ6|\÷šßÀP8ˆwȩ́F¾{ª³œè¶¤OUôâ”X6±‚@}GúrYýûí6‰/¯¯¬þå÷òªÐ/NL¨¯ë¤¢)úri𥼭ù¤ì› Ë )v8ë[ù:;³LeMR)åópâ_ˆ¿±€Â@¦îIŸ{ë6ZuöËC«W+~ÆüÕE»Å„@î‚|ò:=¢ý©|»]U_+¾kK_^ÓSï/¦e÷îž¼KãÃÝAF¤©†Š0ÔŠ¨(ìÐ¥åï×ï +¾ÎÄQç—IbŠÑU ‹MÙd*}“0ýHL¥¾S#¡Hõ]¨ªÝ!"Z-…€ÌÝ;¦s©åM„;ÉLµž‡§Tù`Ù]ö7æ§Œ{›ßðnñÂO'Ëé÷<.W‚¸³7¸4ðÉö¨Ý>[^¾A|W7qˆïðv¿wÌ¥”!¶Ø™]•ªØUüú­éÏÉÓªùXbÃÒz ò`%_ßà1º|‘CüË º†F @á@OdáÞÅyB™bÃʧøäߺ¿›¥Š¾‹L°”ºþù˜ñ=I¦¥¨]wwOúäïÛÎ~ÑÇ&¿SÏb§Æ²ß4­ýPý¬$l÷±C¼¾ÓÓwj”úÞœ¾6 €Â@ÀÊ k:+¦¿¾ëÞŸn¥>å=ÿƙ╣^9pó†µ}]3ݵâ%xÒ½5Ø'G'É$ë;z;›Ëû6Õh*U!K*߉Gñ÷pðá( ¬¿®¤\ã›0…º~3>©1!ùL9䇯Ý¿ŽDÙ }’IX²•Ñò–EÉ;»ŠÇUŠ’ª‰„q(ØL¥v£Ø%Äkr($F†óMH³ÂŽ8ëJ[­§ÃçÛEøÐ¡p‘1¨"¾»ÔîAgj‹§‰Çäà‡– ö@á ½'' ~'ØÐ6;mña p»Ú¡»€ºk*+“…(‚ÂAŒƒetP®˜ôÕÜ¡y`œ¤©¼ËàP8À!2VØå’ 4Ï‘ý,ž©i.ZZ/ 8vYõ&Y9¡|vGÌS‹™F ä,c¬P8€ò-Èz(`Tÿ XáþC]Ô˦|‡Â¯ï}‚ ¦•Ã"ñN¬)9™ÜäxeÊ­%8µ7€Â9\ƶ`h`Z7ÕÌMÔg¡ÞÀ„O\†Â‘˜AÆ€bPM]ÕüZä–HüUƒÂ¡p¡(êÁƒÂÙà C¢…³±Œ%l”h£P8;)d ç(@ɰ—QޝŠÂë‚DP´Fyê/ pv•1H€ó¾LXPÌȼ۴àa”p¦Ÿ`Q…K1±¬®pø> p¦ÂAÆŠ f¾Ì[`ñòNBÂÙ+iÊ‚Ô2–0ch`}Á[Éb-HÙzYÙùpÓ›p7 b{í‰Ü}8Ü>À‘€ÂP8€ÂÅ‹ëW_|vV³£þúæ Ñ/ŠÏ~±ýÅ æ÷’§Þ÷Õ,ÓkŽî§º?9ô9ߪèzd÷æ…Y^þÍÑÚ© ýKåp\xëDß‘DÏ p€ƒ112ÿ‹ ž%Ž(ÐH·(`glõÖ N|>ûïg=ÍTîKÉÁòÖo NÉÐLáNE<6)Ǫዒ§æíž,/Wµ6Ùþôî„*úú´Ê7?šé¸)•ð^áñÄú¸Z×V:-êÂDÙiÓÌ9ý¤73ùmѦŸ$)€ÂŽFÅŠ•¿èúnbà¦Æ“¸Š®•¿ ï&èfª®SÓ“z|âPlg­7G¦¶1 &±Ãª>Ÿí®Íz0“—)Gýðΰ¬(/NL(R4<¹VÑ-všœò’Í•ÝWØm™ýÝG%Qƒ®×¯þN(ßÎŤêPöéG‰=KmRÖQþ,jƒÑTî¹æ4–ÚöÚ›hí(:,Ù¼ºž)œêÆ)Ü?m^D%ðry‹ñß‚uß$‹Ü…·y‹qnâ^æ – ,oÑb&ËÞÍC{çÿ!sg.ª´ kúª®q͈JY‘´›ÓÓwj$I+ßYUdjbà?NùÔÓ~8µ—UsÉSÑYç’¾HJõöäÓÊwn~ˆ×Q­ ¸çÊÛÍHjÛY… Oé"ÖÉþt+MoãJþ*ÞÀm]ÊÕ«ônŠòá~øë'òOæáEŽ-¬iõú\ºöÈ ;—Ó—Oñ‘’¨.~Y‰ïšýæ’þk’ÙñÓ qG6,­§àÄçß±³„~îùŸoÅfq¯xÊ…Š å¿¬¨82;Ëܸ·¼ŸKžÐ/S‚^xá?<²„>ç"7;ðå…ÍÑ>œ:9E¨#-\ºšI ß1ûÉ­››µ>Ü­éÏ3*ØÍ«ßetÞ}wW°\¤ÍäsŸ@¸¬ôÉ®kÝÁ¾·–?tƒ;»[«²Ÿ)š‹–?ÀnfðÏgËËcDîì iLòî%Ò’îyijÔZ'ªÁP8 ˜ 8UG$•z`ù?$ñ'”Ñ3¶”ÞÅAó®|ç#O]’†.å÷a) p—G–¨$NX:iÙýÆwâ=Ü„òNK[jÓ>*X²ù'O}òÉ!ù]£·{çb”uaMgÅôã³¼všANåhd T¾çŸlÐ #'|I P8ÀÑX²ü>¥UǙԪø[ß(âðíÜ4¼“âf‘$T‘…5}›jb&§HôÍ·&¢§«ÜÛ<¹©9úýœäÝÎôíцµ|ŽFì>µ—7í 0õ½+&“?³QñÉRqÛ#æBd:I8Á=WMfvL®M2E p€£<6ÑW „£"fgÂ3µšµ'io®ˆbäÌ%±{â³ js 'Ê:œ2ÊJÛ¤ñ»ÕìÂ)+%ãæG—Ä\øÁR=ÒÏô¶Ç_®ìÁçÞ€l õr ÔP8,‰d.P8 P8€Â pÂm¯=»áÉMðᦧqçáó‡[ ©p|}ü(íß’o:û|ä£-ËqG Ö·Þ3DgȤéþ“¥Þ^ùè¶ÔQ)mÍï9:0M•BÉÐÇϱ‹8zâUM:ycª rÄ–ýDÑ>ÜÇÊûé}É_‰öO+bÖHIù8®Ò®FZso¸ ÖÃOî×2åû=Ôxˆ¶VF+ …w#õþA¥<~(³KJiy%M{øä±ªc ‚-ûi‹f;Ù~u»C;YŒì¯Ä(%@á P8 P8€Â€…ÎЀк#‡ùÙŽ¯ êˆ ¢ŽèmL{ˆ6S8QIö`B¡F[TÕíËêÁ8¾‚¨#*ˆ:¢·1í!ÚLáÔ ÙâÁˆæÐòœ]AÔDÑÛ˜öm¦phyè>PGTuDoãd…CËC÷:¢‚¨#z'+ZºÔD“ÕÑ C÷:¢‚¨#¢“.ïs«×}æüÞº‘–EìÇüèTUç=ÇB몣O:Ý;ÖDC=%DwF[O~ø;ÿû^÷Üš©ª–ÄëxñÓ:Ô~¬±§ºà:§{S%h$»ÒW$Q-%x4ëÄ9Q Ú§Ñå>¤j¨è"u©c¡ªy1Å9¶xˆÑípéÞ½M*ÂZGçÌøâ;§SÒ£9Ùóóûüôõ—óT}—«{C ®½ÑYu~¥ôÀx;;¿~jd…‡?È+_µ¬h©£Ö“-áÏé^Çô îôù&©…¶KvÒú)Î)Á©õ­UÁÓ- YgYÓã>dÐP ÚEêRÇB5TóbÚs,þ¥†x¥µ›úúÖû«¾Î°VÐ9óbšäú`K!T•ò´E-/”u6±[¼”ˆYò®î©ÛÛz²{t 3.<-+K ÕPÍ© õtÊ:Jã–7ˆNº;å=ª±‹Ñæv!¬y 'ÌP(£“•[LUcÊM–ßIœî{s4à[½.b6ÈXS@:ì_?jôЭ^ZºæKöüæ”UÙÞvandkqdUA#ê˜"A]*˜¬ŽÉò­;™ºÑÔšzVŒhÎñï­ äe—è[Gh÷ÁÂÔ«Ž…j¨æ=Ää Þ&±*Ô¢«¬úú1å=\„Í¹Ž¶Q¸†G{‹£QÝÓX­ˆµAJzB|h¸¥e]ÒAƒ‘ÆÂj›AuL‘ ¡ŒJšouêZdRS{h[64“û¦¡ª‚zÕ±P Õ܇˜¦1[þ!ªg3%[arm£pù? Ó`¦¶Ù¨‚¨#*ˆ:¢‚¦ÕÑ6 m£PGTuÄCtšÂAÛÀ(ÔDÖÑÆ mC—:¢‚¨#z§)Zº ÔDÑÛ8MáÐÚÐe Ž¨ êˆÞÆi §.»Îªjýç‘[ksvQGTuDocÚC´™ÂÙ¥†¨`2:ª™²ÜÍÌ·PÏÑ´j:ž‰èm€(`Sm+¸ýÅr7YäÐg€Ófjï_ :€nxrÓŸ¿Åý±=¶×ž`rx’o[í²Rù|¼xFß‹è(HÑ6Œ&‚e!z'øp@vݺ0S,NV<¡Á†fÁtÔ ÒÏ€¼YŇlnm²QQ‹GäïçÈ(B=6Tç,%rj×µƒ¼AÞ püNŠœZ’‚HÝÿßÞùŶqøú(¶+¯ÝܲªÂRÎhÅ´®?ˆ A6ÆR•Pz…, ðE éZ bC‹ÒŠ A ?8²× B„0 !(…W ¤ b‘¬„ôƒ6¤ÛˆWtÌŒRÝ:»Ýv÷¾ðž3ÿ83þ‘DI3Ãß#!‡3gÎÏ7¿3ÏáRd õÐ÷B¦Èh7Înè † !9.éÆƒÄ•!Ô>ï‘-’š$Ÿ]#q´–ø‰­sL ëÓå÷ˆôXÙö#yåû×ȃ dr@Ú˽ò¦vÍV¼å†Àö1îx‰¥ˆ®ºGIì¹yŸ\ äÒÏ‹ÍHž»W²í¥)yÛ7©ÄÈg÷É=I ‹&É@ù5¿"0 @KîhÆ-s*ÛäVÉ…_ò@õòCâùE.ê¹QñéHÙ¢\.BVa/è †{ç°¿jÉ™£ù»./K‹Æ¯ “Ó}õËÝdêS”/q*C.òéCÒmxS­›dR䚇ŒÈ+ãÖôÚ܆ÏCc&¹C­ž890 Y80©ÕÖ(ÉŒªžf4ÛÝ&>m%“ã½è×„Þ ±‚C£K@o†Ch Ñ?üÁ80ÜfïhÛ˜1îxÿ~ ÀÁp`ÿ½6ÎþZ„Ôà’Ó©@o†3{¯F€äô`8åG,ë+9Ú£ñ|Ðét¦öwÔpŒÐ €}Â\½ ý)ϧ,᱆ûp@##€á°‰äê>V ÏÁsp0¶•<×ÈžƒÞ`8ì/9x®=½Áp6? ÉÁsðôÃÙÓm8­Qrõ-íðþ~ž³·ç 7Ά¡ ç4¨«žÆ«½³á&ú$?·æžJò~Õ+ñTˆøøX3!/æ—æ/J+—À^¦I$ŒÑíW6œwI„.îÌ&¤ÍV; Ïå1VÙ¾o Ä¶Æ …GðgàåÐS-q5@vç‰ßU\à òÕÊÏÏ=ù2Üží%ƒK[Òf-‘Ðn/Ï=ÌF®6—]í(òÜQcõ}ÕÅsp0Ü ¹Ú³ŽN:}<ï-_@SøjG4”[ wjÓq…Û\ú•i_Ï:}ÿl°âjUÞ¸s<©ðÆuJç{7èÉðÊ't!9² )u[(HÓÆê”Z·ØB{nC«¼À†;æ±Ê^nbc)úÁÓp¬ye)K{ö˽Ï } Qz|ö÷¦¢R-wÖRŸNŸîî§ù'ƒÞõ4+Óë—ž.9£µ†HW¸#ÝMo牟”/ª¸V¬`ÁU'QjÎDÖ!{êuÝêàùNIE¥•Hd¯©¹¥bl/áÙ^¢Ép•³tGææÇ¿ž¿úòÅ_ý=íÿõWïÒ‘u¼Å…Oîý‚uÇ?VmðÍú½Ÿ½ü2]øÛ«OÁ;ÿSxúã¿¿J6^W=>žã¢×yÔdò¥?Ö;1¸ôΜ^¼E®¶á%GïuéÚàÇ¿^¿ó³³¿øYïQ–É ï~ØkZä@ŒC†«Mç/¶èîJŒ,%hÿŠ‹H?û’¾•Òóç[iÒyõÄ‘×cé Z ©‘¾üb©÷æÿ\T-c Iç?î§­ñFÛîxcœÐ)¯ ý~G’vñ+ê×^¹ ét64xRŽBh£QõÈ'hÖHSÄ[Ä$ô¡Þ6žçI³«Ü«t'ç_ Ý´2ü(vôÖ¤71™ÉŽ©PÔʆ0t©Œþ ¹-‘»ÜvIrwŽó3ÉIaKˆtÒp¢ût¥Z¤£ŸÏgÅæç²BÖT~ãñ âoªÖ˜5íÈtŽc:Ó©¬íÒ?*·nä¡1ÚŸþöõòË¿šW†/Í…«m–§'@*”/^ήñA=%îõèÊëÿG-ãÜ7¿¥ wé›'4{]\’3Þ7ߌµŽ{Zì@ŒC†«ͽÂF&#-%Ni ÏÃҨݺØ«ÆîXÖ¹,Ë ÷á´Î &I*”XgÛ–¼ªíSÚØ»_%F¢J÷áòjr~êå••+åïäyŽ©‹ Ê—§„ÐÆt¸äŒ*ýšøÒóšš0ÒñÚ)gBWù¦ð{gç©€£´X¡Ý*5¦u¬¦ÕÙo¿¹¤éQ†Ó”µéƒoTE|c°¹ºärh`Cx§ôKŽº¥´™~­]dÔÜ5µ¡Eß`ÃyŒÓ ÄQ¿ýÁLÐYaå’èå‹A¯í4%«^--P»fõ:W |Q¥=—z³N£`¥;5®†ñNãÖvµù¡½åoÑ=Ôñ2 ÆÙ ÃáÏã¬H bëI¿iÀžÔßpˆq€‡ XÊpˆq€gÛ É$gOö5b Æ!ÃÈË/¿ŒF@³Ë1€ÚûÙL&£<õx<øà Ùãá°O?«ô°ègÑìÀ†CŒ j?«t²ø¤ Ùã,–á 9px­?ÿùØà(ÐìhvHΪ†lk8Ä8@ŒC†,e8Ä8@Œ³m†ƒä’³§áÛ1!OãÎÕéHòþýòbnp)šÖ/$}$¤^—Y‚bk&zgÃMâÒüÜš7º+,=»6Ûæ:Ò÷W÷¾cþ2+hêfªAŒC†à¬ÄS!ÚÕE||¬Y³„$d]âʆ3”UwvZJíõ4^uw}®=h‰DH"š[ ‹mòôƒèn ÒAÙ´Ü’ºv+Ûþ£æ Ô‘L’TZËÄš7\ꕊX9¡Ô{‰$0í½Îu­º*@†CŒ–ÀëØXŠ&²s—›Y/¹²¡t©¡øS>vbî.íF;®ë’ 9³ª¤@ûÍ2+æŸ z×Ó´åÅn”ƈ”ÓvÀ}¹#’X½;ÇùÃMù¹,˯—OÞ›ÔßÉóJS„OÒc7nÚ,—Ÿ:Wšë±Ùï>îe¥ EE½¯•¦äô:ó–ʾÏ7ÑòuzÎ`’P•®°Ò¦\sT:`ý‡ „¦ð¬o˹}çÉùÙ°XÀâÅi6*•ë}u>M\ù¬eáŒWüòYº´ÛMï|’o ÛjÌ«ùòD‹—¥Ÿ–%š{&Þð“?Þ5ðMÅö§Ö_Ù(Ó\¢áäk× êLã\e|õp2@×ßxž'ͪ—^<Þ` tŸ®á@2b°V§[;»á¥)†¼c…ߘ˜_ІvYGY6Àí)-v&#ÙþîPGØv·t\áŽHtUˆ¶IÚtù}µùæš;PåÚf×È ·T·C{?`™wl’G¡4>Óu||›.[œ¿ØBÒ»‘«åFiø†«®Ù‘?,;†i‡(¬´†¶y ÚÖH<%ë”k.m³—¼•eÖXŸƒ°ˆä0J å‹svü2àX ‡ŽWØË‡Ñ Ø6Æ!Ã@†CŒ`wü’HΞ†lk8Ä8@ŒC†,e8Ä8@ŒC†,e8Ä8@Œ³m†ƒä’³§áÛ1ãáK1ãl›á 9€äìi8À¶†CŒÄ8d¸#e%ž %J·L¬y˜8Û]§Ï"É`Ìd÷bnp)šVïôiܹzäÕ¨ù¹5otW|\ítÇ®?pí»Ó;nªGóZ©5ŒèHòþc>ê£>KËt97@ãÎ|1Nú¬êNbÖοzÞeØhÌ'}0"¾$Y•>!kVJV|yñü‰­òý5­À{äsöXØ\)V(J^Mz*V¦ebâT4šUê£ùˆήͶ¹TuH„R‰²=×>Žî¸üöäÚôèÞ#ïxסÞâ隥ˆ|ì-¥ï»êÝiÒwsR*]à†3”ÝWóšš² É?ô®§•¤§ôôxƒ¼cpÔê+õ§©Ú)¤m¥³ëpÏR,ÈÇÔ.îBØit)þZ±•ÄÝÑc¼ºµTy¿åÚ1îÈzÌ?γÏjÇUíÉç {ù°¶+”û;v~{SQ]w–È>^£ŸaåĪ“°=<|Mþ0'÷Ó¸á'¶è­Ý½T}7ºÕÁóª¢Ô}ͺwÐ ‡g{I¥ËíýÝñ\޼#ô¹WÛ\.òÞÄŽ7š Å[´•Q7‹>Ã-Wk2xwÊ´¡K~§Ôkz;¬¬Ò¼@°”QdqµÍò'؇ÖÜÒEƒ|VèŽZR}Õë— ±äŒÖp 7TÚÜðì:Ƴ´9¶vvC}-µ²Ád8û^¸é˸z¿rýB­ji`KÙònÜ·óÄ瘝À¤|9ïù" Úße—V:ýÊÙé®(›Î_l!éÚD•¾!ŽIŸÃæË-‰è$éU>À'ÜBÒÙ3»?Á×ÿèe|òsUtPúµÕx¯Æ.ªfÙåÛP~§äË æŒÙ¥¿¨èfz¤>â\²Ó²lïœÿdGx[tMWÃ)äj“.S*Ÿ·Ç{–*•d×R$Ê*5ùRº xCL“®pG$º+ÖêôãÚ1ήÎD’“Nßݨ7µ¥|Ôåñášñ•‹’¦ßàIùúQ^³—x¦ºNР‘&r Çßtl<Ï“fš!>00_‹û´¶ë/:Ó”ôøñ— ’¸íèi|RwsT9ÔŽU›¥Ê±êÓ° åwêîçg’SlïaáƒÈÚÉ»Þõó[Ýiñ¨]ç_ Ýâx¦4œÛÑ[õZÙðjÞS!+'²s—›5÷¿û,u…½É-÷i>H5¦OG?Ÿ;ÏêŸŸË ^ìÀ]§÷Û&F)ë~ú²IöaN9‹#5Å{0áÙ`X˜ZûЃE‰—¥‘ á>ÜD‹2jï“„~¨ÖÙNg“ã=„5"Œª +¯Íú"´§Hï|’o »šÂï§ýTtÉ-­yÓ¡Ý¡ŒO*×ËþÎd$JH××%莽£òiP¾ …ÐÆ:)ZŽ|zðòéQ©y-9J)žç?ï!IÑÍ/ŒXÒ Áya SwÔ³|9”‹ªõž“¿“ç9v¹À†õŸ;S¥rj,9…ìøÚ)A~ªgc¼ûj`Ùn¬R8#+Û(f|êÕ}«ê^髺B4Av^í ›vÛ6U±•ÑíW³‚þÐJ7ßçÑ!bW¥†G¡;ví •N_ëŽ;÷~昖jc­ú÷º¹âI¥oÌšO¡rïìñ¥ºCSFt؇Ógh©½Ñ8¤‡ gÊöÚó_û6¸Àá¬ã˜;ÆY)ÃArÉÙÓp€m ‡ˆqÈpáãØ.Æ!Ã@†CŒÛ#NgJ|¹ÒmžZyÞ(^%Ùã ¦\(lã“lcŽvž±Ê§[‰x§L㬚áÌ/9ú0•ØÄZñïîPÕYúc)º­P˜Dw`c·}ñÅ?Ó¯¿þSvÁÌá™Dr¥l,½éTGëiÅ"ÜÖ8n³b¿ Û™ δ1Îz³ztC;Àmì§ w.šòg¬ÅÞɢבöˆqÈpÑ Ø%·©ø¸8›Ý‹¹ÁÏÉEÍ÷GÜMCrÈp¶Šqàpô–!ä)šÂ¦zóÔaLRýÃÇl#e.ÀÝyò†ñlÀÖ1Îò’s¢–™\­ó5L·Öˆ’Ã(å1óõÿÞ þîOÂ×bƒî“ôÁ·wÞÿüë©Ü*[þý©+.å¶ÞÃÏŽˆÓ:¶q©þæVqé³§×f…•Õ h(Vvò¬l¸’M“Ýò8Oü.4MãbÃY8Æñùàïþrꊻä{)Ê÷äqvS*¼‡Ÿ»G¿G5öï»3爼|‹£Rüϼ'E¦®tãöhhج³òcÍ×ùï,¢åŸ‘næ°?Å?yzNo|øÙ£8áRNv]:uöáÈB“4ɶý3ØüÑ÷/ýî÷ñÍ£NaÌó?¾Ÿ9wêmT»2K׬ÿ;˜»ßß_¼.ôàé;Žž{¤øxkZ{Ld7°3{4\m+‘<Šm/ pz©ŒÜ&¾i#9‘åÌx@–ÐíKBØòÛD|¬.ÓP“Ýãì«7\ï…>ò ›#­Jã™J×½é†Il{¼[*p;ÖßþQzH«IÖ†Blïåª-4‘ÿ(q…½@ÙµUþŽ¢uèÆ¥áÀrYz8:+m•j²†j“ë7ŽZo’k ÃÓz«.eŽüˆÚOc34º¹™œrùêÛp\ßb.WôÃW›‹¤ëF+[®ÎR¹ü#BÎè“ÓÇ-Ž&*Œq"…H™ÕÍb¡´L_(A/u¾*“ÀäL¹*»)]2C|œ TÉoXu¹Übß…D9SUª6fÄV†³Ë_H7ØlÏQŒRÖJëP"ÖßïZÎjÜ‚X(ÐðäéYžöŶ A tù@zÌãbNßt¬ËÀ¨£Ë{Úqá |jñøÎd…qQ©ÌÉrºn¼±ïÏ·{†• % !Ò½ß:#ÜN ŒŒ*Y\A{}ө‚t®¸NMÕÀŒ1Ø*íyh@~Ò=^è6z,cé™N‰w˜jÞªµ\xbw¿Æå'CUV OUwÔH/ÕÒ¨vu}mY‡& Cå"©ÚÓ•¬ºBÉ:î®BµY 8Ÿ2b0)T Ç_ “™ i¨ïm篿þSúqÆ'ì/Æ!ÃÊ€_à€b?Jp@†3cŒó¼ÿÐä’³úüpÀ®nƒØ@½bœ=3ܱKN™5ƒ˜l‚oÅm— à6`wÉa”òÐ=W/ê8ÿnЊ¹³ó®a³`º8[\•–}Žv\ýñû~`lõ•“Cýk0ë¶ ¦‹³7ÊŒqâm9öãá,Ö§ãJnk(·¡)2œÍcœ:ÀAr–„Û4°y½w.ùÌÝÀ1ÎæÎ’Ãø$¢ܶÛ­§åg‘d0Æ&‹{17ø9¹x*e3ÆMÀ…$9ŒRZ²£oÀ'è-CÈSœ6Õ›§c’êiáV6œ¡^qBT²;OÞàùN´s£aÃY:Æ!ÀP3OãÎÕ!‰ÞÙp“îµÎךÌXe ±rŒC†³¤Þp7=+» Ò‘C5GˆI>οUä!Vd¸†Šqº ÃjTÂßÉóòcõp%i ÏZჃ!ÖCˆqÈp†³rjÉlbÒGÓÒ|7ÂÜ:îâÌpÚÉǃÉvr†zârM&=skÞè.‰øf-Ÿl,8ÄŠ ‡*pˆóÃåî÷·Ç¯ =uZ˜n­øX˜2”ÓÍÊzöÍ™q®† 5´ñ(¶½0Óøcä6ñMWð©eGâlÚ—ÄJÊ;*×—‹pK°©MÕ± °¹o*·›fâòîñíX»fNp¡a„TÕ#ÂŒtR;°ÉÍßÊÒÆ!¬A¸Ã?…\a/¶Å‡ÁêC¬fq ”á 9ž‘5šo_ø¦ßzj6±õÖÕc¹¿]¾îé{“z%7s“‹öÔ¹6Ôh@š<Òÿ`qñÒ²4÷MëÐÂÔ¦ãÃÖP\g[Œ´££)U sX¥?«hºqi¸Gk/zôÙ­â¤å[:M–8UÔ°†ë7ŽBo¶ÂêC¬f•F)Á>ã×a\+¨ÝVz²î»16{ÄôjþlŽë[ÌåŠ*øjs‘tM_ ‹ªÌ”Ë?"äL긺YÜÝ‘/”pm–M`rþ3œ—U“YE•êgèfÉoXuh¹Übß…W~w·8šÕ¨çÆåòAíØhˆÕ¼4–áã,šêÖ¡D¬¿=Þµ¬žÏºªá 4'yz…§}±íB†Y`h =æqq¦oºjÒª5‰žÉ c˜ÒŽ&9š™ŒÖn¼­ÒÃíža%K Cˆ´V·Î¤†F †Õ&Ê ­ºCë›N¤›pÒ:½ê „Ñå=편ð„æWQ™oÁy\öb5qŒC†v„õÔòõÄÙúI´sKÈtj<°× [ s»Ñ5.?0ª™RN­5$½ÔL£F%hxh²0T.ª*þ.[í@ ‡ÆÖ¡ùޏ;8£ã¥OÅL}ßLqVœÔÎt1®ŽSÄÑBøww^&‡Ó‰aÁ¼µ3–Ùq_:ÝÞ0c8`ŒkÄ w4’£n£N2áô§b•¨,1Ç70-p¨‹ä0Jyˆz3y%i ñWän6¦A w¨1Îzn¶qÈpÀ2çëÎλ†×˜.ÎeßD‡£àÎ1@†«üÍ€ Àtq ð9•fŒ£ñ­öÞ?à>œ)øöÎûàÝ'½¸ ˜ElôAfŒÈppfáÙÓk³/~$#©?Ðg¾¿ëš<õ=Êã}·h²à_?HåØß÷’ïO]q5ÎM?¸­ABÛ¶Ák L€kDÙ~|òÏùï¹3W\‚ížÜ3«=¹ÿ%Ÿý)GÜ“Wšeá=ü4Ø=ê´ÿ)«t‚øÛ’=»ÍØv˜b zKá7MLÏÉ¿p—}í%î{Êã¿àÚ„š8°9ÌO¡ÁyaßKOOJÁk@ËwìSd/˜ü)þÉÓsýÍ­„<üìQœp©¸ý5ˆ…¼L±4Î$œ½rJxÐ,=ªê³ ;ß,þ n÷¹îŒñ:4˜b 4r†Ã_€ã%—ûšãZч¦XC€Ó¸2œô†¬ffä)¼9Ýr6+i2”ZªWåVy4-̃#ͧã.N'ÖLD.V©µ´ªò æšM¦XôF0J Ž÷ŒÔ-©ÃUHî~{|ñºÐA§…™ÕŠ…ÙAsê‰@Yo¾y#3ÎUÛŠÓuý‚*ŶrgŒÜ&¾é*U4,çÜ’QáE¯©æ/eêJ^м*!Nº-Á¦3%t3t³ùn*×N3ƒy÷øv¬¿];8ká!Ö&ÌD˜‚NªóíKB …$1£ÖL±*Ó†ÃøäÑøiß”{wö» ßôÛBͦ±Þ:£z,<]¾îé{“º$7s“I% N{Vq+}×/Íé°¸xIž¼uhajÓñ!ÙƒB”r|‹¥ gÎ3_à­é¾`ƒM…z}9SX¨M¢•þp°uèÆ¥á­½hKd·Š³—Klé4©*óÜí’×®ß8t½P9À!à ´¿¶ý/×ýŠÁ0Ï©÷RG¡Šþ›‰=bƒx5¿M×·˜Ë»ÿ¯6I×ô²¨ÊI¹ü#BÎ쯜ᒅ7Z郢Š“j“VŸrè4šÅTe|œ ¨ÊaÉO]“\n±ïBÂPV´´[ jÔsãrá Ã5D€ó¼ÿÐä’3ÕüpG[“Ö¡D¬¿=Þµœ Ô¾›ü“f#OÏ¢ð´/¶]Ȱžh =æq)¦o:ÖUf½!ßðpб9U/WŽÑBµPØ0 œŒô&Üxc?t3Üî&Å5ò±çÖá^Z`´P0Þ -\ZG{˜}Ó©ÂB«f…â•ÂèòÇžvG\xBƒ¬/8Æg×ÞÄÖq‚ﺻØõÇÚY= ?QÏ‘­™/;·ô€L§Š’¨m+mR‡ÂLa\~24`\¯¡ÉÂPår + ÙKõ]¨ë§yÙC¨¼ŽvwgP¥€tm^Ç·TœUý8Ø«ÞF)m”KöR±w½¿ 2XÀ ºÿkˆ#Ú•=fŒÃ<ÃLj ‡/˜`Qlà6åÎ1z¡ã pÈp¸íP¬±!Ã!À¬ê¶Ò”†>ÇTXÚwì켋v°ñû‹:d88@€«àìi8è  7‚QJvÅn†C€8d8Èpp,àle8è  7Ûf8Àn†C€kð+;4‚í1ü™†þÇ„Øà¤ß®8“5°úÅkû_üóë¯ÿÔ*–ÅLÈppnUÄFÿKÝFÿY7kÂvÇàáÜÌÚö"¶sƒKó{gÃMû]ápmÏ!Ã!À¸ nkß{hcöЦ I/9·|kî¬wþÕµÙ6—¸¼ÓÇÇN¨WàcÍÇ’ê ¹c p–7ôÖ`gy†§h ›êͳ¯ɦðl/)F´fþµ güi’¬n] ò~¶†vÐ@z#¥Ø K$´"ÉÚXÙpp ù'ƒÞgWù`Œ<;ׯyÃ.4Jã8d8‚\îkŽk=È &¦)< ‹]m³¼ø¨9Æ7¬áàÐòõLpóFf< Y’ ¥†¨Ž9FȲúUl…G}¾Era{a€+WfúŽ£çÞõb9t«õ­v©×ÉÝï< ‹î…Ñ@õýꪺï°d€³ªá 7ÛœÁº%Öy[[‡n\¾õYnH1VYÒc#¦™?¨H"3ç)-lsýí×f¶'‡äBC‰©Íö;iæ3AE‘ÜÄ…[í¹ýV[–"GMI Õ+€uõF0J Ž‘RŸ•ûU$3˜ïvç¶úùõ©ÂBwÕ­r3×zŶǙՆ¦6Á±Žò©‹su‘ÕMꯢyºßžþ02óu`¨57s3úåùìÖþ¢{¼šé÷8ºjª<VÇz†C€3ÉV£½ ªñCË<=·?MwªÄ·;íÃîå‚•ºÇ—/9z®Q¥4­?¼ÝÛÖÊ ý2Ôs¦ãB2y!±ÐJr: A“©mr³æeÓ$¶pÈpà˜ÏcfµZŒg ?¹ãpxX’7JxÔˆÓ±GÃ[ÓÛ“aF·§¯µ·ßé(¼U²•®\0¸Ö:”¸Ðßþ ´=ÉUM–²‰©ƒoo¶ö†|ÃÃAÇæÔ2é!´Âtáä1cŒ>îV¯ <+Ýu[È”Xn´PŽ2ã†Û ”.ã†$2¿ÛÑ=^}à ,T•ÊìWpp d„d jI¬€}œÅ ½Ðh¼þúOé§|è­!2 AÄ&¦|¸ 4„áà@hpÈp¸ ‹Ð`gçÝ2×}Ûh«SáMgCE€‡ í#éâìŒ2cœx[Àm ë64œ ½C½¡à667&8…Þ¬šá@tƒÛ*è-š&$½äÜòñ±faЏõ´ür$Œùé:Ÿ“‹§¢Ñ,!-šIãäÍ LœíŒî¸×¼ç?YóFw‹{ˆÅkòsŸñp@­· !OÑ6Õ›g_c’MáÙ^¢ÎplЏ6éÅ• gh£—çÙ'oð|§vÛ§qgÖ½äEáQ5⦄½|ÑÐ`'¨´V,éÍÔùZ‰¨VväTRÉs®E A°3œõ£I‘áàf€I«#ÉwúEK…ذäã|™•ýÉH*o!ib£jl™ ÛÍ­y£§’|ðÈí&fJõ *œM ½p\är_sœ…&Öi Ïò´x^ÉdªáÊYãÎÄ òJ!ï÷>{Í¥ŒR‰‘ã©ñi+Üì”nþ±6ήͶ¹„xJ¤ÛŠv>=½ŒRp0Ž9>,™ïM¥-ÌëÍ<‘›¹&Ì'ÎÓ]„M2GÄ k¾žé&C)í„mláp—¸‚¦À=VfO(5iÌ·ád9O pvïtíÞC š8›eOû¶œYòI.JήÉßmñÇz'—Þ™{å=’MÐúµFV4\ãŒQè–ìù}ÏÝïo/^4¾ãè¹GŠÙÜl¬¯g‰,Öƒo†b†«m¥Œ`£G±í6—©ÖL#·‰oZ_-6¯ò„ë½ÐGds$ zþÒ “ض4a[÷øv¬¿ý£ôPeM*•)WyfJÂ&3tª^ÒDžôU˜ñõ’ІBÉDj }M¤½ë,ú¦ײ·‰Íowõ,óuÛÞOŸ Çyâ—¾êò|ƒ÷k'ég_Ò*­ô|+M:¯6¹È)¢YnùÏþ8d8pœ”ú¬Ôy5à›~[Ð@àÍëdëŒê±l’Ñåëžž±7iwŸ›¹ÉúýÞ|Õ­4‚¡6JM÷#3ç:>úzqyëÐÂÔ¦ãÃÊ‘ˆí±Ê_8´ݸ4Ü£X.Kk¢–^“é;Æ•)SùQæg3ÞU›.#zîvÉk×oèõ&×D\®ia“¶ “ÎxÂ8êJ<åLoÓÄY&ÛÓtዹÁT(­$Ë `µN~íÉ 3bå{Àr†C€†.Ü—üˆº‹›¡ÑÍÍ|ËW߆ãús¹¢d¾Ú\$]7ZÙru ËårÆ Éq°œH4ÉR”ëÈÇéÑ@@•ü†UÈåû.$¸’JV¦Lå9â&šåäÇ-Ž2i’U¡¶UšË &²à0uxù ò1ùIX¼qXfR}g˜ÿD¯šêêDëP"ÖßïZ.Î|]Íp ÚA{z…§4ú2BïͦÛNyB´é›Žu•l*Üx[¥†Û=ÃJîFü膷ÎcƒlŠpƒò‹+h+Ð7*,´UÒ¨2e+?Zؾßï𶺤øµ¸SÒÚò ×§–»FÚq"­©0ÑmÈöxŽîѱ(ìTYnÞÍŇûªßJÀ¾†C€k´dvÐ"„.^~Ò=^è6z,Xgé™N‰w•jÞªìP»…6.?ÐWjh²0T.MªkP~Õj®L™m5Çn°SUåUÅÒu¤;‹¬X£ ¥ûv…É|=×¥»€W€3—ál©·ƒŒ­™Ý.–‚vÜ è]Í—kª|‰f/`Ò8èÍ>ÎfïeæJ7ýgfõ¢ãæDœ.n61œÍœ¨73×P¬­'z`6·AlpÈpÐp¦7¾`ªBÏwË\bº8ËSáMt8Ú FÔà,j8è à3ƒéâìŒ2cœx[@o–Ìp`ß|ýì¿ZO~nvušXØp ྽óþ¸A÷ÀÉ}—ð_÷=øÛ®É5¢ÞðÑ…Û*Òp3Ñ À!Ã3?{8B~˜9wJÓïï‘—bš…Âão¸Ts+Ÿ÷¤ÈÔW·äÂß“`÷¨³²/‹ë°rÖ¿?uåoò âD(Ñ ØÔmÂtn»ÅçiÞ꒯·ÖÓì)~Ñî0àó‚uN O¾;ÐÿÃÜû _Ñ…ôéï=ëÊz¹øæQ§kêìÑÏ^¢æ{øÙïïýaÆY¹ôS£ìÛ›Ìs÷´/\:k'½eh‡…­MõæÙ_n“§s«0kÚîñÊ¿èH…—Zb³¬¡ÉíàŽÓp 7>ù½&ù÷ü3Ò-K>ûì§ãOÑ…/]0«ì>÷ÃKïÿþÎã¶Š^¬¤OÏzÍjÔs£âÓ>\ aÈ?ô®w&ƒ³ÆÞjqŸVŸp”ù#€ÍõF0Jytœlž¼Òüð³‡b\óýçfÚÓ,$ä¥XÑv§F¹k³9w°»ÌßÖ}÷Üß¾ÿÝ#Ïü0sÎ5õäaðýœ°œñ¥Kä÷ŸòáÙííÆF)O%ù`ùT¶}çÉy6M6Y‰/±ùEà†ã1\Ã~Á¤û\wæœüäGÍ K¤X¡´Ö¹3?"†…t‹rîÄž›#RêhŽñÊg§eâ½6ñ'lª4YÃ8d8‰‡cŽÏègµf?ÀÿHžAF˜dÇ]œ"NF;mwéLÜêù»5î½> Ã!ÀË‘»ßß_'pa³wÞ#ÅÇÂĤœnR¦ÍPìÑpµ­4‚lô(¶½Àæ¶Öšiä6ñM—dxõð³9NÕ³†ÊTùa~ÍüÝÝãÛ±þvÍäàeL)Ö§\她oƆNÕ5ìƒÔŠ5Å©À¥ çÔmbÔa4V€C†6Æ7ý¶ 6}öÖÕcÙ$£Ë×==coÒî>7s“õû½ùþª[i#Í™9·ÐñQÏíKËÒôr­C S›ŽË×M6M•¿|hºqi¸G#°\v«dŽî­RMR+Ôgɸò òáí¾Øv€Tž‘Ž…Îä…íÂ$gØÚÛR%‹m‚ÉNA£®Aœçý‡øñeó#öÅc34º¹™ rùêÛp\ßb.W”ÌW›‹¤ëF+[®d¹ü#BÎ$09–‰&YŠrÕL®Í’ß°ª¹Übß…gTÏÒútWž#n¢Y^^É åÎêÕÍâö´X_(½!À5˜áDoôM;ñ©Nà ?\Ü:”ˆõ·Ç»–Õ3kW6ÜÀBv÷žžEá)>…ŒÐ±³¹³ÓcÇmañt¬Ë0 ¯ÒÃížayáu66ÈFönÆ££ò‹+h+Ð7*,´–©gI}ÊV~´°}¿ßáéa/)~•wJ˜Þè&‹#biâ~4ŠöÉ ãºR±“zzè­3\ƒ šÃ´ÓèP·{ÿX»Ð¿ËOºÇ ÝFë,= Ó©ñÀž¶*;”Çn¡ËO†ô•š, •K“jÅ”_uRk}Êl«9výNËì®UÓ,½ÔÍ£øìSqt†kÀ/˜˜öxùwñMŸ¢uÐ EÝPGl0i\ãÌ3l¶‡ 0#ât96˜µqôÖÐ!hÀÐÖ8ýž ÜzØÒmêï”5 ÕL®7‚QJ`h¯±³ó.ÚÁÆï/ª ¬g88@€C†,b88@€C†,b88@€³¡á 7€Þl›á»àá¨Ã‡ `{ÌpÑ\áLÃ5}£í…ävµ™²…q8Ú¿øâŸÅb¶„e Ç Î&†ƒÞÜê"6ú_ê6úÏêYÓfÓ XHo£”n& m{[>ÿÂåj2­ó0‡Ž ‡à6pÄn#äÅÜàÒüÅÞÙ0šXø£•!ä)šÂ¦zóÔc@òiܹJ’Á˜Ÿ=Y‰§B‰Ž$Ï=\Š’³k³m.íÚl… q9Ód4Ý2±æ ++åŸ zw.ª—€†Ípp€ã¦9Æz!湄ö…ÈU½ÞÈʆà?qySxÖ·åÌ*/æçÖ¼ó¯®ñ^ØÍº®n†ƒÞÇÏʆóîIšÉ¨çbâÓPù•OŸ Çyâ%–¾Aˆ›=ò\§ŸmF‹ZZo£”‹ÓtþbK4ºäÜòñ±ÎäRÊë\–Ó|Ö!«K+œ[-Áxê®»w6ÜD\m³ü+sƒ)gZyI_§¢7º$½ê”c``BXX:4<ÇžÙžâJ—Ü–_Z.Œ ¶ýz¦?8¼(<¼>Uï®°Bßtja¨õpí%:¼òWØËË_3ñÇ‚|¬ø’_ìšüÅŠ®à—J7íøYÉ|¡ˆw5‘Ù ¾³b‡ ŽùcSŸk£ÜýþöÜeÒÓsOÒ@ÇGå±Ðe§Ç<=¤èÜ̵ö$é[tWÞJo ¾ØöÂg žXWi­Òw=d¹/ÚîZVgAVó¡íL“jåèÏ«v¡_•ÙÏiVPgxUxè›–vA«w“„ÜÃÃ÷¤…„_Ô…öXƒŽM¡•ròÊ¢y—3ã’9CǺ†PÙ÷.)Uª ïãE¼i§R#>“Èpp ^þml…W+²•å& …Q¡k¾9³-#¾é·' ãj;Š9o²† `§¨´ôG¬ü@¹ <dÉ^—’œ±Ÿ2«g o³fs$ µ7ôóëÃ#¿IÐ1;nþ¼Ò˜!“–¬IzläÖ—-×\¡)ÆÞ ”›B8¥É2»!ÀYÒpÐ0KT©Ñ¬Vè6z,¬Ø{¡f/±s¯i+%] ù¸2\©~¬Y§L­*¥7µ- rñN¬XÆÐ1Å.¨¸SmɪmÙøa¥Y®@B2ÆŽS7E"–lÏєɩ  7+f8,ƒøÕ‰¾Øva”CkÔv£îžô¸Þ-üúë?¥WB¸˜Gj88`1jJT`_°Ì7Z÷Rá68d8€Ýh4·±_‹î Õ?Œ)ÿí9»†kŽñeuÓ6z#¥VÁ°ƒgŒCãØú²†M'ÊÏ®NlŒùË,i±ƒösw—¼ñ|¬YŸ0ûOø•OæItéiÌßÌÆ0ïf©KËs…;"ÑÕVÚb~aüs«ƒâïLFR¡Á“Òà$Ûé· 01Ðwöx¶!ÀS€ÙPm/6úß}MˆjÕ 'Ø©m–o5…U?©ü¢˜ja“Ä⯑±_ì,)D¿Sû8d8·3†¶‹íiÜ™ucòÒ†ç;{9óàÜÌå6Õ">qdO£ºä«ó!á»…â].´5iˆ·ÃAoÀŸ½ í°Ð6Õ›g¹Mž:‡}·~þ¢áDn»[Ä+þ±/%.)_¸¶ÖÁ(%Àò°¯Â¯w&ƒ³ÆÞjq¿YȾ”¸…kj2À¤vc£”§’|°|*Û¾óä¼ðBéK‰pàáÖF=Á· õß{µL¼'ý~¦9E†C€ ^ˆ³ƒjçõ––³ ØŠÓ¹iQÍ-n.Q|þƒ3}$™ýš¾°HÜ78Íæ›¿¹æ¸½ªÏ@Â|u„†BÃÙS%”YI©`<Å©ÀiÁî’•Ýœ6rÑ}º¥œz[°º:˜«rÙ-Òw«…YË,{Ëw†Ó´Ã&N6èÍ*€ß@búZ»#È”À’\ ›Þš¾ls‰ºJ‡Il›å›ÑåëžiÀPÈgÄ7ýöda\' šó&+ÎWÇ2SQiéXùrx8&È’½®žY›æ3ǧÌjã™ÂÛl§Ù pºˆöóëÃ#¿IÐ1;nþ\wÃOP& ‚™ò©lu8r¿Wˆ˜R; ÀóØ@]*‹tº +ö^è£ÙKìÜkÚJIW‚nÆ•áJõcÍ:ejU)½©|6Z”‹wbÅ2FV ‡jvª.¼¸-,­¬Z™êà[l ßtBAU·@€C†à¸†àûbÛ…Q­a>0Ó7¨¿áà@Cæ<°WôinC€3»á 7r[½DBÌ7}kƒè`”·ÕËd Ê! -˜ËppÀ´84‚ù«¿š1çCMfXI u›àá€eÀ…Àyd88°1 àá4€áàΆ†ƒÞz³m†ìf88@€C†,b8àHÉä° à(ÿààYå(¢IEND®B`‚ivy-2.4.0-rc1/doc/images/ivyfile-small.png000066400000000000000000000377101226750426600203260ustar00rootroot00000000000000‰PNG  IHDRÈ©á’å6 pHYs  šœtIMEÕ'ý IDATxÚí½wx×y/|¦íîlï»Ø†¶HHФXÔ,1–-ÙQ§ØNœøÆ)Ïcùâ{›â«'O?®q½Jñg'¶%«²LŠfïèÀbØÞ{›Ù)ßG‚J")ŠEj~»³³çÌœy÷œ÷¼å÷"‚ "n5PqDˆ‚%B,w¼¡Ë_/‹åê‚À¿—÷V¯×Y–Ÿñ{L!üü‘ÿ=ë=}»«Bå.ϾßO/ËB§Gÿ¿wÔJ¶Iåo>þõ¯¢¨·üÊ?üÃ?À§Nüîw¿›Ïço¼Çt:}ùòeQ8Þ„ÃÏÒõÊJdâv´Ž=óÌ3*wbä_ýÑ+sÑѨm¼²ø«Õè$†:UÃÙñÿœ_9ç²v_˜|θ$!d—¦_šòœ0j‘äâÙñÿÔkìÇ.ýß)ÏQ‡¥k98<<ó²EßLÊÔ€ïÿûGŽaY6ò<Ïóü‘#G:;;ŸûÜçFFFŒFãàà ^¯?{öì¡C‡(Šêîî~öÙgøÃ <÷Üs¯¼òŠR©üæ7¿ùâ‹/šL¦x<þ7ó7:îßÿýß¿ýío···ÏÏÏå+_q86›M–G,í=2øAà•rC_ûc·k)´è[Ûñ&~j5¶•*iÃ?²ûÿ\<<±x8’\ j…KÓ/ã3;{?AJULzhë Ný\)׫ä†Á+?ߨ¼{gïïb(><{@BÈ ?»ÖÁ7¾ñãÇÛl¶þð‡/¼ðÂÆáq‡Ãñ½ï}ï_þå_vîÜéõz_ùÊW÷ïßÿÒK/I¥Ò¿ÿû¿Ÿ˜˜xê©§z{{=Ï·¾õ­o~ó›:®µµõßøÆ“O>ùÉO~²¯¯ï™gž1_üâEY¹ð<;:÷êøÂ¡Á+Ïs< €šO±’ò…Fo½`IR!ÓÔÙŠ  åj€a„AãÜØ²·Ãã(‚ªäx²\¦©³µS—ÿÃjl£è†]¨³ŒFaj±÷?0ðk¤R)†al6› ç΃Ó€$I­V˲,Š¢k«[­V#I²±±ñᇆ²b³Ù‘Ëå:®^¯?óÌ3ííí•JE"‘äóùr¹l2™vïÞýOÿôO¢ÐÜ›?øÊéš\:䋱Cç¿ùç·LeoñR(<ÇsCK©˜uÍJ¹N.Ó,/õo|¼Í¹=[Œ$²¾f[?Ë1K'/p@Lú&ºNµØòŘÃÜÙÞ¸Ããj²÷)HÝjdÂnÞ¨”ë<Ï=zô©§žêììÄ0L£ÑlݺvœËå¶mÛ–Ëåúúúd2Yccã‰'>ò‘ìÛ·¢¨¡¡¡;v`ÖÝÝ-•J‹ÅâÀÀ@.—{òÉ''&&î¿ÿþÇ{ìÂ… ­­­¿úÕ¯ººº\.—(77 Xˆ„ çVά©Ö á伄 ?ºç‹8.¹e½7–÷h4úíoûË_þ²R©ŸîVÚþåÏÄ3¾b%EÑExð±±§ÿS·R‚AžÙ¿GüÞÆÃÛþ‡ÍÔ_çùßÍ•bf]s$µI”ÿó^•IÞÕožå˜R5£S5¼§3–ˆ÷ÆæŽÎý²«õ–£'ÅñìŸ=ý#•Üønö¿<÷uoèòÃ[ÿ¸ãGÞ±`ñ<›ÌùMº& Å׋*Š`(Š1uJBois’J¥*• P.—ájX©TŠÅbCCƒø˜ß{p<;2sÐlÛ¼dêU #0—IU½íÁ‡+ÂøÂÁS¤„rKç‚xžÿe¥€ å¤T¢È•bOîý_PðwtAé|È Æg¬7‚'Q¤']¯¦ò6ç}ùRŒ”ª3…pgË^š©(H×똘øó?ÿó|>ÿï|çÿüŸÿÞ°~õ«_ó,Ž9>ülWË;6=½YX½Àr4“¥JÊ q46ôRùÀÁ³_ç„ÿæÁP¼ÑÖkÖ5’¹Õ×΃x€Nm{rïÿ2jã ‡îëy E°wæ+LæVÙ•M»‡¦^¤ëÔrèrµV`Y¦RË ¡øÂê…Dv5šö0u E0¹LËóüéÓ§Ÿxâ‰z½®V«].ÏóÇq'NWwV‡·›7€ã38&‰¥½¡Äl¾œ˜ò‡ŸO{ޝI•„¯Mu3Ë'àë9ßYþ ï_LJÏOüôèÐ÷_ø—óã?ïÔ m5¸?ºç‹ÏnëúXSCoû¡Æ†Þfûf¹Lm5¸[ì­Ž-Ý­6Û6»¬=4Sá.—ËY­V@&“ìÙ³‡¦ér¹¼{÷î§Ÿ~Z|¾wJ(Hüñâ•çB‰¹í›ž–¾!: «çëlãÙ™å“@Rªþ­‡¿Œ"ë=3 O ±aS"»’-F‡gö¯DÆŽ]ú¿,K¿¾2õêœïLOÓG^:ñj.—ã8N¥Rqg6›Ýn÷­½«×^{Íh4¢(šJ¥t:ÓéÌårÐý§T*;::Ä»Á œ#îïý¡©–ìÙü©™å“¼À½nb@JÈwöþ| ÈÞ-ð“×¾¡TI—ªix¼ÛýP*ØÖõñËs¿èlÞëjè¡ëU©DC©ÉÖÏͧR©ýû÷#²}ûöÓ§O£(ºyóæ[.XZ­vffÆét®®®Æb±p8 cýX–mkkë=’-ž[‰Œ›õ-òº:d5¶v4Ý¿°z~íœþ k”æµ·m®ívó†HramAÕª­[;ŸÄqi¹š½â9öѽ_T+LðCJ£Y×llvY5› ‚H$EµµµaF’ä-¿¥]»víÚµK|´w]¯úÁœïL¹šÊÈÞþO/G òDàÒûû~oýwPÛÛÿéçþï7Ú[;?†ãR€R®ÛÛÿ©õ¶{Ñ¥óÁ´a e*»ƒ® u¯[ÛP®¾~Eq%©»ê‹‹þ‹?;ü? À…òÿùýצ¨«€‹£üAœ¯†Ö]}¼Åq†­½tìïI™†©Sžà%(UÐÊðvRõkÁÊ—âR‰EP©DqµÍƒãP…î¡[‚BAÐh8Q®µ*A€ €bQÐh`w¹Ð·ú©·»k|$âÝG‰dn5S¯?¨SÙÞö?®õ-øïìø5 ‹QÝ!Ç­…BA&“™L¦X,¶iÓ¦¿û»¿ëîîÞ±c‡J¥ ‡ÃV«•a˜ÆÆÆ›¾Ð˜Ý»‰Ë—Yšl6´¯àóñ÷݇OL°KKüŽøÑ£õÍ›1ƒAQàõò$‰tt ««|6+Øí(Ç Û¶áËË|½.¼ÙŒÖj‚ €]»Ä øÖE±ŽÆû}á1š) @Ë´ÍöÍ»7š!®#X¤T­UY8`Õ·g³ÙJ¥âñx::::::8Žëêê:}ú´^¯W©Tø‡xÓÚÞŽ%¼Å‚€äóB ÀÛl(I"ccì¶mx½Î&|¥"ärB$ÂëõˆFƒÆÇ¹ اž"">ŸùXŒgY R!ss\s3ªPˆóÕíÂã»ÿò¯¶PyO烤TUÈ«•:Ïó0½^¯www///···D"qìØ±½{÷:Îæææ›»D†ƒƒ, ^ßÛ‹ÕëÃÏ‚õ:€ŸÖë@*‚¼ªUA­F*A€L†ð<àyÇ‘XŒ¯V…¶6¬§ÓëEñº*£%¸ìÖ ‚eY—›{ Áø´ZaáG ‰Œ¯Jæ.@¦6hT­(!H ÃSY?Šâ!“I,WWÉ Ðkü è;ÓãD©ºG§"^àòÅøjô †â‚I y$µ˜+EYŽñGjL‰®WyžGQŒå˜r5C3U“\¥Ñ¿ÅŒU­åå2­8ÄL°ƒc–c’ÙU›©ƒå %jL C ôJ›ë¾j­(^!ÓòŒ{P°Dˆ¸µ#HEÜNÁª³µ÷¬KŽ}[b7†Øî`Ï<ó àÜØOMš6˜HCÄþýûu:˲¹\nttôÌ™36lÈf³€Z­V.—årùMwé‹"(’¥r"-Õi6¾šcë<]©Ÿe>-Zu.N¥÷Ä®PÂ?þã?nݺuiié¯ÿú¯§¦¦xž÷ûý4McƲ엿üeAÌfóŽ;ÆÆÆ>ÿùÏ¿›x‡\¼¼:—\žŒ7n4z'óJŒ¦X@K@H1ñÁÜ#‚åvn1ýÞ³Ù\¯×QýÍßüM ÃÏó8ŽCƒV¥Rq:f³¹R©Üt,Ã…–Òr•DoQfb¥d¨(!ñt¤¤ÔÈ0Åp´ÎpÕ-WIÅgsïì K¥I’¢ßF„hn!šÞ@±X,‹áp8¿Ý ð$ƒ¼‘6†D¦ëÛ¬V«Ñh´^ÿ59üþå8.‹½¹©ùùù¿—õ ®¿øµ[(—Ë0}Þò[~ýê]3ÇÅãñõ\÷Þ¿3Ö Çþ¶É¶¹¿ã EalŒ õz= 655¡(zåʵZÝÒÒ‚ad ½i¿á~ô#©TÚØØèóùc±˜Õj-—Ë*•Êf³‹Å¹¹9…B±uëVŠ¢’ɤÃáhii9räÈÞ½{ÇÆÆ$I±X¬V«:N„p8l·Û¡PÈívs·{÷nÀÌÌL*•ŠÇã‚ ôôô¤Óé®®®……Š¢T*†a±X,‹}âŸðx<<ÏÃÇo2™¦¦¦ZZZ(Š2›Í‹‹‹J¥ò¾ûî[\\,•J:@Q”ÓéÔjµÇÙívš¦+•Š\.§i:‘HlÚ´I§Ó i4ècF£étÚd2©T*‚ æçç÷îÝ»°° T*ÛÛÛO:ÕÔÔDQT¡PÐh4.—kii©¹¹yppÐåra–J¥Ün7Š¢ O>ù$MÓ³³³™LF§Óy½Þ?ù“?¹téEQ2™¬X, ‚ÀqœÁ`P*•===wXy·™:8®þµ¯}Íh4R¥Óé{ì±üà…B¡ÕjWVVd2™ÝnW(‹‹‹n·û3ŸùÌÍu¹iÓ&øB*•–Ëå|>ßÖÖÙ³fggår¹Ó霞žÞµk‚ A$“I‹Å266¶}ûöB¡ V«išV©TÉdÒ`0d³Ù¶¶¶ææf™L655Õßß?99¹yóæd2Y.—ív{4u»Ý¿úÕ¯ ÏóÐݹ¼¼l06lØP*• …‚D"‰Çãf³yãÆ(Š&“ÉR©´gÏžR©XXXðù|Á`P¯×'‰ÆÆFš¦kµšJ¥¢iL&].Çq­­­étº§§§¥¥eqqÑåry½ÞH$²eËš¦iš†²8==½ºººsçN†aJ¥ä¸w:4MóH+r ¤R©ë:Ë—––ÊåòÀÀÀ ¶y T«ÕP(tÓy¶ù|žçy½^kG&Øíö;¸»¾ò¾²²ÒÒÒr[/.koC¡Óé\{+"æßˆ»ÂëâÒ¥K&“©R©¤R)§ÓID @QT¥RiµZ»Ýþ /´´´H$N×ÞÞ~ñâE›ÍV.—±Ûí±X¬««K|rw‡ô½D4…:µÙlÎår¦X,*•ÊÉÉÉööö–––ÖÖÖl6ë÷û?ÿùϧR)Š¢&&&d2Y*•ªV«&“Él6‹Oœ±®Ö*  $DºŒ Û Žã‰Zù Aõz¦iA$ ÒLA„øðDÁ!HEˆK„(X"DÁ!â]ãõÒ÷ Ãít:Óé4Š¢µZ-‹E©TJÓt¡P@Q´P(@WÜQz<žH$R«ÕÒé4Çqõz½^¯K¥Ò—_~Ùn·×j5žç!Õ*l„ã¸ááa¥RÉ0Œ ‡#™L"BÓt2™T«Õ£££$I2 ­µÔëõ8Žs—ËåpŸ››C$ ƒ‰äÒ¥KÇår¥Ói…BqéÒ¥h4êõzáý²,;;;+“ÉhšŽD"çÏŸw¹\‚ \¹rE§ÓƒAxÁ`A’$ÇÆÆ–––,K.—S(“““¹\nvvÖáp`Øû.4ò½¶cI$“ÉÔÔÔtîÜ9š¦%‰ËåêèèX]]½xñbWW‚ ÷ÝwŽã‘HdbbB£Ñ|ò“Ÿ¬V«/^Ûµk—Ùl®Õj“““R©Ã0ŸÏ'•J›››÷íÛ÷ÜsÏÑ4­T*Ng¡P IrvvÖçóõõõI¥Ò| ˆÓ§O«Õj‚ B¡Çq{öì‰D"ÓÓÓEAÇv2™ä80::j±XVVV$I,«V«ccc±X¬¹¹yçÎ8ŽÆãñžžèRÌf³ƒ!G"‚ xàD"ãøsÏ=Ç¿ô¥/ÅãqA çÉ“'ï»ï¾­[·¾úê«jµºT*Õëu¹\Î0L<‡îNE%ɱcÇ:::}ôÑD"|úé§+• ü펎îܹóƒ.Xè®Ù¾}ûš¨a¶iÓ¦®®.†ap'¢»»»^¯ ø[ìéé©T*‹… ³ÙœN§¡«Õh4Êår˜RûÀ0 ƒ2Š¢Z[[­V«Óé„ÓÌæÍ›µZ EQ§Ó «°à8n±XpGQ´X,®ÔT«Õ†577Cc,MÓÅbÑjµ Ç{zz‚Á`www0ìììdYÖëõªTªõ»ÖÖVµZ].—aº@?ü%„B¡/|á 333sss{÷î 2;;FÕjµÃá°X,¥RI¥RmÛ¶ –öذaC½^'IA«ÕJ’d­V‹D"ìƒbÇ‚C)*(¢ò~“ðz½WE¨%“IÀ›¥jbb¢^¯ûýþL&333ó–­ÁïBP5??×&x<Ã@x*^⃿—ƒ"âóù¶lÙrüøñ‡~X§ÓAu*—Ë ½^¿mÛ¶3gΨÕj¯×ÛÕÕuðàÁÖÖÖ|>Ç——— E{{ûäääÞ½{/^¼¨R©‘ÉdÿøÇ_xá¹\¾ººêt:/_¾L’¤^¯Ïår‹‹‹R©4“É466ƒA•JEQ”ËåZ«Q-â®,¹\n2™ªÕjwww©TÒh4‰¤½½½\.K¥Ò‡~øðáÃR©T.— µZ¢è¶mÛ8Ž+ж¶6‰ ŒÎƒNk¨ˆh4›ÍF’¤ jµ ‚Á`€Z<Š¢år™ ¨K…Ãa‡Ã!ÊÁ=®cA¹\. ñÙˆ‚%BÄûCy! –¢`‰ëíp1Ä»á‰ñÁ27üà?èïïO$7n„.d|ÌqÜý÷ßüøq·Û],)ŠÚ³gÏéÓ§].tŒ,//wtt$ ‹Åb6›iš-âŒõ:†™žž¼ôÒKœ}å•W^{í5ŸÏ¹“*•ÊË/¿ìv»:$‘H²Ùìàà`"‘8zôèÁƒ9ÂqÜääd,M¢¹á×à8®R©0 Ã0 4~ ¨×ë‚ h4˜—xGÑh”eÙX,£1 £iúÊ•+‡ãÊ•+…B!‘H˜Ífx§^¯—eYš¦ß ©çݤ¼ÃȾ¦¦&«ÕúÃþ°±±†P*І†š¦a¢s<×ét sss<Ïâñx(‚Ù…@@©TZZZ._¾‹ÅÖèãñ8†aÓÓÓÝÝÝ Ãèt:¸òz½^A2™Ìüü|¡P0‚\¾|¹©©iqq1wuuÁŽ´Z­V«õxÏq\KK‹ÇãQ(N§óÂ… ,ËÆãq£Ñ¨V«e2Ywww ²X,ÍÍÍ©TêÊ•+½½½0H‹¦éîîîd2™L&†ñûýÐw~êÔ)»ÝnµZ)Šzá…ÜnwssóÜÜ\&“ùèG?j·ÛgggQÅb‰DFAƒAµZ½²²( ³³³‚øý~8&³³³,ËÖëõÅÅE“É400ßûKa2™4›Íáp˜eÙjµj4a{Hi”L&{{{çç盚šâñ8AµZ­­­m~~^§Óy<­VÛÐÐ B¹\N$mmmÙl– ˆµá“Ëåù|¦YÇãqƒÁ`³ÙÖBe†aYÖf³e³ÙL&sùòåßú­ßŠF£‰D¡P˜Íæh4Ê0Œ\.…BÝÝÝßfzzÇñŽŽŽr¹<77×ÛÛKQ†a@ ¥¥Ål6'“I˜vËó|GGÇÌÌ ¼ ‹ÅÂó|:îïï‡a<¡PhãÆ‰D¢¹¹Ùãñ‹E§ÓÉqœÍfƒ'po Z­ªÕj¹\ãZ3™Œ\.7›Í ‡£Z­J$žç …\.÷ûýÕjuóæÍ>Ÿ¯^¯×j5­V+‘Hü~ÿ‰/½Ët¬[^×N,”wèXŠ¢©Õj¨µø|¾d2‹Å´Z-4kÁåZ­¶¸¸‹ÅL&Š¢Õj*Á`pqqQ©T Ó+&&&p'IÒëõ’$I„×ë …B(Šr‡aL©`† žç¡åŒçy¯×k4áò õÈÈ0 œ6P…̲,EQAÀ¿333ƒ¡Z­â8Î0 R %]µZ…k+œÛ&&&l6lЦi‚ `âMÓð·Í²l ‡Ã‹¥\.Ÿ={Ön·s‹’.//¯®®šL&x ð8ü ¯–çyH¹ûD"0\ûd =sæÌÂÂBKK‹F£¡(JÇS(ÚÚÚ–——µZíÒÒÒ¥K—>ô¡]¸paûö탃ƒåry×®]ÇŽƒÛn·g³Ùt:­T*I’dY6›Í ‚ V«‡‡‡AØ·oŸÏç3 Ç/—Ë]]]±XL¯×ŒŒ|üã/•JétZ£Ñ@=iÆ p…ŠÅb‚¼öÚk’ô ‚ ÂüüüC=IJl*•*—ËÅbñ¯þê¯FGG¹xñ¢Á`P(‘H ÓévïÞ i.\¸‹ÅÔju¥R©A[¶l9yòäòòrKKËÇ>ö±çŸ^«ÕF£Q™L¶uëÖÑÑQ‡Ãuír¹\«ÕÆÇÇËår&“yúé§ggg!íàèèèã?žJ¥’ɤJ¥‚J0sD©T ‚P«ÕàO¥©©éƒ%XfãÆ°‚ íííp3HQ”B¡Ø¼y3ŽãZ­¶«««¡¡áÃþp4 ƒÁ ‚Ýn‡š~2™T(‚ 8Aärù†  …‚J¥r»Ý‹%™LJ$©TjµZ»ºº‚p8’  Ã4 ŒõkhhhhhÀ0¬µµÇñJ¥®X,Úl6‹ÅBÓ4ÔÊa^ÆÞ½{ëõú®]» |І…B¡|>ïr¹¬V«Ýn—Ëå0çgÐétq9,[IDATmmm€¾¾>¥Rév»á°¸ÝnÈy‡ÕjõŽ; ÓŸÛí&bÓ¦MMS"‘8N¹\s(r¹œÅb‘H$(Š¢(Ša$ûÌårÃÃÃk+¢Žõ(‹ …âæRçÊå²Çãéïï/-Àï‡,?8×Þ’ú’7‡÷‹:›Í†Ãᥥ¥h4ê÷û×Ó°à9W} žyÕùëß*•Ê5©ºê´ëâªóײ? ½æk¼¡Pè}aøF;(Uw`Æ*•J Á`Z€F£1Â-4ÇqV«5™L¢(ªÓér¹\¹\Öh4¥Ré‰'žøÿøææf“ÉÔÛÛûoÿöo}}}ápX*•j4š-[¶ìß¿ÿSŸúÔÉ“'!YòÆI’ôûýAH¥RHõ­V«T*abEÿ¡C‡`èýã?>>>^¯×çççår¹ÅbyðÁý~?Üós×××W,;‰Ÿ+• döR*•:nff†çy(Êãããæ¾ûîûî ßkK¥R­¬¬´¶¶R•Éd4Z­öù|6l€û5©T Dc±˜R©„Ùå2™ °aÖe1 K&“ÕjÃ0¥RÉqœR©ŒD"pG†a˜J¥‚û>hàÑh4z½žçy¥RY.—-‹Á`¨T*.— Ú0 ƒ„Ðð5˲P‚ÆØd2™N§›››µZ­ ¥RÉl6744èõzAL&Ì¿Íf³E‘$ M¾8ŽC5(‹}0ó5 ײï`/…BA8k^J^$ؽ— ¤"É"DÁ! –Q°îV‹EXÇæÍxóñµ#k½·Ã5Nx»î®:级­ùøÞ®eŽã(Š‚®Æk÷µöZè²\ßÅÔ»GÌ €Ë—/ó<='‚@"X,ËÑ,//[,–jµ*B(Òjµ6› ú¿ÆÆÆ`á®H$ÒÜÜ|êÔ©ÖÖV†al6›N§[YY±Ûí†?¾±±Q*•Âй¾¾>XeÉh4:ŽH$Ù䆑Édr¹<“É ¤ÓéJ¥ÒÔÔtòäI’$µZ-EQv»= Á0hš¦C¡Ñh„Ê\.§V«¡ù –F“J¥­­­£££~¿ÿÁ …B°Dm6›íëë …B ÃÀ@¿ßFï¿ÿþR©G¿øÅ/¶oߎ ˆÇãinnÆqÜëõr×ÕÕU«ÕJ¥’ÑhDQÔn·Cê¹J¥²¸¸¸yófš¦¡ÉchhH"‘@ 1ëçt:ï”Wç‚ ЇªÕj‰Åb0t ¬ >Ÿ/‹555±,»°°m•{öì¡(*‹ét: ÃVWW7lØ 9ŽÃq<“Éð<‹Åt¢•Ëå .@6‘L&S©TVWWa¥±ÙÙÙ`0¸iÓ¦p8,—ËY–…å馧§aY¯¥¥%§Ói0†‡‡#‘ˆÛíV«Õ‚ H$ÒÙÙ™ËåàW`Äf*•ª×ë‚@ÖµÆÆÆ'N è̆хÙlÖf³}Z¯×ÃÈA»ÝIšqýµZMŸÏëøA"ÌjµZ­VWWW=OGG‡B¡H¥R^¯—a˜¾¾>Aôz}6›D"R©”$I(µsÃùóçÃ0ƒEQŸÏçv»s¹|*°ÛÔÔ”ÍfC¤X,ªÕêZ­ÖÞÞ¾´´³¾ ãÎv/¾øâ£>J’dCCC©TR*•¥RI­VG"hóT©T¡Pˆ ˆ|>o·Û‹Å¢D")—Ëk†ÙlvÆ 0Ðh4ÎÎÎÚíöB¡066¶oß¾µzˆétZ¥R¥Óiø6‹Aö‹Å²¸¸¢(:55]à@@¡P(•JZËå†) &“i_®R©”J¥7Â|>_ggg*•Êårr¹á®Õjù|Ö]S©TÇd2Á r ¦R)‡ÃAD¥RI$†a¦×ë!·ÊŠ6íX"n î@ ßØØXµZÕëõ@@„H$BQ”Ïçkhhxþùçív;EQ‘HEÑL&cºGGG[ZZâñx©Tšœœljjòz½0s*mápØétz½ÞsçÎ555¨E]¹råÒ¥KLV§ÓE£Q½^¿²²’H$`ùÅ£GÎÌÌØl¶………J¥¢×ëÇÆÆÔj5txÃÐ^˜µ¼¼¬V«“Éd±X ƒ ‚d³YŽã²Ù,$¢]»ÇL&Ã0L8† z<£ÑX*•.\¸P«Õ¡P†øÁ*hEqwöìY·Ûíõz+•ŠL&óûý^¯wiiÉjµ¢(úꫯ677ÃkùÐÐ˲p~b†”år¹;θyæIXªÙívûý~ÿIÓ4T{Fã¹sçT*”Ÿã¸­[·ƒÁÖÖV¨ÒÚív†a²Ù,ÏóŸýìgÅ™õ}‹; ¼oÞ¼SÕjµp[ó’A€Æw«Õ*ÂÒÒR±Xìïï¯×ëN§jTétZ¯×«Õj‘ðXœ±n£££n·[§Ó‰I,"îœò.B,"DÁñ,žçaÌÖ½ê#˜€ÄT¥R ž_©T® ‹Å [ãÍÝq·>¿”¢¨·‹Å[£ñ¸n°^.—ƒ· ÊÐûEyÿéOêp8 Ñz[xàl6+“ÉNœ8Á²ì–-[r¹\¥R)‹¹\î·û·þóŸ;NAŠÅ¢ÛíN¥R»víZYYAráI¥Ò±±±ææf•JU*•¬Vk¡P€qZù|Þd2i4’$WVV¶oß>77‡aØZ$Ö¶mÛΞ=k2™ ‰ÞÀÀôÃêQétZ.—Ñ××çñx`ÁKhfkiiñûý6›M¡PÀDyºc3VµZÕh4°¾r.—+ E`áZH–rþüùJ¥imu:ô£ÁÊ«jµúÈ‘#Ä{ee%‹qW.—¡7 Çñh4dž)—ËЙãx"‘XXX0 ¹\2ê.--e³Ùµ<úS§N ‚KŽAŠ¥#GŽ,//Ãò¸ÐÞvêÔ©ÁÁA½^/‘Hl6d×Íçók'ˆ¸c3¤qâyËÔj5ÈKŽ ©T ?‚ÒP(EÁ^-Ã0J¥²R©Q¯×a„L0t»ÝçÏŸïîî–J¥0v)¬ ŲD"ÍBžfA`qØ,Œ/€ ",/]­VáAØ×¯A`t<¤é‚'ˆò$Ú±Dˆ»B¢`‰! –Q°DÜ‚5<<ü­o} fÍF£Ñ¡¡¡Z­vèСõätÿùŸÿùüóÏ_£¡P(t™]2™¼‘Ôa÷$p€×ë p:CCC‘H$“ÉÌÎÎÎÌÌèõúžžžûï¿ffðmÛ¶=óÌ3O<ñÄÈÈÈSO=uâÄ —ËÇ?üá=ztxxøsŸûÜððpggg J¥MMM/¿üòg>󙥥¥?û³?‡ûƒ5c¡(ú—ù—Û¶m;|ø0Ã0$Iò<ïp8$ ä¼X,–b±˜H$ +• dŸÆ0l`` Z­2 CQÔÎ;Ífs±XL§Ó‡ã--"îaÜŒ z6:;;Åáq-ÁZÇÒq,DÜÈeÚ-Oˆ–wwÈÜP¯×³Ù,,bövˆD"4MÃsÖÔ²»étzjj Fìp=Œ÷Ø“†|o÷i,ƒ·Ìq\.—+‹ëYõ¯ËÔõÖ»Âk£T*ýó?ÿ³Z­Þ·o4($©×ëI’ìíí…çœ66V(òù|2™\\\ÔëõíííPÎZZZÆÆÆ>üáßÙšGïSSS+++===(Š& ½^¿¾ÜÜW¿úÕ¿ýÛ¿=þüÔÔTssóÊÊÊÿñŒŒ¨Õj’$Ïž=ÛÓÓóÈ#Ü8uô H[ZZd2Ùààà÷¾÷½ÑÑÑóçÏŸ?Þëõ®àr¹|>ŸËå‚u`îÆŸ; …8zô¨J¥Òëõsss°þùôôôÔÔÔ=0i™Íæ .$‰R©422²v¼V«qwáÂÈt—H$H’?sæÌôô4Œ;}GóÖõu,Aêõ:Žã,ËÂgÇAX(R­VI’¬×ëžàîq–e!C­VÃ0 &9B®Xÿí-Ó‘ïÆ{áøñã?ü0$JY{Ä0沎ÁÇq²É­UÀ#IòöšDˆ¸5K!Œ¨¼8–ç¹w, uš½ÆGkŸVŠôÍ5rãàyþ{Ž«nýÛx<~Õ‹«N[;yí„õ_s¿ku1ß²—"ï…BÖѼvbÁ­TÞ¡nÛÒÒ‹Å`5TÈœéõz÷ìÙ©2RábÄ›ÁqŒáT‰–«¥Ö&­Î¢ô^‰“ AR)ɧªjÉÔX Gf§Æ7•hê6'ƒ¬Uë4Å¢("SH*…Zx9Ãs|ÏîF™\2rØÓЬ“)%—&êËJHA@6VÖ[•:«ry"êÚ`B1¤œ¯q,ÏÔX¹Jʱ>ÞÓÓ#‘HæççœNçðððZt¼Z­öx<‹‹‹ƒ–À .— EÑ`0C±%‰ÏçÛ·o,ÚèñxH’, >úè;Ýž:uÊår¹\®b±X©TÖ>}þùç÷íÛ#Åâñxooï;Zû®Â ñcƒÁ±±1ƒÁ‹iù|¾b±HQ”Z­Öh4€r¾VÊR„ohÖæe¦Æš]šl¬¬5)2±²Ù¥¹p`ÅÑåñh1MÅVr‰@ÁÚ¤-¤«\›ç“Ž|SqµŒú²(ŠÈÕR¥Ff´«q­–i)IÔi®œ¯ÑTe8Žå^àXÞÖªÏ'+ž‰@Ä›mÝd?á£J´DŠ34×Ð|£éù0@¾T*>}úÁV*•ÃÃÃf³îá†<™L¨ùJ¥K”I$’B¡ÐÙÙ™H$`:Б#G`í]™L‰D@±X„ Í Ãttt„B¡ññqÈG kNÑ4½¼¼Œ¢èÈÈHcc#Ôx¦¦¦ ž‹ŠCÀ\.Çó<,¸mÛ¶wTÞÇq¿ßo·ÛƒÁà‰'xžïîî^?SBÚUÈiybß ¿Á éX0S€eÙD"a·ÛËå² —/_~òÉ'_·EŠÁ…´LA”rT:RB1>T™BR«0ðï[ü†be£]U)ÐT™1;ÕÅ ÅЬɡÎ%**L"ÃsÉŠÖ$gjŠ!/È’ØjNgVäS•T¨ØÖß°Ö2UaQëÉD°ÀP¬B#Uje&‡ÚÞf¸‘Q¨T*/^lkkƒ3Ó³Ï>»wï^‹ÅòúϦ\†£S€T*œ¼ÇôÑG•Jå+¯¼§A‰¤†«V«PÈ”JåéÓ§á™p0WWWÝn7Ïó/^„¼ÜÜ=êt:A®êeýÊó}!ñfJÙZ&ZªÓœD†ã\H!ZÌPÁ…!ÁŠY*)ÑÕºD†'ƒE˜_ÍÕ®\¨•²”TNÀmÁM \.Ÿ8qê=$Iz½^˜Þ¨×뇆† !çèÑ£Eý~"‘€öëD"‘J¥Q ‡Ã(Šz½ÞñññX,vøðaX‰Óï÷ŸUAP¤¡E—Ž© £oP•s5œÀ2±’JO^8°@UÏX4.ÓáåLãFS6^–)$¥U«Ôq­U)IÐÕz>YÑ嫳ɥ˽U÷ç1 mhÖ…Ó©p1/Ò»¾8,àøñã/^|»ú°0¦ùª,V ééÓ§—––R©T>Ÿ?tèÐÙ³gI’œœœœŸŸ_ZZªV«.—ë'?ùÉŸþéŸF"‘ïÿû,Ë~ík_ƒE(AH¥R_ÿú׫Õj:>pàÀ/~ñ‹þþþ/|á †œN§{zz†††–—— ‚P*•°¼l>Ÿ‡ÃÛ·o¯×ë°Žˆ{¯ÇàBéá8F¯b¶žyvíS ÃàßµðgAòùü~ô£ûî»oÇŽÐÃÃ[!##|{Õ‹wé.qw–˜°*âBLX!šDÜm¸ŽsMÂÅÉç”rý-ï¸\ÍÞŽfï^ÜER®fwmþ} 7/X@.Ó*­·üâhºr;š½{q ÍT®)W·b)¼44vöô`½Î¾o"Ÿ/üò•# ó‰MéT]^] –Ë•x,yWK畉™3§.Â=ûìô3ë,{VÒ©ìûe)¼Œ\_] ¬®Ï4[L«¾ÀG?¶ïÓøÛïŸá–J¥ósKGœ¶Û­jºT*›ÍF‰T‚"H±Tnlt\ýéOß\ßµZí…^èëëÓjµ†)•Ê`0(‘HŠÅ¢L&³Z­ J¥R*•º\®R©‰DÜn7 R©H¥ÒD"±žÖBÄû ×Oÿ*V’Þ¥°N§[ZZBÄd2ùýþóçÏC®Nçr¹nf§ÆT”r EQE;wî7~ã7æææ …B½^GQ”eÙ|> …X–¥išçù‘‘½^ŸÍf³Ù,d}Éçóëi-îvÐLEv—èXpÕ¾¶ò~ý]a(1cÖ¶CªNÇó|±XT(>Ÿ¯½½½X,:Ž›¸¸\)¦S5‹Åp8ìp8Ôj5,ÿ¼þrkµŽã(ŠrÇqœL&S(“““*•ªµµuyyy-ßò»EÇrZzn`Ýåý.GQ°nB°®¯cÊÉB::^xÝfˆ"¿fåîƒèš*¯3ü!Aôƒ¼^—cªVoòë.ne¿è[7ûëÖš}› »MÍ^w@nW¿71Î…rÒy½ýëõK£4k”æÛ°B´*Ñ ý߆än‘‡wà„¾Š2“ɬý½™QDÐ7·ï÷ûßLrî®êèºT™×¸0X"à·ÉdÒéô{¹6 ðz8Ž ƒë/éV±ƒ¾Ì @€ã¸“'O>òÈ#Éd2N·¶¶ÎÍÍõôôLMMõôôÔëõ@ `·ÛK¥ÒÞ½{o°ïR©4>>N’¤D" †™Íæ•••\.×ÕÕU«Õ`å0†aµZ­ Z­V*•öõõýøÇ?îíí…Œ(Eñº°°À0Ìððð¶mÛªÕª 4M?òÈ#SSS°Þ}4Ááp¬•h4=ôP<Ïçón·{vvV£ÑLNNJ$NG„ÛíQ*•´µµµZ­æóy…BÑÚÚºF­ñî199 e2†a&“ÉçóÁ½Ñââb­V{úé§ïÁº¡ ¦ë¸\®¡¡¡ .âñ8Š¢gÏžD">Ÿ/™Lêtº .LOOßxߥR‰¦éT*å÷ûqG¤££cqq1ŸÏ¯®®ÎÏÏÛl¶3gÎÄãqƒÁJ¥ ­¤Zt¹\`Z+J¥’Çã¤ø>ŸïòåËíííÕjõÒ¥K^¯æn$“Éd2yùòeÇU*•Çã¤R©d29>>‡Ÿ²,;::ŠaØÔÔÔôôt$AÄçóÁ×F£qyy™çùññqŽãn¡TÁëáܹs2™ AXŽt~~^£Ñ@*˜»f]¿‘]¡ÃÜý–!²Æ7÷ÇÝ ýM¾ת¬Õ~mÙÌÆÆÆzè!‰Dó|`n‚ 0A¼‘$Š¢‚@Ó´JÀÊëÈ€ËÏó0×V €'ð<ã8<>imm…ÉHP(aãk9Hð/¤¦}G ³×x_0Q vaíï½³+×ËÖZ_‡âÆI•à®äÍç[,–Ç|æñëg¹þäõ—´ÆõOXÃë¯mMDÖ7OXÿ‘^¯×ëõoîåÍå6nm­ 8 W õú.n•¿_t¬ÛdnÈc¢¹aýý^o@DsÃA&QRµhcXƒôÿLDÑôW+¾IEND®B`‚ivy-2.4.0-rc1/doc/images/logo.png000066400000000000000000000211041226750426600164770ustar00rootroot00000000000000‰PNG  IHDRd»³ïsRGB®ÎébKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÚ 3}Ü IDATxÚíwx\Õ¹îßž¢j[–Ü6l‡6¢'N ¡“„I(£”“Üä2æÞ¹žœ“RÐPpè&@r(¹h蘎mÜ-É–dÕ™Ùû;ì-iÊÞ3#Û€ ³žÇhØmö¬õ®o½_]Â.l‘Xh6ðÈ?ÎYnê¡Ôþåš± S ü_`<èiÀ)¥î-¦P;ø7Qôg‘X¨¦ÔÅ%ÐxI™KQ d^©‹K ÉLc¨¸ €éo߈ÄBRêæh²ÛÀÉn' {”º¹šôei4Âÿ8 €f\R#Èá¥n.&­É½2eˆ¿¢³KÝ\M¿”9ôì4€ "F$ÀŒR7—@Óß.&e.MJšöÔ I‘X¨¢ÔÕŸqÐDb¡ʼ,þbƒ%WWR[êêÏ0hÄê}À7&çD]o©F”ºú3 Uœâ q=æC¤²ÔÕŸQÐDb!8µ¥Œ îÒE3> ªe¥®þŒ‚F)óûí1ŠÚf4Kâô|%Ð|†—§/{ªÐ’%id<â/uõ¿NÌõ‚¨_‘ JÔŒ6ÄÍ¥©14RÑ3³‘«1e«Ü‚‰jQq5‘Æ ì' ÃMo•†g7¾0 åTà`Б@'°" =ò4ª«€}Qæd¸ ŠuE f|iÊwKýPÍn,i~ œ­¨ ¢!à› ­ÀíÀ_Úù<*–s}™‰Ð›,ã°ãpþÂtáÍÒÐìΠQÖ!ôÃÖ%ÝùX‡Ð0Ht]­¾ƒ’Gr®Ií.`©u8ÒÅ(Ǥ=ï”U¥¡ÙA#Ü…ðÅÜe%¸Ha”"îËT&¨ÊáÜ)V? t®Âé‚«ª’Å^ºKC³ûKš{PŽFð€AI[†Ò@Ò̋ϤÆþ\‡òËHcèa„Ï«j=Â,AŒŒç J·¤ðRÛýš8KÅhàE`jîÒ“ÅaÔ0äXÛž£ô!R†j>m«82ŽPšÝÜN Ç·¸Ku5܉X²8²z¾sCÎ=OëKÃò)#n¶» ¼éU·sn^n!7¢O]%“DÃñ®Ò°|J@¼ rg¡åÆ#ü .D€¸?ãUàùÒ|Š@³0Üd \ ´"ýŠ“x…;x°#ãR€8Ûíöh8¾¡4$Ÿ.Iƒª¾ò_c)™DÕ"e&PÍ’,š_ œSÜ›ÂÛ‚ÜSŽO!h¢ q®X’+ Ÿ¯¬«¢lx«¥¦­e!EÕNnÒIÁå‚,¸ea¸imi8>… q€ÓüX:hÔƒT*IMõ˜÷CûŸ|҈ʺÇRfr8¸p–b9­êßTŠO1hl~å,ЬþãÝ=ÛjGÕì±eΡçýdXe퇦™ÌÇQòsûº”ÿІãí¥¡ø”ƒÆÜ_(|ˆ‚aøèèÞ:uMó›gqà™ïM=óoª–·´qQÛÅÉiI;wg´!~iþ@i MnuþMBlРʲu/~ý¥·¬«©ý˜ßvÚ¬¸mʉôÓÁœ—P./ Á¿h"!ø¶_#ã°ŽüålÞºêÀek⎮Ûóýò²ªm’F)üY2¤Lsi>}Íï!!&䌶‚ˆO ÖnzûÓJÆSfªGT2µ(·h¾ì%ËþÿR.ÔnМª‡늵“åjOḼç&Åï/£«{ÛÞÛÚÖMA¡èh>ÉÐØÒííDà.àœ—4ö€>¬A˜â¦%ÍDÕ˜Úi5=mV_²ŸÐ7p¸üÍÐðÒx}ÂR¦1´'¦õ‘Xh2DD:¢á¦®âA¯!rè•ÒH5 ÓJúüþr0Pa$€.è  æµÙØm\iØ>1°Ô"œŠrŒPŽCˆ;—˜ ‘Xhðëh8þDAí)Ú·þ¸hÍ–~Ÿßܺ}}²/Ù½ä 8ø<Â%ášÞŽÌ}#±P©àÑ'ÓήE8+íX90Þù7 e&P ,+VÒ°0Ü”®Œ4†þ»Rç¾@™B«Ï¼šìÛ~ß‚ žXãrëM‘Xè ”‡£€ ;(½Å$(‡«Kcø±ßìxð€§‰Dhî¢Ñp®†+CûÂz#n²†´f û:šRPAŠv‚¬\nZVÊmY:áH`p0¥z Ê`1ð×hCü¹|úL©}6$ÌLàßQî^‘ÑŠ> LM£ ËæFÃñ¼Îc)¡3j ’bÁ²L©®¬i¿ì‚'—ýòÆ/ÏÞ¶}ãø²@…eZ¦é3¤SÄŸÌà6’ýÕê®q¹+ê½ ïDÃMæ.èÀÉØ™y/t~gvZˆäºOÔ³7ƒ(ë¢ ñµ»à½ýÀtìZ†©ôwŒÅΉ鶜Óç5(¿t¨Bð&ýUYyç¿n‹†ÝüýE¾èU  <Ö±Ù†!]½Ý·?~éïÔJY+7¼vÀðÊQÏö&»ŽÞÞ½õÄdª7h«`i qþãX -ËÔ ¤PË0ü)Ð3€v²ãGc'åt¨÷Jw”¥iƒ9Vð|ÑŒ‚ð\¤1tI´!¾e'q³'ð0B3&0ýÁûn‰Œê¸üF:\òKÀÀ¯±# îjD¤VUƒ(Ó±ë uîhœ6e|ŽH¥¬\ÿêÏöš|È9åÁê¿ýå= ³÷±=Æpû–¶Õ Û¶o>Æï äÎÌŒ_¥ Šªbø|Éêʺ~_à¥ò`å:U]ÙÛ×y^Gwëá"rr$jІãº Ê 9ö$Oqœ&YrStÜ¥M湯9ö G)Z\ CW0Kèp`?àKÀ¯€mÀ 쨆T´!žšq/·%Ü:Ö4ST”k2nÿïï=%ôìüãö_‘þyëÃÿ~~w_çË}}]5†a8€Ï´ «Zˆ©€?¸®nÄä‡'Ž™ñ¸ˆï×Þ}<Õ¶}“N¨›^ T̵Ô<Üß×Ytì ”1€99ÒE¼Þ ð‚ ¢ù¥Íà³Ê¹‘ÆÐsN Û޼{0¯ „Ë'ùìÖí68X\ ÇßRitdÊ‚X}pa¸i¹Û†VŸF$­€§…ß\>fÄ”œ}âUKÚ÷¤œÎV5jÍÞ“ûCyYU¼¼¬z¹`tªšôÇ‹ª*eÃ^3r_M=ã'–•|wcËŠ“—¯}ñ/Š>o¾ç¶´¯]ÚÚ¾n¾!>™±“uÊ n+¤+Ý;“¤IÇ|Ì0÷Ø<½ï>NÑcò¾·àšb´€+Pf_þ \¾ VÿÅþ¥;Òº ø‡¢w-ˆÕ×쌤Éi¦™dÂØ½ cñí^×TT Ó”Õ÷Víð íÕ5›,˪H¦ú¦¦ÌDµi&»ýòlegïÖ½6¶~xEwoÇþ¦™DÄÀï·Ê©”‰‘8Êi¤‡£uifżƒ­Å/Ù R×ëfaçvíÈâ4tTáwÊóÛ”wî‰6Ä;¾ò›HcèU=nA¬þ E/~61.~>tI“VX`µÁ`ä°ñËï{òrOAØÖ±¾|ÅÚ—ÖܺüŠæ–ßëItÕû|VËJÆ Ãÿž¨–5·.¿t˶ÕWt÷¶ïïóù* Ê–21 2ê _vŠ ÑFQ±w‰q–qͶ÷PŽBÒD\–‡Ì{ EOŠÄB¾þÛ 0=ÖŸl"œ÷H¶:mˆ? ܯpprG»(Òº4 }~h’&+ÔÎ&¬Á@EwUeíK§|iç”lël­ìKöÖªe ëìÙZßÕ»m?”ï(ô†/ hPÕÂï ¦}Ÿ[®xFZçàxà/Cìô ØÝLžs™gˆÈW9#Çã/ýÏ= Xl¢Qu èá"bO\Éø–n&ÈüPJã-sŽ^Aù¢ß%½.´Ã0¢ÀùŽ•ÿI„g†¶Ÿo誜oˆì­jk‚F¾Êjî¶ pÒÐAÃñ¹6!qQÿ Ú^†ÔWiÏßÃy;‡øã•¹p?å–zéoÿäåH,4¸ åL”QÛ^t>ÏŸŽ0áDà!£ðow±¶ ¤Ì¾‘µÃÆçu8¦Ìä½}}†Û°$ÏŠÈ“ý¤Z¼D¬fXÎÌ:4ÒÚkš‡áôâÇ(}ÆEvmžÂTèÔ€à<À¯h±¤;»µ£Ü½°¡ÉD¹%Œ0ÊyßaÀ\„Y¿Ý½½ƒr•Q¸ÿ4ç!bøéKõø›[—}ýöÇp»ï¾§¯œóáúW¯T5}Î (‹€­9l¨Zp쮟 =$ûFn{ xÙ³c5Ÿº+éÇæDb¡©Ås±Ð4”ƒŠ~ww ½<á¿a™+ôÜìL:pæA”“¢ ñxaÐ ¬ñ©–¤Ì$ªV‡Z)¸ã‰ˆï÷~·¼ñ޳|7?xɬ·–=ý»D²¯B _z¦\E´!þ*ð\^µ·P¾8”¡Ì4†Š]^Od˜;±Í—»5p.ådž^>`³—류Ѥ6›[õ_Æär'q/Ô[hÁD¹3ÚãÏ8F½^—¢š¹¿Å̽Àyý®‚ ñ>R©duª…¥&Ó'ôç™{õ‡opU `\ít£ª¢æ¸Žî-×®ÛôÎ݉ÎÙ>ÃH{ Åq \ÒWgðš="‡r@3µ åäÁ®iK¯fýËmo#<<¼P°àvþs>àäH¬¾`ß/ˆÕ p,2ÜÏ@޽¦}N—h’ÝUo×g=zýÕÆ nX‰ò‹h8ÞV´Êí÷ͱµSÿ™Lõ""¤R *ʆm:t߯ýçÑŸ³q€ez~rÒØýŒÎ®­ßkïnÙÀ´’¨Znøßÿð4ži1Ü@'!SÄ\=a.ˬ+'q1I¡Ü Ç·FÃñNà/}EiR^ç”A?_Är3eVnþ{ZÑoÉ*”›'@˜ã²\WºILA²9[—ˆtÉNsù…Ïè˜Ú)WN·ÿS}‰.|¾ ¦•ZûœøÑ®îmïÔ ÿ–i¦¨>ño{Œ;  T´«ee¼H´!n¿,W;ˆ°0`÷˜³ V?¼€x?¨rÏ/×\+j®Ø_áÔ%ì¿æ`i^"Z(C¨u4ÀB|ò À4—ÙŸöìì=¶4;ŸîŠÄB·ECN– ÇåniFžsÛ°¢ß²áì¿iŸ)¡ùvH¥zeÝæ÷\m©wLGWË´qµ{>7ªfÒwF ³Ïð'd Æó(O'U<{õplç›—Ö4Îé É”$âí³QMç Ü Ç[ÓŒaÀŸ°ýkÅëß’cT‰ÕWçywA˜ãHŠ<ÒPÝ‹v{;¨*rÂõ‘ÆÐ~À^Å,§€Ê€c#¡ÑEƒæ÷‹çWÞùxdvg÷ÖW÷ž|ØMݽÛ)/ž[»g†ô¹Wo ´unúv \=eÜþg‹­kš—ÞÜÓ»}4*¤Ì¤9¼zôÀω†ã]×"v!|Ï¡yÇbŒ¢Gå¹b.ýu=-q“ýN+¹Å幋AÞó|Ïl~äž…:ôÈ<ï>åà!¨ÕÙ×)ð à|”C°½ìónp ¤N%ÕkSÂÀÊBmÿ‰ n¿T4k6½Ék,ùM[ç¦ù–™ºzÔˆI/UUÔ&§MœAV6o]uìšæ¥Óö™tȉÁ@eWsËò»·mož'†Ñ7¬²î¡©ã¼h|Ý^¯e=þyàCòíä¶cÄêë\fª TåZµ=fiî\¿0Ü´9ûp4ïn(¸Dåè:ìð¯öy›‹IáÉäÞ7Ï/EÃñ„£õüå7ØßÇœ¿GGÃñK¢áøÑpüìºÎw@g믭ƒUç ‚ftͽ~YÍŠu//îKv}{ò¸ý.[;õºd²'4U5ËGœzqO¢{ÔŠõ/?ÚÚ¶þkåÁa«&žñ£,9¹¾…ò„–´SÛÁâAséù[#«Ç¾oš)V5¿ñ‹æ–å {]–¦24ˆT*ѬpÚ{«_x¾¹eùaãêö|tÂè½O¿xþ­×_w÷yß\³ñ­%K—=y˜‹h‰¥VÜuºx-[™¢˜» G…•9Àž®õþ2ÔTÍ”fƒßi èHÓ'Q¾¡Ê#CR¹-ËD-õ™fŠTªrE똑S¯3ÍÞe™ËŒµùÜ“~÷§ïŸ¾(°vã›§¬Þ°4fbÕ´ï¼9ãë¦ßŸJ%\UÌK¿óxKÊì»GİвkŽ*ëÃNè#Í1:/ö6Æ-\XD~—#‰f `‚æJ™Â’r&¾lVÕãr¤LSϺ†Àß}1 €4íËn#P.C¨¾Šò(Êw°ÖG¯ˆÈEŽ5šhC¼)ÚwH ©(&•5ïŽ>þ‰Süé¸ÚéóM+ÕžHöÎL¿nþq¿èä?=ÔP¹zÃÒS“©¾QË×Ä›LöL¨(«>wÒ˜™ÿÌããºá=Ok­—,üx|¤1T‰…ê°ãmŠ/ÉŸI*ïSÛÁWT‹†ã˱·6Êïþð^è „ã#±Pÿr1aï"4;·gv¡< ÇS@ÂZ—w©t´¶ëGl!¬§ƒ·“´ hÜknj¯ wDÕè³Ëüå«Z:Ö]³¡åý?líØàj¿é¾ïOhnYv[kÇúy@Ý}ãÞXöä"¿ØïGߺk“7±|q­ãóî˜üeL¦;3v2pD‘êz¦ >›†jn¼ß‘P..)Fr~…š@K‘ÅÅÒ9“sîuúÃI•rÀç1qÆ XÉÝ'd¢p3ešž¾N¶mo¾hkdžÇÞXñô½=m3D|´¶¯Ëß}öªºkî>ç‡ë·|ðH{WË©†ØÔ}‰îé·­¼åÆû/Ü;¿V-‹2÷z’L2©Yñ=Ù\P8øªcÅôìmÉr8û7(È_£á¦7†j˜Ž†ão#ÎÞ9áЇÁlœã#Øây+\–‘Pó˜#ÔΑ$ÚßæØ¨®°m=ÅÆå¤#½aA¬~äAóòûùVo\ú½öÎ͇VY bÙ˜Ú=ž¨>iù]K"Á»—,›ûËÍTª¾£»õ µÆiÁ`]=íÓ?XÝ”7gga¸i ƒ¶“,ŽÐîØ?,9]ppQFTž )Õ~6™9ÀͨÞÈŽ·[±kúx ŒxlV2ðró°ÓJ¦Ûœ’1–™6ÉõP(«ÓìJ_G¸Hß`‘C<6´HsŸäÚN®ŽdIœ‚  úËñûËÚ}¾@jqû7N»ß¼ ¯ìÛÉTÏÌq£ö™:m¢ÍµŽ?ê‡ëÇÔN;ÌÈ=~ðÛ-Ë̘Ɇ½@y_þ¤ëA7¹ÎÌ9¬i®5I_FAz!¦|»¾h&ŠD6ÄwxßÌh8þ6Ê_½õzõvbÚç(º`0ÏJ3ÈtævÖšÅQ„'¢áøºHchììÉŠÁX¨li§ÅùûTõ,kÒí:…Ã=E0M3P¬Þ²ßô9¿«®9eõÆ·î*+«?iì~͇pêÀןùÕ…Ý??ï‘«'Öís©ÏèVÍî¨Âomˆ¯gƽJc‹ævB¶ÊÖD$kéZÙÙfûu6 ‚RÉKÈ3ÆœèBÁ#ÖÃÆ$"ÛQ®‰ÄêG"üÚ1º;eÝ€ë–A‘ö]ª:¸> ) 4v a±L+åß´mÕaë¶¼w‘ßüˆê1K¦O>t»Û-}î„?Ž9íï–•*Þù˜INnp2Ïi`ñÈ4ìéà'¢}ßC ÃM;½Ùj4x¤¨\¨¼]®éûdô9)úwGóŒÇ{l%Л”ìí²Éæ8³v³ãVéƒ"SXTÁÀHŠe¦cʃÕ-«6¼ÑéuKý¬3¬Åþô -GvñœâÚ‡(‹UøÑàŽð’7<[^“^ÙAòj`íì )3خΞ‘j2@i²ßKÜ—Q‘\,¸¥ö¨ ×):ô‹@›Ó] ìúÞ§?<®Ad²‚Ž#ó];+Aƒ@ÈÛÏ)´FÃñdq QPK@ ,QU1âÃ0¶šfªjê„Ùe6÷ó2 ¦–e 3• ä_f\ q*«¿ ¸@Ðêt“ƒhÑüǼRRd ±ÿžh8¾tW!&Ž¿‰…=×J©WzK@´°©Á¾æà…h8¾= }Éáueöö´¦o!‰…Å΢̕_Ÿ‹OÞVT`¶š2KeTY°ÊÚÒ¶®¢»§}ªcpm{N:´mUóÒd*•@Ô(šÓ¤µw+\è]!7Sm ®iJ—TýŸíÂŽ'ÙµM‰!̧?:._&f¶ÑÅó|ÖñA ñ–…á¦í`;ÈWAù"߯f)ë®+0Åq›¹ûþ²íU#6«È„Dª›–¶ÕG?ùÂuž ÛÞµÅgY*9jgÑ3¶©¸u¼«êÒiYô&+›/#œSE$úžn';tsWH›†øËÀ=™Fq—x^E÷:r ñ´ ‡P}lDýT—g¨×ö×þA^/ö1EaÃL$z*7¶.+Õ•~_ÖŽæFÕN«óºmcËò± ³7(bd‹Ó!LX^DäaÏ”‘•%frÁÖ†°È«ÚÓ.6×"ôäüv/Kµºˆ"Ñé#¤WæÒÅ®‚â–έ+34%!òüÂ!XÁ‹’4’Jš}5]-+´•´u6ÏXµþï¬EÃ8Â4“ÁÑžÒ¤M/¶çu«§^ Û]26‘@^á£k¯ ò@ñÛ9Jaó¯c¯[Ò´ òàAŸíîPZA_Ê#Œ"g<–j™ˆQð—·ˆ‚Ïð³tÙSWþ顿DÕ?÷Ê­e[¶®:YT}¹ö‘¡š>x ;ßÈÝÖ“¢î!™ß½ ô¶¨]öö#iцxBÑE½®þ"O.–g N3– òðÆ¼ÚØÅÂû­ì€·‡ò±ð¿á×€?˜´Ô$`”ÓÝ»½öýµM·]w×y•ÃoÞÒ¶v“e™ÉÕßüzgOÛþÅjK4©d$ZŒí™‘—º‘åôB‹ƒƒö(Â?ùèÛKÀƒÀ™y}?^ÇÄlö1Sáþh¸©{fáKØ{Ÿ;!²úŠ“Ïµk%ˆX¦™*kïj=|Xe]W0Pž´,ŸáC°†¯Ú´tÁªæ7š,˼ǴRW­X÷Ò‚¤Ù[e¾]Óõ¶yþEÏe®ØâDö±Aþ Ç5b¢áøv‡Ì÷|ßb–ðÌÔ”çvðVò¼cqN@f€Õ. ª(Ý­W–×*+jÖ˜VŠþâT~ÃOOoçè–ö5Ç·mßîMtΔ|é!; êE¨“kTh»fÍ«˜<ðw>¾ößô'ß“½„[EÃM;³WÖmCy•¨Ìe%ÐÐZ}ÉÞi-m«gª¥t­HÃçÃï âóù',"«s†“²0$©*¯e>Sò;år)EY´0Ü”ø¸ Ç;ns,µ¹ïYLr湕(÷íä’ÿ"ðc„ŸEÃñÞ¡Þ_ §±P05»,3‘wÄ.Ðcæ%¹ƒÇ|}(+vâ‡öFb¡¶»Þô¨™›•Eé¸lUÛ|ˆð7>þ¶Ä©ww„{ J ärµ§¢ ñv˜ÿ´£÷ú‹x¸i ýÞ‘Jzá·¤þãæ}ªÚ_s¶H%È&p;ùCŸŽÄBϰc‰¼F´!žä“ibO²Â|FòjY[nçn¥½>≅*Qþ œîé±–¼,ýØà„ôt’O¢¥aýHc#œF¾ 7ûSîµ ”Û>iÀ ÁNó™øJ®¡œ;ekÏ®€ÁÎi’ïb§ËPÍîߪ€ŸHcè „õØ18@J!…ù_‰šð9lƒÞ‰EÙ_Ò9ŒwuÑëœ2'%Ð| š³AOr¬ËíØ[„ƒ(¸IDAT4nCèz±ë¿€áÀd„I¹¡¥ê]„ #;!7ŽFw»‹xO/(Æ€çØ5ÀÅ;#óJ )Üz°÷E:É—¨ãÎÈ©ßëEds·ÿÉÓlëuÖýªúëhC|[‘JÛ"ø à2Çìðþˆ›ãEÞà:<⡈æ+èઑß*ü89U;Þ..ܼ¨$iŠ[ Öåu]ä‹J,¦Ÿ÷B±å?¢ ƒ!›;Ø~Ü]íýàÜh>ê&lÁΓ®Êëe§ ™-ÎNÓV¹ÊÙðbgÛk îJüzIÒ|<­ hE¨ò¤šù*D«jgÆÿÞϮ͒˜³«Tâ4ŵN`cA šMG Ÿ¹%§Ù€yø‰Smkèr1ÿÿÃNzJ )ŽÓt¢N)µbйI!-Ê^“pjŸ ÇwÛMîKËSqs· Ø\p™ñNú ñº§±«j=ÔŸ”¶ûvG©Õ"±Ð”ÿ—icÉ#:ÔËz’˜QžDx9Žoþ4ôEIÒß®žE+"c°ËœꜲõ#@ªJTýi1Aºí6ƒ®Á.·ö&Ê»m;õI¶ÿÏàr4 AIEND®B`‚ivy-2.4.0-rc1/doc/images/main-tasks.png000066400000000000000000001003431226750426600176110ustar00rootroot00000000000000‰PNG  IHDR¤ÌŒ>ÜgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<€uIDATxÚì½ œTÕ™°ÿ6, *g3qgæKblôÓ,²ˆóe"ˆŽâ°¸e±[Œ³±ÅùEt’™`·æŸ¸°(N"‹f¢€LÔ(í6ÿQÀ@Œpcm•­»ë;ï½çvºuï­ª¦·ªzž/Uu·ZºªîSï9ï9©TJ:‹n¼€B €B €B €B €B €B €B €B €@ÑÒ— }¨¨¨Èk»Ó¯9åU³OÔ–‘ËR9öÚ¯eQ*¿çë#ÜG*|‡©øû˸ãÌíR‰¯DÎW×?Bð RQGLE\w¶I¥²[©ì=•§ïþí¿×R©8(noâdÖñBj$´Ò¼îcÌ6ç››ƒMœd¢-+m2ñJª9µ¾¹±é—ëWmXúÎkï6ÚMš3÷FH!…6R#£* ˜8õ@¤-îÌhú øK˜¾¸s󮚗þãÕ×­¬6Y1mÎ%¥|†!…¼eòô«O™lÌäGæjodXºg÷®½·?÷óçb®ï³ÑèHi !„Z-¤§_sÊíæâÆÖÊ,2Zò2Úrؽ {öìÏŸŸa®~¬7­˜6IL¶”Ï0;TÙw§]=d2ŠŒæ#£JϾ=¿ù¹1‘¹ÚßD]$~b·V?u„´|ùÂ%Ÿëin62ŠŒæ#£Á†‡ 8ôê÷8ÚJi_GJ+R@H¡ zÖãsq2ŠŒæ+£ú¯ò ÊŸ9ýÓç™e¢Ÿ‰CLô˜ÑRˆ÷L©8EF ‘Ñ`ë>Gò%sñIIgI{™8Hhº€ƒñÛ]I¥ EF •Q=VϾ½Ž?CªEM{%]à´_2Ç*(jȶ?Œ"£…ʨ^vïQ©YÑ#ÄÏfâ`ñû’V R@H¡€×÷0d-TFíë¼4•t?Òî) ¤Pˆ!£ÈhÁ2êì®YÑ>VF{#¤€Â )2ŠŒæ/£ÞÐ^ŽŒRÔ)´^H‘Qd´@Uº[ 2£•ösËgR(LH‘Qd´`Mµ|F+@F!…Vè2ŠŒ¶BFSéϨ4ÕB È(2Úa2õWCH!…6SUdÍWFó{ó ¤€Œ"£m+£)>*€2ŠŒv¢Œâ£€2ŠŒ"£)2ŠŒ–­Œâ¤€2ŠŒ"£)2ŠŒ–±Œb¥€B»)*2ŠŒæ%£) ¤€Œ"£È(BŠŒ"£å*£() ¤€Œ"£+£) ¤€Œ"£È(BŠŒ"£È(B m*¨È(2š·Œb¦€2ŠŒv¢Œ¦ðQ@HEF‘Q„EF‘Q„Qd@HKJP‘Qd4/ÅN!díLEG!dEFRdEFR@F‘ÑΑQÌRh Qd´õ2Š‘B m 2êq܈‰²âÎU2ôóCsÊè¸dÅœÕvÛò’QtÊ…î¼ÈhœŒ^~vŒ>!këÕ¯¬’…OÏ—õYW°Œfêm¾™ÑL.Uã‰ê½ËjeÁŠù¥+£)” dH‘Q)43:ôóÃdîµu2ê´Ñ­”ÑTÈÀZÑLŸ´2 PT!EFsÊȩ̀yYÑ€ë.¸Á“ÑqÃ'Ȳ疶BF¬Ïè½Kk¥Î2 P!íH9-‘>£w=:[¶lÝ,Ž(}{÷õbÅìÕ2÷ÚÚ,õú€Þ¹Ú˪fʨO—Ÿ]í­×xì–¥Þö¹ ˜Æ9AVÞµZÎ8iXÆ*}—®–•wÿ¶%î¸r޹ïáE*£˜)”dH‘Ñ‚d4þxÎãÈ+3*2õ’éÙB9ªÆ»¾påüHS4Ý÷žÉuž$»T "ƒŽ,«^~ºèd”™C!d4¾ë/¸Á»Ô¢¦†Ýì“>BÞL"/®¯÷º,{v‰w{ÔéçÈuc'›ËÑ‘BšŠ{ŒfÅõNöSýú52ça?ƒ«B7~äD#¥UÈ(BŠŒ³ŒN½x†ÈÅ™Ëv7ÈÌgD˜[þLÚÿtuKæ²ÂÓ“Ï d ëBÒŽ7Ô¢’Ñ(T$'Ý]#[¶nrTœŒVÄ+eD“f6•G ˆyôÙR7èSƒ¥ïÁ}ýŒ­#£qBY42Š™@™@†ÍI¸Ê>ºš^d4¬”¹T3d€ù—÷”’Œ¢£P.!EF[ñD2e´a÷.¯ _ ‹²e4ºLÚédÛßsýÛëã…,´býÛ~fT›ù5SŠŒ ¤PF2ñC#„ZTäNªC:élOû;æurK±‘ÏÔKgø}G`nÞº9¶€) -fRvÙ [iï?N-jšýí»Q€. MöÈè˨®Ó&}Ctê%32öJgN³§ÕjzŒíØÎ¸zÁƒÞ×-©•ÁŸ,Uƒ‡Èü© ³ŽY”2Š™@™@†´#(qUî}¼6c¨&-NÊXÑL¯1): Ôsªå²© î¯föå²ì™%ëW½ô´ÜùðE*£)”)*yÛç…õ²ç×}qO©Ëh[LÚrRÓæ'£zñüÏë6ïšxËÄ:{©·w˜ØëïÎgŠ2¤'§È(2ZŒ’ „Qd@HK\V‘Qd4q?¬R@F‘ÑN”QtR@F‘ÑΕQŒR@F‘Qd!EF‘Qd!dí e|Q(˜:´dT§æ\ü£e‘{,|z¾7[’NáYl2ªsÓ/¹õqoêÏs¾ûµ–Í–Üö„w9úæ¯!£%Ò"—QW£7|‚̽¶ÎÎ'_<2*‘ÛÆ(fÈv!£ëÿ²N&Ý]Ýr{ÐÑƒåº &{—gŸ6ÚË–“Œjftøw¾’ÕLŒ ¤Ðe4 T•ЩÏð¤4,£ãFL”Q§’G ôÖ¼¸¾^–=·TV¿òtËÑÇ/—Ÿ]#3˜æc܈ ¾,în…+È•ó²îW·ÑÐ&w¥Þ÷Þeµ²þíur6ê‹çÈГ†IÕ !-û.X>O–>³T¶lÝìm³äÖ'¼ëÕw|KÕ&|Û\¯¬úÉïZ®OÿÙåé—žö®þÒ9&ÆÈàcüç¼î­u²ô÷‹eÉïgÈè³#›?Ø$Sïý\qÞ•2üäÞºÞû}¹iâÍFˆwÉØïŸŸ%•7]ô]sƹò[.•µ^Ûn2ŠœB E-£ASý–m›3dtê%3dèç‡el{ò */n¬mðäÔÍIêöáã^>ªÚÛFû¨ÜqÅï.UævÕõurãÜë¥~]}‹Œ^á YwüȉÞeÝÒ{2d-!›ñºL8k¢ÔŒ™”±NÅtð17™ÇÜGæ=ùP†ö=øP¹ï»?o‘ç€5¯?/ëΔ&VÖ¯h‘Ê>f»CÎôD@H‹‚ΔÑQ§öú*«_YÕ"£COîɨJç½×Êú¿¬·Û’ëÆÞ ãÍ>/®_“ñt›ÇŸ]"Ëž]ê-uº¿í¨ÓG·©fEUF5z×¢;e͈N»t†— ½|TÒ˽ez[¹ñ§×Ëšuk¼ëš©ýÅÑ™†é¼bÚ„?ìê¯ÈÒY¶¨iÊ?f4Ó«xªŒêvµ‹çÊ’ÿZì-ŸxÖERsî$™ðËb³¬á£t×ÀO 4òù‚ÌýÕOeÝ[k[¤RªB:¼j„¬\³¢E"Ç|åï2úÞRñw’Š¿ßÖVÓkTûܯœë-ÒB&eÅ Ë;DFÑQ(ÈvŸ]øô¯¯£ö!ÕB£ï™ÜrÄ-[·xMØçþ`”ä7´S´ ÅKëÞ^ïí©ÍÿƒÌq5 êUÔ;4ç{ÙO{(•½º¥µÞ6uKîñšóUHµJ~þòyÑ2š0{S0øÿ`íðúó2:øÓ'z·µ¹=ß¡´™þ…מ÷2£}õ¯ù^oûÅLÈ(@[A†´e48žµ¤ý>O>¡J¦^2½e]ýõ^ôŽš92èèA2ª…Iº<33*^Q—©—úCI©`¾³u³w¿Jäú±“í0Sþ1¦]6£ER7à7óOûú ¯©^ûgF0EÊg*]ܤ²íõuWþâ‰oÇȨ^}iÞ«›‹wM¼¥nm/õö{#Pd!í]- •,'=êÈ£<]¹fy‡Ë( R@HpÎr’QeÌçy—+^XŒ ¤È(2Ú±2ªœ;ô\¯˜iÅšåÈ(@{ýÏÚé…ÍêCJ3}±ÉhG0EçåÿMR(yÈvŒž"£ÈhÁ2 €2ŠŒ"£i)€Œ"£È(BÚÉ £È(2 €"£ÈhÑÉ(‚ )´È(2ŠŒ ¤È(2ŠŒ ¤å 2ŠŒ"£)2ŠŒŸŒ"§€Bç),2ŠŒ¦˜AR@F‘Qd!EF‘Qd!dí$ÅL!díL%W ) £È(2 €"£È(2 €2ŠŒvŽŒâ¥€2ŠŒ"£)2ŠŒ–±Œb¥€2ŠŒv¢Œ¢£€2ŠŒ"£)2ŠŒ"£) È(2ÚJÅL!…¶òQdEFÒÎEF‘Q„´SAF‘ÑVÊ(½I!…¶4RdEFbèÎKÐîì2ºw(2ŠŒ*£ÍM©&>>PjTTT´\?ýšSÚìXkcö‰Ú²"rY*ǾQûe|Åç|Œ™ÇJÒ§…̃UH®ç›¹]*ñ•ÈùêJW/Ê]õãß%§ƒRü°GHÁýà¼g>ˇ"£Èh¡™Ñ¦½{¢·"} %K¥ù\1w¾¹>ØÄIº -+Õ⯤šSë››~¹~Õ†¥ï¼ön£Ý¤9ØhØ5_á{°Ä É¾inl~EF[ÓL¿w×¾]v‹”³%_ÂPª¨€>c$î?ÌåUÈhYfF+Í‚“Í]«<¨ò‘Ï<á÷_8ÿsúä—‰ž6‘ÖmÕWÁG!…Ø÷ñ¾§Qd´PU>|çÃ÷BBÚŒBI’’Éæÿ—LœšS—ÑR–ѬJE·Š“?ú°ßöõSo27û˜èmâ ûc¥[«Ÿ* ¤åö5ûÚ¯×-inj~ EF ‘ÑÆÝ{¶ýiÇ+¡Ú„Õh/›S(1n7_J³­h £ÈhÔ9­W¯¾=§žþõSo373qˆøÓîH)B y éÎÍ;÷4¼×p2ŠŒæ+£Êûk?øcª)µßŠè~®”"¤Pü_©Ô8sqc^º„Œ–«Œ¶Ð³oÏo~nÌß_d®ö?[Ú)EH!Ïï[ˆú//ùhÛG#£Èh>2ºãÍooÛàeGU@÷™Ðâ¦Ý&öZ1mBH¡ØùÂ%Ÿëin62ŠŒrN;lÀ¡W÷8¸ÇÑVJû:RZ”"¤CHU*êç¿4gûÛ;ç§š››Qd4ù7L5o}cÛÆÍõï¼aÅSEôcÚØc!…¢§ça=.0G!£Èh!ç´Êƒ*|æôOŸgü•‰~â7ß÷˜8(ö©}ѦU/ËÕ¸¯©á¥E¯üâÈãŽxý„aÇOêuhÏÈ(2°w×Þ]›^زv÷ö=»¬Œî¶ª·wšh0ñ‘ÒFq†?(BŒþTœŒ"£­9§õ9ò/™‹gìópw&º4!¤ƒ~H´©U3];ßß°õµ­on¿ã˜ª£‡öÿ›~ŸïyHÃ{Þ»2Z~2º·a_Ãþ÷ïÙµ©áÝÚùž¹¿FGFUD·™øÀ^î´ï¡½ö=PäJê 넌"£ŸÓzöíuœøÒ}ö;q¯½¾Ÿë)ÄÓl?$[©èÕÜÔÜãÍçßú­‰µ’ƒÁPB˜rÀÒ)ø¥¯ÍòZ }ÏÆŽò… ¥Â_#£Èhk,Ý{TjßÑ#ìwbƒÝÎv2¤)D|ìšÑØ%éŠ@]×h?@:µ¨öƒ W "¤åñƒ¥Ùy/|dß'[­Œ¾k¯ï²ï¡@HùÂ…bF¿ãCF‘ÑBeÔ¾þÁûg—sþl°çÏý|¼RˆÇ+l²²|®š¬`è²Ã%% :gSpV>B¼?‚ìèñ3¤[mìtÿQšë¡¨@F‘ÑÖȨ³ûÁö¼©2ÚÛž;»“ÈAH!žàãÓ’·pe»¤g p?THié¿7Z ßìûAÅs§Úe{ív)!; %(¤È(2š¿ŒzWzØ$NpÞ2Ê)!hÏÔˆ?SUwÉžfµ‚o dEF9 ¤ éA’žF3˜±¨™—EF‘Q”´t¡¨ º*£=Mô°×ƒù‰™}EF‘Q’¤% RèŠBÚho7 ÙQdEF‘Q„ ­ÏA ßÉú~ìa×k“}7ô#@F‘QdR€Á-jª”t“=”ü/UdÍWF1ÓR„>¤ÐÕÞ®ˆ"£È(2ŠŒflŸÂGR€97Èw8 £È(2 )2ŠŒ"£€2ŠŒ"£€"¨È(2š—Œb§)2ŠŒv¦Œ¢£)2ŠŒ"£€2ŠŒ"£€ £ÈhçÈ(fŠ´È(2ÚzÅHR€6EF ‘Qt!@F‘ÑΕQŒ!@F‘QdR@F‘QdR€6“Sd-HF1S„EF;QF™9!@F‘QdR@F‘QdR€¶6TdÍOF1S„EF;SFÑQ„EF‘Q@HEF‘Q@HÑ”ÑAG–w­–êQ5È(fZ’tç%€N¡etèç‡ÉÉ' ‘Q§ÎX¾ì¹¥òÆÛëÍå’6—QW‘QŒ!(c½üì7|Bä:OPOéspY¸rA›ËhEìkX~2ŠŽ"¤mF1ɨŠh £š ½ïñZiø¸¡¥™~܈ñRu¡ÏhÈ(FŠ”›ŒzB:—љN—Õ¯<ÕgtáÊùY™ÑëÆNÎjÚq}½Ü»¬VÖÿe]ÆcëÛ»¯Œ;sBËý(õfÛÇŸ]"«^^•qŒQ§öbЧ{·W¿ü´ÌøÅ´,pÄ©}… ûÂð–eó—Ï“º%÷ £€“ŒªTª0¾øF}¤ŒfÑ—QÝ>,£ÊɃªäöIwÊÅ·L†Ý»ZdtîõuF fl[e¶tô  !Uí{pߌ톞4\¦^&2ãçÓZ– úÔ ™}å]YÛN9Q‘üo×±Œb¥)@ɨҧ·/uõë×ä]M¯²yæäan¦× èå£jäìÓGyYUåº oðdT³§s™-›·nöŽ¢Ó“ Éx,*˜ËžYâeYµË€fIï˜4ÇÈë ‹›üÏ7zÛj6tÁòyÞ£ÐÛÓ¿>Sª1Q%õëÖ¥Œ¢£)@YÉh éC6´“ ¨Êf8[êS³¦ »dæýÓd—‘ÌàÑ/X1ß ÷ ,X1Oî]Z۲ﺷÖÉú·×y’©÷³eë&ONUTµy>QO’?j;Þ!ó§=,ƒ,õk×§Œb¤)”,G™˜j¢ÉÄËÖ¨¶™ø“]¯—[ËMFu/¯x)8Bž2ªý7塀3«>ŒŽ/êuX_Ÿ!£!g’í~¾hîn°’ÛG¶| -÷©ÍóQ 8â(dRèrl2ñ¦‰ÿ›Ç¶õöR;AþÑ^ÔÄSa­(vÕ#|h…´ê„*Y¸r^NÕK"*h†×¦~¿à)å ¨örΫ¦/LÖ2û–"£€@×á6Ç›øFŽíªœëA ÷Z+­6¤òÕ¤b˜iÙ–É·FÕxMë:0þêWV'ʨ¢ÅHš¹¼ñžë%ih'mn÷ú‚šíûILgc ”Qg—-[7{×µÿèü§æeþеÏhÊÝ 3-E˜:\®2ñt+öÛi“•öüR‘äƒÅ4hP€4õ’ÞpN}{÷ÉÑq#&šuÓí°MžŒjSüÐÏoy4*³ZÐvAÍ¢jÆrê¥3ÒMüfÅø3'ÈWÎÉ6ΡÔG´fݯ0ªúœ+dÂY3dtÐ1ƒå†ñ7¥—#£ÐE C ®‰í71Nülçß°¯ö7ía¢ÙD£]Ö,1©Áb››^…4(N "ŠõYïÉÖê—WyÍóS/n–NoYô÷t½¯[Vë Ó¤Ã<ÍûÁ‚ŒãedL%^F3_ s?›*w^u—'¥ajÏEF¡KA†ÂhßÐ2±¥€}>6ÑËJéAâgI+rya1Èh°î®EwÊ̦ÉêWVeí©Â:óé²pÅ<{{?4Ómnš;9ý¼%ÝÄ~ÅœjYöìÒŒcê€÷: ”u¸D ‹¥v¨¹ã›²ô÷K2¶ÑªüùO=$óŸ|…®õk¸Ð?r®Ù5 ÍyÄÄXýMlOX–/#Å/<¸ÙĬBL®÷KïÝ@ÛŠŒXw“ ýFÞkb·½6c›i€¶;'X‘¬´Ry†‰ÇóÜw¨ø•øûíçvŸ½Þh?¿.=‡]ÿå=Å$£’¡‘a¥´Û0h‡È¨Þ®ðå‡ÍÕwM¼¥žm/õöûþCb‹ŒŽÌ®±o±ªN~Îcíãx¤ïgнŸ)]ìo>ÖJloˆV&uß+`¿+±AÒŠPdÝ 2ŠŒ¶FF!-„~]@}²ÀývFxanƒ@F‘ÑÖÈ(rŠÆˆ£ŠØGDõ³¢3¹ŠmêIŠ'w›EŽ|F i[õ‰¬¶2Vz,„žóS{¬äß_T?2æþŸj§¿uÐbQÄ:}ýjìßn–}ìóFLʃ«ì÷Cï˜õZEƒ‰7b¾C$ô;YL‘Qd´•2ŠŽ"¤a¡zÊJËH+ ˆæK½‘Ò£BäfòêìÞØˆÇHÖö6x=úÙûêoŸÏ{Ü‘!ñìç<ç Gä6Úmnv^ w»!Ž`WDÄ"ç9µ5qÍõanvžÏHGLég PšhÒOlÄñ¾‰‹Lü§‰+M¼Z¿S²[|R’3KŠŒ"£È(´^H5ƒ¸ÆJäÍVÞfµòþ9’ê¢Ð¯ïEvùØdÂþµH^!}VõyÔ8rHs¿i®Š¹Bú¥ê1o“̦û๵GVr¬ó|ò!øÛÞlŸëû·€ÒA§Z&~v4ô{©ß©ïÚí÷&i £Èh+e+EHÛYVþªCâ%™áfû~­¬Ö°Ý¹¿àqm”ôðQk$Ý÷´9Ô¾šS$ºé¾­q3ÉŠö}ÆÄW¶YeâŸÅψN¤cŠþ á½Én·CÒcç!EF‘QdDH5ƒ8ÄJÙmŽXµ– ó9Ò‘µå’nþX.é&þ*É¿ º=õ8I,ßÏ>Íæ;¶émŽÜ^(élîÍíô˜Ç†¤>ßǸÍ^ÖÛ¿y €’à³&þ`/ãЩ|tÎÉ}ιB4âI›ïgÚåØuÍ’g–EF[/£X)BšFå,+fË%]I~[+…4¦@2ëòÜv»´¾»À2Ë äq’î0Vr7·+é. 5$Ôq’'¢Á¨Ëíó»P:¸.€ªøži/‚ 0Š©µfD53zLÂ6·[Ùì!£ÚT¿ÇÆÏMÜg¼6ÆHiö€Œ"£É2ŠŽ"¤Ql´²rœ•È)Î #ßá‹–;2.f 7M±R'®IÃ>(ÁN¹Ž4õŒY^’×)=â@[Èè±9Ä7?6Ñ:GD7ò1éÜPêoÚçóš#¬a b_D뢲¤È(2ŠŒB‡ ©+haY Šw¶ÇlŒý™K2«òפaŸê%»€(jYøqׇ䱿sqC_MßÁvî°P5ÎòãìþÁÄ‹r¼nI¯eø„™OáýCÛ·HlyÄû%èî2Ö‘š`ö®(6ØãÇÎ5ëY¸à.ÈðGIÓ6IíæÎH66ôxÝ ÔdQÛmè> ¨»ÇËÕ-æXç˜QÝPF†ö ϲÖÚ>©Aßìðçp–ýL¹óÎB+éW‰?lSÏÙõï:2Ú#£ûCÒÙh#X¾ÏY—g“=2ŠŒ&£L#Šv‚~¦uüùò:an”²ÕÐö"Úš"1wx±0ASq¾3™åúE?+¥Q÷ÿˆdw1i— ax»c%»¿ôS’Ýï|¤½ÿ¤æï ¿ù±1ÛÃÂ-w~ÌF=§)Rø iI?öÂEŸS¤sб‹_IjÂ6𸆉œóA £á¬h8ûÙìlÛè¬otÖåÈk!£È(2 Å)¤ùè@úÄ?qÄúKáEbAßêêˆÏ+™AQMÔ,_c%¹P0éý ÷åÎ$6VÒ™Aw]#wáûv[. =–`,Þ¨û’<$.jr@ÄÃÂX+Ù³¬Ý‹FJa}?óy]ۢ賵 •Ü•ôw™ø^è\àVÒ‡›èÙO7š""…Œ"£È(”ªÆÍÌÑ'Cú$vÎ{t›½œ%Ö77N¶¢&„¨‹Ø¶ZâG£’ãýdùê#žßvÉÎòÖÙ¨ŠócCÏÉ•Ò@kBǻБìcs¼Fc^#·g0~ñ¬ÐsÞîÈt¾#räÛ7Ûý,}ëgIº{Bu;½/3ñ¤½¿(T8o2qDWÒGeFã*ç])u³¦y ŒŒ"£È(€ê›¢ã,&6vòã(Û€¥ÞÉÞÊü…%3( ¬ŽÇ¶üw¬½ÿmY²ê€GýUk#²ƒý$ºÏ¹HfS{u¡Lò±Ž0nw–‰“¥tcCh›|~tô“®ÙF+éulÐ1ëuF¥KM,¿¿hT%}T3}Ò0Na)Í{ QdEF¡X3¤] yÞm¢­•Ö7ц³¤IÃxb6ÅÉ.—Ž9¡Ÿ#¤Cìå"+rA‘S[Žõ‰´®ßl>Ú7ûXû*ïg9ï‘¶¢‡Ñ\•ôÿdâE‰Ö)©Z¾M­EF[+£*B ù4MâA3þ#RøX³næ3W¿àðLf"mß½e£dŽbn¶³ÞJR02Ddf3·Kz â0#cäzLn&9¬~yh‘Ìþ£á¸0çôÓÍçu *ú7HfŽ›ÛøG‚Ê­6Ñ_–°ÍË&Æ›Ø"ÙÃ:¹ÍôAVt{ÊhØCQd„ }qÇiåä),CX'é,›+žaÜ⦱Ræ’4ìSË­@F ËäV«ÛLÉãxbŸ›{¼à5ª—ü ÁêœãD>“VÜñ˜ªì~ù¼ùd_«ìsß`ÿ殈¶5Ç‹_I?4a›'L\,~s½[IïμU¼ÔŠÁí‘Qd„ «‹i{9²@t €rMSY±_[4¿”ìÙÊÂSꎔô°WA„¥z–•ŪÐñÆ:¯[¾¯ÑF{Ÿq].´ëÂIï7ߣ±’9#[SìóqÿæíÁ©VFOØf®‰k­`†+éÃ2ê6Ó·[V4¬•È(2ŠŒB Ðñý ‘EWBsí4ño—öaáB+Yõ÷T¬³—…3´ÁpQîò³$»;j»|Å=®ßl0´T]ÄòYy¼^ù;ô#nÏ.t ûU_Ißd_SÚ)iNúBŠ—Qd´kÈ(rZ’Tð«Úô U‘ó4£L4ñ`Ä:Šf©=Iî¶X´kóa d]9„¶¡ÖJiÿN~*š·&¬×Aî¯R·’>˜YiŸó¹Ú'™Ù§:èsÖsÄä3ö £ÈhkdT—¼úðÿ<,þìbo™Xg/õöûþ&«Zdtç%()«·ýPíÌI9zX)¾,a›M&.¿KAwGÜÌhÔ yÕÔI?u‘Qd4û1B ]’~=h>´è÷ëD!ícïû« Ûh%ý$ñ»+DUÒïsÂm¢ÏcŠOdEF¡}¡)@éIÙѶ§ÎúEg †¯Ó>“CFW‰?àýGFÝJúð€÷ÑLŒ"£m#£˜)B ]š`x!„´t*é?›°ÍýâgF÷Iô°N¹¼ï¢ £Èhôc$WZšÐdÐ59[üfúÞ1ëU*gšX Ù•ôAñ’í:ó2ŠŒ"£p !èzh•üâÕ uÍŠ. Éhx楽È(2ŠŒB1@† ë ý?ï¶BÇûâéõšÄWÒ‡‹—Š ’EFó”Q¼!€vC³¡¿”ä⥵⯽'%UIŒ"£È(B Í'Åo¢?5a›U&¾ceÓ­¤’ÑFÉ®¤ï £Èh!2Š•–"ô!è\´‚þ9dôQWJv%½;óRVÒ#£Èhá2ŠŽ–&dH:mž×Jú> ÛÜnâ>û}ÈhT%}0ûR‘/!£È(2 )@gs™ÍʘõZI?YüÁøÃÃ:%/!£È(2 )ääV7'¬×—¾eâ¿­°T•ôaSDF‘Ñe3EHà€ÐJúL\°Í›&¾ib“dëWIß$éÌhñœ®‘Qd„ Ã9ÒÄ2I.^zNü1H?’ÌJú&‰žy©ˆ*éC £È(2 TÙ´?Ç›x&‡Œê¤ß°2®¤ϼTd•ôÑÒˆŒ"£­‘Qz“–&dHÚ—¡V6û'l3×Ä]R’•ô‰FŠŒ"£È(x!h?.3ñd‚Œª\Þ$þt¡Q•ôQ™ÑQ]È(2ÚmnJ5ñÕ‚@~|ßÄÏMôˆY¯•ô—Š?C“[IïfE£šéKAFÕOÞCF‘ÑBeÔûµ¶·qOôV¤ORèaEô–„m´‚þŸM¼(éÌhXF÷HÑŽ1𛿯æW‘Qd´5Íô{wíÛ%ÙCœ!£)X´i^›è/KØæeñ‡}ú³¤+éÃÃ:í‘ì¡JFF•}ï{ EF •QåÃw>|/$¤Í‚"¤àqŒøsÒMØæ ‹ß\ïëˆèÞŒw%}<©×~½nIsSó[È(2ZˆŒ6înܳíO;¶Hz84÷3‚˜"¤eÍ©VFOئÖĵöÚ-‡ŒF;TJ¤vnÞ¹§á½†»Qd4_UÞ_ûÁSM©àó±_Ja4@HÚm~_eâ“1ëõD9ÍÄ’=¬SÉ/I¬RJSý‚——|´í£‡‘Qd4ÝñæÎ··mð²£A_ký·Û~vö;?à!(+t>úEâO …r¯sÒ/”ìâ¥ý12ZrýEã„TŸsýü—æl{çüTss2ŠŒ¦"ÿ†©æ­olÛ¸¹þ7ìgDEôcÚZÒ"†ñ GûþÄĤ„m´’þr%sNú&‰ž“>ÜD_Ê'Ö`ª}ûš^ZôÊ/Ž<îˆ×Ovü¤^‡öˆŒ"£{wíݵé…-kwoß³Ë~Nv[ ÕÛ;M4Ø~AŸëf¾žR€r øYѯ&l³ÖÄ7Ml•øJú°Œ6;'ÓrÈò¨|kfX3];ßß°õµ­on¿ã˜ª£‡öÿ›~ŸïyHÃ{Þ»2Z~2º·a_Ãþ÷ïÙµ©áÝÚùž¹¿FGFUD·™øÀ^î´ï¡½ö=)@É£•ôËL|6a›U&¾ceÓ­¤“Ñr­ º>¶RÑ«¹©¹Ç›Ï¿õ[*ôý­ü÷2q¤'J·• hQÐfù­„¾gãGH÷ ÙQ„  8Éį%¾xI¹ßÄmöz¸’>,£RúÅKIÂÑìˆÆ.I|™dÍxjâ=õiùü`ivÞ Ù÷ÉV+£ïÚë»ì{h¿Pe”8Ú<¯Íô}¶™iâ!Éž“¾1$¢Qã‹–ëI4ià#I·¢7YÁÐe‡K:Kª3`U Ÿå$¤Áû#ÈŽêø½Û¬ˆnµ·ƒþ£4×9QýCZý†ªðÎÃ: ÎÍ ›aâo"–ÿEüæ—”d6a1ËÄ£Îö¼y¡#¸ÊÄÝ’n~£'ËÉ&–KºY9­¤â¥r—Q±¯U7+ñš=ØD_‡Ù8Ô io+¤Ý} t ÎÁ¹ÝVè;X)éÌh·Ð÷ ”æ{AœÏ”û½Ï¼õ)@«Ð“Ç-ödrs+ö×Ç,~^“sbwO`td‡¶D‡sÒaŽIØFû1Oµï¿n!+^*Õ9éÛCFšCrüÀ¥©¾ýêLÜ#™sWÄ -¸ÌD­ý…Ê¥VÒÿF²‡u¢’!…..¢nÿÍ.iVéÚ„}ïµ2.\÷%  ÐZ4ƒŸÔ¥DÇ:Ôþ¢õ’Ö‰Jz(®/e*Î!…2S·?X7GJ¯IQWBݾ£á9¿ù†…!ŸJú7ÅŸ“~“ó}I%=B E$£âȨd=gÙÛ®”Ö92š4ïw9O·m‡Î“þKñûÆ¡•ô:©¾]ú‘U¼Ä%„ŠDJ\)+éfú¨¦Ð½!!EFá@8^ü9éOØæ S$ÙwßÇqÅKTÒ´fj‚¶}CUD èÛ¢?‚tÆ-ѯ¿bâ%I3Î@!£Ð–hFT3£ý¶ÑHwIôœôûCïI*é¡­,}w*+Mü1ôC¿°ìçzèâ!…Ž )Sú[Éœ£Ú{2 mÈ?‹ßg4©’^'qX,Ñ•ôû#~ !£Ð–èd µË/6±QÒ#Ž0Ò ¤m,¥AáS0®£Ût?2 m„VÑßš°^û‰ê4 k$º’>NF©¤‡¶$nö©JÉœ:9¸¬à½)@ÛH©;_±+B8š ÕŒÓe Ûhýåâg ÜJz·/óÞÐ$*é¡#Q!=HÒ]ššïR„  ¤4ÒnŽÆ7 P‡‰ßüžTIÿ²‰I&¶Kº’><¬SXF©¤‡ŽFe´§döe7ß ¤ ¥nÓS…dÎYLs(´‹^§ýlÂ6n%}eè‡R”Œ6!£ÐÉBêN¡LvR€6”Ò”DO J§}h-Z¢™ÑO&ls¿‰ÛìuwX§ý’=þ-]G #ÏN>W÷°ë›ì{¶›ÐR€6•Ò(ñä ZƒÎº¤•ô½cÖëÉ|¦‰=¬SÔ€÷tÎÆ-j †È«àe„ ýÄ µ|ÇÄÝ ëµ’^g^zF2‡‹’Ñ SÚŒŒB ›Ñ&IΤ ¤D¥Ñ«¶yßÄ7L¼!ñ•ôáqoÖ º¡K„ ‹ÐÇÄ"_MØf­øcŒ¾'ñ•ôQ“00¬BZä?e+òû{ú5§à±*bö‰Ú²"rY*ǾQûµ,Jö|ڣğ“>©’~•øMùû$¾’Þ•Q*éÒòÀHhe*•c$î|ss°‰“œ“eQËèÐë¿”xß©à>Rá;LÅß_Ægn—J|%rª¾„àA¥¢Ž˜Š¸îl“Je=¶,R‘ªø¼’jN­onlúåúU–¾óڻ’ù*C•PÖ阄m2q‹}é»…d4ªx‰Jz„´ldTô#q§æÔ¥ÈŒ"£±£WWš'›»>¹ò Êq'žy‹þö¯k^úW_—ÌIÈÔe£ÍóÚLß'a›ÛMÜ'¹+éÃcŒ"£@7^‚”Ñ«O™l.^œDd´|e4tŸf›n'~ôa¿;íë§ÞdEK‡-:Hâ%Œ.-KÑ=&¾mâg2ÌGÄ>d!-/½æ”ÛÍ©q¶ÄˆŒ–©Œ¶,NI¯^}{N=ýë§ê€í:íå!&zY±BJý¬çO$¦{‹ø•ôL¬Ìa‚¬h”ŒÒL€–§]=dœ¹¸1/]BFËUF[èÙ·ç7?7æï/2Wû‹Ÿ ìYæRª?âåø ½ib¬‰×$»’>JFð!-¾pÉçz›Œ"£ùÈh°áa½ºÇÁ=޶RÚבÒr[§ÿ\%þ Lqsú§Ï3 þÊD?ñ›ï{H|su)¢€ä>׊?àýG’]I×DïÊ(t¨²o_ŒþTœŒ"£…Èh°uŸ#Ñ1´ž‘tAŽ+S¥.TCMüRü qwš¨•tw*éRˆô¡*d-TFõX=ûö:Nü ©ÛìVs j.³¢Ù#f½>ÿï›X,Ñ•ôqÓ€"£iÙò×È(2Z¨Œêe÷•Úwô›h°±ÛŠiS‰ŠÕ­&nNX¿ÃÄ•&êÅï¾¼\ÌI€B ÚŒx2ŠŒ*£öõÞ?»L*~?Òû¹Ý_bŸ͆ê@ö'ló¦øýE7;ß]qsÒ7JffTQ„´\©@F‘ÑÖȨ³ûÁâý¤2ÚÛŠ[w)­J{í'ªýE‡&ló²‰j+än%}“D÷ Æ¥x   Ê¾ƒ…EFó—QïŠ h/GF’Òôxñ+é“dô ñ3§ ='½Û¿6jŒQèâ!í@!EF‘Ñe4øŒ$éÌh0•h)ü˜<]üi@“*é皸K¢+é÷KöN̼€Bœe"£ÈhÁ2ê_t³ZYb2ªãó> ñSéªtj%ý/%º’>JF©¤(Rh²ï+EF‘ÑVÈh*ýu£šêµŠ~Q‚Œê ÷ß2ñ+IgFÃÅK{$³ß(2 PÄ!EF‘Ñ®+£QµbRív ã‹^–°Í&—›Øè|?ÅKŒS€2¬B ¨ªÈ(2š¯Œæ÷æéÚèHšýjÂ6ZI?ÉÄvIWÒÇ ë®¤d!dms-¿:Füâ¥Ï&l³ÊÄÕV2Ýaâd´\¦P( èCŠŒ"£]UFKC³NX§$½_üÌh£dëä6ÑUÀERdEFÛ‹sL,”äJú™&Hv%}0Æhxö%Š—R@F‘ÑŽ’Ñ"·­«LÜ-éæ÷0Z%ÿmÿåÈh*FFÖ !dEFó¦ÒŠèU Û¼o¢ÆÄk’9'½[I%£TÒ ¤€Œ"£*£Å§]ùTÒ¯Nú÷„Jz@H;QQ‘Qd4/-*÷ú¤‰Åâ1űÊÄw¬l檤o É(" PÂPeŒ"£Èè¢ôÈ!£š¸ÒÊf·ŒRIPæ!EF‘Ñ.*£EbaÚ<¯Íô}¶¹ÝÄ}’žT$¾x‰i@R@F‘Ñ.#£]_ž)þT I•ô“M,—ìa’Š—Q„QdÍÉ­&nNX¿ÃÄ·Lü·PI)2ŠŒ"£mˆrÿ€‰ ¶ySüì馌&MdF‹CÇ!-jAEF‘Ѽe´ËyÙ‘âÏIŸT¼ôœøc~$™•ôM=ó•ô€"£ÈhW•ÑT×Ò³ãMüÚ^Æ¡•ôSí3‰ª¤*^r›é #ÏI¼°Mü~þºcªOR û„Œ"£Èh.†Š?¬S’ŒÎ5ñ½Ð÷JÐ_ÔÒ)YëÇËP’Œ5±1$¤ú·>!EF‘Qd´+¡Íï?7Ñ#f½VÒ_*þ M•ÎË5Ø}x*Pd ë‹èS&Ö„e»ý¬÷ç%ò¸Ù¾³Šìqëßt¤dgGuùû·¯BHK\P‘Qd4/í<;íaEtFÂ6›ì¯ë%“QÆ(ƆDT…«>´Í6»>`ƒýLGeÖª%ݤ=Ö^¯¹ï 6Â'®‹À»n¬½<Ž5Ï'øÞÙ ™ÍëcíÇJæÐsýBÏWŸß#Îú±¡Çæ¶Ðñ ½FµvyuŒ0¦ìc?ç Î1ŸŠ¹ï|þÎ!¤õöo^eŸsk"£Èh©Èh'›f=´‰þ²„m^ا·%]IÖÉÍŠÒLP<"úˆ#¢ÇI~™¿ºä„»Ýn£ò³Ñ.ë±Ý±ÒºþŒ·Ù86BÞôùŒ ‰ÞmRxŸÏ~VÐÆ°í”˜×¸_ž¯›»Øç~ž##žc¾ïúˆbÿæýí{ ðvS„EF‘рψ_¼44a›'L\,~s½;¬“+¢{$»x‰aº&ÕVž±¢TS€ˆºBº]²3}A³ðr»^¬pö‹Ø6JÀ ‘Å é\cˆ]6Å pMhÝFGÙeÁõ '¶‡žK½Ý6X'Ïzì*»¾¿³}=NðÜ!!ÓÕ’Ù¿s¬å¡ÇPãÜg¾T9/‰Yö½p³}=1­FH‘Qdm/tlÑg$¹’^¿L¯µ‚Ù-‡ŒF;] ÑZ+^ZÑin·¢hX2…¾GÜuì•tÕ%Ĥ>«5]툪ûœêí¶ý¤°¬¢îw–Dg£$¿Þ¾¦ÛCscè~E¼ . 3ø;Õ‡^Ï:)¬¿§›µÎ‡Yö½Èo­dv‹@H‘Qd´¤e´ãN›ßW™ødÌz•Êi&fKv%ý>Éì3Jñ@y%šá,ŸØÛË­@t¶ ‹ëdÝ>ŸAÔ†¶‘6¾ß~’J*džîw–dg—£²ÅÁq·E3ï|ŸOÐ\¿½+½ÒvEF[/£âq7Û“@ï˜õ:ã’ÎI¿P²‹—öKtýEŠƒ ë4Ç®‘Ö7Ç.—tÿP‘t–¯.A^«ĵ#è¬á¬Â÷»H2³Ëc׳­ŸOkúêN‘t6]ì{fBZÄ £Èh!2ÚÎ&§ý?jâÖ„m‚JúgC27Æ(•ôÅG•‹ yY¥#\‰^ȱ‚þ¡IÍÂAÓüH{?ý¤u]’dî,ÉìêF{ Õ´QÒ]âî·ÄëÈbuÌë·"!òéNPHs}PÑ›¤» œÕ+„EF»´Œ¶ŸÎõNúI Û¬¿)£dWÒÇ1ŠŒ/‹¬l\h?÷·µBLÝ⦠˷=áþú9²S— P­™j¹½¬•쬯ÞvÇÙ c[M°\ÒÕïîñ‚ç[±}½#¤QÙâåvÿ¨ñA§HöðPQýfseG§Ø×û6ûXm× 6BŠŒ"£å%£Çˆ_¼ôÕ„mV™øgI®¤gF›‘Q€’Ó!Ž˜æ[0d±[”C^]ÙjëþŒÁxšÇJz¼O·©[X´ÑƱ’ÙG³µrZã¦{¼m’ÎÇ z\õû,»\÷šÐóÉ÷o”ÏT¡UöxÁˆí.¢)2ŠŒ–ŸŒêëôÙ„mî?sºOâ+铼€Ò >$¦…m yI"7…å´-Q‰»Ð¹W€Ãþ‡·Ûx’¼Ý¾n³BÇØn—Ý#èÛC¯a˜ %z¢‚:IWÀ'16ôºÇý]Ž“üGh;_J¥8‡´ˆzÒÕó+×¾§£dtØI#dÚÅ3÷¿÷ñZYðô¼‚etª9îÐÏ“IwWËú¿¬ëò2zùèæD¹wi­Ì_>¯He4%ÏÞ÷ÂÃæÊ»&Þ2±Î^êíV óå«öK®OÂ6ZI¿@²+éƒfz7è/ ÐÆ§ M<±î&Kíg~·àGa^?£Îõ¹Î7@0+ÓqüùÛ`JЛ¥úζµ?’!í°ošŽÊŒæû½W&™Ñ¸ƒŒ¶ágý*ñûŒÆÉ¨þhú¶dVÒ2Jñ´Õ_…mOÜT¡]†îüJIFýšÕLh9˨fFë–Ô–»ŒjÿÏ»­Æñ¾øM=¯9ßn%½›ì€Ö i!ƒ³Ã¿Þ­J !EF['£yÉ£aðÑ'ÊÜk댼Η-[7˨ÓFË £{ëV¿²Jf>8­e/Ý.X§×š}=ñ5‡ð‰£äò¯U{Íú-ëWÚõÎ~ì–eÞýÍ|`º\~vMËö3ïŸî-Ÿ{}·_ÃÇ 2êôÑ2àˆÞúeÏ.•»™ñ,ÿ‹¬¿˜&գͱNî-×ÛºŸ.›ñói²êå§[„rüȉ2êKçÈ@{ÜÍfÿU/>mäõž ú…árΗÇHÕ`¨µÍl–¥¿_,óž|¨XdTÇÕ¾ ç%l³Ö~I½'ñsÒ»2Ú$éÌh¾o:€0Z˜S%™ý&¡}éòÝ"ÒŽ7Ôv”Ñ ˜Ѿ½ûfl©’8UfdHi,æƒ>5Xn¯¹3ë8ãFLðDöÆÚÉâfIu»¹×Õ…¶OeìFåT·Ÿqæcê{p_¹gò½ÞeÄ¡Ò Ì¿Éãn”Q_<'cŠé„³&Êú·×ʪ—žö¥ÕÜ®“9"ÒÀO lY6ï7uŒŒ¶ÞLuÆ¥ÅâOÇs&®¿/š[I%£’]IEN'Ö,—Ö6ÊAÉ‚–ˆŒºÛŽ>Ñ‹(4c©™Íà0*yËž[*÷™å »Fl'œu‘—ÿÔC²ô¿ûí˜Á2ã›·xëæýæÁ‘ÑVž*´‚^û‹“°Í£&¦ÚGÐ-$£qÅKÌIíEM%&£yý*v®«œÞõèlO­ ÃH¢ fÐ\yû N>¡Êˆä ¯™=Q]Ù°ûC™óèV4O̸W½ï¹>CF]vi‹Œê3[gDS›ì•*eÇæTBoüéõ2šôœûÏË.XõÒJ™þÿýÐk¶×E£¿tŽ—m­]<·EFuùº·ÖÉü'òÖ 9ñ”®*£#Äc4IFo7ñ½Ðç?®x)ªÏ(@›C†´e4]ÔÔº&/{(~ötKœÝÙ¦ýx‹´™=ª©]pÄ€ˆ{-¬€IûzB™÷8£îÃÕ×eù<©>ç ©»ñ>oùÒß/ñžë‚§’]ö9üÄQÞåŒoþHD#êù|b`W”ÑËÄì¹GÌz•Kí;ñ‰®¤+^¢’RdTºÈ ÷Ù2𝣸}E󬦗„jz9Aïu<Ò5k×xMôÚ'T³¡Š^Nþ·k½,h>Ï)Ü÷µÝd4üLÕ1Kµ¿¨r\)ÙsÒSIiÉS30…íqó6?‡êöMÚ)·iEÉhпtËÖ-¹_ìṮR~¿0·µâþ†ñ7)c„t–×wT¹þ'×y}¡ãªécöË“?™ø†‰‡"Ö½i×m–Ìa¨¤€.}HKNFEÚcœÑ éÉ' É8¢'i¡áä7Ù§eT%òº±7ȸáãs?Ç#OøÔàŒªùñæ¸ãÏœà5¯¯ö†pÊOFÝç®YÍ;¯ºK&œ5!fSA½J¨A%õ#©®Œêí»¾ó¯2ø˜;DF 4Aý5pKh™VÒŸoe4\IŸÏ4 È(tdH;€Ž.`ʧʾ £6ÿÞð ĈgµJ0ΨŽ)zûwf¬Ë¸Ïe™ýYã<2xfZ¸¤cŒF'èßš«™>ÊJuLQês&eûé}Ñ]ûÖ:¯ I‡xºaÂM^dóÓŽ‘Ñüu0xé´Óë ñç;Öðz».JFݬ¨›ED!EFåšéÛû ´Ê½Oï>^&4ÀÏšVxÕò“îªö2¤:®i€VÓkÕoÊÏ¿€©~}}‹˜zÇy{,X1¿%;šOŸÑ°Œ6|¼Kê–Ì5BzJË`÷Þ}­{Aj›ëõ «ãŒn~“Œþò¯¢>@›ð×¼þ‚¬ýóÚ®$£á7€Ú¶fF1ÑÓ~ÆS’9ÆèÞ%+ çK80n9ˆhÏ¡×iOÇÈhñOªìßs}'Ÿ:®è0e¼]q:мöKÉó¿xñaså]o™Xg/õö+–Á‹\aåó +¢=$]Q.`¢‰ ‹6LhÓփ봩f©ýÌï¶tµÉk² ÎõÐÕ!CÚiß<Èh{UÓ—ŠŒpúpŸ~³•ÌF»,(Nr…”Jz@H‘QdÍCF SÄ@F›uÿX¤6Jff´ð{@H‘Ñ’•Ѹ]ÑB¤´)t=œ9m椄EF£eTÇqíÈhëeT$õl i*$¢È( ¤È(2*RˆŒº»ìŒQRê¾Lô„EF‘Ñv“ѬW#悌BŠŒ"£Èh»É(Ò E S‡vÈ(2ÚA2 Pt!-ÕyÚûѲȽušPâ3˜‹¾˜d´ïÁ}dÉ­OxӅ޾ùk-ÇZzÛÞúÑS¾VÒ2Šœ@¹@†´Èe4ã†O¹×ÖyÒZ¬™Ñø{CFJ2¤íLGʨÎ?éîê–ÛƒŽ,×]0Ù»<û´sdáÓóŠJF53:욯Ä4Ó 2 €B^tbŸQTm²Ÿzñ #¥ƒ²dt܈ 2ê´Ñ2àˆÞö/®¯—eÏ-•Õ¯<Ýòt›ËÏ®‘™÷Oóæš×ÛŠvX¸ÂïvÁñgNð¶ë{p_oq½9®ÎM¯ãŒºŒúâ92ôóäjð–e –Ï“¥¿_"[¶nniž×ëÕw|ËËò.õD˶«~ò_-×§ý쇲꥕Þýå12úKcdð1ƒ½uëÞZ+Kÿk±,6áŠàwþF6°I~X÷™tÞ•2¼j„·ü‡uß—›.ºÙñ.û½ó³$rÊÅß•1gœ+_ÿÑ%²öÏk‘Q„´èĦ¾½õ.Uê\zÉ O]NTåŵ FN×dÜëÔKg„ŽÛW.Uã]÷¤ÔÊèìIs¼c¸T™ÛU“ëäÆŸ^oätM‹Œ^á YwüȉÞeí’{2Ÿo>žf¶™ðI͘I‹s¢ žp¢ô1yÞ“eP¥ùgßûy‹<¼ðúó2¢êL#dEýŠ–û×íF 9ÓÑv—QäR(vuÚ92nøxïúêWWµˆ’Ѝ†fDï}¼VÖÿe½Ý~”\7ö?|‚Òt3½nóø³KdÙ³KýmOím«—š) 2£*£ëß^'sÝé]êŠi—M—¡' —ËG×Hý¾2|ƒJêº5ÞãРŒþÒ9±Mþš±võ—eé¬_ûá¦L¿¶)ñ2¢*£ÚÔ_ûØ\Yò_ykUR¯8÷J™ø.6Ë{Ç \oà'Ž’5¯¿ sõïiÁ´‡T!näsÅš-‹53ªRºxõ¯Ú]FÑQ@H¡ éÕ¾¢+f¯ÎZ~ïãuF×·QEU›Üg>0Í\~Øò—=·LNøÔ`+‹º…+æÉêWVµÜV1=yÐo[Ýç #Ÿz[qeTÿ›ñ‹irÏä^“¿vØüÁæôc6Ëê×½àm«YÜ 3šTÀ”µÜ.«:ñïrþ“µÈ¨®š÷›‡ŒD*˜?y„,þÝc-{ksþµw_%•+ë—ˤ÷¯”SþöTO@UruŘ3ΓMïo’Ç~û+d!EFóaæƒÓeõË«2Ž8àˆþPQ·,‹Ýo@ÿ~3Â#ØbÅr 9ž hßÞ}UšUH¬˜ïõ­]ã…fI×™ýV¿ô´w)Ÿ9 ˜úôîÛ"™ŽúËlösà'&Ó‘ÊÇ~û˜\yþ·= }è?ï—áUgÊQG%þúŽ‘Q¬Ê†}ê:JFµˆé̆™ê5Å+:ìSkŽ˜1LTŒg§â¼)•Û¦T@Ïùî×¼"& •Ó #'Jí÷y—¹eTⓦ]MŸßo‡´D.þí¯<Á>÷Œs½dñ¹FL••/,GFÚ2¤%"£ÇK逸 <©Ôj÷;jæÈµ“[LgËÖ-Òçà¾rîFÉ íTe‹—üîâ5ÿ2Çô©A~–Ô¡Ê6ç·d?Í>jº%÷xÇÒKmÎW!Õ‚§ùOÍ“øqF#4Ó\ùðã]ÞÕAÇ –^!c+-lR6ݲd0["UF_xíy¯ˆéâ¼DNù»S½Û¯ÿùõ’Q¬Ê2¤¨ªmßLŸ9è½fIµß§M½dº#„Ö¿QïÉªŠª7”#£žÀ^1'K†‚þ¡Á]L»t†×¯âé7틼¸Î/XÒêy]0õ²ð¶)™vÙL©>ç OŒûŒJv3½Š¢öë úŒö·f­ÿÿáb9çËcZ¶Ÿ`nkA“î÷´W1Ÿÿ8£+Ö,÷®]yþUÞåcA1SÈ(: åÒ’Qg¯Ð ÷3˜nÄóN¯øHÇÕ§…+çy"ªËæªË:ZzšÑ4ZM¯‘±¼÷Oo©+æÉɃ«¼lè=“ïÍ:FÝÒÚ£Õ¾œÃ¾0¼e˜'—ËŠ2Ñ–}ë×¾ pιúî–5Óîû¬|q¥Üó«ŸÊç])7Nœâ…ËC¿yP>Ú)¿qƒÞ¯\³Â+bÒ¾£zj‡È(F eÒ’Q·É=ûˆZM¯Ã6iös܈ñÞr]æù Õów=2;ë^´0*È„*:ØýsªýeÎ}êX£:¾_•n·]·Fjf_ÞRM¯Ì_>O–=³$ã>4ƒzçÂÛýæú„¦{Ï•§|ºxMñf½Ž3zǼY-…MŠ^¿Ý,›÷ŸäÝßÔõÆ`ˆ§–ì(2 жvÄÌ0íôÂúãö>ù+{Ú]FÛq:Po¦¦Q52ãþiò[#¥m17}Ö8£á+]l:Ð[&Ý*g)çß|®lzoS‡ÊèKó_}Ø\¼kâ-uk{©·w˜ØË'  ¤²Údô`ĺ›L,µŸùÝ6ôú~Íùü„å\]šì;ô»¦¸d4úÑ——Œ<ò(OFµ©¾£e´O '™8ÞÆgl\hbgø•@H‘ÑΓÑT‚™”ŒêÍs‡C=­(F=ÊŠæß™ø¬#Ÿƒ#¶Õ'ªý,º…^¤Rd´ód4ÖDÊDFÅ ©WÌôÂSÅ £g™˜`åS%´wžûÍ5ñkû}²ÑŒ”BZ2¯Œê:£’F9ʨgxW)E”íoâ²÷yÕÄMôpD´É®Ë«oBZ«Œ–k3}ò~]º™~}Ûd¢Æþ‰zZm ½¹; ¤È(2Zš2Ú AýcÛß„Vjõ ɨ›%hw‡´@F‘ÑQå#+˜ùð˜‰'ÄÏŒö°?N+#þòdG!EF‘Qd´ 6ä¹Î»z’#¢Ž€"¢€–È(2ÚA2ªäÛT‡„šgâë¡W YÒÅLH) ¤È(2ZÖ2Ú:9ýÿ Øö ñg€©3ÑÏ‘Q¤REFS­5Á ­Øg˜øã~ñ€K ¤È(2ZÖ2ª¬‹Yþž$<}ÒĘøøENÝlT §€"£È(2š/ºë[&ö…–ëNSLŒ3ñdÂþZܤMøš-=ÆÞ®DJ!EF‘Ñr•ÑÖ™©Êg¸ÙþßL¼hâC7›˜aboÂ1¾dâY£­’)„EFËQF[™+ÕÞpn¯6q¤ •TX5ñÏ’Üßôv»Ù&qÄ´b )2ŠŒ"£I2ª¼f/µßèuŽˆêLLûm¼nâ|ä8æU&V™8QÈ–BŠŒ"£ÈhžRºÞ è&>ɨö/Õæú=&v˜ø®‰kL|œpL@_›ðÇKz }ÄÚ æ²GF‘Ñ®*£­÷RÓþNñ›ë{YUt3¥ÍöÏ©r¹ØÄ«&~lâs1ÇÔfû_˜!~ÖõÃУd¼R€Ü\ ~?î8ŽˆY®?/•èÉ+4f‰ßÅFø<B È(2ÚdT÷|ÅÄËVB7K³½ÝhÅ4R _û“^hâßJ8þ%&N¿bÿìqš9 ä…JãgML-p¿£mDñ/&³Ÿåðd|&¡h ÉEF»¬Œ¶ú\¢Íïûu›ê÷Úëû$³ù^/ìÉí›&¶%ÿ¿71IhÂ(”é&~ÔFÇÒÌè­ösþ, ¤€Œ"£.£8iÐ<¿?$ AQ“[àäʪÊérñ‡|z.á>´+À]&šè”ä}"ИaüsÄ£‡¨‡|!dí ©›!u›ë›CÛ„¥TØ¿Xü~¥M ÷5ÆÄÄoÆïŽ”ä}î½ÅÄm­Üÿ'ö³Ùˆ éA’9<B È(2Ú©2D“#¡A¸ÍâêJéÇ6 s‘‰wîóÓâÏ5EhÂ(mn¿£À}æšø©¤3£9?9§B ~€Œ"£­‘Ñ3Óæpº·Ý£§9 ¤5Ü·Tû‹žmbeÂýé‰Q›!—š€”äüá\β?üò¡Nü‰.ºKf‹DÔqR}= £ÈhÇʨ{RrEÔÍž†·Ê–îs¤ôñ«ïÿÅ®‹c¤‰ì%MøÙŸ5÷G`“ÛMÜcß{­Œ†?OÍ¡c%}ÖÒ²EF;VF£N|ùžœÂ}OÝJü cª'Eê­„ãü•‰Çů&î)dK$áG`ðP¥ôÇ9dÔ•P·KNP¨èþø@H!N ‘Qd4MuÎ9%œ½‰ªÂ¯¿ iŽcéàO™8ÖJi%R ÙM&øœÍŠRm¦ŸÚ'jô ·Ÿ8ÙQ@H!Ò‘Qd´d4*{'¥ÛÅŸ=F¥3iÚQ­¾×iGÏ2¥qRê~Æ\)Uýw‰îNlï )2 )IJ EF[#£ÍM©¦.tÒ ‹iзt¡•Íõ Çégâa{’=D2‡¦AL)–R ín‰7„ üÆIÉ{È(2Z¨Œ*M{÷DoÕ¡'w©()ÕXkâ< r«ÚÄïLœ(<ä’Òß:Òé^îEF!…‚inl~EF[ÓL¿w×¾]’]Ô'œp¦´1BLwšøž‰o‹?i:·6á_"ŒY KJƒ}áëÈ( ¤Pû>Þ÷2ŠŒ*£Ê‡ï|øždÓ™'¨§Û¯T/—‰?íèË ÇÑf{-Ô¸ÏÄáH)@N)ÝŒB ô%óÚ¯×-inj~ EF ‘ÑÆÝ{¶ýiÇÉÌJºÜwÖ (*[îWºÁÄX+ILÐýÏ MøIRJ3= ¤p`_0;7ïÜÓð^Ã]È(2š¯Œ*ï¯ý੦T¸˜Á•Ò®’)H_+ïuZÄËLlK8Ö â÷•»Jhˆ“Ò}È( ¤p _.Mõ ^^òѶFF‘Ñ|dtÇ›;ßÞ¶ÁËŽ6:’·ÛŠÞ~+©.òþŽ:yº}ÞžÌÒgŽÓËÄl˜è”笙œ%z&&„òR=I×ÏiÎö·wÎO577!£Èh*òo˜jÞúƶ›ëßyÃÊ f?´±Ç _WÒ¨“gTßÒ¿˜¸Hü!l’†²Ò¾§kL|YhÂÎîg+×ô¿EOEÔ Úà…­¨¬S§N<ÔÄ&Ž>ò¸#þ÷ ÃŽŸÔëО‘Qd4`﮽»6½°eíîí{vY¡SÕ¦nC^§éü³»­âmëÉ^Wûðò¨"ÌÌtöòTÿjb@ÂqTZgŠ?•¢ÛoV8´Òp9×BZöBª™žƒÅ¯&þk•Òn•ÝŽ9¦êè¡ýÿ¦ßç{ÒãðÞ‡÷–ŸŒîmØ×°ÿãý{vmjxwÇŸv¾gî/È.î¶Òù¾‰ÍVD5Þ5±ÃÊjc•³ ')í’Rm–ŸcbDŽcisÿ7MlŠÈ@Œ˜|F+>ÊÁI©¢KNƒ½êÇ¿CÂR(@H5[¤YÒCì‰X¥T³£š!ú+»¬øýè’Ìù¾iª,ñ¤…d<4Ókó¼fGuا-VJßµË>?;ÚÙ…MùŠi¥dfK{8——™¸É¾÷ãÐ×à[&žúÏ•<§_sJ¥9'1ߟ盛ƒMœdß;qß± o¿¨}¢¶¬ˆ\–ʱoÔ~n–ó1f#ð¾´Ïe¬Br=ßÌíR‰¯D—–Qýœ¿’jN­onlúåúU–¾óÚ»Áð ¥D†]ó•BŠBþB|»Û“n+ GZ1U!Õ¦üC­°öúΕAæ¯ÑЦ §fG·ZS}ßÊhд«fGã¤4˜&´» WJ?'~þgrK3ªÓ§ ¿ôdTôñ»uäûýŠŒ––Œ:OÛ¶Ì5§^ܹyWÍKÿñêë’YØ•óG9~ƒB¶VØpO+¥‡[ío/—t–´‡¤«Œ¡<„Ô+|“tvt‡Э6vØåA•}1eƒBXJݾ¥‡™˜aâŸrëyñgxú“Є_Z2zõ)“Í;åGæjodXºg÷®½·?÷óç"é!°r…ß ¤ý…TᜌUJµOi_{"Ö8Ô io{‚îî쥋;d’~ÁjßQÍîtâCI7Ó7J×oªO:Ó¹Oa)ÕKLºý|Ä¡Ùã+LüÊÉ– ¥Å,£×œ¢Åk7¶â{-m9ìÞ†½?{öçÏë×%=Q@ìØÌø B Ñ_JîÉXOÀ½¬€bOÀ½­¬ýH‘ÑòÀ.)oôc'öäúÒ-R) gK)Õf[mÂÿÛÇÒY ¾k¢A§h9íê!ãÌwådÍ·pwÛŸ·}ïÕÅÿó¨ýì$ÙÙR„!…<¾<ݲ›ê)éþ£ô!-ÂË»ÓpÍóû¥´š¦ÃMøQUøú#íâ]šÄk&&˜X+<_¸äs={ÞS§™= EFóE¦i_Ó–?VFÃcxB Ð.Rê6áë¥ÎØ2ÑÄ_Žu´‰ÿ¿bŸ&ü..¤È(2š¿ŒzWÜñ¼ƒ!ãºñÙFHÚKL£2¥zùœ‰Q&~“p•ÐïÛm>-éáÕÒ.$¤È(2Z ŒŠdŽ_ìþàÄkR€6—RwŒÖ()Õ>¢Z}?Ý.‹C›îŸ¿)ŸLiRd-XFS-þR)ñcxB ÐæbšŠÓ=Žœþ„´þ§„ã|ÂįLü_ñû¹'1Ä´3¬EF[!£©´¿tã3Œt†”6Iv¶4ÒWÅoÂÿeŽc阦+Lœ dK‘Qd´e4ê¯Æç!èP)u žÂRª35éT¢×Š?~i:(»6á_(ÙOйªŠŒ"£ùÊh~o@H:@L£ú–jÓühñ§CÇ/|PüŠý¾B>2ŠŒ‰Œ2œ0B е¤´)AJ×›8ßÄ9Žõ-¿7ñ·Â˜¥È(2ÚõeEHº ”F ¤H©ÎÞ2ÍDµøÍùqœ(þ0R߯,EF‘QdR€Óð˜¥AÆTÇ!Õ!Ÿ^H8޲ýï&æ™8)EF‘Ñ®)£8)B P RWðô–‰ V:›ŽõOâgKOšð‘Qd„à¥4<í¨VÞßaâë&ÞM8Ö±â u½Ð„Œ"£]KF±R„ ÈÄ´Q2³¥AßÒUâWá¯J8ŽNI¨ƒè?fâ“Hi(*2ŠŒæ%£)B P|RWð´ÅÄ7LÜn×ÅñLüÁÄp¡ EF‘Q@HPJ÷Iv¶ô§âÿ—„c 0ñ¸‰©&z ÙRdí4EIR€RÓð˜¥õ&þQüjü8TB¿gâ?M|ÚÞ®DJ‘Qd´ƒe#EHŠXJ›c¤4Óí&®0ñ}{;Ž/‹?íèh!SŠŒ"£È( ¤­Ó\ÓŽê8¤ç™øcÂq>aâQ³M"L;ŠŒ"£È( ¤­Òð´£®˜þ‰1V:“¸JüJý„lé *2ŠŒæ-£˜)B PZRš4¾N5z£‰kÄ¿4Ž“Lq;YEOßx´5˜¬±§ü˜Ò]øQÈhÔ2 3…Ä4`\©}léR²¦‡ÚãÑgH_1[D'JÑl)d2½ŒÂH!¤)5ÅÔ© ¿–¬.üÊmM±^D/%¥gRªfK!£Ñd: !Ü…ï$¥‡ÈZrtºzîWß¿!b¥h¦2 XFa¤R¿"ݲ¥zl)ÏC:LD½G;"^±¬%HSfÙQÈ(d2 4gá-€VI))!5ÕÌ¢î1RįDŒóh+OÄDLP{ZŸ”¿†EF—Ü¿”2{ö :bõ¦rZ½±œ7ÆEFû]1€fMšMõ{ë(oan\d4ó;}hÉÔ¥´yû&šó|d´+È@ë¥Ô«à‰³¥‡E<,â²– uã{duáO š³´£gF;`<-xu¿ GÌe™ÑP2 3MF!€Ø‰)QK†ÔÌ’ê¨ñˆ'E\éÒwÛÿVÄ@S”Ìší'ÕoãD‘Ñ¿ÎögCYBóG=@}{ûè®›r©pyAÌetË{›iÐÔþÑpÎRŽRj>ÚÅt—ˆŸ‰˜*"Ç£-Î’^­ß§$ìÂO”1£vöh ’ßÓŠœ!íîß¾ö‘*¹¯pùl)ªý®è/·óó-Û7Szç.tgv.eÿ`¨ÿœª7+éÙª2!»Gä•3{fÒâ)eþý,¦…ËfÜÍØã)ûÚ¡þìlm}-½òÆ:Ú,®a’Þ9ÆGãMðo«­¯¡ª¿Z@Ü6G>ö¿rõêÏþc†M¿‰Žk„Œ)$”š™R'1}BÄV²–íæÒVo"küé3†”&¼˜&ªŒ†‚%pñýeòѼ9–QM{?Ë©¯·O޵¤Ôë+E4ësü¢«ñeúd4Ë—rªïcÉÔàëù2³ä˜Ø’—ŠC~!£B É)¦ö.üMdÍYº@Äu.íœ#‚í¡Ÿˆ»ÈšRÊl?9~M'P5= !!e¶í¬ ØÇÈÛ–V•Rý¾z¿`Íš4ÇÚ'„±ðÅ!ŸGU×ÿTê+drìÀq´ôqÎÞz”ßOJãâü² ërpÜ~ÝÇuòo¾v(åy€Æš` ©¸fþ˜©²}Έ²|ræ–…nÜà R^¹©¡x•>ð,m~wÍ~~VâtÓÃL!¤¢’R{¾)§{EL$kÞÒ_’UÈä÷ó¾EÖ¥¥dêÂOåîx;\Ïiß6mI~ИQ–N–Âi¥ùþÖ÷Ø'ät6-ŸY.Esé+ež²•}í09޵pYìR×w_õF¥¬˜—™Su;™YÔ(Ž)|¡@>êfWU¯”a7ÌD’Qè(„@ôRÚDîÝ÷O*áä.üî.m}WÄë" EÌ£dèÂOÀyFY _y³Ò&£ÆY6MïÜUv¡ïü¸žìLÜMÏ¢ÊÑôsº¨Â)ç;àñªÜÎÚǪ\ïMsnº ÎŽš2ê$”n RH]1åÌçJJº´ÃT®Fé/âû”Á$ž”&ŒšUö^íYÓ4…jÑaj'Ƕ"‡EÔæ~®2Úìö …Œ)$½”š6â$¥_ˆ¸SÄ­"$k ©D¼©Ž}ÝÝÄÒd\)Èì¬9 Ê2kUäÊ(gOy;gIy\©×ÔN öS—Îé4|f¶ƒHžÇ™Q™u‚Ú¨+æ¦vJH…™&%˜ÚOLõDúzÙQ½ä(?>'bŒˆ<Úù¶ˆu"QâšXé'Ûr Ž-ZêÇ…H\d4?·DVÜ3Ý/¸X®ÆÄÝð<½S¨yF·Õ×HÁœŸW"ÇŒšRÇS;ÍŸ\â?¥V[pëUio5ÂEMÅ÷,”w§E•Û²2«‰"£0ÒdRhW XvÔž1Ý.b˜ˆGE ÷hkYUø“”Àvü.ü¤\›že”YXQ,çå⦵Žåìèê åž2Ê­¬ÇpֳߕýÉg«À'C0YèÊÖ•R!š¾>YT>kuÐqÜfƒ¸nà ÔãÂTYôÿþìotͪv…Ž&'È@ûj™¹ì¨Î”ž¤–L)Oót?YÝ÷Ç<ÚâIôßñS²2¥gRÏ”&—Œz¯ÀÄÝñy säDø&\!ŸW’ã1>5pTéœeÖ”R×¶³u•¬)ö Knnñ]r» Oñ´à¥ùþ[œýÜ,ª­«ñïgAíð2 #MJÒš1ŸhÃ_0OïHS‰޳T|KÄÙê‘ûiŸqyˆ¶8}6CD#Qu:õËÿá‰T‘ÑhÖ¦çeI¹kžWxb %9£`÷ þ{'— ã¼·_¨}I<|*bˆ:õÈÏ¿TÌü&±@†O|êWÈÜ0?(¢&F×^£®ã×´ž¬å?c9®Ôž-ÕcK?1JÄŠmñ’¤›Eü›’ÚÄW •›yÎQ†ç5…ŒÚσh&#C @û1ZISYÅ+ ˜ %©ÜmÝ­ÜO/ƒEÅ©ýp–å Яɚ"Šç"Mwië{꘩"–Q‚ÌYšÊ2zWv®\§ÞD/ 5ÎÁÿ‹I 2¤´­€‚äø +lÛÇALµ„šUøæØR®BáeGk=Ú9OÄÏ‹8Ÿ:x>2£-?òPîª÷…ŒÆ&7ÈrTô²‰L%Hj;r¨ƒ½G9JíÈ™îÝdÝ,‹¡”Úís–rEýX¼ežG[| =ñ¥Û¨.; _œªRY°ä¿!JLwÇXLÃÉ–î'«[~Úç‹ë["~LíX……ŒBF„€ØÑËQ–K•”ÔFÑ–™ù´Ë=;Wæ ¯½Ôó 9ÓçUÑ?Ævß¹ªÖíTP`ez­qÿѶísx}N¯mˆËûÖ+B$ë¬Å4K½Ö¹ê;Ò«•”šÅNüøDìõh«§ˆ×ȪØoó.üT’ÑÅùe´ö±*È(d@HH(X˜Ì̧ÀìÜn%À>Cêr !ЇÔýÄz>O-ÌQ¼?ZÚõ8×¹œ)öz=‘^WÿAPÑA¾#¡ºðùñMÙd opƒ%t¦ˆ?*Amóž…ŒBF„€Ø‰Ï‘9]‰á.%ÑŽ»´wÛöÌ2›ˆæPËXÔd…ÅðRõ~)±ä.q.(Z‡ëeD"°ë•,ûÔ½v#ç!­q9]m¯³¥v)å"'ÎrÏVÛÜà®{^vô&jÃL)d2ŒBN!¤oŠ 1í¥dÄ©ø&Á­¦–ªn=ÕPµ‹¼ê.õ‡”<•Åð5e¨{ØM-™Åh2ŒNøŒ×íû=]Éišzt×z,q¿JDרûÐ÷WÇïÛ O' 9}¬ž>òhçBÿ+âq²æ/ÕbzF<Ä2 …ŒÌC @|Ä´H ¢^IWƇ+‹eJ2K ±q£‚ZªØy\c®:Îke¨Ñ8ƲÔAr9;Ú77ùÌ0Î}HE4Ýàs×]ÛŸçhã/iÍQ¯³–Z²·m…þ-}š»óÍ,êûduá?"â¶xNÓ‰¸MÄß)N«;µ…Œ®˜±J>N|bœ›\#>·„Vo*§¥¯”úÛ›2êÊþÁPšøøxÚ`Ÿ<6½sWº3;Gn×T½YIÏV•Qãñ#þ«Ž0N®²T¸l6u¿ ;e_;T<öË~æ•ä8Êhú¹é4ÿî”ù>T²¦˜ª¶®“‡e_7Œú]ÙŸ|™Yþk®ª^I•[+­û'¯›û9q>oçã}}¬ckëjhÁêyÔðEƒÿzý¿?€Æ™H}.éão¯ñX#•¯_A+ÿ¸"HFû\rM¸a" è;Ðüº?¯¥â؆Ï÷úßë¼[7üÜÌÆš ´è÷ψcöAFAT C @|Å”Sä*›Á¹fæóP‘5÷…ª…}¾ÎÁ†`™÷vHí3çìqmÞwÐ8^¿Ó£¼_=Ç«9©O½þXv‹ûT„úCB¿ž\õ™µÃ÷Í©àɾºÓa²–å8æÑO¢ÿ†úÃE<Ŷ ¿ 2£µ;k¥rø?P%zýþ£?™™QŸU–ß½Œ6Ön ¢åOPãWÖ_ˆ?ŸAî¬r‰ì¦pßõ4~ÎÏä¶ìs–1CFuSýžò1SuÝ— åq¤œAu›ž©N3Ð7ÐUF÷}¾OÞË;¾M×Ýuˆ«éÚ;¸ã*òËAQ! ©V¿ûr[ÙÎÕ¤6y gÙQ®¼ç®{žòéS¶x(ò¦ˆŠjÙѶšgT#½óæ)[Þß"ã®vî’笩Õ=_Gæ<£\Ì$Å1·DvͳñsÊÇŒµ½Én3‘òxP®¨ç.{':ëÖ92ZpÛÙUoUð»ÍUjÑEÃmèM<½wÏ35u5r;Ë£Õ˲L?¤»GN–cFM®ùð!¬ûäøÓœÇ®™wËdzpâ ùó;{[Ž}4÷qy¾çÉ£î¥é“n…•&#C ©'¦DÁcKÍq¥ÂÚˆK»ç±ë¸´s6Y“èsþíd­ e¶¥5ÄvÒûýöËl¦¿ŠÞ0"–J®¦·Äu[€R.¬(–]ìœA]ûh¥­ÍZ½¡<"5Yµa%u9· 4Š'—Ȫz¦‡¸ÇþWÝôAçT¯ x[¹‰ ˜ìTþåew[‰í)£ Èh+ºé³§ý2 ’dH8©U¨‰ô‹˜&â>²æ/5YLÖ¸ÓNdEéêû3ZŒ2Š1£Q!™˜Ú—Õ]ø/“µìèê^ä¼”Z*õ9Ì'C#!£QÈ(°@—=€PRjl²Å.²–ý/~4 2 VF!¨R©-¥öÕìrZD-ÝóM.Ç9d2 R­Ó& ž6JÓãO›lB …ŒBF„@«¥Ô|4  ô4O¦:J)d2 R­•R{—¼=Cª³¦§¨e)È(d´u2 9…bª…4Íp0sŒi3E½$d2êpB ’i hšÃ~È(d2 ¤â.¦Da¬r …ŒBF„@¼¥4F@F!£n÷’ ¬Ô …Œ:ß#r¥É 2¤ ¶éT?¼43-œúzÈ(d2šj C  #)+d2 …QÈh–Qx)„€ŒBF!£B 2 Ma…•BHÈ(d´e: ! £QÈ(€€ŒBF!£B ´È(d4J…™BH€Xù(d2 Ríd2 Rí d2¥Œb4)„ˆ¥‘BF!£Q!ÐnŒBF£‘ѦÓͧñÏB ´á'ŸAF!£‘Ê(súä©ÎG!} !" éTÓûQÈh4Ýô'|}DÑl …‘ñõ±¯×CF!£‘Ê(sô“£ŸÙ„´ B !"¥ùo¯Ö­k:Ý´2 DFO?uâàG_îWÊcIO©Ç&ˆ)„ˆHH7>ÑøYãBÈ(d4\e>ßñÅß›O7£Dô¦”BH!¤@xBÊQ»jûº¯~õd2ŽŒ~ù‡?>¸KfGY@¿ÁÅMÇEœTbzB !"R–ŠÚòwK}|¸¼¹©é4d2Úìø67ØypwCí';•x²ˆqTÅ %¨Ò&ÍéKÄå—NZš¶ÎN"ºŠ¸@DÏ‹.½àšÞýÿ5z@F!£š“GNÙ÷ÎþÇ8¢d”Eô ˆODìñ{E 9·­Ì–6»Ý7€¦ž%â\ç‹øg–Ò3Î<ã’K|=ûuû—Œ+:wöùÏïœM==Ùøuã7Ǿ9qd_ã§_~tø3q==^ô¸’ÎÏE4(åøTÄ—JVOAH!¤@¸BÊCÆ8KzžˆnJJ9;Ú]Ä·Õ¶."Îñ-gªót€äÅœÒé4µtÓs÷Ï33ÏI’ (`µº €± («€+ÉÌlX¬2¢É©_¾ð¥Hbâ’ëdï²düãzÎÑéöó3=Ïäää‡ùö·¿-Šâ î511ñŸÿùŸù|>“É\›¬’$qÛÿäé”gêÔ%'–ŠÐ‹"KM¢ÉəȈ$‰‚ÈGþðP49™§R4“ "—#ÈÈlÔ#Iï -Eg¦C‚ÈÏF=4›KeC‰Ìl2œ‰Œˆ’ÎE¢É©éÐ@"=ЦCýþð ÃæÇ{žä¨D <$¾[ç›o¾ùꫯz½^–eGFFcccù|L&ëêê  ‡Ãmmm,Ë ‚ ÂÀÀ@(:uêÇq<ÏŸ>}:‹¢xæÌ™©©)žç¿ð…/`öØc}ë[ßZ‚¸W1&fÏŽNŸÄSþKwT&q¯ç€Aëhïá37ï`ǯÊwfò1ÁsT¢sðå*÷¦–š=Ûi1”ö¬(Zß5üª^ksYëÖÖì@b9êÕc?6ÜC¾£µ¥ÛœúyŽŒßyý·Ægüá!G¤ EðsÇEI„!Dâ®õŸÿóÑo®¾ùX÷Síý! ‘žy»ý—­Ã;ÝqÃÆ/ÉëêêêèèøÊW¾òä“O>öØc?úÑ~þóŸH’üáøÈ#´··wtt¼úê«›6m±Ùl^¯×d2uvvîß¿ßívwuuÝu×]£££@`zzúÛßþöÌÌŒÛínoo…Bñx¼¬¬ìš™¨$^`kë}Nþõ²<%ÅrŽ)/± çFJ]-/ú~•{SSÕ/¾ó=®¾ýº¿íyýÆM_õÍtG¼À©= ºdóšê›´ý,¥™\sÍ-ÑÔ/°Zµ¥¢¨õÄÙgܶFÒ81s6“ð6ôä“OþèG?ºãŽ;î¾ûî'žxâÁü@%uuu‚ (ºsçNŠ¢4Íàà`}}=A,Ë:tè¶ÛnûêW¿ú›ßüæÆo” ÿùÏ>vìØµC¬2×Z‚ƒ1//°rÎÐØáÿ|æÓÇÏ>]îZ·ê·ƒdË{6SàjSfrQÆš§’m½¬¯¸ÞmoЧýf½ÀñL"0é‹F§;Bñ±õõwè5öùŠ8žN¤gLúâ,Óª,O‹¢A0 ÂÀÁ0 HA’$Aơ̂߾g÷?u.F3ù¨Ziäy6• ™õÅ(‚âñ8Ã0(ŠÚl¶S§N=ùä“¿üå/a´µµýë¿þë›o¾™Ëå(Š’$ EÑŸþô§·ÜrËŽ;Òé4Ã0¢(šÍfŸÏWYY‰¢¨Ïç3 &“itt´ººàóùìv»Z­¾v¸õvû/u? È( ó™vSåß|æ ¹ÏW™X¢(0¹07• åÈx±½qÑ2‰t€áH§¥æbn<4~Džü.ÇŽmhl°ZmòÇýû÷×ÕÕ–—WÌ_ü~ÿÖ­[ ¦„Ñù×NžJýú¥¯Û†|Gåy †‡oÿqmé¶K2c…ãã‡:Sƒ«¥®µÛ[æDˆéÐÀc/ý¥VmE1G%…ö[Ÿ{…À5oÂè=XY¼AIè}ïUXÀ5bÁê|%• Õ•ïÈæc=çÞöÓ7}G«¶\dÍþ£Ï½õ/%Î5÷ßô]½Æ¶bI’”Ífa&"—Ë)•JQûûû7lØÀó<Ã0 …¢³³sÇŽÙl– š¦µZm(Óét0 '‰ÒÒÒÁÁÁ7ÑÑÑqýõ×wwwoÛ¶mrr2 AD}}ý¡C‡vìØÑÖÖ¶cÇI’Nœ8±nݺÑÑÑuëÖavêÔ)Çõz½,3p!˜‰Œt¾¢Q™ë˯ë=Ȱ$@©Ð ÍÚÚ[ Z‡|Ù˜¿s`ô Í•5h»6|‚æ>íú}2; $À ¬^cÏ’±úò »š–x<þöÛoûýþíÛ·OMM9žç³Ùl4˜˜P*•eee¹\.™L LOOK’tà 7hµZ•J•H$¦§§·nÝ:00Àq\"‘)//ûí·Óé´^¯ƒ(Š& ™X Ãà8N’¤$IÑh”$IN KJJFFF"‘ˆÝnÏårb]8’™Ù®á}Ÿ¾é»ÅöÆá‰ãþðÇ3¢Èçé4Á;×^¾ìDÏ3cÎóÄ5l]Ým2ùòTòh÷ï9žž3 Ýô*÷Æ“½Ôª,Eö‚—½V‰Dî»ï¾7ÖÖÖÚl6E+**\.A;vì¸ýöÛQu»Ý†1 SVV¶eË›ÍÖÕÕ¥V«EQlnn­««³Z­UUUkÖ¬I§Ó­­­EEEz½Þd2á8nµZeee~¿_§ÓE"š¦ ÃÐÐPee%MÓ•••‡ƒ¢¨«–ýBÀj*åv<Ð…cÊ`ÔNørd|`ìY[Lff'ƒ}ó²?†*ä´ rc‡ä´gªmžUvSÅd_>üÏTÛï_ÿ_¡˜· c]s˜˜éyî­þæC<Øþ«±w>}Ówžë_d< Áó™ß;-5Ç{ž~ëÔ/ä7`cån“®èÄÙgæÍ™}ÿ0?õúÿöLµÉ™k*o¬-Ûþâ¡ï67Ýw×ÎoÂî†k (ª¨/ß¡ÀT•©ÔÙâ´Ô¬©ºH Jbÿè;¢$ö¾-³ †­ŸÛÖü>gí FG# I§&fzä¥BwýúGüá¡/Üùß-5{æwãˆum!• ÍF½C‰ÅP ìŽÖ‡Q—ß‘CãGü¡ÁpÜ'_\[ºÍe­Óil­u·¿ûû¼o{§Nϯ3®­Ýûvû¯õºË]­7nújX×"tj«R¡åv:8Ð=ò:ŽVcYCÅN€@"xûôÿ%Až®®_ÿ9YÜÞòY³²î=8Ç­(Z?1sötÿŸŽŸ}úÍ“ÿ5¿^T Öµ…l>jÒ»`ÙØt7ÇQ›\·î/d«¦¤É`¯|e•{³ûÝ¥£ÎÙR»Gž²âéï»ûçªK6õzöÛê…!Äi©éó¾%/ £…¾¾¶AÉLeóf½[«¡wEòê’-ç&OÎë ï\ÿ9zoÞ¹ní_ôžÛÏ ’$I²}kkóg*Ýayêõ¿ƒ ø‘Û2}aƺÆl ’HÒ©ßù~ûÀ‹$–-€®o}†wÉ*‹7”:›´ÜMU7. (°Ë+Š7ȥʋZëÊv¼OK(ôõ5›±|MÕÍ4—§™ì® _Pz9¿ÄÑ|ëöotJþØP±kát%c]Ý­g=û˜³OmjºW~65Þ ¿ß&Z°c°Ò¹0I§• }žJ¼~⿦Cýr¾ŠÐÿÝÃ/*Úµkú®€%Š=ýúßÃ0*J‚$‰óK‡;Ö=¼« Ä*à#`Ô:!Dn^´‚ ¨¹ê–ù­8ª$^…,ŽgºG^Ë‘ –#€ÔJcyÑ:·½ñ| l)b½òÊ+Á`ðBîWQQ±wïÞB¿pA¯Â“§Ž>ôÈ]Rì…?(«€ %†a&³ʆäm7‰tÀ¤/–¿%1›©•FÁ)ô]ËÞg¢çf"#C k‚1/Ig0ŒÈSIQb©iW¯­½µÐq,›X©lŠ–¹Ö!–È̈’À ,c•©Ðe¬Xõe;DI€ †»¹RÖ1EI€ ‚`iÁ‘´ XŠXÇÿÕc?s8mJ¥Ã æD(ä]­r> 0ÀdUÿÝ·-t_çÃj*þÇüG §îݳisë…¾÷Ó·z°€EñÔã¯Âî†. Ä* @¬ Ä* @¬ («€± («€. ±ÚNvþá™—xŽ_ºðÁ·÷áð0êÁ‰ãíß:JQ4ÏÏ­e³¹Bï_ÅX|krWgïCßûò‹¯³,WZî>Û=àpÚ›jOo_ÓÒØqºë¦›wöôôOMøEQÌer¿ö¾ûïxkÿ‘oÞqè.—ƒeY…w:ík[× ô _¿kë¯~þÄŽ[''§]EÎ'ÿÿòP2‘ºýΛ Ãp­ÌX’$?ÖîtÙ_x~ßð '‘HNMúOŸ·ÛíÝÝÝ«>cY,–@ P³«vÆZ÷î¹Â­k`Ïž=—¡¡:nrròºë®+ŒÙÕI,šÉ¥²ÁËÜÊt6 p—[Óùð‡+W®L-y:µÜ¬Ë&¡Ð.»‚&°P+äyE?ºå’$ ‚°ðJ9†‘çûŒz ˆ›ZŽÇq†a˜¿0S†egóƒMÎÆùà3ËÅ|µùq¯ÍÓ5µ¬ :8“zùOˆÀcÛ®W·´.ú\K#B.‡ŒuºÿO}Þ·³ùd>Ÿ§iš$ɾ¾¾\.7>>žL&I’¤(Š$I’$WhþÃðÒK/1 8}útggç;ï¼#»ÊI¥RÇåóyŽãR©˲ét:ŸÏçóù£GrDz¬grr²¯¯å¸QäÜd ¨(ÎÍÃÃÃGŽ‘CÛg³ÙC‡Ñ4MÓ4ÇqÇòù|*•jkk“ïØg2™Ã‡SÅ0 Ïómmm‰D@qÔ?ý^0Zø{xá…ææàtZ’$¹òááa¹Îááa¹Ùr›ß|ó͹‹_~…ý÷ÿNÿê×óUµ··9rDN§R)I’R©T>ŸÏd2¹\N„\.'äß|GLéŒEÌ3/ŽŽŽ^Íz%2VžJ "ÿôSÏÌBr(¥¡¡!«Õj0¦¦¦ìv{>ŸGQ” ˆ|Ðáp¬JCÏ;'Ç\U(‚ $I„(Š@ ŒŒD£Ño¼ñå—_^¿~}ss³×ë­««›™™9}úôèèh6›Ýºu+ Ã0  ü¯¼e_×`O$âù[Zj‘H¤±±qffÐÓÓCÓôÉ“'EQÄq<‰õõõÕÖÖF"‘þþ~Qišîíí5™LÅÅÅ Ãüú׿ÖjµµµµÉdRnðPhÄaq „]zçü d±Xûöíknn–ývÊ?BEggg-Ëã?^^^ît:eú¤PJœ Jyæ½Iˆ¦ç&ÅÇ×ÔÔd³Yžç[[[gggq—CË †ÆÆFH„EŠãG$Vjhh8zôè®]»®Db9,ÕNs5 ¼­ë6:ŽL&£Ñh 2 n·A|>°X,™LfµˆeµZ- ÏÏm#"™LÂ0,Gnª®®.++£(ª¨¨Èf³•••y<žç›šš†©­­•$I¥RÍÌ̸\.¹†ëj«L¯-+>xðàÍ7ßl4Z[[QeYV~‡ ‚ ×ëu:ÝÙ³g×®][\\,ÿf¢Ñ(Žã%%%,Ëʱƒ›ššôz=AÙlVò îÖ2c‰EcÈ·P*• … R©ZZZÊÊÊÂá°V«M§Ójµ:‰”••ÍÎή[·ÎåråóyŠš‹þ ½ïá¦0æ8®­­m×®]‚ÈßêõúµkךÍfA’ÉdYYÙôô´N§«ªªªªªhllÔ?xOüYbý­{òùüå‰V¼øî†¥äè|dmÍåöŒõË»Ç㩪ªZ-WJ###õõõ—´ý«u Žã¦¦¦.Æ@866VZZº\1Ë3ÙváÂûR»®4­0_øÑæÒeÈÈji…ÎbÃ¥~¢ ¿ÅGj…f»:y­5ÛÕ9:¶pwÉ•¥r<¡„œÃ0 A¢(q‰A0­Ê"¿È ŠF£Z­–a½~ÎMy8¶ÛÙ×µhþÂÌ…éT*¥V«1 abbBž†I¥Ró×ÈB±×óÚ1J­@+\‰ŒE1ÙcÝO5ßIÓô+¯¼RVV622òñEéõzQ_|ñŽ{÷VVV®Vï —ÉdR©T$Y·nÝðð°$I ÃÜ|óÍ0 wtt„B¡ºº:ƒÁ ¶6›Íëõ²,+“`hh¨±±±««kóæÍ===ñx¼¼¼\Ž£¹oß¾G}TÖûûûa¾îºë^{íµæææS§NUVVú|>†ahš–šýû÷oÚ´illlûöí+è*+Neg;;;ª«kX–=wîAç7ÞhhhøÒ—¾$kL …¢¦¦fµªÓéH’”OÙÊ V«%Iêìì\³f EQ¡P( J’äñxÌf³V«•gÐÎÎΖ––·ÞzK©T>öØcù—yðàÁ¶¶¶ŠŠ Eçõ,‹Å‰DƒÁjµz<žžž¥R 8pà€Ýn7 ›7oFQT6@°ÊÄ2é\{·}=ÉšMÖ;ï¼SÎt¹\V«Õjµ¦Ói9Óf³­bC3™ I’EEE‚G2™D¤¹¹¹££CæÑhE±¾¾ÞëõÎß]§Ó ¬]»v|||÷îÝííí6›Mfž¬tvvZ­Ö’’’ÑÑÑ’’€Ãá@Ã0³Ù,Ëh4Råp8äé+°1^kX¶VO+w_æVÆRS 7šE#³Åë³õ/ Ù—cÉf³ «.‹Ò~…`Ìß¡Q^¨—Ðj…+^£X1`YxS›}5Ï_8œË[¡Òét×Üô³|{ÙÄBP\©é€Ùà–E“D"AŽãf³y^^Y¨!ÎÎÎΛ%WµÒD´³³sýúõáp¸¢¢B¶XB$›ˆ8ÐÒÒât:e£Q*•Z·nAò·mmmV«u^àû0«Ò¢ù 3¦{zzL&A:. Z,½^/_ÐÕÕ¥P(Ö¬YƒÎ'îîx,j+üàÒÊXY2v²ï.ÕnI’žyæ™úúzÇó·û·û÷ï/++³Ùl¿øÅ/n¼ñÆ]»vE£ÑH$ÒÛÛÛÐÐN§³ÙìîÝ»WF2†kkk§¦¦Nž<¹}ûvNwúôémÛ¶õõõ9NÇ£T*NçðððèèèÞ½{ÛÛÛwîÜéóùÔjµÇãI$òºGOOO:N$&“ EQ¿ß_UU544„aŠ¢*•jzzº¼¼\¶ÁNNNf2™x<îr¹ÒétggçüÀ766ž>}:›ÍnذÁï÷{½Þ[o½Õï÷ã8îñxdbår¹™™™“'OÖ××755y½Þ\.‡a˜¼·Œ$Éd2YQQáñx6n܇¯Lb­d¼VPf*Ø/IÒ¸oT¥RÙl¶H$b4ÛÛÛ;;;ûûûu:,Âû|>ÇÛÛÛ#‘ÈÈȈÍfkkk›_J[XžEqjjª¾¾¾¦¦¦±±±···¼¼à÷ûI’lii‘UÅH$ât:aî   (ª¢¢BÕ‡††6oÞ Ã0AápØëõÆb±cÇŽ)•JyÄÄÄDiié™3gfgg=ºuëÖ|>ïóù"‘H:®­­M§Ó²J844´~ýúÚÚZYq‘‹‡B¡l6[TTTQQ‘Íf5M.—³Z­±XLž¹ëêêfgg{{{ƒÁ`mm­¼(ÔÙÙ)I’¬^»Â{:i¬ØA0Çò†S%K?A$‰ã8€ã8I’4(ŠòEá8AF£YÐÌEhnnæy^f³¬÷ÉãÑ×××ÒÒb³ÙdK‚ k×®Å0LþÖçóY­ÖÊÊJI’:::l6Ã0v»ã8£Ñ‹Åæ·Ö¨Tª±±±ªªªÁÁÁúúú¡¡¡¢¢¢L&#[b§¦¦†imm5™LÇw8N§EÑ|>o2™`ŽD"†ŽŽj4š†††ùæÉ:r<F£†åóy—ËÇF£lÝ8}úô–-[NŸ>}–‡W€,é,›Xá„Ϩs]æËSIµÒxs,‹áø%jÉ'·ò‹A"p˜«–E¬eËXvSÅå0|9[ q”¸„-ùÄV~QгyÙËÞ…S \1Â{ˆUÀ•D¬®3½¯ýùÀ¼Òþa8~ìô¢ùÁÙž¥™ ½ôÂëùùaU_¤€O4ÞÛNtÞu÷žW_9 {É:Û3`wXkÛNt¬ii8Ývæ–½»»»úƼ>Q³ÙÀôô̽÷ß±ÿC»vo?v¤­¸¤ˆcYÇÍÓÚuM¯í{ëîûnûã^nlªãXŽ$)£ÑxUu¹(J,Ãö÷ oß±idÈk4[ž$cÑøÝ÷ÞV¡«jÆ’$Éã×éµÏ=ûòÙžh$æŸ:zøä‰cíž‘± ×:x<Œ(ÅK/¼Öv²s||Ê]RtðÀQ£Qo±šÒéì‹Ï¿zªíŒR¥ôzÆ¢$Mø¦´ZMOWËqzîÏí§»¢‘ئͭíÝ¢(‚°ÿwŽ=ewXŸyê…#‡Nê ºÂð\m3Ö]wï¡Hº¡©¶´ÌãøSO<÷éî²ZÍkZ««ËQu—±,Ëó‚Á ‹FãjµJ¥RªTª±QŠ¢Ÿºg;™L©5êêš Àßûô¨Çwßýw„CQ“ÙXßPËæ pÏ}·Ûl–²ò“ÙèõŒ¯k]£×ëP u: žþ>ÁXÜ@:æï$éÔüGŽã1 -tV‹bMÕM ½—-e -/j’Tè².hrZÌ'ÞâÄBàŸ²dœ¤Ó…Þ¼¦€!¸I_¼ 2ÖH¦CÂqwb,5a1”Œõ¬VVVÕ¢E’iÿ%' !W1± Y•\q=«Õ€•Uµh‘8€½²Dòs#£]½‚ ìØ¹Ål6Åb‰Î޳ë74«Õªƒo{è‘û¦§6»E§Ó^žö:xÜ?={ǧn #Z­šaX­V35é_·¾yhàœÓeŸš ¬]×äŸT*•E74.~*©ýtw>GšÌ†X4¾íºMÿ,C³Ñh¬´Ì-Š¢ÓeõøZ74/j÷ùícÏ~å¯>Óq¶´ÌÍqM3¡€a88.v»X–eYÇ1…§i–㸊ÊõBûò‹oT×T$âÉõZ&'ýZ­F’$^k2V½ë®,b!‰Ä Bqð­ã¢Ñ¸^¯;r¨ @ IŸ}ꥻ¶Üpãer¿Æ0¬o|êà£M¹çþ÷ÿóׯþù-ž¾uôoÿþk}g‡fÁh$._ïtÚŒ‹ Ry¹ûϼ²ûÆí¢(õt÷>xâö;oEéèá6ž\.{wWߺõkÎ?LA ˆÙlŽå¸p8zêä™]7l{öé×›jþÙ3½,Ëjµšp8ÚÜÜàõú ÝÄ2™Œ“Ó’²Ù\ßÙÁ›×½ðü«7­»eﮫœXz½îŽ;oæA¡ÀÍIR¹l†át*˜˜˜~è‘{íöË烴±©vmk KÖÖVÖÖWÇãÉ [œEöûŸx~ÃÆ–šºÊé©€R©$”Š%Þ0{o»¡¾¡Úë/*vª”ÊꚊP(²uûÏȘV«©­¯ZôˆŠ$I6¶„‚³Ùˆ ÈíwÝŒ¡ÈCß #pm]•(Š/˜-&Ù Oiy±Åj^âq,ãšæºÙÙ0ðÍk ü¡‡ïÓë/ÉôeËf·ØÊôµ IDATì–ùƒ€ÓLZZæ–.—PVîX,¦ùy ›ê–®Çî°ÚV@Mm%`ýÆ€N¯O¸Ä-}Ázoé ššëf‹é2tݲ‰%JÍ¥®báò«ò€+®gµ°²ª-‹Ô%'–Qï¼7F’$ÍÏù ÓKt=Œ¦²ÁUñ…¹h=òÈËjÀÒ³DUÖ’E‹\¦Aäþ%A”DQDIEIyI’„¹´0_jrölžJ2l0è’$Q’$ Hò£ "'Jâ\µ'™‰œ£™,@”I/·6?æïdÉøÄLO&±¾9ŽE‘ã¸3gÎ$)Ÿó™Ï”ÓK½%Dadâ¸$‰ü»}"I’( 4“œ“$I’Dñ£zÆãñìß¿_þ8vì˜(ЧNzóÍ7e’¿ŒKM“t E¼Àð—ÉG%IR+ ™| QÁ Z;ËQ92I(4éÔ6ާ“¯OåÂZ•Y«SÙÙñ€„À( £n{C"3ÓsîM‡¹Ê u 0æ›é2éŠÔJÇ33lžÀÕcþNʼ¾þŽË¡ŸÂ( –œ*/j˜éÑ©/JcxüñÇÝnwii©^¯饗6oÞìõzív;EQ.—ëôéÓŸýìgåmç#…aÔ7Ó¡JÁ¦‚}zE0ƒÎNøx '|,G]·ö¡%ÚPVVvöìÙšššp8,ÿŒ?NÓ4 éTjÕw¯dÆ‚aTxF‡a´ÈZgÔ:qTiÑ»Z§Ve†!D’D®t˜+• ]ŽŒ»íM8¦C¢goQ’ Ö¨ÌOÃ0JÑY‹¡DAàh&ë0W "/ˆÁnGÇ3K•ÓR}X¥ÀÕ‡ã㪘˜éѪ-YaSSSEEÅöíÛ+**(ŠÚºukyy¹N§“™L¦íÛ·ËGÁE&A,I>°$$à²ÔH’d1”¸íMK·arrA×^{mîí!f³9*•J–e¯ˆˤs™ÞÌúáG³ôš9µÎb(±J~µ©ñn@$1á²ÖÜŽ&·£)·›+ùÁ¹Ö^N~uo·cÇŽó3+*.ô¼S}ùõÒ$÷ŒËZ·‚6ÔÖÖÊÇkeÜtÓMÙÀ¡®º«H#XŽd9òÝÙBµ‚úWq'F*”>Özh&'EzÇUËu¹‚6,Zä@€¤Ó*Báùså…@«¶Š¢€¡ ÀB§˜Ë­çüŽJ¥RZ­vi·¼)\­^Ø9êÂÂÿñxÜl6³,˲¬F£Y¢Ù—ÉUä"ZÏÄÓ~³¾8žžÑªL©lE0ʔ̘Z)¥¹Õ žãi®BL£4…ããF]ÇS‚ ‡¡D<í/wµúCƒj¥Á¤/V:’Ψ}0æÕª­‘„Ïnª`8RE%¡£˜L(6æ°TµÎ`l´ÈV·ZÜÊä"³QOcåîHb‚åi Åí¦Ê‹©°«««¤¤Äï÷ ‚ÐÔÔäñxÝn·ßï_³fMÿúõë/Ý›}zzº»»»ªªÊl6Ë|r¹\MMM²¢ºk×®ygA›ŒEÒ©™àxF¥4pm3•ÂCE¶ú@xØ uŒLœ¨(^ϰyït»ÓRHægQ–£pLÉò´Qç „‡™|$œðéTSŠ’(I #8¦´›«F&ŽÛLå’$©}:IdfU ]$1AP"=cÔ¹Šlõ1d:“‹D>BVËþШLz­§’²Vx‘†ÃáH$"‡±ÌÎÎær¹d2955e2™öïßÃðÄÄći…’’ŸÏwîÜ9½^ŸN§ ƒËå¢iº»»Aòòòp8üñKETïŸ ZG(>fÐ:Ò¹ˆËZKà % LN£4É;.xž…  R03l¾ØÞNø8žVƒÎ)ëö,O "¢Š@x¨¦t«wêôšª0Œ¸&-/je9R¥4¨•ÆxÚ/4Üñ”ŸÀWmÍËB<×i¬3=6óÅz(++3›Í§¢¢B£ÑÈr¹œÉdÊf³­­­ãããKh…««Õêv»S©Tee¥óÂívÛl¶ÎÎÎl6[VV¶ÊÅr‚$3³kªoºOKM穤۱†`ÃQ6hßÛT˜ÉG/ÒžtA¸Ja‚W\Ï*Æ)^AU‹ñN·«jèZ¡SAäYŽº#ªS[uj+Ï3óR¤ŠÐ/¼k.Ñ­‚å¨U¹ËŠëY­¬¬ªE‹² ]Ë&†îQhiÄS~Ùßäæ_Ì•ËQDh¡ÏQI­Ê,IâLôœËZ/ %ÇÓ+ë¨üȪü~¿$I²èêêêééé@ °eË–…Ëä""ÃäF€$áv'á*V`êKN¬S£R¹°^cOeƒ8¦¢è´€ŠÐeòQÆ4*Åd V`*Ú¬Qš2ù¨ ò“EQ #â)CÅ®Xj:“ª•F‹ÁÈ-÷d°WM# ŸÍT!ˆÇ3*BÇrT(6F1Y£ÎIL”8× ðêxÉÎ’‰™Èp}ùõþðÓRí –:›Á'ããã² ?33#I’Ïç£(*Ÿf›Î’¿ú-šÌ0ÜMÜ{ÿ îµ’%’NE¾™ÈH2Œ$&ñt ÈZ—H ZÇlôœÅPbÐ:Bñq«± QŠÎPt†¤ÓòÒ)Ž©h&'k…y*Œyå7l&E\Ö KœÍñ´Ôß ( O&ƒ1¯ŠÐçȸ\$“‹ÚŒå­ƒãééÐ “­ÞKÙBàŽgƒ!D"¸º@Óôôô4Žã{÷XÄà̉À–a)™ÿ8µB§µ&”wZj™@MÉV®VHb‰½IM0DàEpÍæ´*³ÅP’ÍÇ8žF\–БaŠÎp<£S[ááê’-ã.YÔklJ…Î;ÝÞX¹‹aI×è4¶x: ¯ m rî“‚ÒÒRÙSkKK‹Åb9{ölww÷–-[οRá°³_ÿ¼Ä}™ˆõaK:jBO³Y¡DN>E (ÅÌíÇ€! ˆC4›£ÙœlGЪÍr¾AëT*ty* ¨^cMeCF­S¾—ü2­roECq ÅÅ1B.˜§3G%VG9MNËk0Œ0©U[V¶mf¾žËVð#«2XYï#4 GǪëÝ€,]¼Èu6üdÇ„6h¯”_öjiû+®Ç¸z=¼‚ªŒ«±¤óq:^ó‡‡ÎÏÌ‘‰y‹ÃÒW^`…+R¦˜@dX~kOÌôPLvµ¹¯¯o>nê…C’Ä©`ßùù GÊ2î…Àãñ=z4—Ëuww:::½½½ï¼óI’«>¸èŠúf9Jy%‘W+¡ø˜¼\“§ROÃ,J"ÁG‹’¨U™‚(:A°WY %@’xž™zH:£D2DŒçYFŒZ'Åd% !0*ˆ|mé¶@dX’D‚!Ùêãi¿wú´E_‚¡ ÊìÊ?2šÍùfºujËthP§¶T¹7¯XK§™ õÊK:åE­ÓË?þxMMÏçÓétF£ñðáÃkÖ¬ñù|f³9‹ÕÔÔôööîÙ³çÃbXD“SÙ||:4 œFeư“Ämo¢˜¬Y_L1Y‡¥ † ­Ê‚"˜¼#o{‡aD¶í - Á*BC0Ñy*E39Qq”À1•ÓRƒÀX]éöñÀ™™0ëÝ¥Î5¡¥ýz£ Plo²ËbÉI%¡[SuSŽJV¯§Ù¼©d Án{“ÓR½âó²•Ùíh’$Ñ qLF³"såBkõÖ­[ E (**bY¶¤¤D«ÕZ­V­V›Édl6›ßïŸÊ~¾™»¦tŠàøŒA°2×Ú•$p5Ç3ª€ X>7ÀñÔÒmhhhÉ´uëVÀîÝ» EUU˲ ÃJ®ÀÈ~iµByÞšÿ¿4>p Š` wlæÈ¹ƒÅr¦|»• pµ rów7h<Ïȳ<-¿ÂÞgocVrF ›#Èû¼ø¯,óê!Y Ö#©\€€â’òL ’٠ƀÎßåüÌ=¯Î)J‚|™ü¤²f½@䢖h„%ÉÅIv®I0ü}¸èݯh­Pþ…-ö«â ¾ßVÃêbÑn«UMÓ …bé`«Õ€¬Š¢(9ÌçG¹|Za:–ÿ‹’Î…I:E3Ù™ éT6EA6~¦saAä³d "ŸÈÌÌå \49Űùx:s<-J¢üC¤˜lŽJfòÑ<•äVž“Ò¹p <ôî}#«ºù|™fzhü ™™˜éIdf.²Â@ Ëåü~?EQ@@’$¿ßŸÏçåõ;¿ßI-¡Pè7Þ˜˜˜…B>Ÿ/ ÉŠ!I’‡Þ·oßÊ‚g­²ŒŠá˜r:4 Q™Æ¦;1,©"ty*%/*p†cN«¡,œðY ¥þð /°ÉÌ옿C•C‰?<¤U™qŒ(pu < È( åE­¡Ø¨±G)1”ðÍtÙê ZÍæ"‰ šÉùÃC&}QEÑ%ÙrÉr´ÅP’§’€T6$k…&]Ñ ê™O?~\¯×G"Ç ‚èì쬨¨%wLJ††‚Áà®]»ä~ ^ü³È “ɤV«å ÅÑhÔf³9ŽãN:ÅqœF£I$ò†°ÕºûJˆ¥& ±Ô´VmMgÕY«e »W¿+Ý+òdR¯±ë56†Ó¹H™km(>F³9ÊŒ" ÆJÒéÉÙ¾å‚ÀG’&]Q–ŒuN€$¡§˜ Š`¨$jT&µÒ(ß Cp¡7ë‹îÓZ]`18ƒcÊp|\©ÐMÌô¬,(†½§ßTWW›ÍfF£Õjq¯ªª*))I&“jµ:›Í®Y³F©TÎoô[XðâŸENà8®V«R©”ü Õjív{WW—ÍfS(«{÷•K«¶ÈGí,KlY1½w±œýÛæn c®æƤ/2鋜Àµ.€<ÅÓ~³Þ (¶7žß€Kúâ¨.Ù²ºnܸ,8ïUWWÞük¡^v‰ ·a!äUÂK´zùÄ’¤Ž—Vëö0Bï3ÎË¿ ˆü.X/C=«Õ€•Uµh†­†ÒKK¬ù¨°úZaˆUÀ'„Xdž,t\+!ÖÏúø/~ö;ßød,– iæõWßÎçÉQ¯e¹¶¿{ü±hœ$©B÷°<á]Ä/ù³/þéµ×_}k]ë†a7n^÷ãþìæ=»¼^ŸF£þýïž»ûÞÛªªË =XÀ2ˆeµ™ŸüÝsŸ~à.š¢[Ö5Åc‰ÿlCSJ­ªª.×ëµÇgÒ™B÷°³uCK¡¿ ¸(by¦NÉ‹eð‘XW{ëù1Q'Vmé¶Bp¹Í P VbP VˆU@XˆU@bpmëLÇÙD"uð­£òÇŽönšfV\["ž)Œå'ƒX¡P¤¯wPÄñ±Éɉi€×3ÞÝÕ7;ê=;(Šâ„ojxÐ35é?ÛÝOÓŒ$I^ϸß?Ë0¬×3ÞÓÝÏó|:•é>ÓÇ0s¤apàÜÌLðÙ§_óú†=rþÓ¿ÿәγ±X"GÂ1Q=çÆä¯ÆÇ&ÇÇ&g:ÏvéÍçIA{ºû“‰ Ÿ#»:{ûû†^yéÍÞ³ƒ’$I’Ôß7‹% Cûñùîw¿;99™§“EÅïíîêûÅO›Ï“$E=÷ì+'Ot»]ÿß?ýHÄÿ·ÿ ΆQ}ýÕƒžs£ÿño?CP¤£½›¢™}¯¼ùÎÛÇMfã?}ûEzžüÝó Ö•—tŸéS*‰_ÿâIßø$Ër¾©ªêŠçþðʃÝxóõw(’þã³/—U”¼ñÚÛãc µ€7_;øÛß<»acË׿öz½îϾ|ݎͯí{ë÷¿{îæ=»¾ùõÿW’$ФÛNtLNLñ<ßv¢³»«ïé'ž¿áÆJ凞dšž è ïù—&I*ÊÄb‰ùL–åⱄZ£.Pd¹èëñîÚµkñµÂÎöžÏ>|ï¦Í­?ÿéãõû?Å㉱±‰b·ëÜÈè¯÷`:tðx}CJõÞùîÏéÁ—þôš(JþéÙtêÈ?üó7™L¶íDG8›t8¬ýõ/~ùóß<7ìíëèöOUU—íÑ/tœîN&S›·¬?Óy¶¿oxíº¦»·K ŽJŸ<ÑCP<ž,))Ò鵞sã Ãd2Y@(1 ~ÿLCcm$õÉÁÌ5ÍÑ#mV«™¦•Š#k[×ôtõÙ¶t*sßgî$ECË~Þu÷Þß>öì_õ[·ìÝýëÿûäk>pË­»•J@@©$PÅ1LAà0 +•A„’¸ÿ»~ò£Ÿ?zz÷ ×J‚!‚P´èœ •JåWÿê‘Ꚋ»îÙû¥Ï}ã±_>å.)â8n~F±XÍÿð÷ߟðM­_ß\YUæ*rÈ_ñ¼JgN;Çq~ÿì—?ÿÍ ›Ö ‚@ÓŒÓi/)-"Iêó=Úß?Œã8‚ 8Ž}î ´ŸêŠFb&Ó{.b…BoÐ'IEÃáMÓ¡€aX’¤™@PŽãaF„¦–å€Ôj¥Z­¸é–ë½ð(Šäód2™N&S<Ϩ³4–™â’"Žþèßþç;ßÿ–^ÿÁ8}æ¯þð§__†6LNúN»B1çqeÔëCQ´¼b.Òâ©“u Õ Y[À°ÂÈ—z½î_ÿíÕêE¼Ëýð?þùò´¡¬ì}Ç»«kÞHgÛu› Ô¹,N¬ŽÓÝ©TúJk빑Ñ€]¸yÏ®…±-–"–Óe7õ….+à‚Ä©ÅÜ}-N¬’ÒâB°úZáï÷Üÿùñ/S© EѦVaÎä£@$–CZŠ¢§’F E0³ÞÍpd0êÕ©­™|´ØV?óX ¥rð£pÂWU¼‘áHIe_ÜÁبAëˆ%§…&“‹ZMeñ”¿ÄÙ<=ç4Wã£f½;šœÂ1BEèSÙŽ)aѨÌ9*¡ÀTY2fÔºXž’„ 8ÇÓ8¦Œ§ü·£)ó^5A\/ŠXF:::èØøôôtqq1Š¢4M755íܹ3ßu×]ûöí-**‚ Èét^<±sU rÿ7¦}q¥R)k:A£Ñøµ¯}­²²‚ @ ÐÛÛ»iÓ&›Ívñ U+8¦Ôª-4›'pu8>ŠU¹7c^9ŠÍd­Æ9—ѪЪ,n{Ç3(JhU½ÖŽ"8Ãæå¯&fzÌ7Š` \=9Ûë0W…6c9ÃæaÖ¨L(ªP:Ž£Cñ1­Ê’¤‚FKVÇ逤"k/pþРÕXæ –¹Ö¸æ¡`ÉQI›± C Aäh./{¨Ç1e&›÷V¾«–kÑŽKû+v]È•’$¥’)ƒÑ°tL¢ A*:?EŽJœ`<™ ⡾à@p9*¹¬¨q4› F½.kíùòåUŒ1ç…+O+Ô aFì/¶Xm«ò`‚ÓE=Î[Œ%˪Y¯±-wâ¬*Ù ®1ÀËh€®`Œ9ŽÎÓ)Ò)%[4:ÙêB¶|Înhh(X.°å+­+‘±&f{´*ËüàßøÆ7><00pÛm·%“IQ7mÚt‰b³ŒMMM9Îd2ɲ¬Ñhôz½UUUccc*• Ã0ÇS©Ô¶m—qWÆ$·‚2å®ÖéЀÃá8zôèÙ³gív;EQ'Ož¤(ª³óRE¿I$Û¶mëîîŽÇã¢(vuuI’Ô××—ËåR©I’gΜ¹± ¸|Z¡ŠÐokþÌæF¸ï¾ûPEdÇŽ†av‰ZUU…ãøm·Ý6>>^QQ¡ÓéNŸ>½k×®ááaƒÁ IRuuõÔÔTaD?©Ä¢™\&ÿ¾í{<8‘â@2«ßÊp|Ün®ÌÕõn¸<on­a„teí\ˆJðUµE©Åo¾r ]‘­º¢cB_dw/ûM ˜Ç bB¯äUØë9 Vʋ֣ÖÛÛk³ÙÂá0 ÃÕÕÕ*Õœîæñx EYYÙj=[&“9{ö¬B¡`Æf³E"‘ÊÊJùµ844´eË–ÞÞ^‹Å‹Å0 ›œœlii‰Çã555^¯Çqžç›››åÖF"›ÍF7nÜx©õÙ«pˆ¥¦!zå•ÇF'9ŽÁårÙl¶={öLOO{<žÑÑQƒÁPZZj4+++¿øÅ/^LCu:Ýnïëë{à¾÷½ï}ç;ß9zô¨Õj%"ŸÏ ³Ùìt:%I***â8.‹mݺõùçŸ/))w¹\}}}<Ïïß¿ÿË_þòO<ñùÏÞëõ¶´ö¸^1Z¡^ck¬¼¡®¶I„¢¢"£ÑXSSS]]m·Û4M †7VVVšL&‹ÅRZZzñgÒƒÁàÙ³gGGGG}}}GGA …Âl6ûýþáááP(422B’¤ÑhÔh4===;wîaÏž= …B¶ƒlÛ¶m`` ¬¬lppÐjµp‰°ì%t>²¶ærŸHdf 'EQApGMÓ†Ñ4Ms äŽãä­rA‚ 2Ÿ†a˜aù•:_¶€¥á™l»pá}…K:4“»üšW$1!¯Ô²d@q`þ¿œ€ààhèw[Ë-hùyé…9­ðZÔ †‚VxÕk…‡:×k¬¥ö 4)Â0l2™€,­×ÖÖæóy£Ñ ËËËWÑ^šË寯Æ**æ\t@”J¥$I’wž:uª©©I§Ó®];iöIDATHð Ö %I ˜ìÓO>d4EQ Z­Öl68p€eÙ5kÖŒŒŒ|ÿûß_ņªÕêT*ÕÓÓ3O¬D"QQQáõz£Ñ(Ïó===»ví*Œè'˜XÅlÆ2#1•K³i4š‰‰‰µk×¢(‰DAP«Õ.—ë|$¥e@Á`€ H«Õ"âóùÊËËKKKS©Tiié¾}ûvîÜYÎO8±ŠÖšêßÛù5¿óØá˜ÛŽWSS³êm]»v­œèïïß¹s§L\™OŸúÔ§VÑ[ÀÇ@¬E+Lå Õ%w¹5/¼@oV|ÒW ¯2­ðÿ%ØV B ]IEND®B`‚ivy-2.4.0-rc1/doc/images/searched.gif000066400000000000000000000003451226750426600173020ustar00rootroot00000000000000GIF89aÄ©²Æ‹–«LdUl‡h|•2Nnz™»ž«º©µÂäèì Z˜ h0r¡A|¤Q†¨_Ž«‰©¾i”­Õóÿëúÿ–ºÁžÂÃüÿÿ³ÚÇÁëÊÿÿÿ!ù,b`&ŽdIÅ€˜e $Ù ¢Ä:œ­€ Ê#W¡("›¨ ™2L'K0±ø¨VB Xm»™H„ÅŠPÆä‡Z¡ðõ\ƒAôU—_ì ýÚ‡'³cß}´_ ¢ÿ¼×(¡1ZUĘ>Û)¹i«0èAHç ±°G|ÿˆ˜‘ëç‘Ë™_Õ}ï¹naPIEND®B`‚ivy-2.4.0-rc1/doc/images/xooki-edit-small.png000066400000000000000000000726771226750426600207460ustar00rootroot00000000000000‰PNG  IHDRÝ4æ~sgAMA± üa pHYsttÞfxuaIDATx^í}xTUú~tíºêºº?Wwí®…uí®ÿÕUwÕµw¬6DЍ‘&½)˜HGjBh¡&!! i¡Cè„’:Éüß™/|ν3sg25ùîssŸ3÷~§½çÌ;'ç¾ç;§¼ÖþÒ(9A@'jjj.ºè¢‹/¾ø´¨Ò²òÃ(ÚÙgo‹:‡Êˆ§8N=õT[uÙïN=Õû¿ûÝï¢ìöêšSN=å4<Åa¬Ç ôÓS¢jìQ'`ß¾}0ÍW/'xYNA@ ¦íþôQ¯›?éyÅ•ÍÞþ"¶çÕÍ[4mͿ̬[Fµüæo]GÝߢËåß ýø/žmÑù™/4ÿrà;¯}úH³ŽÏ ûæÃïÍs­Ïûß'g>ùɹ¯´½øÅ6>ÖöìÇ[NqqmüÉE¸ÿòG¿æ½³pEw´§¸É§WO·ùýï]Õ¤íEMÛ]H)ØóFÔõ²‚s5nsá£-¢äA ä<üvTó.—¿ßå¢K?¶Ën/¶Û/yáÎ7ÚÔddv“Ñ;ßìð;pëKŸþ.#g÷šu[ìÇìu›l×÷/‡ßùúç·ìvë‘µºïÓ¨V]íù°Cʸa/u<q›}ùgdñè[QOõ}xöæ^¸"Œ;¸â©“_l]ËŠ¦O(õé3­¢¾ê÷`ãw^{³ã)w<ÓËmO£êàtdê‚fÁÀÌÆµ¼Œ[m¾½›«'A@B‹À’ô茼ñ½~ÛѨWR£o“ºüZÀåY™=µU¯+³ÖÏŽ]šõÛâe{JíÛKª÷–Ú§.X^]coۧŧß_—’7öiMŸ/ýâ« ]»oiÓ¶¤Ý§›ÆŒI+š‹¸HR›¼6ÿÀîgq¥”2?ÅÞs¶iùªOUˆ(nîÆ¸ s=×tØòy׿üáúíGz  3T§HÁÀL͵¼ mHî‚€ ¨Ä®ˆS½óÇwÆ}11ùÝ‘Éi¹ãœì9nJüê_.Û³eùޏ&þ2sì¡cö{½^NX5q+Ž”e=ùTÅGŸkÑ2½Û7¸ƒûޏYc2vžýÌŒUoänl>3íu„cÒâ>žR\ýffþýãi¸ÒGŠKO-Xõç÷oîý§¶Ã£.oÇOSs'}7j̺í?ú±Ý¾wÈÂიÚkôˆe«GkÕ16÷CoÕ²ð²|A ‹-J’¾¹´UôJœ9ÛKÚÿ0wežcÖ‚ø1%gÜ¿®ÊÛtd|lÂĹË'Î]—˜¿yw͇=ßkwœ—+Ë+3ÿóhÙëïnüFz·'â®™øÃò¸7G>ØwÎsÓ’šöó<Â?¬ˆMYs/G=1ø–§D=9ØÈ˸“¿zûéÿéuó}}ŒOïyú?¦Ä¬Þ>{vV¿ÆÃ:÷:,%w¬G^î<àa2 /‡c”2 ‚XlEú°vrKìöÃvû'1+É Aíöei^NÍ?`|JÖÆC13Óf/ÎýefÜÌe…9›Êßÿæƒv®[œm/³¯¼óß{Ÿi’üÖû™=·÷‰—6|;lÙÚ)êˆxäÂùƒç>0bá|#·¾?jé/ÿxéѸ"¬—É~þ¼×úláeéü‚€ ¦/wžœ;a“g·i™ûíãqïYž;Üš½azÑ©« v¾|ZšmäÄ}Æ%¯ÙTÙ¢[«ÏÀËÎÉܤGžÈêÔŠ#Ç®m´}nÂÒœ“FĽgÆÜÛùÆÞ3bLGÄ4*óQSŸ.IsüŠœwÛÝï~?){ó„AÊÇËÓô^Óî(Å K\½q¿½ûŒ-8óvž@%)kJÛþ7uu{ÿq[¿Y÷EŸéÓ&ÿÒñ»©õYÙwü–wº·/ÃÆFܧáijÎú›!$©=ÀÚÂËÒ±A ²‹5í|ÆÛ]Îúà›sq"€t‚X¿vïçCîé8øº–ßžßò»?¼Ûó­¾»èÃï.ø çï[÷¾Í»]Äöj÷ƒó´Y×s›u=OÍZx9²{¤”^Ü °2{Z»ï}>䮯†ßWŸ€’yŒúÔšRA !`³U~øÝU‡ÞÓyØ=õ¾zÏMõ¦òÂËõ¦)¥"‚@ÃB`ÌÌÖíÞòŰ~1ìž6ýnÈ\7·ÞÔ_x¹Þ4¥TDh@>²ç£Þ×b° R5úýÍó“«éêÇ!¼\?ÚQj!4,ÆþÖ®ýÀ`Ã9^þg»Ÿµ¤vYG=Bx¹4¢TAhXÔTW܇ËRÆùÙ÷·L]è'×Cx¹~´£ÔB¨çälXœ˜9yËÎlÔsaÊŸ~“2¦2>ð÷™‹¿S!(-;ø.GnÝ­òrµŸ©º$‰tV­Z5yò䪪*„=&›¡C‡rîÙk²fþ»sßþ²#%;ÓR«On@ÓÔ˜¸=æeÊû‘ÛE¤ä‚@8 ¼fÚ'}¯wÒ±súb¨“”Ô\À“ão1dŽhy†¼ìfDiÚlF{˜M˜06TG¯¦)»óý‡zé¬[Wû¯Ššˆ1qÜ)))ùûßÿþé§Ÿ"œ˜‘õ~÷ïgL›ùkÔU©Q/‹úó nÌìüõºñ#¶8ü?S`:ö8³ð¬Åžú·¢¨+Š¢®ÌŒºbÙµ7eÅ ÙžºBmTtl4PGÖ2ˆŽÐoˆ;|8P² ¯AÍ=Ç<6uA÷6ýoTÇË4›‚†T³ÌáSlJR'^F~ÉÉÉ×\s Ñ"Õ¶êI“&ûŠ‹®í˜­]âþÝwßë³Ï>Kö^x!>>úè£ÄטÀMu³î>ø€,[µjÅ÷ùå—&Mšà㫯¾J7gÍšEf—_~9ݹ⊿jCé[U‹VyÎY¼âš]Öì±ó¿|åœûœûÎ÷ç5ýáÜGçyÿÖ¨[S¢®^}ÞÕóO¹ ¥û[Ù³&:þ á3Sƒ£…š}è EP8P²£ÃÀ[?î}n‚ÁѬ–£g¼ì0ðöHÍw^FÍþõ¯ ’C·nÛ–—››š’¢MVÀ¦wïÞ¸‰§çœs?½ä’Kž8qbÇŽ8÷Üsa9zôèòòrþøÇ?’eÛ¶mxûí·þä“O’’’7nŒ;ªûí·üå/Á£SN9…ìÁï´kçØnKãåϺö|úí–õéÝýªï9÷Ùë.¿ýܳ.»óü&Oÿ¾ËK~5è‚W¾8ç•EgÜ>ýÌ{לró¼¨ëÖœ~í’¿þuþ%×-ºí†Œv/&vj?Æárìœpâ°2šjŽôo‹”?´>º·ýÀ[1MѦÿ ‹Wý”²æ×“UÌŽñò'ýþ¶igVhËY÷Ü}äedŒáð\@¬‡ëáÇwlß^°vmZzú²¥K,Xн{·ûîs8ßãYˆ?ÿùÏDšï¾û.3gÎDøÿþïÿ˜£iœ‹›[¶lyæég@²gŸ}6îlÚ´éÁD /ïÄf-O=õî}#p饗RQ~ÿûߟyæ™c,¯ò2ÂGK\¾,vñÒ%óŒúSÚ%ürZÓf—vyøÂ×.;ÿš[®¸ÿ¨F^öö‡ü Ûy/>÷ùçü'þÌû;ãQwfžzǪ́ۓ¢nXsÚ_–ÿ÷o}.¿--ºWæ¨!¥s)|¸áhPsÝÛLR&·g´êuxùs¼ârObæÄvßßLþäxÔŒwƒ[wå†>i¹³”î·^*_x©WVV‚d™”=Z\¼kcaaffæŠåËccc¡”˜>}.ˆh—k®¹Ö”—Ák°¹é¦›öïßO“È0»í¶Û´Ôˆ—i *W\qËóçÏ_´hÍŠ_ âî¯~±i~Ô¥¢þ6è/Í>¸¨Ó»þâíóº?÷ç–ÿøÃ {ý5—ÞÆé×?r^#Üisö/|ý?gÒþ÷Íæœõßõ§Ý~ÓiƒæžwÓˆ3O9õ–´G¯]Ú¥Cþ¸1»wÍÛ]¼š*kÊÎÂËÖ»¦X F¾z¯Óáò­¿»zEÆÄ÷¾¹´M¿qBç h ¥ûý-¯hyXA·}Ϻw¾¹dBlÇ„”1K3Æ–Wœ4Œ3-ª¼üÀ:tˆRÄ‹¸ý{÷€”³23W¬˜7oÞ´iS££cFŒñÈ#̘1ƒÌÚ´iÒ|çw0”Æ,i¼œ‘‘Aób/^¼?ü±þô§?! 1f™À@{éÒ¥˜‰á…pg÷îÝDÇ]tSÿÔ©S‘~ž|òIWIÃü kæd|ôlì ÷nŽú˪¨ÍÿÃÃq§?tæ}Ý.ú¸Åe-¾¾¤ù»W´¿û´»Î8ã–Ë/¼õî›^¼ë’'øÝUçŸyÿ{x¼Õå¯w<ûÙÝQ·9ýÎ]Q×4¾cÎð{çL½?zp£Âµ±¦ù /‡ÕF ÔŒœúعǘG÷ÜZ]ãø4oãÒNƒïÄ ÆÇ}®kÙë¯â:†O½¶íÊ}ó«sðƒ – þ8£••²yÍË”èÍ7ßLòŠ Œj7oÞœŸ›·"1œû믿Ž;vذ¡ýû÷u~ñÅdyÕUWñ´>¶hÑSSSi L¦ hü{ÞyçÑûï¿×½{±õ­ýµ×^cKLmÓd—¡£Œ  a³?þØ /ó‹¸ {uÎä! ß½?)ꢢFÏŠjTôÇk6GÝ<ÿÌ»~÷â3šsÎS ÏynÀ9o~zÞ»¯ž×üÎs¾êóÇ—o¾ìæW5ùãE¯þû”û_¾öÿú¿_†=úó7Äÿüȸ~wŒîìxù š…—­tJ±|@ ªª¢¬ü(®>Ä P”¢í›wdMŠÿòÓþ7wt»Í²tÏ^ÆË·eË–¡&¶êêClÞ¼%7'wåÊ•‹ Š?~üðá#0¤íÚµëûï¿ÿÄO=¹ªùÿûÿO› 0µt“?rocE½sKÁ†­3‹ú O˜Ùyé¿î˜{Æ•K¢®ÛuíªîÈúËæS¯ÌºlKÔeßFý{bÔÛ£®Õh^Ôc£î\õ÷‘Qÿ˜ÓëÎ…³þ½$ú‘ݯØã•Gï9_!åõ~I¶A!°µ8wú¢ž¿-GE[V¦äLOÍ™1>¶CÜŠ!s‡Ì]1$vù ß–}u%ÐÒMŒû||\ÇÜK]A´k߯_õ@jˆâ朽´ÿ¼äánpž±¸×œ“S˜—4ü»è§²×/Ì*˜ßiÈ]ÝG=8tJ3‹-e•—‘Ë D£Ô±Rcû¶­ëÖ¥§§/Y²¤ YÅÈ‘£0R)C)¹ˆ¿þõ¯ÌË4AqÊ©§Ø¿oÒ8I¹ØZ,³Û—§M)JžUÔuXÊŠñ…ëãùWH-’ð²ÅN)f‚€Rrf´üö/í4úð»+{ŽþYîÞ¿ñ­.çãÎÇ}¯ÃlÆû=/㙓öØœ_¸ î2\%øÃ¯ï# Rãæ€ãã÷Þëqéácâ2Û‹óßïùg5‘Úþã³·L[ô· ê/SêFàŠw};wí,ÜPR^ºdI\\Ü”)SF3`À÷Ý»wïСf„ßxã 2¦‘,I•q¼ùÆL”\bo™×½=’¥™k7Þx£E^62;O‰¸ð»€Üt™‰·Í#ö‚€  !‘÷iÿ›: ¹£çèGÕGÙ.\92fö'?Ïi‹ç…+G œðJ§ÁwA³ña¯+÷ÚfŠä'}oè<Ôá©Ö5sq }¬ Ð’B§Ëº¸ƒLùeA7ðï ÿvN/wHþ:`_VqtÆ¢o«««àÁcâÜÏ­4¨U^æÁrVVÞà!é]»v:Þõee&%&B€1uê/cÆD<¨gÏžŸþyëÖ­›7oŽ—x;wf^8p ÑÜêÕÑ‚‰XK é_wÝu”fœ}ÈQðêÑO=õT\i´ëm™© (–Œ—­ôH±Ü#^†~¹]ÿ¿Ï:Ùár»ïÿ>`ü+3¾Å –l÷ýMß ÏsX«ÝLf.émLvUîll xœ‚{ =îk¿–¬k—z߃¹ˆ..vÝî8èvrqç¤æÚt°JôlUÒOÂÉo Ènb|çmÅyNE˜ËÃk^6l–ó=zcptrR¤3¦O;nè!ß}÷Hù£>jÖ¬Ö}€±B„‰I-œ±hf²¶“¬Xí¾ý0…B¼ YˆÍfcc#ƒképú*/« k:‘mZì}ûöASH/ ãuG¼Ü¶ÿ 2/Z队ä£U¯«æ% íþÃC˜µ¨u`t|÷?,ÄèÕ˜uÿq/u|»s\|/S*>bã„Qðòqj†ïÐ]û6hélßçðAz‚‘i°|ÏG}®9zlÿ”ù_~Ðór|ì2â¾Îމ{P¼7»œç f?òr³·ÞÊÉË‡ç ¼ëKIIY¸`–‡8HyèP2æs±J‰—_~+­±®oÍš5ÄJ¸òœÀþó¾ ßÇš½;vh<þüóϳÁ 7ÜpàÀª”Xx‚É ¨8;V„Ÿ~úéøˆ+ÄË0 ¼~¤0 <˜Ó§RMŸ>ýâ‹/&ËóÏ?ÿûï¿ç²©¼|á… RŒd—.]°4‘bA:›ë²«?´RGLLŒðrÝ¿’‚ @¤çýÖ¶ÿ7ôŠvh è<éµOú^‡wkãhL“4†u²äµxa¨bXV~Þ6”e)Ž¡.Ük ñ„U?ázœÜOLq`>yÞWZCL[øµÓ‰·ét|ÇwÑOÃrÍúmûÝH? ànø m?à‡šÏSsÊ^—GŽ9`À€Í›6¥®Z•°hÑìÙ³ñ®ü…w} *¬–~ï½÷à¹ëA q>묳T¶¢EÒ8˜à.\Hw0WÀO×®]ËåcF†Í'à é4”Ëü? Ë—/çsæÌÏ/£HPÑñSøNbæe÷ÈÓ§ùhÌËôˆæÊq ^Æbã? ­Ø ®<(;/ ³uG`MÁ¼÷û¤Ïu$;«²UbÆàÝo.Á«¶i ºáNÛþ7ƒþ”]¦œ¼eRüIs»óWŽúôûFàÊ/‡Ýë `§[g8ÜøæÇGHŸ˜g1”>9‘{@¯ÈK«æIpŸwNqΊÜÛ®ÿx? K[uUÛ~71ûC0—’=Ý#–x™8…F—P¿Ü¸qAAÖw`ZyÂø ?Œù ¤üõ×_öÙg-[¶|ýõן{î9Œˆ1Dýé§ŸÜó2³› é`ä:ƒéRåh<ÅBp~Ú·oßÄÄDþˆ‚i¼|õÕWÓSJV»`1‹zS ãçÇ/•«¥â,FG¬nݺ©¿4øÝ^öØÅ@°ŽÀÓ?€÷"¶ÿ°×ÕÕÕ¶¶˜ºÛ 7ç'ÄŽS/ƒ:Á¹j]GÜÕ('Þï9¼pºvS"Ì6nOÿ¨ÏÕê–(ļolJætvîY(N³3ËΉ÷b6yÜoí 6¯ü çe˜èÀBD*C¯è§<ÖÔ/)ó¤êåW\•—“C‹­ú)fÐÀ=zôèÔ©Tq`€”ÿûßÿÒz&eŠ«—AñLpÐ;_{íµÄ¼˜L€1fø)a!&1þð‡?МÜ{bêÖ"/¿ùæ›ðmDó!ħwÝu²À¸˜ï¼â<ø#&Ça0|øp¾óÇ?^D7ù\p`†<—R²Äæ´R†*‹ßL°/{ìˆb XD`“7Ùi¼d”–š¾¨Gëï®R˜G‡Ì Ç­id€iâzcR˜ÞÔÕ^AšØ9‹Ñcôÿ0¡L‰8qÀq’ºfïׄž'+1©ayþÊHo »ü÷âUчŽìÞ°%ŠÌxàÇÀcM½ãåÚiâÓÏJMM™6mZLÌXh„!À)ã]ß[o½æ‚ÇNÌ``’j9÷¼Œ9f4X’Zƒ±n?²ó{µ>˜‰vÅËH–<ÃËóêR@bX:À¤”2ß¹þúëñ1::š³()qŒ…·nÝÊwð³Ä±¨Ø˜ÀÁþÁOˆÃcGAÀ"9@»ûÖêÞJ+Žôó¿!“ÒÛŒüß(‘9KûƒÕ!3(¸ÃÀÄ88œÊ6uRØA͘ƒÎÛ¸„‹±~s2ÆÂ'¶Gqn†ºo×ÿ„ºëˆ;w·RÔuιlNßj½¾óØ—ÃþŸÇšúÂËýúõÅ|ÅÔé3ñ¶­W¯^xׇåÎXˆYãÇ{ìßÿþ7\»‘k|M¢ —1âfŽƒ r×ɼŒyþاO¤†åÝÌ›pD4Jö£FÊÏÏçôƒb¶g¥;W^y%îð41œ ^|ñE2À >b± §ùðÃcÅ9jÄw°Ê6äP”Š¥4¸Ãú<•« ˆ«O=R ÷àM¼Ê½ÜéT2KÌœœšã˜±žùñ I¯r\Le(ÂdçvSAñ dÑ›sR˜¶¤rLA`‹%yZÖ_ÿø_( k͆Ԓ/qd® ˽·`—nçŽVE‡Ó+?¶üÇØßÚcEøgßß2`ÂËË2&À2yÍÔq±Ÿí9¸áø¤/¢\ÕÔk^¦!3$ýúõƒ¶¤Œ™à¨iÓ¦pð:Æh‡ÆG¦ó*/WTTh¼Œˆ"µ™\&n6€Íi§F>é)ÍóâgC‹Î1ÍòHÇéc’o)S¼3$ÈæW‚Äæ—]v™«RÑT²{Ý´¼ýÞê‚@Zî¬^ÉÈ«SR½£ŸÙ±·Î(8å_æuÁ ïñiŠÚ­L>éwýº¢¤-»²1§¡.Ÿbâ8sÝ<­`9…‹k-o)J‡A· qŽ‚±Ô›²pîbåÜvè=­{_sèp1V‡Ãã(^Ây?†Ì÷¾ãwÌX¬¸¼ M.¸ sxÇE37¬-Z~ðð.X<¼³ýÀÛ ÏÕþ<Û±«2cc?ƒ<Ž8ñøžÙM›ÓS³clËÔŒ±íªÜ™¦ù¦çÍÁS~7Hº‹ön×$¼ÇSFÊÞoÓ÷úü¢Dl˜‚•ßœÅñiGv}OßÕc[âe¤¢m!ÊÚ àäoÃà.Ã#³–ÿæã^èmÜèøYƒŽ’ÁqPøÂÚ;<‚ül0³#µ26ikc^¸g † òÌ3Ï` ´zZè#~à½Òwe€LË`?Hèà€ B µ xÇy2)”¹î¨J% y×ãGX‰ŽÑ+¿¨˜=öH1Ü#°|õ„åãœÞòX™ÃÙŸq¬£›ºà$Ê+u¬qò£“LI}A¤L«Nè>˜ãe7™~>ønŒ‹‰Ä{Ï€0Ã1â¦D8Œ—‘äÕX–âp‡D++ñšÑáS©ïuovù}jÎL÷u´ÊËj**G»º¯ÚpX3vS2WY Š–2³$§¦¢{L’2-ƒi]\KKÑå‹'>#°lõ„¥ic¿VmHjöÒ>PA‡¢£g~ˆ¡ôÉ"e&×¾¦s rûý-%»vÄfZª¤¬_°†WZ35;W‹œPÚa•Ê‚•#·çaždÁÊöÜšU0Ϲø¿7ÍYÚ¯x_á¦kŒ”eÌÔ^¦TŒ3¡½ãs3KDA@ˆ –¦…œXªì}ŒAtëﮘ:¿›VÌu´v.¶>>Ás´Æï^Çüï Ïûgã•c䄎]jðRïbU7–·hÀ'Fè^!ì;/{• ‚€ ààU9nÅ`¸ŠK<áuó—Ý1E`:u;ü—æxݧh™S³sÃV –“2žÜË3&ÒÈ÷x:Ä˵äNÇ·™ÙÚ˜H¿q/bNâ{OŽ.¼ì©Aä¹ „ÉYS'Å1nN»¾½¾2¨híÜŠ·p¦¼\¼·®Ý”Õµ‚eÇ"‘Á,Ÿ´8ÛMEiÈ|¿×ÃìŒÁò®½º«9¤öëŠd¯Oð Báe¯àcA@1xiÖeÄý VŽÂ¾$~÷×ÎCîFN‹0,2ïKÓÂõû"  WÓN ±±HÚb}æ'2ºÝ šÆrm’LJw¾õÕy³ñ²·@‰½ „XýÑmäƒKÓbzþô8f3úþü\ŸŸŸÅtÁwÑOÎ^Z«ÓÕ ŠM©{Œ~¤ß¸—`æ8ÇâúRÿ±/öúé„§P+uÃøú¸ÿ{šV®u%Šå*ù_i¦éù¼:d¼ì\b, Ð+œñŸ4â¤fLn|6@wþYGŒ„—ë Dü Ááœöþ¡›ž³¬¿!^ö/ž’š D6˜‘8¡Éœåß'fMY½6~UÞìi ¿"‡ÏÏ“õvµ;¡ô¾Úï^ö;¤’  D0pÍܲ×_àoù°‘ ®ðtáôæ|ÂS3{ÁÇËÆß–ð{m…—ý©$(Œ@eeÜ)›û±fùø»¾ã*f¨;ð0U^ª’¦ D0puo¦»PÇËÿl?èVõJŽ8¼¤ùý^ö;¤’  D6_ÿð_¼ÍÃpØIÐwur7|êÃ5¼aÑ6¤Ð­zýµïØJË~Þq/UIS",6=£å€ M@Рf8$ú´ß͘eþjÄ}Ø*é=û7´zÂË…WAÀk„—½†L"‚€ P„— ¯$.‚€×/{ ™DA  /^I\¯^ö2‰ ‚@@˜µhðs­Ï~­ý¥QøÃùÔûglÜ»zÓx9A@‚@ÞŽiæ¾õâÇœàå>¼hBêÃc–þ[NA@à#ðsÒC_þØèå6—œàåWÚ^ÜyÈ¿: ¸'ÌÏ¿»)ÌK(ÅAÀ: º÷ƒ¯ohÚîO'ñr×Q÷;·4?±ôåã>×ÓÕY9Ø|ßȘH«^Wâ&åm\jjPÇ|%º ¡Eà«ÿú°ç^ð2¨05w¶OÌšŒiï÷z\ÚaÐí*Ms÷™C‰dù…a Å…==‰\põstd‡L›w»wP5M$œŒÐ6˜ä.õ_x9)kʲŒqow»WP'HWUU€%Ëʃ1q%Ê8± qhÆÚ8ŠBl~ d'>"ÊÐ)oâ„ý¢ÔѸ¾áÜšfx‡ 0Ã3§-È:%gÆÒô±‡í£4áµÉ"€(”¢ H–²ÀÍ€Žåë}· ‚@ð‘—Á€ Kp(ŸM;Ÿ¢¤+HO‰:q…Mª18`3Šˆ›{lž—<œã€á&®Hgä´wÀÈdÓ¸C§oŒ¢fACu9A@ˆ8|áeŒ‘ÁË4¼Å(•>ª¼ŒGç‚O‰I1˜%Æ„%“5¸CãhÄÅˆØøO1q±fýBØ<ßÎÁÈ*﫼 KJг^ޏ¾(BÀk^Æ4î虂F׬_æÅ”. øˆI |Äaœ¸0ÞÎáŠ(8AÖ˜^€1®ãíR\<5>ÂýñqÉ'&(`ƒÔ 6¯¤Lé#̆¥IéÈ+Aéâ‚€ ¡˜ó²{ܧýn…F '$Q?òSܧ0®|’1=¢èj\ã#Õ†ŸR@ýhŒèƒ6E¢‚€ ˜èä°®dZƳã—SA øLJ}ªë˜ÛOZW^ž”òtô’ÇäA@>ãV<ñÕ·é¼üãÒ»Çß&§ ‚@ð±ðŽ#®;‰—máP>È!‚€ *~[<ò$rÂË¡j ÉWB@ü/KOA ¼^¯öÒ‚€ ¼,}@ðB@x9¼ÚCJ#‚€ð²ôA@ áåðj) ÂËÒA@/„—ë=¤4‚€ xæåêêê={öìm¨ê,v”ØáH~¢áxû°XŒ ³i‹¾q•òÖ]9[Vâ鬥}o-+<Ô’¬ à#žyÄt a@À"ºØ€ü8¼ÔŒ#úÝ YÓ6¦ʆmå,Ù‰=ºüž»$(uAÀ3/c l–9ëöa¹oß>›Ífeæeó6.÷Š~ T¨¢ùNבÀ²`¬®´9 Œáõaì?€ è7ö*Ha€wî]OÆ0Ã\Œ§¸ƒœ‚S²”&îP ¿.êAàö c!1”F`í 6‚€ PwüÉË`äiΣžQ3x¹´´Ô Ö*/s %>Ça»B|¤;8h>äHƒkŽE[#âöåâÀüäááÒ>‡8À›”è•6¥%&E¿ L¸\rì–KìG0PÍ´B"Ú]¥ÅÉ­€ 6‚€ PGüÉËT¾í#à^îÔ©S›6mÀÎ8à0ÆÑP×o^Æ<øoÒÀÈ<ÛŽCX½Iw ؘ—<¼ãà;Ðx˜FÀDl@Ð4JQ"5Óâ"}DÇÜ4Mƒ°1¢Ð<)Cþž›‘&æ78s=lpOi?r"h­œ”š¾ÏýL" ‚€uüÏË2#{ŒŽi€¬†#‘”Qfëãå¢í »Øåg-é­¶ÞÎáŽz“ï@²F–d€92é™覚 # çB¸jF'¨œÄsÈžR1¨Z!Õ¤8}ëK,AÀgüÌ˯:”æO΃ŠEç,{ÅË>7ƒDA€ð'/ƒÂ@¾Ä¿”ÞøÍ™3ÓÍóçÏ\‘†õñ²t,A@ꎀŸyY›©?Ô¹ƒe/×½“I ‚€ à–xFŸ£ÎÃçèá+k,ê伂^ŒA@0EÀ3/:t¬„… ü$‚@pðÌ˼<$8 Ï\„ðl)• P/^¶Ô¬ÂË–`#A@ðÂË–P^¶“ ‚€?^¶„¢ð²%˜ÄHü€ð²%…—-Á$F‚€ à„—-¡(¼l &1 ¼l Åàór·Ÿæÿ–˜7sYN}:Q#ÔËâb$4`„—-5¾u^މ‰QSœ9s¦¥ F 0ß"†y¬úZ¯0‡]ŠY/[j/÷¼Ü¤I“ /¼°Y³fÌÂM›6¥t9`)ÅhnꆕI+2Žøøxo£{k¯ýœxݺ=†ÿÖÅRh˜/[jwãeònŠãùçŸÇ4 >E÷333?pK–,±”™Óhñšmo¿õÙƒîýHÍÆŸ Ÿ<¬W‡-…—}M¢44„—-µ¸G^¦Ý³pP€iºmÛ¶Ÿþ9íÀ6V²/·|ÿ]¶D\ð; ŸW: ƒë‰Ua€¼øÊÅ@¾ì#úµk×â7ÑqáK/½”l 6î³öê·ÄJ½„—­ $6 áeKÀ#/k4j&‚f:öj®Yãe¤Ã\¯†ù— ‹ƒ?R¦ ànݺuÖYüS¸øÀGcg Œ;Ƹ”߇ÒÂË–:œ5l‚ÇËöï‡s¸EÛ#/3çràÁDeéãsÎëºkóÕ2Eòæ¶”>OA¬*“ò 64æ¥;ü;¡0ÑÓMãÕ«’»7^ö#˜’T}E x¼¼¾`ýž=Åàf ʶªÝnjâ¾8Ãh¼ì÷b›¾÷SùØzÆò¥9hú% +nÂÌxòäÉ r<–—ì‰ÇÕtüX;áe?‚)IÕWÎËëÖ­]›ŸËš¬U±¸x×ÁU4Ÿèx }œ“4gñ­í†?9}ÙðN?8¦js6nvúá¹ÙI£§,H7q›2×M»òƒÓ0ÁçåúÊ_õµ^Á釒KA ༼&3£¢üHÙ±C奇KíC #ͱ…3/v¹ , ÎíóúÂôÉÄÎxúègàJ¬;3–à›Ï~qù´ɰÿeñ à´Sðy¹¾ê|ëk½‚Ó%—‚@Ày9;+#uå²´”ÄÄ¥ñ;¶äeg&•”VÁň˜>‚y‰‰‚ïÿèw4^ÆüKLéÑö=…ù›cð ÁçeYï„f•,ðD à¼ÌÕ.*Úœ•¾¬¤äˆÄ„µsÊ YâY܉‰ï Ú¥0®ê#bdà ¦Áçå UM2pC x¼ =†6³nX¸)ðr5–Uˆt‚ÇËTðy¹>¹+’º YËsg.Ï™³"gNbÎot&Õž¸3k…Ã7™‘…—-ý^„„—-•LŒA Œ°U” t{Jì»öÕlß[³moõ–Ý5›‹kŠvÕà¦Ý~ Ô,¼ìcºçe~iU´û}×Ω¢'ó±©$š N”;¸}_͆ÕYE¶ô ÕiÕÉù¶Ä\ÛÒl۬IJ½Ì1ó¼ñráú ¹9f#öeÃéEŸ`òš÷q¡å¨ãŠ÷¼¬ò)s4ÜYÐâ:òhûXôŒ+ÂäÆÈÔ€ýa]É’„EpR¸jÄ€G–·‚§wHlƒL½rñ ²p²A)¨a|tõfzßU}-V™[©£ÁE¬àcÅÆUîÚ}¯Vá[ÉWl"òÒƒ›Šm«7V¯*°­Ì¯ÊX_³ Ã6?gõ¼Uå¶îŽM ÅxùÐÁC`– … _Î5YYš$}à ,'A€´,ÃØ°=K;a0:¶+©5HݬFÁGÄ…š pÅG(Iíóáž—U¶bº)“Ó ¼arD>ƒL ( —aôà¿‚Òñ·2¥Ÿ„‘;6B°e¤:´Ó˜ÙïÿœhŽŠTdGîLÉqýºhir:üS„2à&ý,!LöXUH«Æ¹üäQ„ïÃLsÂçê'½2¡ú8ðFWãïåEBŒN CØ €+GR]/á@õ"ß\fí¾±¾üSMéh˜ûÜK%b"PQzpã.Œ”m)ëlYEöi Š’×ÛÁËóp¦•¯Û¼;69¼œ““m·ÛlU55¶ŠòR„s²×¨ðñz?ZHBÚdR1ãŒOG+M DßdFq9 бJ«ÕÔxYŠÏÍæž—ÙK‘:¬Ã×›= ©'ؘ(@%nã<¹£#¿Bð@OCü¦Ä955Œd»wïŽ;ˆˆ€1.ã ¹'Õ$3¶¡ß ººJ“ËCþáÑœ¬Z~5;T•E•9µj;šºs¢_#ï8/À¢úÿÓŸ>t®0TÝ¥ÿßiV„}çs˜†Š &Ø€AŒcmƦYP0Õq¨†Û ;u4je¼LãArßAaª²±üÚ}Ø#}#ÍḚ¯Pï«îœPe#Ùñx%DF§©T¾O16bHãeÆì C­ÌtßU}iL­¦¦6þJùÜc%b˜ ^./¯µO™·ñÊ»›.É*kÒzà3Í¿]²Îþ[jyîÆñrIIIAÁú¢¢MK/ÚV”™ž–ªá…y ø¾h5àÐ.Á뼓ï‹;ß«Z¥û6¢™eºrÌZàD\$HÓ#ôî5ê¸bÛ#/û½È{¿º@Js;uIAâ ~A¼¼n›myŽ-}£}Ò¼Mé…v –‡Ï,ˆÏ¶ÏJ©/Ç…d¼ÌuÛXX˜‘žâ—ª?áåàc.9 õʲƒ¹›m Y¶ÙÕIöy¶ù¹¶yùöYkª§%;ÆË!æåˆ†Xx9¢›O /„ ðrvQå씪…•óÒ«â3ªfgTM_U95µrÂ’cyñÞ/óË¡‚ÿù /ûOIMh @¿\|°|óΊmÅ•ÛvWnß]¹¹Ø¶¥Ø¶iWÕÁÃÕ™ëw /ûÞ„—}ÇNb  òÒC;ö^œ¹kaÆöùiŽs^Úöé;æ§ïHÈÜm¯9ëý LÏ^Ïv‘R aŽ@Ù±‡Ëìk·Õd¬¯L-€`®*9¿*1§*auÕ¢ŒòòÒ’Ù!\‡77:::66΢ºfÚ‰ðDYx9<ÛEJ%„9Ðcäo­\‘Sµ2¯21߆÷~‰¹Õ 9¶¸5¶Ù)åYëC÷Þoñ²ä˜˜Ÿ,X°,IÑוà¾*nƒr¢·/ǼL[FAE 2o¼ÅôpxD ¸½³”ðr˜÷~)ž ž€—7l¯JɯNYW™œ[½<gÕâlÛ<纒œê1V¦¦÷éÓ{äˆá½{÷JIIsÃËêb2ã-£hÉŸºÅ¸¬]rl¿jVG²«¦^ÏN/¥ÂZïw/ç8y93Ô¼ àbÆMúúÛþ?ÅL0‚ÈûHñx™þa,-¡§8#Œñ²º›i½I w–^óÞ/ÅÂçxÙfÂË!/»Ç óäOþ‰àoˆX˜·‰RÃÚnRxIˆˆìŸ( ;K /‡g§—R aŽ€sveR^eJ^er~õò¼ê¹Õ‹³«â³l±©å¡œÇsà¬OxÙ JmÄ×¥GˆÄ ž!pœ—«Œ¼'¼\ÇÆ-/ÃÛÜâ¨àùˆ>ÆÄÄpÕ`Ãþ-áÇ•ƒ7ÞŠ=ò¦Çp¾3Õ—’üòh~œMëRÇö’è‚@˜ ¼À†/ƒÝ{ì1ªù>f¾cÚ…ß$Íä…’}%“Ÿ3F¿À*dìû¼ cøJ6u½oÑßñã?ŽÄÕòã÷€¬Ô%€Í)I ÁB ¬yÞñóòòp ~Î'ø¼ŒýJâãbUǪÏ_TOuï 3ê’¿fzDöä‰XõeìÊ‘±š&HQÀãF­ø;&RF‘LÝCsÙø§Å´.~nBINæ¼¼Æ1¿úyŒ\‡w|;]µƒßû4ÚE;h'Üüy^Oœn |^f?Ÿ“o_ÕW/û/Æ#P£üì¯Yµ'ÿËìËXõ ¬V™Òc˜ ^6îEc+þŽiÖ…S¦ò«ƒešo¡]E8MX«K@ûƒ$.ò¿œ”ë˜_Nº’\Çæ~‹sªæfÙÈÿr(ýÉ忬±U•ájÄÂÍ>R0&©Dr Pè1è®Pnà&-*1ësU•Á{PÑŽSXKè ù>â’ð«T €FʤÃãì(55‹òrpzOsñèï˜6ChhÿepqJ¾c½:1¯jq®m®s½_ˆy9suúÑÃû²V§[Åý>R´Ïø—ö"A˜x{”€p±Òä“!à#é—yC)Xšî8ÄÂvü[˜>™ªÐ.'´s§CYàþ¤Eýjª‚ÝÄ/~°—ü p‚—ë°“òÀË6âåY!äåµùùi)+Š ó÷ìÚ„+¸£VŸyYÛGжŒâýRµ ¢(hTÝ5 ƒb¬ÌÆiÜqŠöšÂAî8ÀÚ¼s ¥£~$cÎb抑ÂËè±’¤ Pÿp³{Þª®ÃÆ0yç–¼­›òp5™]í#Å›Bax _ûKvÁ!X˜ÆËD¯Ú¶Rä%fˆ §mXy¯)ö¤A;KÑþncÆ8ñqÙÿg!ãåúÿí‘ A ¬×ag¤¯ÚR˜k`êðTC5¿lE/¬UÞ£ÙXntÍEÝð[Mo iÕ€·„3oëè¯ýLñr’µƒÞ–‘ñ %#à>çëmÓ¸jkðw•µŠ§·Å3µ×°õˆ•¿:†›Â«ë°±•ÔÒ¬ê%kÂÃo:/×d»¿4F /£jõ‚G 2:.i™ÕuˆˆûÐãgaÚ7íÃMa£nZ%Ä…„CÝŸ›´ÒêØl*{Úê[ÕV“=ÅåûT“~ƒëˆ2³½f£u ä±=íÿÍ8P\Ø€s¡áºsùÉžÊ@êCÊ@ERqVËc¬/ÊC¬Ñ½{wnšºäË{“«u§þ€¶@v\w­­I<Ãú¯ÊÀýMíܯOµ/™–“ÛBí“jš¤Yb ,¶Q6çåuØI9•›÷Ôí®Þº§&Á©““uØu¥îó2´ªÆ÷DãVª$Û˜jEÕ2«¸pDD ×rÇ囦ògb+lF¾¯fD7¡Ûái«šk°’QæÌe {\M¥Ðœ)?åòàN·nÝ  .ŸqU~cõ½-FËÃí¢Ö—¢€kpÓÝbÝ9¢±îÔ¨Ÿ`9ã`ZYµØÖë®õ7+evUNÖïk}RícZçôXÎ ò²ÃÿrZ¡-~uå¬Ê_“+ç­ ý²^,\¿!7'G³ÌÞ˜ˆyaò³Œ°ú”ÕÇ®ÿG ÇðJ=x>ÚJyT›Pñ²½°ZNd¿°–YKºfšŽ—MçU´q¨6Þ¤1¸zÐø Ã"|£hì†òà#ÈøÊ÷Aؾf¬ÝV5Úš–£:^æÿ ´ñ²±î4FSÿ‡à1»•2 SÓÿ£g5}n䈺†$úFÅq`”j±î¦ùRiuWµêêÿ:Ä×®úž•º3þj½Ôö¥:2žª½±œ4;q饗ÒÿRü?—¹©Ú|+å /¯wø-rðrÆFHâå++ç‡9/c ©pCaÂBúk² =´ƒ}ªÚdHq²¨Ä­êŽÁÚ ÓšY°`™•p¸c$z7d*^vU$ú¿ÛÛ_—ȵÇÒ8÷¢UÇM¦©0jhÖ%8G¨òUkg¥|FƒÖ"ùÝU9ƒÐ1X'^ÎÚdKÈ®Z–[5#µ2>; ôËnÍq,´Ùª*jjlå¥çdëËOXKGMš9Vc¬êŽa MÄ$wSË$Ct(7¼jãpãe¯ /Æ‚€ *˜—W­­œ“ZùsBΙ«Âž—W­\¾gWQñŽÂ=Å›Šw!œ•©¨­=á½KÔU!ˆ¢êŽñ‘b©‚e218†Ò xZãgå^¶‚’Ø‚€†­ÃN㥬­\™o£sI®-Üßû•””¬/*Ú´tñ¢mE™éi©Æ¦å½Y1ÎÕÔÇ´ŠÚ¨;fFæ(´¢ƒeDA"´Ûb7^¶”˜ ‚€Š€ÉºÚG*Ì÷+á:l,,ÌHO ÏF s^ö(‰ucP ©·q=êI]µ¾úÊM]¬§¯ù€ö¶×yœ´R#†'R¹ ëâJc®ê”Ýh–Uˆ¬ÔË[H뫽Ëu%‘ÂËáÜ0Áçeøù\’°HÕóªºNz_¯¾7z¬åwë¤ÉÅRÕu2ΤSÆ;qÒ«±>AÓŠººo%.½Ÿ¤·+¬{UËÉúYS_Ïj— 1†ªÿÕ:ŒGí6Õ—ËãÊ?5ãlª)ÖðTë¢éµ¹<('¨ÉR»h:£†ÍAºÒð^j}5¸.œ¾öËAöšÆ\Ó)Súô>™°R˰iÓ&ëúq´x^©…3cpÙˆ—i#9¯zyNõŠ›c©LÛ\Ù¯¤ŽM|^&¿E¤ÍÔ´ÀšÆÄY®4¹l Àé€éyé»ÊZQÓûª^ØU\Õ†óÕÊ©êgA(îÛHÕn»²t¯Ý֘•j+šbΈ1WqÓê‹Pá—ÏU¹RÝRñÔT«nÔA“¢NmG(Ws­{P²Z#±9§àQ\ǯ[}ŠÖ~ñ#èPñ2k6ZZ/«c£&—þåTuÜ<^&Í,Å5jEÕñ2ë‹YªÆE‚š¦˜Æ\TÖ“ªkü4_Ï®ÆYš––ÓTûÙ¨š\mÌÈc@Zfª•&a5éaM5Å*ž¤õÖþŸ`-­ZfäEû¿¨ÿ—¸Z£Hë!¹}ÅT©ê ÕvQÛ‘ñ1Õ˜uÊj©ÿ“!/Iµ7¶µª1—ñ2#ï/;ôË'íï&~ñ…—½E€æ1°u—¾PMvÖÒ>8ë’‘›¸¡/¨:’¬ /ÛØÿrèýâׂ¦Ï@ôùÉÃcW Dà›Ñ,Jëν`ê^ÑOÅ.ˆ@ß±/à,ØâašÒ·’/û†›Ä8aê¿î­Ò¼ÛE`^ ™A»Hí¯Î[š>aÐôž›1šÆG܇κggš‚ðr€€•dú@øúů#î`^JáñÖŽÀÓm×{×óÐcgÌ`€¦i@ˆ#´¼£UŠu¦ÆG¨¾¤)¾!Ùú常¹ÑÑѱ±qÆÊc°#)ý)´¼L"eÍ7. 04ý²êc×+_ºFG,ð0ÍY[ôAì [¼ÀôèÛÓ4®æGØ7!Jë«ú0òØÙÈÀ·zYL\k;Ó¼|ðËl1÷à›Y©¯ÅR¹ê·®Ú ¼|äÐÞ#%ûJ*-;RQQZUUQYY^Sv¶UUF,/Óz?ššóòrÜÁI“Ȫ¨á˜9mp“¢h\iŸÝ·J¨x™õËT<ö+¦úöeý2ûØå^ȾtÙçÁ1êFœûü%½‡š¾i¾ªÿ_òssÙ‘?6¼o±ºŸ±Ñï0i´Ég4œ¨©þU?ÔäG˜ê¨út&ÐäR‰ 5\6úSFâÝ»w'l~¬¯û.D¾1Éñ›¶3´ñGŠ/iµM&Tk»ò© Õ7çÅíåÆ/³›¶vï+œ÷±æöu_~í7[íKì‡öPç|Õ}²Ù¯7õÓúrÓÀzÛoÕ~ˆ¯áÏ寷¼Ìïñ,þ Â,ø¼¬é—©RªË]5Ìúeö«Ú}«f”§fª6ÍW»iôŒ~‡ÎpLÙñ•]4¿Ãê×Cn³?hN‡[YóÌ.ž¹R¦þ”ñ;D)ø±¾äÛÏÔ©Š0ý.r™úVVíñ%Œšj­MU ãg¹˜úÔÖ:ÔÚËUsåÚ½¯pXõVê±üZ}¹lôƒªvoc¿¢6U11õpíÊs¿·ýVûnjíUoy9<ëmšÁçeU¿¬ú/¦q"ûÉUõËìcו¿ct8m¼LéРCõù«þßí*¬út6õ¬ú/ÖFˆ4¶ÕƉªduì£ùJ¦ñ‘iñe^¦±³©?exµÆá÷úºéTšÿhfW¾•­ø’æÿE؇µê{ i¾¡ÙG3Ê©¶÷%kã‹ÚÅU»»*³{_á<^F²ªßjµÌn|gk¾°É×3DÑ|‚#}”PóëmZ_îcÚ„·ý–±2-¿ð²·dë…}yÙ‹R†Î4|7sþ 6  Mš5ƒ£øºg¸y[ Ó2Ùgwùz^ö¶ƒyaz^núeÓ:UÛ®î`f'þŸ°ÅgKÊKôã^|‡¨iÄóráú ¹9&žï§/>aA_œÆ†íôÃóS Bƒ‡ž—ƒPIÉBü@¤òò¡ƒ‡ðŽ¢pCaÂBÇÌ隬, ™‡Úœ;s’Æü<¯' è˜øžÅ¶nÚ•ÿb—«ÀÚ|sûžB„ÁÔx”¿yl`I„Žx::¶+ÙàŠG89lÊû\áewWIOhD*/çädCÇg«ª¨©±U”—"œ“½Fm1ïÜ”±Ýc^Ïþ²xOï|Ïñj≎—à:qa_í&ÈÆDè3–@¬øÔqí†?‰÷ô;¾‚¬ÁàlF¼oz„/»Ò[Ôišj0ë¨GöêKÆyᕋ馢”ši9-ê²½*+co1ñÖÞU¾VôÎóò¨·µ˜Ž<Õh^éÓ-ö+e7›HååU+—ïÙUT¼£pOñ¦âEggeªà>ûÅå%Çö«‚d{Žo>;iôÂ4‡kâeÓ›¸ˆ tœàh7q7Eyô³ 8 6G‡/Ó¾«¦ÚLMÊeV5Ÿ©j{µ}²Úa5®Ñ×3eáJ×Iz £~™öu†lˆ”Uê¾ÑªžaU× Jâw÷ˆyk™5]-—Sµ' †iyT{„U]cÈúSM÷ÊZp°>šÊFš\U'K¿7F 5k$<²! K8_Dt¥É%8¬b¢©'Õ¾¡õµ/¹×#Ss³[ëo¤·¡¶3ê”ÚdWýÁýÞÞTG­o[ÔGSûõõÄUöñ#•—KJJ ÖmZºxѶ¢Ìô´T­þÿlåcæá½~÷î/Ù…9ePí'Cn1èøÔx÷é&q1dưš£àÆÔ­<€G_Žy™Ì6l×§P¸$¡/»ÒfjzL.§©N“µ¢¤"cc F ³&ð4ÕuÒh×TÓJ…Ç—šS„U-­š»±ŽªÖ•¼P™5­1Tí)eÓò˜j¢_6WºW•ݨHjÙŒ¨22xÄq5Ý®›¯:C¤j·MËÆiO‘fܨóÕòR5Ô¦Åp¯G&0U-6w*ÆøhínªÅÖz#÷-®ZH£Ú·aéQ {ÆJÕ×s;ºÒ•»i2ÓG‘ÊË\™……é)ÞV;8öÁçe/µ™4fTõ˜*®tšÆñ²qÅ%m)­àñ)eáJ׉G¦šV*<†]è÷´i€êëQÍæÛ$¬G¬Üäë_íy€ÊïC šFÑú†jãC7e¨K\o«©¼¼nÝÚµùù¸¬ÉZ…:ï:xà Zyò‹J~]Ô[Ia_(Ú 7éß!âV÷—›Ã>—f^á|^&=†êk¦wߪ^_`Ò*‰?ez§O:ùf]­+M7û­Vµ´«ªºoÖ™ ¢©~7‘—š¯µçšÆF-?kºUM•‡5\~M­ê»U{NSÓ˜CccªµÐ43Zÿ§ï,ÙõÑZ^ª¦[[à1®ªI7ÕÂ[gHåå5™åGÊŽ*/=\rhi'¹{¯Ç¥Ø—Ûú lY2pBlE»C/k»C©ûK²ññð1ÇœÍhǯŽàó2é1ÄŸ2ÉlMµÀ¬§†V7þ”‘¯GM7 „®ô¶j9YUFÚA£jÖSÿ öœ;¿VAîo¬Þ£= ¬h¢~®U]0Â\w£®™ËcEcîFÍZo­-ŒycŒ6T*S-¼uöˆT^ÎÎÊH]¹,-%1qiüŽ-yÙ™I%%‡ÕjÓvPØSƒeP*m…A1®êNQØ—ãeŒ©Õý¥`R¦}ZiC)u)ëàŸ—Õõ~âOÙT ÌzêÀùSö¨é¦5¼FÑ•ÞÖ¨)&ͬêï˜ôª>Æ­þÕžkjùi¼ImmÜêQMãeŠëJçNcd‡×dƒž¿‰F9ûÚÖl4}4ýškMÓ­­Ðâ’–Ù¸V€¾w®üM[dHåe®^QÑæ¬ôe%%G´ óË=Þ óEÛ3`fÜ)ŠnòþRãã:" .&FæM¤,bÊfÁçåÐê—ý¨ßôj¶DÊ>W¶è…ê79@Öñ»ñ¼ =†6³ìs/÷{ĆÆËþPü)ûGI%‚ˆx^g셗ùu¤l‚@Ø" ¼À¦^ ¸á´oº½ð®“”.xÔ[^Æ~ØÉÈ s;jpâ5 â Ú¤!ð²G­®7£Ô½–9NÓbSOj±õcbbÈ’ßþke¦º°™ÅdŬ¡!Poy9)k I) µÀÒ·Øå!L>P²â9œx¸soªkVeË~éÁçå䂽gq¹ÃÕÖÕ¨-%_btŸ÷º6õƒ¬úØU}à2hªöÖT‹ª)ùT=,â’br.jª)f-ª+=,ég©œš®–´´ÖýíZñŒr"»Ç{Œ@ŽêÏ+½ÔºÀXû¥ËI"õzËËCëöÍШ™”ËXˆsYÆ8\ñQÓ5«²e¿´nðyyñšmŸwlƒéÈ¿¸QëJÊJ£¶TÕf€´½¦~Uß¾FÌDRÆ|U-ªKÓêºc¤¦SXs©¬6–{ÿ¿ªÏeÄòèo?TÈQõmê £`Õñ¦æ„ÓX~*0ÌdºÃ/_´ú—H½åå)ó» µ°<'4vó‰,[&]3–-û¥¥ƒÏË/«þ‹i¼Ì¾bYkÉX#kúPÚ¼ÃèYÓlµaø©ñ‹-*­¹r¥‡e.Û^~}õ'@ÜûÿåõcÖýíªÿs`¯ú2Öü cL#eu°lZ~ðàÚ/=M©gÔ[^ÎÛ¸ M…5#ªZ™EÍ$“î°®Y•-û¥™ƒÏ˾é—ªõ ’ Õbîd6:?9º!Poy¹n°ø'v¤ð²j+©0Õb qKWñ„€ð²'„êð\x¹àITA á" ¼À¶^ ¸’´ P^`Û /\IZ¨¿D6/ÛlÕsããq56ÔÊôNÞïáP·)Áû@Ÿ½Yï ÂËÖ±KA@`"˜—ËJKûõïŸÝ·oßÒÒcZ£’3O>àíwpÅ2üRkIׄ—‡­¤,Ôc"˜—§ÍZ0jÔðQ£FŽ9ü×Yó´FjÞí" ™y¼ ùù±¸Â KNh] Zo Cx9@ÀJ²‚@ýF ‚y¹¼¬´]‡Î“&ŽoÛ®ÂZ;Ѧ$tÀ‡2>&fMÆë°U^¦õ&:„—¬$+Ôo"˜—Ñ0ee¥sæ.ÆÕØHð[Ä7±öËüðWZˆy Œ¦±ðš6‹ Ð!¼ `%YA ~#Ù¼\ǶÁä²ú2°Ž©£ /ûRIPh4h^t /aI_¨—/°YCËËää׊ÿ_͇²ÑÉî°³J¤éÆç²©ƒ4|4s«x,›õöã²qšZ½Ô¤¼rîì&+iúŒ1_W¾ª­£d´tŸ¦æ:JëouÉ×c\‹¸™6e]Êi%ߺ¤Š /{l}ß BÅ˪/`”Þ½ÿ_t2Õ‡2ûfÇôŃ Ü‘_cSŸË°á¸HÓÔG3â÷i¦=žÙW2ÛóÒÊFûI³ŸeÍ1ù0Ú´i•_-›Z~ª—Ñ2Ú‘§S­.šßj`K^=ö?güöºJÓž¦=O«—Z~W¾ªÝì·GðeJ¾Ù‰ ·‘Іúù $?ÝÝ»w'Ÿ‚Œ!Ùp;j8p\Ea¸è#_Ûê±Z¾²#{dèŒ›š¦©¿o4¥º×µZêçZ_"¿ƒ®pã|Õ¸ä×ÛˆƒoôÑ xŽâ4t ¶¬ÄédÖcŸ—ç¦nˆ‹õÖÿ¯©7dÍDZGŸË 'ejÏþŽñ}æ¯"Ea÷šïf÷e£Bªy©­CN¨9eNJMÓU\Ð ~*(5²AMýV«6ä.Uõ׬–ǘ¦æiZ5Ñ÷Üø/ˆZ/­üF_ÏšiΈ3ÅÕî«mÊa¶Aè× ‡Öa,ækêÏÚX.¶jÏ•õèï(i¾È¹.\lµ/¹oGÍ]8’Rýz»qn:"›—ãâæFGGÇÆÆ+¬ê1 ½Ð ‚³•Tðy™ý|½/}Ÿ­øÿU}(«>Ž1^ бûn¦^hÊߣ=5ꘅœ>HÑ‘8}ðm§q®«²©c5/µ¡_!Ç©8PšÈH+'Ç¥1é®]»¨ ªOgöga&•AK‡÷|1Ž9M™ëhå«Kõ¢ÿÔº»òUíf¼¬â¬Ž…ù¾iš4† ÁÂð8Që?03/#.F´±Žm’”§Ú«íhêgœÚ¹Ðÿdj¿RËiÚ—\µ#÷IêÏW/kýÍÛ "˜—/KމùiÁ‚1ÑÑ Ë’´­ê—ií®ó“G@ƒUXW’š;aì&…UXoîæÛV¾VlBÈËVŠçÑ&Ð~™¾Ç Z1ŸÎVÊ)6a‹€ûí+M‹Á¼¼25½OŸÞ#G ïÝ»WJJš^&ަ+m%…ÝÿðWÜ/ƒ²—¦õ{»†ž—Åÿ¯ßU@ó2À‰7éëoûÿ3Á”êƒÇË0£Å~DÍ/ƒ”).֘В?¡çe?VF’`!Ù¼ì%ö'‡™ Ú¾–àuîà¤÷~x%ˆ0Ühð~D^xÙ`JR‚@ÃA Þòr84a¨xY}çàê(ÆTËà­ÙJÖVl\á Æµ˜NýÓAÁQßS©ú_oß_ùÖý|˜U3Â+8¼º°¢2¶^Ò1îqΚb£®œû l¨­‘>Ë3îÝ»7i-T1̸/i?šIA¶aÔp¾ªŽ‚4-¤sg †š÷[¤‰û\fzû }MõïµêÂË^³­õ!çeêªnj!í{ÒÃÒªªå¤;èO0 °©æ÷:_ºÃ bþÁ` ©lšàZSõšêjÕ4Õda쾎F}±Qó«5qDë ­M5Ý®ÚOO£WÓ§Lî3šÒÜYÕ\Stê~`M4žjí¥µ»Ú]Mû­Ú”œ¯ÖϹÿ»ÉKÍ×´j}Æ+­º‘R„—­Ó¬×–¡âeM;ɽ„eúÛÎzXmÁšb OHhŒalª9:¦:_ZËGÚdîõÈ4¢òи^ÕD«U5Mµ¾Vꨎ—ú\ãš‘®ƒVÛ…qã1&ýN£ŽÜ74m¯i[°nšÆ˜è/k:tþòÐÿ¤àæ¶F ñÃO]…þ3#M´éx™û§©—i\lœra4­±Úÿy!ÍYS¯¦iìŸ~תG«5´G¸ßwì «Æ`5Êν$ç@,JÊýn¼ì©¼ò\ÂHå圜l»Ýf«ª¨©±U”Ã/¾-'{Š(èuè”7qùb¿(Z懑/H–¶õ£ÍJèJ#bÓGˆ…ûÔüÍoú´C ð²' ä¹ x@¤òòª•Ë÷ì**ÞQ¸§xSñŽ"„³³2ÕÚc;pbœྺØ$‹“È×7¾:oQêhœDÜ´õÙ“ñ2NÚô ‚ÖËÊ{[ÆË!A@0"©¼\RRRP°¾¨hÓÒÅ‹¶e¦§¥ju{¸e­Œ؆ôJÎ1À°àVÚG p)ãÆÂ2ÿº¨n’Û#c妎^õ17y½Ü”-Ry™«´±°0#=Åcó«Ë²é=žÇ(u7>/ÃÏç’„E¦~iéý8ûºµ®G&ý¦QLïÊUíª·úVÒ™jZQUW‹—àärL{]IïßI"J~Âp¨é¸Ò½ªev—ÞB£J¾ôLuߪ˜ËÀ8#:ÊFþÆX›H!ö¤ÔFún4ݤI`Ý®Q lô¬Ù„3V\/n­¾n4ïª.Û£†ZÅPí¦ª»ºñëžBÄó²EÔ}ü‚ã| >/“ŸOW~iUݱu=2¶:uê·ÂªÙT»j]ߊdÕo‡Y3 ÎbM«öýar¯¬ú;fªé}µÌ®âª6Ô»\i¢¹T(ªZÂTÎKŒB`U«)Ì4M·{ÓWÓ#ó÷"̱r¥)ö¨yçþc]CͽוæÚ"™Á¬¡ðr 4f*^&0s5_·´fÉ£™Æ#¬ßtåßVÕ®ªZc+úVu£®–סѨY…—Ç€x¤ùÉU5ªê8Z-µÕ¸4ÖÖl`Fÿ2›j¢U|Ôÿ'ÀŤïÆM÷>yYì^ÓMc=7>¦©­µ¼®°ÅŠf`Œšbۺ׼kíå^CMþ—} Ž ¾Ç*ÂËÃ6dãåVÉ´íª¿”9@ZݰÕD×´pÀÊeZ« æÖã†;/ؿ߾}ÖëãË úZI'ó*œn,C5^¶Rx±°E Üyy}Áú={ŠÁ͂Ŷ¶ðÀôeÃ?âÐT¨Ç/‹áä;¶g=Ôæl\­·ì­ÏX>BÍ(|æ1¬^lA lS^^·níÚü|\Öd9¤ÅÅ»8¨‚xÿG¿£SĵÓÏÏM‹ëþ’]Ýc^Ç©ŽdŸèx lÀ¡~xT3|¼ó=‡Ð 7'.ì –o7üI~DöšgAÙÁ¹ÌIrè ]2^6EÆ_:§°ýRIÁ:"¦¼¼&3£¢üHÙ±C奇KíC #í¤í«ýìÔ<{câì¤Ñ<ûÅå Ó&Q.LŸ¬Ñ%ñ,†·tŸâ‚[KŽíÿrÌË eíÙ«ˆØs|sdAqéŸ:#…—µWš–Ö#WÖEcKÅÄÄP€¦e`³:öl‰.D.aÊËÙY©+—¥¥$&.ß±%/;3©¤ä¤õuÞnÚ•ÜÿÙÊ1ì¥áóö=…¸‰!°F—4/ÁóôÆ eœcÈLQ(Sâtž“Ên¼Lúe£[¼úgŸ¶š–Ñüí²nWÕ,û¬±EúÈûsÓ—ü®R<+–¸ °±&ÂÜ/˜”\ð0åe®IQÑæ¬ôe%%GŒu‹‰ï‰t˜O ’ÅGœd††ÒF6˜ÖÀ3Mnðk=ˆÜé&b!÷4O ³Ñ±]q Ï÷~¤Ó¤a)û·eŸ¶F--ÌŒ~5ͲÏ[ ŠU÷Êš«eW¾aæqïCw—(‚@D î¼ =†6³°R!C5¿LšPr’¯XÜÁA>mé¾Ñï°ª·UµÏì'—õ¼š^^£¥jlA¬*cL#eu°lZðà:‚ÚZŠ*øpçe?V5øIŸ—i#lÕò“'O~+HŽ‚@Ä! ¼À& >/Ó:ìÈ8ÀÑXM§BÜ‘ÑxRÊÀ" ¼@|…—®$-Ô_š—m¶ê¹ññ¸ñçWvxG õøy^OReÐÒ|ôØ‚$É0#}¯Ö¤¨… /Ë 4­/‚@X!¾¼\VZÚ¯ÿììì¾}û––ÓPc‰È”äÆF€ ‰£¡²(>°Ê6œ@8ne H¿cæ\’0Øx„)#Ò]ÐMVzxlÈÐò²Q/¬˜µÃ¢öØŽb ðååi³Œ5|Ô¨‘#GÿuÖ< ¬éÀ*,*Á?,*ÁS,á5xÄȰÁÉaÈaFÒcºª ©fcçÊ@‡È EGàçyßòM‹*^6Õ “_1£/`ÔEôÂTÌà ¾¼\^VÚ®CçIÇ·m× a P'™œcÐx™˜›žD¯dL öp‡†/ó>,íÃêu) ìé&Kž=¶PðyzŒø¸XS½°Ñ?¯ª½°ÇÖA h„//‚²²Ò9sãj„cLl7ܤébdòYĶÆ3Èš±êà‚æ—iÉ $…é P0f<Àþ´&…nZŸn>/³èÖÆË¬A½pоl’‘ `°æe‹uðÙ Nd #„¼L5½p€ZV’Š@åe¼»£eÜ7ä¼|RíD/ÐÆ–Äÿ!Ð@yÙºK)¼x98u–\A Î/×B× /\IZ¨¿/[j[uË(ÌX”0‡Š—U@–ªgÇrè™-Ãß o8y#j¥Õ|@{´× ¼Ê q½µ÷¶<°·Ò7¬Øheá¼›Æ k^Ž‹›g¬ÄȤGöí±b‘4s¸Z!Yuo*ë+CÅËÀ„4päàMÛ ØèÕˆ}ãÛŸËØÎYã5Örð^ÅðW‡0uÏiòû¬¹Næ4áÙ%! 5"B‚;0ÆyolÚ×™|@ÞÒ×¼òã£êšýMS\Ô]Ýå8ÐÞÕ(í­¥I®PyOkÚ›Ó§¼€ •Ÿëë*/Ô×X/ŠÊ‡«j:ȋʦQ×QÃSmSÞ œÊ¬î/3ÚP\ý‚0®ÚŽ…¤ú"®±oPíÔ~Â6¦eÓÚŽ &—®êèÛ—º>Å _^^¼,9&æ§ ÄDG',KÒ@çå`gì Ež—Õ0‰ç ·¥B†¬îÅI‘–äÌ0  ¥h7)ÈãpÒæRÐÉa”ÄœßÈ?­ Ä©îJÅ*=uÇ¿ó24ë”#hßsB€mð…ìÔ©¾Ÿ*àšö™XßOºuë{J“ïkEi‚&˜îUßД53©*¾Fjúœ,²C‚xD±øÊ^ö5oÑjúÆ4ɘïg©ésùaIåŒ\c^T µ^(!— ¼lŠ›šVGõ)·©Võ×ÈU[»o;Š é¦ohýDícžÆßinb7u¬O$ëC]——W¦¦÷éÓ{äˆá½{÷JIIÓêFZcÜ!BSŒ¡´0q.¯úSw2ò24’ËØ×þ‘1>ÂfiÖt„yŠº+•éÎR¡âeu_]f° ‡U<Éd®Á÷Í8>Õ´ÏäßÙ8æRý/súøRšH„ÆŒ¼æ|C#k WÜG,ÎËtl[ÛÎ1,¸ƒâr¾ ~“šŽ9}u¼¬ú’VÇþ”>vi¡Á#—ß8^6þÿ¡ÖËX6”Ù8Î¥²©%QÓôMÇøŒ!ÒqÕÖ®ÚŽãRiÔŒtŒ}ÃØOLûÿÏa/#YÒדi}à²ú%|y(ÇŒ›ôõ·ýŠ™`Dœy@Ê´Gªæ­žh Ÿº §Æû^s€FÙ4æ,0ÇÇ¥™Ó1^怸CCcŠKÙѪN?T¼ìªƒÒü@»/¾Naëß¹ŽU«OÑMÛZÚ.Rš8¬yÙ ˆ“úû9!@û?©am«'Ú&J[ª§n(EyiþŒ(æ.x*dAµ]©Àטªw‡Éiáåvàó2ù“ƒŠ€ôª¦UÓÃ2U«K̨*ºð‘©“5ª¤—ÐôŪ~–´ÉFͯ‘yÕr"Lš¯ªŸUË –Móí÷r²Æàm¼5½­ø­à—§a'Ö¼ìf©i‹¾AÃlY‰úø S•ñxëZzºª#T¼¬êˆY…êJëÊ\c:bUŹv£/Vó5j~ºiÕž3¢›¦úY­UŸÑ~,'ý®˜ú°6êmÅou¨¾\õ;ßðåe÷ûHùÆ®ˆ“¹xQêh„›v>ט9mp¥;¡:‚Ï˘ÇX’°ˆ5³š.ظ6ÏýÔ„ªKUu¾¤AVõÅ4^V¥¯FÍ/ñ>ˆŒ(4[¤>¦A1­4ÕÏj¿(6-£#åD²FÖ¬)&¹·Z®W¨:›ä[Ÿ_^v¿Ôüäá «Æ ˜Ð'øèøÎ·s|Ãßëqiß±/ìÜ»žï„ªÁ‚ÏËì?TU®ùŠëúצá_£ðåe÷ûHmÝ•3ÐÉÈ8ÀG)/ï9°™ï„ªBÀË©ìÓÅ ;«'œ2‡ê0õíªä!,g¨ð‘|0áËËh7ûHáéÃ-kçŽ9@“tm÷}#PóÓmâürîÏRuA > Ö¼é‡`¼ìÔcÈ!€ðr›/T¼¬¾óX=MGìÑÞ+_Æ®´ÉjR®ôÔu)«4]•ï!¤Õ°•²Y©£i]TŸýWp^~l;ŸË¯UªŽþ¬ÕÔð&Ùºm+}É´lî½x«Ùgû:â)¼\—/¾‡¸¡âeË+ÿËªŽØèwXûnh^ ösFš ÒP³6YûÖi6ph½5ßÊœ&¾N›6m"/ÃF ù*c6>’×`®‹éÒõ&‡—ÓÑ4àªh®£©ÿeM»Âún*Qäç¦cQyØÿ·Ñ¯4%Âzpòüɘ«sÄ5m#7øs»¸Â–û‰ª£wåcZµ!?…äPó£­bË> ÑRš?k¯ÚŠLÖi²f߈ƒÑg! VíÕþ úª¶H7ÂËòÅ,ä¼Lßyþ—©÷Ó÷ÖèwXóÅìÞg®¦q&IœÑC1nšút6¢Ìg&JŠˆ¯,ÿsãËXýV«>‘]É”—alÔ€}4«u4ú_¦¸êKZõ_ì*_W}NÍ‹}Ok8p\Öƒ+ Cµ ¦mÄuw:‹­]œIøS²F?ÚŒ­©l­F>øÑV±u¥‘÷ªÝ¹âHÙˆ¡&«WW6™"¦~׸²¦>ÍÝŠð²/„k1N¨xÙÔ.Êlê“WÕÓ¸Có;lúò™kÔ8ÓZhc%ö³ìf<…¸ª¿`ëqšø}@³aãP¾(q\Íó¸/÷:áu’ì;X­#åeô+ÍãkÍϵ«ñ2Ò1ý?šò¢ÿ TÿÎÚ>,ÔKYNáñ2ùõW}m›¶‘ü©]Ô¶  îì[YÃAýî¨zp+~´¹ÝøÅæ5®ÛþŸ ÿôñ²Z g€iäeí{G}Õ•Osáe‹,ê³£Gú?Q·)º×/££˜þÿäBZÏÎâ|«õÝ[ºš_öWú¦é¸™_¹ŸkWø¹]Š¿‰ã‰öIð!®Å(2^¶”×f,WUUy­nd]IÝð“Ø‚@X (^Þ¿ß±±SC>B‚€ðrCîrR÷zƒ@ xCÅ#GŽàù†y îÁ,£S /×›o¦T¤!#(^nȘ†°îÄ˪ÞÖ¢ž”^’'4ù½“ÅtÔº›¾³ª‹®S‹ë­¶Ô´luÑ×¥.(Œ+}®ÏØ:–‡ñ©c:®Êïm{ù¬_vƒ­«ï¦·e ôw\x9Ð5}ò'GúMþv±¦˜u¾xDú9ꎬ»d-'½ÓàûTJ‡Þù@5ìþ­”©öSÕ2ÓûzuŸlUÃ@>ûÙÆ¨ƒÖüA³®™´Ú;*3éÕz™jqU2ëv]é²Õö6ÕðºÑçº*šÉTË÷Ñ4ª™µ(¤›VuâšܨÃU1QÓÑÚBÕ/«e3Õðªõ"a©/X{®ýVeC‡Ô´Éjùºu[÷qé8éüÔ¾¤~G|ÐûëÛ.¼ì/$Ã"/kj|ôhúYبfdÃÒ›J¸Héìñ}´¦ýÔÄ\Òl|… ¦é[5e’©VZõé¬6 é9eS©i\S­VWmïƒ>Wmµ¾®4°®4È\SS¸{®QR¹ÁA+›)¶Z½Lû$ÃÈe¦&SußÜF¦÷Õz¹Š«ÚpަåñAwì/^ö’a‘—iLAcaUSìj¼L6䬙´œÄ¹ªS «:hW[Sí'ý<öV];Gaú©@XÕ «ZiUckÔJÓ˜Zõé¬6 iŠõ2ÕǼø’DFŸÑ¬“5þ/ìƒ>×+ ,øË¨A¦ÿ3C{òÿVt¸*&ƶPq £–ÁX~µÒ¸˜W©ðÜÕxékcjUÏ®Ž—ÕzÑX[‹ŒÔ¾4 Wßô%ßtÇþbáe!éç½_“fÍ@rTailƒ  h ù ‡€RK<â0o8ºiáå`~ž×Loý/[÷Ô¬Zb4S|"¼=%ƒŠ€ðr½jøàŒ—ëdRA üpðòÁâc‡÷”—¨¨8l«:f¯©¨©.·Û±TÍf«,™µ<ÏXêé ú?×úì×Ú_…?œ¶¥ûùðC5d%^ô’± à?Ž=Pm·oÛgß¼«jãΪ•Û* ¶Væo©Ü¶×V]yxÖ áeÿÁ蔂ÏËþÒºI_ˆ Êܾ¯fÃÎê¬"[ú†ê´‚êä|[b®mi¶mVbÙÞæ$ /GN{&ì=ëŒÓè9®¬yÐüÛªZTöu«¾¿fm¥ãJCêJëj“I€WLª¶Ô¨#6êRëÈø‘ÓhRRA@G ¼ôà¦bÛêÕ« l+ó«R×V-ȰÍOÇY=oUù†­»c“„—#§Û,^³íóŽíQ^’ëjþ”IûIû„EÅÿ{­ËÒuöøÔŠÜÂâØä|cIå½_x´ž¡¾Í/SÇ̼´‘¤X‚€'ÀËÛ«VäTåm³7nÙ¿EÇÑx{Ê’âùkì¿¥–çn^ö„`X=÷—ê RA@/¯Ûf[žcKʫڰ×þLóo§.ß½(ßþÛêªY)àå8/GP/^Ž Æ’¢ ®¨,;˜»Ù–e[‘]½<¯jõf{Â:{Äkª§%;ÆËÂË‘Ôy„—#©µ¤¬‚€ ÀËÙE•³SªfTÎK¯ŠÏ¨šQ5}UåÔÔÊ KŽåmÄ{?™_ŽœÞ³—yeRâgVnŠWÇ>À@kAc™‘‘«VvõÈ/e tÝëÞô'¥PuäÐ1[ñ¾š½í8÷´°ï>`ßµß^VaÏß´{^ê:cŽòÞÏÏ­à¯äºý4Ô UÆ_ô[½ådsm¾uÎåàŒºèZœ`XM'üÏ5k×ã‚kîÄ}Äjòá—ˆˆ0n:¤Nû÷•tμ¬Q­Í9—# ÒätjórÞw$â 8’=çrÉXÃQ¶s.GQk£¸Î×¼·‹+L¨ßªùª}• Šp;ª}Lm7˜ke êÇå¹Ó§¾²ÕÀ…ïõŸ×¢ãlî¸ÎÇõÝ~ ç¬ÈèþÓáeѦ¤#‚@ ñr •tA@ð áeßp“X‚€ àøê¿4O§í˜ÝÍéô¸f·×8O:,îxJö$ƒrwY¨¹ÛÉÇ[µ½Yða­"'r¬cvµù /Ë·Kü‹@õ—#§5þj\ó料Ýë7gó^SÝŸMºMl?d2nÛ¶-÷·üNïiî“ÕžzÌ…  )ÿóý»÷óπŊ¨9Ö!»­ ¼ìß)© ‚@uã¯Æú …>ÿ‰“z£[´¿’u“λ}¦2/û±"®rT²^BóJ‚@E æ­“Põòò2:~öÙg_yå• æ«÷ÙÀ4PQá˜XhòÅhF±iG«É¾é<¸ûdñtôhG:r¬,·Wz»óòIAt”µÀñÛos,¦©æˆ(Ó¦9§›zvÂË ô #Õ‚€@Íë_¥;v'ò{ä‘G(×G­ p!ئºº‚n"@7KKÛkJ_þ|$¿ÚãåÚd)å7Þxž>ýôS] pú”²ö)ÚËŽTÝÓ¢÷´ã9êiÜø%zôË/“fÍšÎÑ)q-}²¤ôùÑ믿æ:;®¨]æ1N`!!A@ð5o|=În¯8zôN›­<>>¼9s¦ƒÈp¼ñÆk~ز]»¶L¦¿˜œ¼¢E‹æ8aŒ(θ%öê£;©¼ÃÉÂI½óN N³uëVàMN$KO‘Ñ;ï47>¢üûß÷ãŠÁ¡‡‹[ô®]]…÷jE¨ädIYÉâ&Š š^²dÑK/½ˆUÀSԙŽ!ñw`vÁP fÙ /û£÷I‚€ `†@ÍkÝ1¿\zøð~:ÉfÆŒ©/½ô ¬O?ýäüóÏGø©§žÄõõ×_ýôÓ6¸aˆ.(bMå¡—:Žà,^ë ^>)Y$Ò¢E³§žz‚ÁµE‹·)ãIÕfáÌ´6‹ãáp‡bQvGŽ(=´]åeµ"(—3¢%Bµs*FNª# ¸xÈškgÈNxY¾O‚€ (j^íö³½úØ¡Cûpbæáþûˆ¹èJ\†+}|úiAã˜4i\yùQD,)Ùo«8ôbÇá'ñòñd)eJ„”sÆt(/æëãÆöéÓ§.Z4t™˜¸Ôy³ŠŠZrøÀ±ÛßQÆËZEŽ3¯}âÄqHDj¸â†ÓÇS®VkÚßÇEvÂËê‘’® Ô¼æàå#‡Jö–8O¢]Z\Ül»½W|\´h^t´ã]œ“ˆ ±3Å*)ÙW]~@ååW1^®>züé^Ä¢¸¸Ãa5º‰;à,P zÄ) ‘Ç÷;¸õ¤ñ²R$‚’£8‰‹)T"üÈ#ÿ¥Vçô¹Ž°qŸ¨5Ø,;áeùî‚@Àxê³áöÊÝØq”O{Íœ¶²½¸ƒ+…ù#™‘ G)=´£æÈÖG[÷åb‚—Kî8vpÛP trXM‡oRÀøHMáèÁm{¶æ4?1^¶k¡’«áêhUPë¨Õš lÌŽk*ïýÖ7%aA ¡"Ðaè/½ûí­{×ñ|èÝm8$wtlݵëη¾y¢õwuLÖUô'?ú®QÓ®Åûk'Ä‘£¿*bš£1;áå†ú‘z ‚@Ø# ãå°o")  40„—XƒKuA ì`^þÿ¡çb¦”ÄÊÅIEND®B`‚ivy-2.4.0-rc1/doc/images/xooki-edit.png000066400000000000000000001467421226750426600176330ustar00rootroot00000000000000‰PNG  IHDRºhÇç ªsRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< pHYsttÞfxÍKIDATx^íý ´Å•çòºßªêÏë-wUõWߪçW]®¯º¿j·«=Q6`<”MÙ.vaÛØ%WcŒg—g31Ù ƒAÃĠ+BLš$FIhFB‰A‰AB y¸WøísC77†;2óœ“yòW®»®òDìØñ‹ÈÌÿÙÚñÿtÖ_ƒ¿þë¿”B‘vxá… nžä2 Á#OÀQr’qL*sLRi:PJQø?xu„Șú2•êʉ™£#¯- ¹Œà:€€€H XryÓ¾?胤³P.?±fýU7ݪŽ_\:dÊC˜ÑŸRIÈeMõ„ÓNá¥-ä²tG¿" €€€d#`ÉåÛÿ@ǯÿaÅëPryî+°:iIÞ+Gݺ{ï>:fÍ_øÖáCîAçU+GñÊåMóæ-þñk®þ­Õ :CçéSuž—Úßœ|¾>\%”é8ådC:9äs¶‘ej!º    R–\žöüá©ÏžöÂá©/VrùO¾z•u¸²õòƼ¹kï›»÷RyÿÁƒúØ×ÿ7W†Üè‘Ë ­üÃÓ7}÷ÛôÛTÌô÷"uþ§+Å•Ë/lù$šË/—§LœòžÏ~Œ~+W?pʧÛ/—ÿ€”UçH_¿zÿõkö7~¯ÞOÿ Ñ2e+•¹ôúîíoîÙþÆ’ÅÛwì?lÛ}@ýÝ8OÞÜsÉuÝV]ª¾áŽ1‹¾ó¿÷^~ ôÇãçþ˜ÎÐoú{wÿI:C%ݺ¦‡ÿvïyÏlúî3›¿û¿ï=Ïõœ¯ËÏ‹ë~à´“)¨üžS>ý®Ï~ì=?¿€RÌïúô‡éwÈçÌs6`öG—37ƒŠ    ÐÁ,¹l½ê'”Ëwݺ}÷ËÛw‘,Þôú~}lnü½:OŸÒA%½Ò“É ¿ù]ƒ/Ø=øüç~ú£EßD¿w >÷yç/úæ7èSå /[¿~çÙJ.Óäòÿøñûïwz»\ \Vö¡åŸ_ðòî ‹6LR¢™:ÿ×>ö]Ÿü°öÁl“Ы˜=r9›uÔŽ'dZ@›(,ùxþ°Û6¿òæ¦WÞ$Y¼áÕ]^ÙE¿7öýÑøýjŸŒî+pÁ°ÛBÒsõ/Î_0è_wýü¬]?k»û~/ôu:oÉGÓç¯Þö‹¯ŒýùWÇÒï_¬Üðm}Ð?õ!‘ÚÿíûãN2çËCæüÍîKícþóÏŽùò•žã?ÿŒñY}ôw?½`ÑÆIïýÑßlØöøÚ­ónœø¿~v>É膒>åc„Ö_rNBW1C.çDŠê   5"•Ë”¸L8Ôo’ÎêKòž{Íí^ÚAÉâ—ž¸Å=èüÆߨðâŽs¯½‰Ô.øêi/}mЮïýD[¾6ˆÎ02>úâè/XwFãXû­kü±pí ÕÉug|aô%rù¯¾sû‡=ùÃçNþ«ïÞ.—ËT’óéÃ'ÿzÆÊWþ?:íËóH+˜{ñ g®5~ÉÿãßC.×úšDçA@@JE ÜåŸ_yÇ^{â™m£ñÇk+žéÿgßÉóôû5*É$c~ɺW–¬{UýþÎo&˜\Ü8Ÿþûåã½r™4ñcŸû’ÊëNýÊüÏ}‰~Óßo|ã;ô·VÌ|”÷—Ÿ~ýì¯^?û4úÃõFŒù²›>ûÂÖ•¥ìAÝ‚\®û @ÿA@@šJ`Çέ×Üþ•Ûø |ɯ! »Ž¿ô¦Oo|qYS=ñl —³qC-X¶v²½Ÿ™µÜÿ÷%£?õ̦Å"‹(ÔZË­åÖ@@@:‘À[o½ÕÛÛsðоžÞCôbŸîâ¾ý;ošô££ _ï33.»ùŸžßòÆšxeûF::‘_©û¹\êás   %'°ïÀ®ç^Z1mî5£îýîÐ;¾vÝ]ߺóþ ¯¾wÛ›H:¿°uÕà®þíH,­L»úgH.SáPgi9J€¦ôʧï/9Îsr¹óÆ=h{¸äü‘î¾}ʸï i;åÑ«ÇÏÜ÷Ï£çJŽˆé!7ÿóK¯=åú½kÏö%k&^=öK}ÙÏ'ÐÖ€­ëZê#¹Œ‰   Ù ÌYxãÅ7~ÂN·Ð/óéø±•¯ì¤/_9æ_¶¿ù¢éÇÞýo®~æQ÷}_¿ööÓÜ“ÝWÔÌDr96T>oìzyôÄÑÁ*œL¿õ}©ÖšF>%cÐòÌ êë;·Ð ‚·Nþ‰U~Âì‹ÌÄhŒ@k@.·†3ZèL´¬2e*Ÿßõá#KÅù‰³÷óëOØ“>¡{ÊÏ—¬™4éá+FŒÿ}D‹47ÖiV…ûTø²µS;b¹{¹\îñw   ¥'°gߎßuaÀÊÊ}yÆNÈùHZóQa­u³ÚÁdäñŒüH# í[iŽf¦×K£,R.Óú&ø)?C‡5Éɼ>Ð%˜6ïZ;„ì„™Ï7âÄÅì¦;ëò}êyü¬ói¡:™;(U$Èå&IǶ™Ý¼ys¨múhÇŽ'NlžsîÜÌßV‘ó¶@@@ 9h9äÆ æÚpÌ»}FP9(²MµÝuüy]ÇÑkÍñV# —ó˹4 K—.=­ÿ‡þN«,(ýË_þò¢‹.òŠæÁƒÏ™3çÚ[ǹöz²ôÚÊuO޽ëñ ._wýõ›§ÎØns\Í   PZôÞ}]îͲð'.+1íJjwmæ¾b]Nß¹çµÒv¿³ëp¹ü£ýè?ôÿüùŸÿyóòäB’‚»Ú¥ë¯oÈÖÂFŒAMn^¸p¡iœ„òyW_GØñ̺Ùoÿû›ÿËÉÿÃ{þ£÷oý¿ÿÞw»îäÓÆþ¤§ï¹½p—Š5ØÙ×$z  PQ`¦µ–I7’.(qÙ+|­¸²°L×ñ󟸣¢X:ÀíN–Ë$ŽI"kmJL:µXÝ–Áš)—GÁ‚¤ÊêÕ«O=õTêò÷¾÷½ñãÇ«*gþì,%—é˜xÖõSÿ“èý'ï#Å<òÿøèŽÿø¾{þôÓ¤›I=ÏyÏ×}üØ[?ò…ýhŽÍrRÒ¦L\~耀@' gÖ£w»±äóº>tÎðœg¦&÷©dRÕç;rùÈÉyÏ´Yà»^é$VÕêK‰äò®]»®½öÚ¿û»¿3.ýM’÷’K.¡OSÕ%X¦ ”j¤ðò­‘ËÊí[osì±Ç„“N:‰þ~î¹g¿ößh¦ß$—ô''_ø¶Ï’P¦ß¤˜§þ§÷/ý£ÿI¿éïƒÿñýôIgÒÐßñnŠ:Ïýö×( ]8 Vëòƒ·  F`ÿÁ=c¦üÔ\úmðÈã~3꯸õóçŽø åÛ[úYùþœææ¯×a ªÕRÈå­[·R6/©ºãŽ;ŽóÝ}?½í¶ÛHäÑIúèï|gê;jgžy¦%—ßþö·ïÛ·7DS¾éŸ¨)ê6s”éŸÚ+³GV1˲²C?Ñ­$‘)•YµH_EÎ9çœÿù_H._ÿËñgþÅ×é¸ämßò§Ÿë~Û—¯ýÓºí?}HÉer&¹LágRÌOýñûæwº9nÄ{{ìÇgP®s†o/©žg._­+Þ‚€t×v¼0lü ½ëõ9Ã>0vÚ/wìÜ2aÖùgûÀy#*fW;9Í×ß}æþ»;ŒRµºÓ~¹Lú˜”ý6ßN£< dÛ^}™d" >’‰*êLªZ¨¢ÈšV¥ïxÇ;ôßdд dºúѪ]ý“ºY˜"Ó–ø¦’þ¦È·›MYn˜œä;5mÊeú[uß+ •Ÿ”ü·û·f²<Þ\!UŒR¾²r‰¢õ¤˜Ï˜r¦| JÒ üfúMŠ™ 6«œ Š7Sì™Ä4¥j(ÝL!çugžJ‰Î÷þøTZaãák´bêµô¿? /SÝËžƒ€T—å]Ü>ãœËoùì…×T’ÏöÞ›'ý{OÏÁ­¯­¿èúÑ›Á=±u*sŸ€y×7wîÙV]ãy{ä2ÅŒI¶†´2ECu†Š+Sî/Éå‡~xæÌ™*#™Ïc&-®Õ§ '›²ØÌ$6Ïk¹fêTK^›’NçS[*ÖkJaÒµfa•wa•ñ*cEK|”é›dÙf"I‹c\ÖËbCZ?nÈÛϤWýHŸöÎÓH7«x3©gÒÍ'ý—3H1SªÅ›)¹™"Í?ú³3)êLŠyéG)ÎoV‘fÒÍtP°yÝyïìÿóï)aCÿsÅ»ßMÒyëO¤E6è˜ùù“fn,²ÑbéÜ1*:  P ‡ß:üÀ¢Q}KÈÝ›ÂÉ¿¸æï(§bïþ×Þþ•_w}pເÆêËÄÀâq%ôöÈeÒ Þœ WÖZ™Ò0(®LrYieZé‚V‚#¡¬ry­,dS›ššR­=ÊÇðÊe*o†{MËä-–¬¶ùÌg>£‹QÖ„ÕJhŽÐ«~fLšL‘ÖgHyëMÌà·äÍ?Hèè½IZtù¦Û¿ikõß­u åZ¦ƒt3éco¦¦?öÎ/Ð?)Iƒ¤sã÷Û¿Né”§AñfRÛ”Ó|îŸ~žª“V&kfÖ/R¶‰f+MzzëqÇRòÆ´³?MÇÈo‚ÜØ÷òŽÂ#Ê–Á’\fp@@ &H.Ù¬D§#÷Iç³®}Ϙ©?ߺíé¡ã¾~Þˆ]’9°)‰*0{áõ5á–§›ôèßüÊ“MÝÃ¥ r™”Ÿ›¯L]U)ËZV¯÷Q\™¤žŠ+S†Öʤühw:3M•\–¦Ti Z}šã\6-(û·^¹3%µ’ËÊ1õCËzxµ P.SßMûÞ¿i¡Ü$z„T}ñ Ja`R·üe#™t3i_ÒÁß{ç¾þ'¿ ×þNþ³ŸžþîP˜Y…œé·’΃Þ1¨xîÓÍ$šu¼™¢Î¤›)êL*™L©Øó¨?ùý¡Þl´òŸÞO¹Î‡Ž;nðßœL©QÚ…t3åoP"í,(ìHj±<—ê‚€€@vs-(ƒù²ÑŸY»ñáaw|ýÈrr‚ Jî{ð² Ô­ å…ÿ®û ´âuó:Þj¹¬´²6µ²ùzÉe¥•)…€âÊzu9õŽ WÕ¡eWVZ™„&…li6’‰?ýéOIºy3˜IRGã²'Ÿ|2#—ÍEèT(ÚTÆZë»qbòM7Ú±O]&Ú”Z®ØŸÆÛxï<¶‘müW'Óï{þdЭ;H­‰AùÊýç³é  RÌ$|I@Óߤ)êL‘fRÌÚ7zMP«gUX¥>Sá3ß~ºŽ@“,&…MÉÐôEšé ÑLr™BH7¿uÚI´¨3‰fÒñëN<–R5Þ}溿\±ð—ëÖÍ̳uy±W ¬€€@”åc<¼lŒ%ˆû6ö;výóÝ<ñGôÑoGýãoGD¿/y"óÚߨû¾m®¶öîséÚÉî¿H¼ðº¹åŸé¸â–Ï]sûWošøÃ§7-* NKå2IOýr›)þtʲÖÊæë}ZÖZ™¢Â¤•é½:²Ck“hvE¤6c±æ:#úªŸzÍÎ[Ì›g¬)ج^:F—©¤™=bÅãÕÑ©û¶X¬hÍ Z΂^È£‰…Ç "ÝL‘fʦ 0(BLšr”éz)‚Ä”>AÙr¦ßýMÞ~:åfŒ¦Ø3©g{&Ÿé}AŠF“Œ¦O©$¥jPš”´ÒÊ}k9GAkõ7¶I¬Ó®(”­v¤üæƒOZwÕIo=ùÚKN\8ó”[¯oÙÏE]'°  r½‡{Zzó%£?¥E³Z cõ†­ºû©çÛ¶cÓk;žß±s+ ¾ßù€7ÿŒ$KG†ÊÈÛ­UÉÇž¸óüë>|ôˆæÖ÷ºäõw‹ÏEi\V¯ß¹¡eW¶R–)C-…¡^1ie Ù’V¦Å’‡ ¢R, hæ0¸ošÉê@S«×éÌ•àÈa·˜ZÓ-´½ˆ¹% ™R6ÉO½ˆ0ºL¾YMè·ý”µPp=)Mð×-™F˽Ýû•xø¤S)e‚´,é×™o?•t3ek„%ÑL *™âÁç¼ã4¾ö¯Ñoʯ éL1iT¦4 •÷|ê±g’h&é¬Öª#=MûG璉ÆZï:ƒ”´Úv›¬‘n&NŠ™š~î½Çμää)77äòsëN멤˜çÜóY:æÍ’i.ê:H%ðÜK+¦Í½æÖÉ?}ßn›qö£Ýå[îÅWÖN¸ÿÂknû Éë‹nøØ×}„úã7£>yÅ­Ÿ[õôìÔvëP~ß]ô…ʧó”G¯*v¾ÖÉeRxÖ!*Ã|½O-…¡_ï3µ²JÃPqeÒÊ´ˆÉeµñ‡ùcfM¸‘lk%cªÈoSBû(㦠÷fzèE*(J^y˸۔˜K[X¹Ëª] ¥3‰%¡|$Ŭ 7tó¼ñOÿ%E<÷ñi¥ ’ÎJ¿’h¦ôb’ÑtF­¸LÓ®%¤q)äLbš~“n¦R´ ES†JSn¡ß>˜VtVÛR@ºñ¾ ­UGzúÝg46IùÛ“)8MÇ©ÿáoh‡mzóïúŸžúðˆ“ÇüÄÌñß릞JByßæAJ4ßzÕÇI4Ë;X‡[ú  Pr”žõB¡u^ñÔÌek§,[;õ‰õ³há¹g6-ÞöÆæhݺxî¥å,óøºiÝSqñÿÐá÷…–‡ÜròÌù#žßòDá@Z$—•Ü´2 B¯÷éeãôë}WVi¤wIàÒ2´Å)§œB6]¹¬ßŠs_(¤Ø¶þÔ]™>2cÃVªI[óSªN~jkæ‹}Ô/rÒÚ±"Íj­ŒP-mÊRù”ÉM™Ö–h¦5:ˆ€ÞqP.£% h<<š+eÓêo´ç h’Ë”UL‹(Ób·ÿø8µ±)i Sà™bÃJC÷ ë¤?HCS4š¢Î$£)¡YmHY”ÝAI̤¤é¥@ZøY-TGf*C±g <þÞ±÷þî¤Û/ú4ý~Ήú ÒGt~ê5§Êo.ü‚A6 $ZªïÙ?Ôs€Þí£51tŒù÷c¿Lgšá[‹ä2‰EkÛÑTËÆ©¥0ÔËj) •†a¥,«¸2ie -ŸsÎ9J.K¶ê`4¢]¦F£j²>è;ZßÖz£÷í(Uƒ41-^±tügh=8µ“ŸÚد‘îÜ·¶Igu’þVÿTTÆ)ã#¯ýõÕ%­L9Í«&1­6ÜîËiþG:ÙTûWÞ<çTJÉ  2écú›âʔʬ~S \2͸``@@ä^ÛñåZÐZú ªœÚ—·o О~a!…7½¼Ú,#üûÅWב5²søp¯Ü%]’”e¶vClj•R½ Ôæ—×ðßòÚz*0uîïïžsñö76S•Ý{·_zÓgÌôåßßöeŠ:gÂ0l…\V¡e•¬~(þj.…AZYíÞ§–ÂÐ)Ëj) 3®¬Ò0H+ÓK~jÕ¶œ¯»A.Ktgã»ÍË;hÁfJtnÄžÿí8Jœ õ’é½F\ùþ'EIRÓ‹zêu½u{¬Ú.›>"ÅL‡RÆ$©<Ée:T¾²ÒÓô‡ÞX›lÒßd|ĕǩ”eÊÊ ïÙ·cÜÌsi§n¶EËÈ?ÉÚ3M–SÙöƦknÿJÔZò‚¼½ðúýæÆOPV7å.S€™_vóg'?ò» ³/3åg7MüÑì…78¸7Õ¾|‘r™Zòj/õþœù‘õzŸ™²ljeõzŸ^ CieJB D’Ë´·3ÉeÒ»ÞFIvÓ¾zT€’"¨bè¿ï!—…rÙ-Fiê á›yÕõÏü%¥Szá©g’Ø%õLål¬ø³cÿ|ç±´Ö2etÐJŒ¦=±iEúƒ´5}ºõ¤ciE9z×Î/¼èG”BMŸR|šR/hMŒù³2sbcE¹TW‹½T` @@’\y×7dÖ++Ÿ=ì#ÆãÕן#UGeè÷+Û7Þ>ý¬s‡ÿýù´u¶oûÚF›67ùõˆý‰×ß}&EX篸cõ3tOù9ŸùØzD&ù¶aó’ ¯ûXhE¯mø£¶'4×°aá€O/¼þ£ô‚c’'TøñµS­eª¹F­7¼¢E©ia¾¶®$’„‘¤óÁCûé7ýê@´|ÁrÙ«˜­°NY6—X¶vº¦¸²»†ÒÊ*´LZùôÓO×ËMXBŠ^¤eæÌ|_÷-CU¥ŠrÙÜ E÷‘¾¤ªÉœå½{Ò·Ó, ñæ©sè “”uC’wóŠ©$¯­ïN´–§#ËÝŽÎ~æ ÝvÃ=ß9¢5ûå2iâ!·~nË«OY—Í (é9ÃŽíÛÐäC$‚•DîSÉ´­É ×Üþez¿R/h½aÚð™V~عûµ©þþÜ͸¯î?¸GÞzõ¶×ö¯÷ì•ÅýrÙ£žµ˜î¯8gÑIÚ½§÷à¸çÚúØ1;ÐÛ(À|U÷(ÆLKSS³Ù÷7v½L©r’’-’Ëz ÷õ>•²¬^l•×ËÆ™)Ë:®L;w¨à±¹¸„Rîz´Ïih¹Ò*sI¯\V»p·òÇ+—s¦’ë¿ä@h-—µÊ$Lɵ”€á¶Hé¶´Æ÷~wØø½ø†øõˆ¿ïÍ¢ˆò ÷|›Ö~î¥ÇiQ¹‡—ÞrûŒ³¯îþÒÕcO½dô?îÓÓú¥Ôy/ÞÜý*…·ƒ µ?|{$¢,Ø¬Û ?œpúˡ…¥)eÀ— ½vÃØý2šv§¨né““žÙ´hÁª ×ÝuE¦Ïºö½g}ŸD>î¼´õÉqJõÞ÷àeòŽÐŠu}ò´?Ñ•§f†%—îrTæêl“®ã)ÓCî ­šwT¸»ÒÜçäÐq_7ß)ܸyé¬Çº(èN9*:i„Tä>DK)—½òHíÊ¡>²–ÂPZY-…¡´2…–)C¿Þ§v$ÑKaPh™”¢ÖÊÿøÇÝ…äTCdÖ’Ëzå¶k¸ü º,dý(  Í#Ð'—¿Ûy=á¼Ç;ìØg^h¬|à6JI·ô¦Ú×´{Ê/X4jÕ3sÖ??ݳs®¼«ëÎÓÏþs‡ÛÇ ùØ—ßl*Ë®ãi=5Ò‹’¾ôööÐBlG³“Éà‘êOžfnøbÏS½Z¾6ÅØi¿êw€š¨àöQûpÿ‚‘VO7¿òä‚•w]9æ_t™‹oøÄ#˺i1 “h™ÂärHÁP*e[KaÐûa¤•õŽ$æ²qúõ>ª¨w$Q¯÷‘L¤”e•†A«{ì±!¹LÎP~³VÌ´¡I'-Wæè2’1¢— €€Ô„€•»üëáüퟤÌZo÷÷íß9|ü7ÎöŠÿvÔI¿F¯ýxþÈÿºëC”ìW«:kbäñ\w"årHÀRò-¯1`ïè€*õ4j•4"Êý…jûwݧÐogˆ-îqôGOtùÈ‹}ÚZƒ–œSÆ)k™¢ÈôÊ#¥^P|Ýú AUhÉ‘Ûgœ³xõ}ô: ÄŸP™¦Ëeµu³Š+«U–M­¬–£Ð²»ÓµÖÊ”ƒa¥,“V¦E—)w–t0h¤¶(¶ín»-ŒM–¶X™£ËHÆÈs5¢.€€@'8*—ûrH.ÓRh¡¼Þƒ‡öQŽÁ¹Ã?H ïÑåc)5™ª¨Wý¼keÈö§RÐJz´,ñÑTã#òÔ—•áMYÉe3£¯ÌªgD{wSª }%ðÈåPÈÈãiÁ8 ]“§®/ýiâpñŸ¸iÒ†ß1ȳ¼FŸú.A+ÜIà´M.Óî$$vé5;ZúÀܑĻÓõM·7wºV»÷™Ka¨¸2ieÚèŽö”¦ß¥µÍsL%m[?”ÃMHéë»—a“õ÷ˆ;¿¡ÒÙÆ´éÑeRu”‹Ú½Ï|½ÑÊfÊ2ÉeRÉ”‹Lr™2.¼Z4º+(©-oa ?[åÕútÖfÔ!ÑIßHÐSyòÇl”rE(…Ú[‹ž º[?ª0µë~d:ã•Ë$ÍóÊ‚05‚6¦ò´~ˆîq¦3L´Ø+—i\TÓ¡ìÊP§O?ó™Ïè†máÊ4ˆg&+=Û%Z   P†\¾»o!¹#Ç ¿úžÇž¸ÃÍë¥ie4ÒÓT’þ µ„iû:ÒÍþtˆ€\¾àº,Z}ïù+ÛŸ%ûœ\>ª5Èå¡w|»ð+Qj?R‹R,vìÜÂ;óúÎ-WÞz4Ûø¨W¡1FOkNÓÂsdö¹—–Ó#G¿QXï&ö÷‚44)òl{ šÎ·B.“¦Ð²ÚéÚ»†Ú½âÊæRæî}j•eU*®LbK½çÚÒO¥5[?^¹LM[òˬERŒÖRõw¼ãn[ú ¹íZP¯?º?J.{Õ0ÔÊ["—µñЂÓÚ1·Ö¨¶#%í]ƒÏ+—u]ZÐúª@@í[ú¡Ô^ß“¤vëÒd}“)äf#   @tùèN?ûý»–¬¹OÉeZ £§÷ÐáÇi5´î>“Ò0”^üÍ ŸT+KÜ6ýW¶4· qò¨ðíÓÏá7é uÖü©Å1(Sbùºé´’å3„ó§õ÷󮺛çF™^÷Ñ}t^4°Ç VNÐ6_7•vEaºCZ™‚Ü…¬(×t¹L[I¦VVKa¨”eÒ»ô£´²Jð– ø±^ CÇ•I+SH’dnH' £ËÔ.£ÞÔGÔŠ7ÂJ//òâO[&hÉMêrËä25D¬¼¢Ÿ¼¢Ý£¨}%p#å¼\¦Ñ4G‡Þà4C×L£”~ãVÒýÞZˆ.g»‰£€€@³ r½ööÓúôÜ }+(6¡eÕ. eZÏaúü¡Ãïø×ÆË|*— /º¼aÓb*°ñÅeŒüˆ-Ù×ò®s ³Åei‘ µ%ž©GÖ„Ö9ÆÃÇ¢7h…ãQ÷}ŸóĦ|búJ‚LÏzÚ…{`&F¿V>ºXGß2 #?¿ï{e'Ó mðù-O4ðVö…±¿ÉUc¿˜ó ?ÝVÓå2…BIæz— ×ûôî}Þ®ÕR Õ)Ë*®¬D^hûkIt™Ä"W¶bÌ®€£ ‰ÐTeHX›Z]VX›+g¼¯ 2¡_ú†`öB]&©-Ôʪu7‘Ã]Pû‰èr³o÷°  =4XtãÙCßwþu¦ßôŸµÖÛk;^ µ“)Cƒäò¹ÃiM ZGù¨\&­y딟:‰NzîÀ0ó‚•w†¼¥u$.¾ñätùYCß«6磫ÍVh•Œ›'þûÏÿ?ïš}áòuS/¿å³¤žÑåÍGDáÓ›%åNv¤ŽÐ†Øôúà‘u6Ì ;©ãh:ÉY­ï)À<ò®oŠò1 ã´!vˆ*íNB™Gä²-šûâß>'i‰½ ³/¢Ý¿É,ý*Ö>ôý#w2¬ÅÈeF¹*i¨wºÖ;’PB‚ZbY§,2„ý¨eãÔë}WVñiõzEIé‡rméS¦Ñht™BËIŽÜ0›†¥Í&Hj m‘ËfJʼnùØpý/î…0ºJ¢àù›)×Ô(SÑåBn0  Ð$´´ðE7üEŽ»îü7JS6[¡ëÅ7|òöégïÙ÷ ë«Ç~ñ×]¤eÑT2ýPæÆ-“~Z Ã+^/»éŸ6½¼ÚíË®=Û‡ÞñµU|{‚/ÉÑzv¦zÂä1Å<Àæ ÷|‡t¶ë i‰»æô‰ÝP6¶“ÝA/ù‘>¾ìæ"c§ý’ÞY¼þîo ã“×£ïûíŒd›.—Usȵ×ëÝûÔËêõ>’Ëîë}$•Ôv$êõ>3e™´² -ó«)G£Ë!ÁJmy•™ù¦]¨.U¤v½M+›Úç¶Èer€ÚUb—é¯bÍ(»0w9dò¡C´©Š œþ/‚ñ ÑåüwXhÚ¨V‡ åE«ïýÙÕïºiâvÑeʵ U2º&œNzŽRr'Ü…–)}áõ£e´?kŸ{t‰4ë…<ßrr$@ç.¿ÝímbrÑ W‰ÔÑìhÍ«º¿h-MAëaæÚÆ^¸|[¿Ÿ”[Lr×Z ¤‘ÕÚ|Û9O(âN”h‹)\E] P=íáwñ ÿ@)jþ䳚§¥ôHpJw?(º¸ždè›.—Iœ5äò!I;][Ka¨ %F) –>eBË’Üeïâ*¢é•’fîo(\ª¥$Y !hýP‹z&ÉeúfBŠœ~Bê­·û4LT€·`.EZHN­@§òÉšWéjOÜUüty=Ä^oIm“¬»,¹ÈQ@@ -(6<ú¾ïÓ2ٽ龎Ÿu¹JÃÖmÏŒú ’¤½köEç {?%Ü5ûbJÏÝ`·v˜Ò!nšøCO6”P1òø›'ý»•$MÒüî9ÛòÔ«¶ûOz57-váѸìÛ‡´ëž åÓ³ûT»³´s Sô¢¡FGò`Öc#É Zzùåmõì×ö)xçýç7r¬ûíÐx´\]þÑo…\&esò 3õî}Öë}ÖRÞ×ûT¥X¨Ðrtë¸htÙ«À´ô*<­ÞÌíµuI~AKÜ7I.›­x è­wA ªbZð.g&@{3’­õãB=5Wê ¯^ຌ8Mþ+}šÿò€ÈLà­·¼ë JÃX¼ú^Šq>÷Ò S.SP™^D£·ýº§ýâW×¼çšÛ¾ò䆇¨-JÞØ=0à‰õ3i¾²Ð2»è†Yù͵W)øJŸ•!}å˜ÏïÜÓȶ~H…±’Ú}çîÒ7òøëî:ÃÊØîíí™øð{ÃjÛà%½ôÉɦ'„ŽVƒžõX—ë!=ý­ºçÒ›>­pÝ<éÇÖ7‡l£Ù ¹¬‚”za.…¡—£À³Ú½Oït­–ÂP«,ë¥0HÌ)}FÁ˨NŠæ.‡–.V–y¹ìU¢:Ï!ê“ ¡êf[wÙZ_™WäÞZ]ˆºAßa\;Vàß놙hÁ×ß^¼/e†v¨1ùg»$P @@Š"0}î5ç ûÀÙCß{çý¼°uÕÁCGy)Uƒö£¦å–éU¿{çü–-5ú̦E×ÞþUkiÊl¦ÌÝÁ#¬4ç_ž¢? ¸±æÚÈã^z«¹ˆÛâ5÷5B¹î¢ö™#9s—ߊ:-\u—?*ì è¾3]ÿ1Ê”0ynóÅknûª?!›–s21®¾íËjÇêÑËÛ7¼¹ûUú›¦Üe"ã©uÏÍU‰÷=x³˜|”[!—ÕÿÈ“R)Ëêõ>µÄ² -›ZY¥,«®ÕR*®,×Ê4ÀM.Gu$9àM‡ÐŠ6´*…P.{[KÅñNzùH·©ti˜\¹L¦`•D—C4tª·7ºl-Óú–"¿P@@Š%@BíÎûŸ×§Ïö>ZwYibõ³s÷«WÜò¹KGjÅSÓÕNuëŸìü®I^«mJÌÒ»\ÿ‘ó¢/Æ©%ŠGO½æ¢ãfþÚ'Oý¹¿ë>Åz%Ñô„¢Îýf_u7›¢ëø)^Mem„Ôs_6¶±€Ý‘÷ zÕr›«¦](§âÞ.¥<©ä5zñ•µc¦üœ"ñÊì–מ~rãô³"I?ôºäﺿ@º¿1m…\Vò‘V“PËÆé×ûT\ÙܽO/…¡vïÓ)Ë$—i5 JÄn©L¶è²0ƒøè,ex ˜‰¿L›Oa‚ÓÑ7ùøÜeJt1ÌÑÀ0}Éñö‚š¥¦íÉU&wYåZV½©ÇÚ]nš­Œr©À€€$ mJ®»ûŒ¾pé $—‡Üò9óå¹ýv‘,~õõgÉ&Eš7¾¸tëkO_5æ gû€ûzißïù.½ (JÉè{ŸïÙ—WÞÒf(´%µÿ½:wÙã‘Ç?²l ¿½Èü'îè·Ö¿â[ÿzvŠEŸä¥õ’µþ&9KêÙ³:žZÚ^DùøËnþ,Eå©c§þRú›QŸ¤â(rLÑeÊr¹÷ÁKèÅD:yÅ­Ÿ£ì J WßôòšrmSU±$›HQT-çîÞ§S–Ý¥0”V&Ư†aú-º¬Å"ŸŒ’€üšô©¹û†·0ñ ½„g Ù;vDÛòÐæEWÆ 7¢r9´7¡jZG½9QÿͯFÞè2ärÒ-…A@ZO€är×ÿûÜáOãËFzÉêû̪)³Y»DÒ–6õx~ëJÒÓSùÝêgt½·üöÁ#œí¦µN=x>":§Îý½2B/íqK¶™Fÿû±_¦5ÚxV¤P¯¹ý«~áÈi^õôle“R)¨‰#éü Ó2½ºGÐèÝÇ!·œlž§ñ³Î§¬nw¯z°ðHY‹¢Ë:&J≢³”ƒ¡VY¦0$‰!½ÓµÚ½âÊ* ƒT/ieÊIZ¹ÙÑe²/Ü;Ú…æÖÞLFDZû¤¨¨ât Ðê×êKEt‰\¦Å›½¯ªvµœ¥/H\¥‰èrëïìh@@ @¤óHºÑ q«7<¸ùå5+žš¡òn­ŸžžƒwÏùÍÙCßÿûÛN}íõçi©oJ.­¡FaZâ²O¤’*¥57(,=zâ< kò:f-)Ñš-½y€\6£Ô>gh]Žƒ‡KX<õÜ|œÛ·6­|Gè¨V_œþ[V/h æÆÒxVGºŽ§Õë˜Ý³oëä²Îè%¬´2;•\V«,«¸²™²LùÊjC3!ÉΜ»,Œ.“}Ê4H•€S7= VÓ¾»ËE¸“¶•&k:´¬Üàw‘Èe2Bš8ÄÁÌ-N 0[ýEt9ÛµZ  í%@JÒyûìÜ´uÕˆñß ½ý6:IɤŒï}à·´ 6É>Ú£„b¥*=ÃûC›äÙ"•Yº¸ëø/.£¤^sa5o²T‰Wý¢ÎdàÑQº/HܿψN>vUxßGCnþgµþ±7ãHš²©˜.O»œìÛ¿“j5öœpºƒCŸ:§Š…,ˆ¡!´T.Ó¼Q‰¿¤ƒ­×ûÜ¥0H3©Œè²q®€njî²jŽQŠ®‚¤/®“ôÅ@¨¹gΜéV'=*¬®€[ÛJ“A&6,”ËÛ^}9”yl&Kж|Iâž–è6û‹ÜåöÞîÑ:€€@6ô,[ùôý´ òÙÃ?pÖÐ÷QRòÚgÕ¦hUæ•ÏÜOÉô à‘HFöÐ÷QÕ„¦ŠôfÛïÆôïÄ¡2}UX×Lüí—d“Ök{ôñnhÙ\î­ÏÂy#ŽÓù’þÒ‚Êndw@ÖÇOެ¯¼ü©é¤z¯îþRŸ·ÇŸßï¹'ØÜ_Qm+H‰ÔÓç õ¯Ó< &m¤>wûŒs”Ô.ä§ÕrYge†#QK’Ñz½ä e¥®¬µ$qeU¦©¹Ëª JE Œ‰`¥bTØužBÔ’Í´™…ó„’d±÷+½lRÌB¹¬8xu¿µr½å)TÌô?+D— ¹Ôa@@ Å(´|õØ/Qâò¹ÃþþšÛ¾L ôæ¤ÇyBù¸3çÿÕµï=§/´¬Žó¯£Õ!N üB®R²„gI¸#‹Ä5„©©¥å‡ië»þ ¬±ÅјôÑÅ((9ø•íåˆ(ÀÜ0õbpWɸcÖy´L^¿²ïoW ý£ÂºŸ…º»¿¨¾6¬zfítØ_¬ÿKBß ”ž„#ØL›¿c.F.SgäZV•¤äµçˆûC‹‘Q’F† ²ö¡ÑeÕ©@FòRtœV›fÈPN…w³Í„Rœ)‚ËX ¥¬©Fµ“ÖܵkcÁ›•!—Ëʲv_Å£3e¥3® ]m:Œè²üæ…’  å!@ʸ±^r× ô–Þ›»_¡¼‹§_X@NÉeú¡e"_;õ·£ÿ‘ÌG—}¸áîBrºS´³ -q4¬ë}µ®!@„Z¹Œç> Z¾ï¡ËSÑM~øwý–-ú¼k9wÑÿtã½ß &“ \£ƒü™ôÈ•ä)ø#¢Ü5ëd-X,¯ÏೇÖfNêlÛä²ÒC”.lýÈ—¿`$ Jƒ6¬­1('ÄݧZ tïÖ¡æHŒ’â¤*¦n¦RB¶¹w]¨:åHPaWDÒw s% ¦³žÙ 6PėάX±Bò5†˜[Ñpš»úY–)cDQUò=´.²Ú!Ü|W’T2a,óƒ%é`Ò%   P’ËÃÇÿ¥#S ™¶k¦U2Ölx–¶ŒÓ*Âßø:ã77’\^Ì80}þ0#‹×Z|­_¶PŸGËY¬í¨ô<¬¥•æhÔ^S¢sC»›B–Yì¢ÿ#òÁqÃ^ñã·7~’¢×”M1fÊÏ<+FÔÖþOúóªÇÍ8×\¿/µª|›å²DëÔ¤ ÉSõÍ!OX½&¬R»™íÚ@-ÈC€ä2½ vÅ­Ÿ§•'>tù9Ã? ·Õ0ÍÒCmÊ#W;üXymÈåMœ\ÞöÆ&ʲ°_3“"lÍÚÈv8’Ì00AB+]ZÃ8[O©â€|åÀ«~ž,go´¸¿úmÓÏ¢ï3æw’=N¸ðúšIÛGÅú€®ùÚpÙMŸ6÷úº’­wºVar9äGª²Ay(œ@΋ÕA@@ ƺËN¿ºûTÚ‚nìÔ_Ð&´5×­˜1 ºÌÊe2K°OG6bÃîîÎf×ýi¾Ð/mðñrÿÖ©Ý|éµ§Hß[iÄ7ù$»[[÷Ÿ±âÄ ¹|¡xfÓbbEô~;ê¤ßÜøI ~Ó"z¤¡×l|hÝsó®óyw#î FžHî_0rÖc]Óæ]ûÀâQ´Ý®=ÛÍ S{×:¹L-®~`’d¾½Ø'XU˜vúØòÚú<ˆ^|eÝÑ «éÊ8ðö¡^¼¹?cÑê{yžßòDßûŽG ^yëçsö‚o±¥r9Ï` .€€€TˆÉåawüë ÷|{ϾwÌüõ÷7=1žVv»°{ïŽ!·|®!—ä.G¢Ëdá¹—Vüöƾ€´’¤æo½óQAé 97jÝ÷àåîÛ‡©ïšs‘‘Cl$ZØÂ]»¡Öî8ºŒÎ-!;)+Ú+Z]䆻¿£×œ¦?ÆÏ¬×Iu^RrYB e@@@@ ÉåÑå×w¾4}Þµ?ÿý»®»ûÌC=\+´nÆ…j?ç#ÉÜ«~ª:ÙñgA°ûüY¯å‘à¦Ý¹Ózå+½éå5´4²‘8ßxvò†Þf¥ëxÚýD"ß'̾H¹àº®º;/ ËMÅ ã   5%ÐXwù®oÑšhôv¥Ûž3üس†½÷Ù—¹8h'ŽsG4BË’•1tõõ/,¼dô§\é9ðU¿)_­»çK É÷íé=4áþ C;lk3÷'(ûÒ—)9„^ìÛôòjÉtyhÉÍZúÓÛ…ˆ~Èe y”½î®o?ò#´žÃ•w;ìØsGK›nXŠ‚©·MûÕ¯‡÷íí'Ë]V.Òš·O?Û^ÇÍZQÎÔÇE*mòì‹ÕÛ/.;’Á<`cêþ,ó¤›7ÒŸ¾L»Š<´_âÒª§gSÖµê;- AÛkKje.ƒèrft¨   A}rù JXûì#ËÖN>{èûHÛ;üƒ´¨ÅâU÷Òr‡íïí=ôÜKË/ýé#û¥ÈejøÉÓ2pñ…)Žåþ¤ûþ9áþ‹(*\ÔøÑZãgïÏÇ`òC¼çwÂêgú³ýÍiÿÕÜć†ke.¹œ*‚€€€'—o¸çLÚ„¶ÛXûì£\÷á†&nHÕ;âï¯ê>…’ï_x}ׄ;oäq:H,YC7Iz÷æI?æ̾U2TÊÇÓ/,,vðÖ=7÷‚‘ñhwn •£ëÇÝxÏwwîÙ&wéÞ/¥ü ú6òÔóóåµ²•„\ÎÆ µ@@@@€#@Ñåîù.mæwÝ„o®~ÁÈ»¾yö°÷+5IK&ÿzøé# 6Ÿ×õASï&ÉejžòžÏùa¿HµÒŒ-÷(‹£Àв¢@Ë$ö«£žX;ò1æ®ãy¼;i>½øÊ“”ëLÙáÞ·'“LE C.G¡€€€$ ÜbÚ‹îܼè†xxé-ÃïDoûƒ¯Æ’pIáR‹×M8cÀ:nf޲µÒ\ÿ¦O=ÿXrÖlxˆ$¬cjïî$ý'¯û¥m;6 ZPäñuÓh æÔZÊC.g€†*    !@ïðÍ_1nÒCCf=6âÙ—.\ueÙNyôjæ˜üÈïhgÚÇ. îÆÍK©"kù÷ôéÔG¿'?ü;òª­¡]'é•»îþ¶zgÑÞ‹Û}Ñ8Ó‚üã$¤VaÈå<ôP@@@‚H1“0U‹µõý}ˆ~3•¤#ÃŽT‹·¬?m’PV^غòŠ[>ÇEЭu3úþIËáÑ®+ežFËeø   Õ @kÀ›q®TvÃÌVVF×ñ·Nù©w³Ãòtr¹+r¸gZÚbåúûKÞgÈå’Ü6 L¹È’̽ûßœ»üö£Û”°oõYŠyøøAÍÞd$?;Èåü a@@@:í5Ž¡ãNÛ·g«;–Þär:3ÔN'@‹iÌ^x½½íˆ9Å’Èb["›ïÒÂÉ• ¹\‰a‚“    Ðj‹VßÞÔšÓÁöN%>I}ó¤ß`w«»”©=ÈåLØP @@@:Àºgçzär$œ< Ý"¤¶/¾ñ´»JUøA.We¤à'€€€´”À¦—W_tÃǹ¥”­ ·½ëÇ9òšÖ›{pÉM-íI¾Æ —óñCmèP´÷•cþÅ`V"ØÙsÄ.lnSÒ_…v3¡…5*Ä r¹BƒWA@@@ uh©¸ëî:ßPaÅ•…]Ç™ò³;·¶®E´¹\EØŽ#@«¼Ý6íWž(²JºÐYGšu,Ù§ži¿û¼lçžm•ã¹\¹!ƒÃ    Ð =½‡î{èr;ãÂLPVúø¨86—˰tÆM“~´fÃC½½=­ð»è6 —‹& {    Ð)^vë@5쬧ÂÌV¤¹GÚÜä¾/_ÿüc»÷¾^]$ËÕ;x   Í%@ïäÑØ^¼úÞ‡–Ü4éá+ï˜y-™<ò®o^;î´ßu6ö£cÈ-'_9æó×ÜþU:ß=õ瓹rÁÊ Ï¾øø®=Ûõh®‹Í·¹Ü|Æh@@@@ ² —+;tp@@@@ ù —›Ï-€€€€T–äre‡Žƒ€€€4Ÿäró£Ê€\®ìÐÁqæ€\n>c´    PYË•:8    Ð|ËÍgŒ@@@@*Kr¹²CÇA@@@šOr¹ùŒÑ€€€€@e @.Wvèà8€€€€@ó @.7Ÿ1Z¨,¸\¾õ‘    õ$¹Œ/     $¹ŒÉ    9äòà‘'àzˆG—ëɽ"¹ŒØ9€€€€ @.·nr¨åSð- @@@@ Bš.—Ý%ö*DÇr5Iﺅ“ªW—<N"Ð"¹¬‘UZ2&9ŸT¸“¦ú   D Õr™ØY:Ò ?›p½y««Zú#]Ñ€€€€@­4].׊&:     Ða —[· v‡Mt@@@ê@rr@@@@‚ârùÖGþ €€€€Ô“ä2¾ €€€€€@ä2&€€€€@.#¥@@@@Ò ºŒïR     €èrú7‰z&³£×    &xtÙݵg@@@@@ & —k2Ðè&€€€€@ËY¨¡€€€€@M@.×d ÑM, —³PCš€\®É@£›    Y@.g¡†:    5!¹\“F7A@@@²€\ÎB u@@@@jBr¹&n‚€€€d!¹œ…ꀀ€€Ô„ärMÝÈBr9 5Ô¨ Èåš 4º     …ärj¨    PË5ht@@@@ Èå,ÔP@@@@ & —k2Ðè&€€€€@ËY¨¡€€€€@M@.×d ÑM,Š‘Ë;ðScYæ Îà‘'¸‡ ŠH h¼Ò (  µ$P€\®±PD×hƵã•Ëêd3š«ŠÍÌÜŠËUtø   Ð^yå2#(…ÏcWÌ™ºðæ*a0³ÀõVÌl­¬à$€€Err·EÍHm ÏEšYàf®Xø°Â €€TŽär1bV Ÿú!…=Ϥ+0ÉÐu®-»qîhäÛjÚÂåµl¥0ÉÜ|’7“Öâe•ßÕÂ' ‚€€@ @.CèF Øy•Åfs!E(/#—ËQõéfWGÝclºáv^¬óI,ŒæV âj±3Ö@@@ ½ — ‹0TìT–ËeF ºZÓÐÑfü5[CIµ´Ôö†«CLBß ’zgje¦b†Èz±Ö@@@ ÅJ-—éû ­ bç®P.KŠ%©L¯ô´"¯5ªâ=/‰m{嬗¹D »Ö$$C>H;=` @@ZFr¹*Z´~;kó¨7KÕIÄœD°Jd¨U&š¹Á¨jIs®p—‡¥C®Zã()&!\ìô€5hÈå ÈЪ¸X쬅\–ËeyÂqRìÈåæ3F   m €èr wd“Ë9¬è€€€ä2æ@1 —‹á+   %#¹\²©¬;uËß2GåTö’‚ã  e!¹\–‘¨º5‘ËU¦ºùOâ¾n]FA@ '¹\8Òš„\®éÀ—»ÛËåx Õ ¹\q*¿—M’ËÇsL¨ïÌGMÂíÕ$°Í3‹!k[Xú€\®ÏX7·§yä2 _÷Çu×ÒÇËÍÑŽ°¹ÜÈN€€@› @.·y:¦ù(ºüàãèò”yk!—ç:t@¨˜õ®Ô-Þžºpu[¸ÁÔ ¬Ir9u¶¤‰YŒTëOå4 3ƒi‘AWžÇyQž„ìe?Ì4Í|#JºpZãjkZIê¸ùý6©b™û’ÔÈO@Éå‡Wh¤^<ÛŸz±®gqÿ¡Tòœå½³—÷ÐAСäò„ž„\nÈe¡b¶TfËDgá n0u·^.›f“ËB IrÙÞfĨ6KZ!R­ïMÅÏ”ç…fÈOÞË&"UNº×$ûÚ‚ûÝÆÛ´uÒš®3¦}õ·Ë“é²K8UÌ1-ZÃ}oGB~†úe¹ê‡fC–¦Yo/Ü“î|àç5ÿ­ÉÀøo]×!;Þù™zßCy6€\N€¯R/ÌcêÄn%—%ŠÙU™^íÆžÍbÑ¿ùêÔ[+Èmö_þ•LWtÑ2Ëå´Ê/—µ(T¦ÜG¸+b˜F½:ØÒ%– µðºáj¯°‹ú/ˆ–Òò‘ãri뺌fe:Ó¡ñò:G.óóÇRŸüå땪ŒýPy«Š9?Sç¡w>„‘&¦ïüb)úÖ{ Í" ä2-‚ÑHÃxæh†JÆø—o]®‚ÊtÌZÞK‡ú[E—ÇÝ¿†~Ëßà¯öBr¤’µ2ýÁgeðr™‰=G%2 ƒ¥’%Ut-ïä Yàk5kž´[f¹,Ñ‹9â&c¸r™ ˜ñzH"Ë\=mª³éè ·@.»úÕ‚—rõÃГ€ ár=Lß £ýÊ’˜’n†x ¿`„¦Ÿv‰ßÐõj:Ä™Ÿ3ò #¹Þ£Ã‡ í% ä2-GâxéúÃú˜»¦‡´²:f®èчRÌs–5^õëžQ3¹¼wÏÎèÁ(æÈe=™²ÉåPvu»ÒHB×F¹ÌèHážyøå· »,‘Ëü½ƒœ»úR‘È”Ô{V»är’ŸrõÓ¹¾è«û^9n º5+$M¤Îùå²ä‹GTª2œ!—“® Î&’ËZ+[йÖrùõm[¢GSå²NPÀŠÉ·åòÈ)—•(Ô?–úqÏG…”õHÎiAùÓl¹ìÊâÖÈåh»ÌŒ’D Cö£5:Ê^ BñÇ|I‹~oÑÓ5*ù>†¾´0_fR岚ù^ =o}UsË[g„ä£sƽx½#â6'Ÿ0Œd7‰E§( €´‘€’Ë´ ‰~·þÐZÙc¦|ŒedŒÚE—·l~š?š”Œ¡Å«)—ùˆo†è²0ÄRÒm™»ùår[ÜNjÔJrRO\÷ mÈ~Ï«cÖÃØ[ØûåÁTüÚˆ©WB¦B}4 šrÄ{žWÌ¡N™ÑŠ-ÉO ÌWu¹]“ð÷Ú±³i‡Q^ÎÞ)”úMÀîæ$ñ"2«0ƒbÙÉ0Ý*!¤.÷›ItÞ†Æ1îVIº3 0€@[(¹<}ñ¾#ë+¯mä+«ƒÎÌ[Ûû“•1cù¡}Û”Œ™±š~×%w™ºê¾êwÏøÑ/l\¥ŽèrrrëJRák‚z5O.»¯¶~âÖP.·2Z¬9‰¯9"t@ >\¹L*Yie-—•bÖéËõ•Ëî´ ‰,ÔÊZ›ùÁ–ÁèÂfy¹øö–ôªÞPî²é¼+å[µ@.·ž9Z¬Ô}È § µ% äò”EûhÇ>µÍµ:æ¯=LE—ç<Ù8¦>Ñ£)ËM[¼·ŽÑå\ŽÆ•k;½šÔqÈå&…Y—€’Ë÷ÍßG[÷‘bž¿æ0¤’Õ1wm’˳ÖôN[Õ8&­è™¸ôДŵLÆðÊehåÖ_WË­gŽA@@ ¶ —k;ôî8är…®ƒ€€@Õ(¹|ï¼½´µ5˜ç®î¡ãáU½ê ¬eŠ+Ó1sÕ‘dŒI÷Ü·äà”ˆ.Wm¤;É_ÈåNMô@@JN@Éå»Ý=kÙÁÙ+z\qH¬8HÇì'zf.oS—÷L^vÒÊ`Õª×Br%ÈZ¹¹\«áFgA@@ ½”\ÞðâY wÞ¿d×ì%»ÍƒÎÐ[}꘺xSîžüØ®§_ÜGµ&>ºŽ~×h!¹öZ× —1@@@ZF€äòü'_ÎÐÜÄǶ(© ¹œªä"¹œ *ƒ€€¤ ÉûúÎÝw?ºiä”§¯¼sý¥ãÖÐqa÷“YMÇcÖ¨ƒÎèã’qëFN~vû®ýË)¤Q¶8Ëű„%’¼‡ʆ r97ÔÊKr9/AÔP’wëŽÞ•Ï÷.]ð±ÕûéxteãxhÅ‘ãå{é¸Ù>:¦-Ú;iÁž[R­—_~‘~#C ;PÐÝà:¯ÅN¯¹Üé#Œþ€€@‰(¹LZyÓko=³õ­'7õÒ±ê…Ãt¬|¶W+6¦céÓƒ¶2¡u3èu@ªµpÕÆúÊå…‹–Œ¾éæ!C.§?„ã’ÅËB€ºär*1”ÈL@ÉåYK÷.^׳x}Oã÷ºž…ëÓ¡öÁnl…½¦±áßœUcæŠÆºr³—Õ{ÝåaÃGL˜0aYßϸqãFŒ!Èb %IÈe %”(„€’ËÓï[°¶Wie:¬ëmkjCì9¤˜i+ì'zg,?4£/º —“ÇzòäÉC‡;v옾úcèÐkédÔD óe¼Œ\63³äruó1]ŽN6(Šär’”z1jÔ*ƒÞó“db0AÜ é¦Ó¼\V%™„,ýowÈåvÚ€\Î8ØN¦¬ :$qeS³ºí1rY͸°"ÇÙZÉÈ¢åÕ —[Ž ‚€€@} @.·nì­ä^ gXÃåLºEu31¨›Ë­›µh @@jOë.×~ Tär .ƒ€€@U @.Wuäêì7ärG}€\n1p4WÈå ÂDqŽ9æ˜âŒÁ€€@é@.—nHàP”ä2!"‰Æ«4¡†SvTa÷ïèXä/ ô“iH»eõÖ$-¬ ˜]ˆú¿¿rÇP@@ Ë…`„‘–¨³\¶”™—»Wó1*-d3UØ¥–/vÒäo]ÈÖrÛm7äIê¸ËÖ@@2€\ÎŒÛF žrÙ [š!aw0¼2Ϋäx¹ìm×U~B¼¡PnS*4n†{M·Ý¨¹‰.ÊD™ …Cr9©|~­ß¶« ƒ€@ @.×`;®‹5”Ë!I§Ï'Å8½ñQ­ -ѩŢõ‡ûÏlšÏªÅÿ“™Ër;¢ÈLÀØûE¥qé¸ ª€\®êÈÕÙïZÉåPÒ§zE°wžX6M¡ÌGšÍ8«7ÀœaZz…~(ð,—Ë&FIGCË k̯Þ¿½ß7Ìñme`‹*  …€\ΈqÞܹúÈhÕ²¨•\f4%•D“ärªôŒ2“–G¬™ø:“/áºÐŒv+OÔ?Š@@ZCr9 gÊîë?öÓ?³X©qkOïT5”Ë*™$UCQÛ@4E3#û,.‰FóãËtJõZ8=B2—‘¿rãQþ¦“©_cT1Š€@»@.g!ŸM.»›`gi»u’ô®[8©ºÛãzÊeKšé Vê‚þ§©Ã$A\W k m™Òÿ´¤žåIT(›®êº'3Ø1­y«'ÉkmA× ñ,v\Êq¹Ã ¨;%—§/Þ·`mïâu=êX°®·q¬=rÌ[ÛKÇœ5cÚ½3–š±d7Õ3c5ý¾ø–ÙBˆƒÎú ó8Æú7ý“7T‘Dryÿ¾ÝtìÛ»‹~ £Ë–FÌ)…ЛT,Éù¤Â‡Ë3$Þf+#¿®²ÙG­¤Ð²‹+guð¨Èå,ƒEúxÏî7ô‘M.SÃ^­ƒÐ¦gVdZ}Äèoý‘eMnÜ´2"ñ_î¹ë[¨ËYf-êôH €€@.g™¤ß|ãµýG!rY¢}-•­BÌ*Ö?…š[RË…húÆ'c¤ö‚Ú‚\Î2kQ@@@ Èå,ØH¿¾m‹>Z,—µÇQ¡™³¤Ü¾%ʽÑh4#¦%A.g™µ¨   ‰är6sñ¸×^yAÂEårYù.}*šnDÙJ–áûÂ;#w5¤×!—f-Š‚€€ä# äòýËö-Yß»týáÅë{èX¸ö0ó×9æ®é¡cÎÊ^:f-ï½¼gβ=T«v¯ú‘,ÞúâæàÃÌe–ËÞY”]Î\X^Q—„\ÎwÕ£6€€€@ÈåXT”ñK›žòÑ” FZWaüÕ{óŒ³Oª•§0ä²w beŒ´+¥A@@ i —“Ñ’,ÞüÜ“ÖÕÊZPšÉVÛÞE$T™ÐGf–°0"$m­„c^›.é^¸yîGfwB­óî?]Nžµ¨   •ärr$Ž_ظJ­œ¥Ô ¨›\ön;Røì¨ôBÂ6ÆëÔåäZ0Ž-h"iz{G¿lN&õÈ-áÖ_E Úk/¨œ¨ ¯ž¡…ûÙ`þy•ßBfç‹­¹œ‘§VÌÐÊ æ¨V7¹¬Ÿ9˜•±j±·Ñ$kI…ËÈ®­>•^\j¶ͶßÖ9l¼3z]æ^4Û·fÛoÙ¼…\ÎŽZ-ˆ‘½>jf%¹lEFC/ ¨¡b©Qm³|tlã!;¼}áMÙj׬嵯#C˜fa÷KŽÄ¾É-ÊÁ ¿y=´ü÷ÚO ãYœ>BÿµK>ÞñRþ»vÜÎz{ê^>ÑÙëÍçbùhÿµYóLëûëm=:î¦óÞY ,s´ª2î’ùÉ\_ü¤J'’ëÚ½(Üñ’܇óÏ+áÍ9Ãu×Ê*J.ÏZº·±ý5-‹Ñ· öÂu‡é˜O‹côóÖôÒ1gU㘹¢gæòžÙËê½ v+Gm¹ —-}àÊói!œB® =´¼ùê’*ªLÈNÔ~ÒÙ-ÌØ·žîI=Ý#¡}]LÂÁ똷k®Yï£T2Uxû¡‰çí—¥ùx‘dùõ¿Ù\V¡(¦(óÒð6Ô–þʯ#É|v/þF')¯¢u{‰Îf¾¹÷ÛB®¯¤y"éã§üÞ^ȼJº9KîBm)ã•Ë;ö¼eËm4ê'¹ÌÜúÝ[¤p…n‹r±¨JêŸh»’§¾WF“ŒòǼ·-‰eïÔËÇzr›ŠÓ-’!šQ;¡>FÑéÉ錦därT›J¼òrÎÌ!ê3"^DÖEíµÏ\Œ<ùu½lù~Yƒn1woQþL¿$7çèþVÔ¼ u§¨v…—ž5 ™W¡¦å“­ %CÑåßO>`ˆ.—a¼àCƒä2/—õ"é&ÅŽšŠ>ö„ò"d'j?êaHyeŠ÷(¹ü\]¢Î0þ'=n3pH²í#ÿø”hDoB>!û¯Šå œÏîÐóó™ÆÞ‰ÄoK…—¡{™„¾-”D. ç§¼_Âùü³@rK½óg˜WÂY½ù´·¢ËíåßXÈ¹Ì ÐîÖ*^^ÂbE±†\6Ÿ‘Þ;ÿdMÕ+¡G~H€Rë’ûcÒm7ƒLdæ[T]I3nMžŒ‰àˆÚ^¤Qt!7’db”k8g²ÛµÌþKdsÉ3—¤×I·9É•Ë q¨z¨_Ù®kf\øù™yþuý&Ý”øoÒý“1ÅÏÕBxÊ'UôþÓÆˆ.·~£iÒʇ(fïnÕz_’P7r Yaua±¢X×M.«gƒþ±žˆÂç›ví3†L™ uÓ)×ÁkÊuÕê—û´ÚMâà%`>¡µqëUÆêBˆ§uÞúî5òGxyZó-:9Ýq‘Œ#ß)-×\ž&Fs(]˜¡‹Kr XN2óYûìV±8¸oWSÇ]XÞ½¹1·k¼Mdwïø†®nïµl]ÎîèKœç§PQב{çaÚÍÆ3õ:Þ‹Z\ Ñå·›SrY¨˜Uå$mšT83‹Ö´¢Ý«›\Î6.q‡ÊÖ÷úÔ*j”“ì$®ÖX˜]‹Jœju-$½Š¼º–Ô…*Né2ûl]GIcQÚÂJ.O_¼oÁÚ^µ, Öõzr—iqŒ5½Óžè±üÐŒ%X#ÓªÔ ó˜:±[Ée¹bvµihéè^€|EWšó5f{ÂLØìJËZ\mÈåæ±…e‹@H.S>¥g¨c^ßèrÞÉC:øõm[¢Giå²<†íêé¼ìÖ‡\.–'¬€€0 —[7=HoÙü4Dµr“Æn86Ö¼BÉVèÚr94TÈF@Éåû—í[²¾wéúÃ}°×÷,\{˜ŽùkŽs×ôÐ1ge/³–÷Î^Þ3gÙª5fÆjú}ñ-³…M:ë/ÌãëßôOÞPˆ$÷U¿{Æ~aã*uH´rT.ëÈ®D[Öø4ytÙ+©…³DR¬fB´›òë*j @@@ò€\ÎC¯€º$‘“´²W.ë“*”ëÕµf”W¸ÀcŠåÍ^ƒ¼‚\.`æÁ€€€€Œä²ŒSÓJ)¹,Œ+7Í‹Š†\Î3`m\¬] Ù6µÝÖódv|È01šäS™gèfæ*ò‰2‰ÈÜ ]±ð&’V4 µ^ WŽW~Ú°ÐI —Û<š%ß»ÍtÍC.·w\ò<òÔÍÓëvµ›Çg¾®Û£²õ±]þ´«]ÉXG}‹´¢Ê„Lµ  ÆÉx%G„’ '¹,g…’e!P+¹¬ã.VÆ:o>„˜å⽡ hyóÑ›!´i6õ3Ô_åƒë¿¤¼% ·c]Qž…ÄÒ,Ù‘s\Ì.¤šbÆWZȾõ ± ÍÛ.ã¼dܽó“ßè|6ç-#aMV­}™KÞ½5óäãºé[ö%RE<3^ª9kª077¾¿î§…\¡ey^‚@.fZH VrÙº•»%÷YnIï£Ôz<»ÿd²„?ò!;®Ús•“)/ò”7~EÙ‰´ÄÓn¶KÇ…¤qIõŸ‘MÞ Í[!ÿ¨{©ó3µÝ¡9²½`ÝëתâõD2Ö¡2ÞË!ÛüŒNÂhè@»";ÄÇ-©Ïè*î®VöžÉv‘¢V'PryÖÒ½í¯iYŒ¾M°®;LÇ|Z£ï˜·¦—Ž9«ÇÌ=3—÷Ì^†M°;iT­/5”ËòG¦ä±ç>Âu`Æû8qŸèò)ÃȳѨD° KÊ›NšýJmWþ}@?h]žÖGr€ ’V¼‚FûµÀè6fŒB|¼ÍyÇKØ®%å“Ú婺[âgTæ2×//]t¡¶¼v˜ë‹™Q5-Y.+Ëû¡þzïÑ µ%¹\Û¡¯pÇ!—™9ó¸•knïs(ô`KU“Qm'y¼…u!¹:Ÿj'*J¢z(Ú}á•) S¼ÃÑîekt\BS.4Ÿ…íJ&mrø’ë‘ÑmÞêÑA‘ }Éu¹,¹ŽP¦ã @.wüw`!—[/—C‘­è“Ûª(y<.—Uä,ªS%íFuR/›L…W,ïIt\B:²@yåiõÚë³pþDçgª¼ftv´_Ìw°è¸ðLTõ¨wªçáÓñrÙ½ú2\ÂËŪKr¹ºcW_Ïk(—ÕíÛ•îyõ4õžg’· c‡·oMM³°Ù Ó~¨k–òp]rkSIíJìX2Eâ¿ëŒ÷Iœôxµk½äîàµÃÙä'ë•w\„ ÍfʙӞ™?î$¯uÝyç³.ÓäÇÑš„ü@»×©pžG[±àd¾~%Ü\gÔÉõ(éoÈ”ä"B™ú€\®ÏXwNOk(—‹¼è³°ØæR­•ܽÔî <HWG0C„f4›U' äòôÅû¬íUïùѱ`]oãX{䘷¶—Ž9ô¶ßšÞiOôÎX~hƼêWõ‘¯²ÿµ’Ën|(ÛÐyC€ÙL5µVQýmª“0­'€K£XæU¹%ÛkXËLr93º6T<òëÈ鄲–ÓHë«×J.·/Z0 @.Wi>Xê6¿ØÍo¡-ø —Û‚‚€€@= @.WiÜ£r™‰=»¨n%GÈåVÒF[   PsËUš¼\f> E‘].íð_|ËìÒúÇ@@@ V —«4Ünî²™y•Ënš2äri‡r¹´CÇ@@êF@Éåû—í[²¾wéúÃ}°×÷,\{˜ŽùkŽs×ôÐ1ge/³–÷Î^Þ3gÙª5fÆjú-¬:ë/ÌãëßôOž~þ ž'àª[óŒDLGÓ9*qÔa&ȯ«J œê€\®ÒØIä²Dpë03¢Ë¥þœr9iÛ‹ÒB€c   PËe©IrY’¯ ¹,Eßòr!¹,ߤÀÝòªå@ƒ   Ð  —Û6Š -}ÓÍC†\NàÓ-ÈHh± ÉŠBÊP¬žÉü&½î¸xwŽ•«í2 4|2€\nÏ( >b„ Ëú~Æ7bĈöøQÍVk(—½Ú×½h]йš³^ƒ€´€’˳–îmlMïùõm‚½pÝa:æÓÛ~}Ǽ5½tÌYÕ8f®è™¹¼gö2l‚cȦOŸÞÝ=fÊ”)ôýLž<©»»{Úôi9LÖ«j­är( 9škÁÈbd6×ë‚AoA@ò€\ÎÇ/SíŸsÉå îÔÉe:™ÉX+ÕJ.«Ž£]®ã¥‚>ƒ€Ar¹Љ6.½²käÈ®®®ú6lØeW M4Sßâ5”ËJ1›š8CtAåú^3è9€€@Ë9àe­:yòä¡C‡Ž;vLßý1tèµt2«½ÚÕ«§\vÃÌJþò¯jU”åÚ]'è0€€@A — ™h†R/FºQ%cÐ{~ÈÄHâWg¹œ …A@@ò€\ÎÏ0£ 'SVeŽ+—safÈåŒsÕ@@@Ò (¹<}ñ¾k{Õ²t,X×Û8Ö9æ­í¥c-ޱ¦wÚ½3–š±+c¤³. ~”òø¹\ž±€'   Ðñ°îrÇqBËKv;¹Ü`rÌ1i¿&Š‚€€% äò†ÌZ¸óþ%»f/ÙítžŽi‹÷Ò1eáîÉízúÅ}TkæcOÑïÐf½.åAgý…ycý›þÉLDO@ËY½KŸ.o}¤ÎK6ósmš¢ÙÐyv ,P‹×a&ȯ+ÜÏ@@@šJ€äòè34q÷¼—”Ô–?Ö!—3pPÅRÉ®®ue´«§µŒæ¥¶)¸Ý¿M#^Ií­’·ÿýõ!—‹" ;   Q$y_ß¹{䤧/·æÂ1O^0f \4víåãÖŽœüìö]û!—£x .*L­`0ý“W±|îr(<õJ·[Èå¢H€€€@”IÞÝ;·ïQÇî{÷¼±oï›û÷ï¦ãà=îïé9ÐÓsP‡zë­}@.Gñ\ *LÍö’ ‡d4“˜¡ÛrE¹©ÍO‹Â¹\I؈€\Ž"*Q$œT8¿\æ11Y"øB.khÌF}©û’0;žd#·Šµ%aÔ=oû[H§x#mÙFÑ;Žägx@$¯îøšÛ5jó,8ÐL%õ+4‘$,ƒo¨’Ÿ@Òøæoδ4+2ø ¹\ìx5×Z’–ö¾&è èA¦!^õKš¡wÜ‹\xÙóŘO…ö“z—G½Éý‘—Lu^^¾Å>´¸9†CfOäå%åã%/ÙÞÖå~¶¾d±dBÖŠm¥õ”ªÛb™É7Õ7Èå*MÚP.2õÁ+F£åÝ /ó6¡n…©å•Îņ–ÉzF—™@‹5‰™ø¢WmóÑ2¾ŠnÚtÏrÕë2úˆ‰0þ¸‘×¾y&*ÄÓlZ{èºj5½Å„Ê›ãârAæ»ìE¤Âü#ô7cßâS•ñ·€;ô™ÐKoÌ<”Èïü1…ŸBÖ”ó¶& c<4¬*.êPO­ó©×uèúµÎ{G™ošç–h~FÇ×{]3÷«P¿Ì*f£ æ>½Ü’î{Ö¼Jº.R¯/ÈåèØ•¨@Úõ*Ý•Êeæ. |œ˜7qù3IÝŒ¬{_蟦\ˆ6á>}Ý›WT¦0޹ž{ Do¯L÷­§ˆ²ï>_ù *ŸÚ®Û:Ï“ñÓúÈzü ÍVe|Óo?Gjd¸.˜9)¹^øÙ.¯Pw2ÌCþš’sã§´ÛJhÞ††Ø{ýª1â›ã˜zýfà,¹ zï½î5èËàOæñõ‚Î[k\$ý•ßxÝ ÓÛGÈåÌwË6T„\VÐk%—£·˜ÐÍ‹¹©¹6ùÂÖóUU×?î§I÷÷ÐC1µ_Ñ'œ)û¼óU·¿ÞÇsèñÃOÅåm—×ÑçAÈ&Ó–ÉÐQ%_k2óR€¬ÞG¸E>§}ïEš?¡ë”¿x­›ÃG2g\ß¼×iÈ%wÞ2W®d®†F0Z74Ÿ™i\Fgxí3×]êýŠ™'¼WüeUN 7wô£÷ù—™„G„Vƈ^y @.×P.§Ê ¨ôÞß™§xÒýÈzÖ2÷Í¨ÙæÉ)ý –h—?Y>¡4É<Žû’™£ËTe|3ßÞ½²/tµªÂ’ù½~£7a¾Xh3ËMÉÄö"Jº$q–Ìù¨ÛIîI¾<‡O(ߣ}Œ^§®?ü4ªØ¢ü—“gø#ºœùn‰Šm#P«è²y¿–èæq+ײr™ë-)ñÓr†Ö<“?ŸB·ÚÌr™ñÙ+/à©áèc#ú”åu¿×~tŒ,}c–Ö•#¯A½Ÿ&ɦl7²Ð$g&¹œªB„x½óÖVÆgÉœŒ^×–‘hyþëDÒ¸KüÏ|Å_"+­ë.ôÈ]ã’{¸œ?Q£—3¢þKî·Ñ…\Îv?D­’¨§\ö~ËW7Wš¸ç™Û·Yؽ[Éí›^ÞŽvØ5®Õò~1åÍR£ Ö#ÄrزlõÂü§äîí¬Õ/ë¨ðº eãf©^mÙýƒ/×çJŒoêm.4?M\…Ì7sò02ŠÊ{Hš$¡ëË;÷¼³Ô=º_YSïŒÐñ"ÊÃÁ{°î±^ÿ³uŠ÷?Äͼ®™ñJ庯Jº&¹Ö¼÷O‰ÿüÈÏCÉõ…è²døP¦\ê,—Ë5UöÆz¶U¹+øÞy4ÊÖ£²ùSÀ¤)¥ 9gyÉRvTäTú(QD!Èå"(ÂFk @.·–w§µæ yvZ'ý EµUK]¤lã[6J=x9œKâœT8‡Sm¨Ú©×uPlr¹íC’ @.'#C¬ —³’C½ö€\n°WË!Ë·o¼Ð2G@>‚(™‡f!€ä ¹œ^UçÍKG–8?ñ)u4»¡Ö؇\n g´   @ —Û< H+:t@¨˜µêM’¿$”ÕhA.·yÖ¢y¨Èå6¶’ËBÅl _¡k3ˆ”æ!—Sh¡,€€€@.˹ð¥VV©æ1ub·’ËÅÌËe+ö¬|“ŸÔ…Í?BÜÂV¦‡·]ÆZIÈå$\(    ‡ärziuu Yëc÷>+ƒ‘ËÙ>Š*ã¨Y­’Í’¡ZÙ¢ã.eÈå´™—¯t†•;­mòµß!µó0‘ו—ì¬Ø ÉŽ méwÒìÊpßhW§Bí&õ7§ó­l+§«µ­¹Üº¡')¼wÏÎèÁ(f&w9ªku?å%-1íÕÖ^³¡ôÈeùl»ø–ÙòÂVÉÔUjy‰c›’2’¶ÊV&Ô¯<ý•ו—,7Fµ4ÕÕrËïU~ .ö<6óÔmê`Œ7ÃçfÜÚŧVíB.·n¸I¿¾mKôˆÊeWÅê3Lê…¥k%%3˜U­ðr9”§!‰ZE—uÔÁ ?x—£O M1åC+ù‡–Á7ËG3’v£FÔœa8èOõ천äƒ:&|Ý–kÊô“ï—ëOÈó¼ú›o×üÔº”„㥚Hâ#ç/J/ºOëºÐö͵×;?£ö­! µËŒ£üÎf–´ˆ ïï%Þ¦õôˆv'Ú¨|2„®_k¢†æ¡å ÿÏÐ-"zÝ1—¼ËªÀûƒw „óÄšiîNr_ ]_Ìy ¦;Žî?Ñ YTÈå¢HÆíÞ²ùiþ'cÈ#µ™KR—˜×“¢ÔŠNQ/ÖJ.»Okýl=\%O#æÁìŠ-þ)îúcÝ.C׆×O÷QÍ_ZLyK9™wjïßÂÇW7˜n„ø{ý ùo4e?v<@¯÷ñ–晇ò©È#?4ÌŒMí¯äšòNïÔy}`¸è’æºo¸­Hæ›Y74³ù­eñ— ?ŒŽK†HˆOˆ9G5¯5·¿Qÿ½C,·“zŸÉ3,>ÞëÈ-“4gšZr¹©xmãî«~÷ŒýÂÆUêˆ.''W¨’LbåSÒú”/,iQ.ÜùQ©¡\våKy¢Êk·!u›Ó?üãŠʤÇ9oÇõ‡¹íZO~²…<‰Mo™?’ðê!+/¨bç¡5©¼=r¯FŽ„úkV ÍÿИ†æ­÷ºÈü€q[aü‘sãçm!×uhÔøûŒWöyÇ:õ¾ÁÏf›×…›d¸“æÓ®ä~nöÝ;?gBóÙ{³U¬BóÐûQ Øf—\n6áˆ}’ÈB­ìŠW¯~Õ©ºa7¦Ë/[ay,,ì•Â!gÜóIùléFîHÀò1þqÒ.’Gcêc/\óö"ÉIë¡ËÔMz „ð¦žDH:äçãŠ$ Þ¤G>#‹Cò——Jr9nöE2o%×_Æm%êƒä> ™œ–L ±Íã¿„O¨¿þÞº©’y›ZF|tþ çCæ¾0è-4Ï D2ÁRË@.§+¸¼’ËѸrÁ­VÜä²\.Kî8üc8ƒ\¦*™Û6çU‡V»L¿ÔGINZžè½ž—¡Ç˜÷¼Ù¯(¾@Ô¾évŸœrYøXåçªåƒ[ȦÉ*Ú.ÏJxEðÂÔëC*·Ÿ–qá„æ¹Ä¸kŸ‡c}*¹îtü¼"rç³5¾‡(:á}Æ´½‰yças]˜ó'Ê-ÚSÉ£¡Ø2ËÅò„µV¨•\nÐZ¶QÂÛqÇÁ«0Úèš\¡už%}Èå:OȪör¹ª#W¿ÍL9tè€pW?%|ÍCâ=䲄RÙÊ\|ËlË%ïò:IÛð}t®——×%J¸Žfôäó'´LR+ùH:îõ§Zã+™–ò“—”à•[“—lW»Q[ìX‹›‹v¿–Wk‡vµ[gÆär³ Gì+¹,TÌ–ðê`a±6ƒHi¾†ÑeFK5Ife6+¯(/™2;Òʶ؇7ǰÈ쉼¢¼d†/fiÃÜò uóô½ÙuóØOÅn~cÉ\7CŶô1ƒŸÂ*™»“¹¢Ð±P±vµ›Óm¾:ärSñÚÆUê…yLØ­ä²D1ór9xöÖÒ…M™Ð5oÜk­ydk%—uPA•4«˜+} ³¾ý{-«Â¡˜ø{£ä0Î*|]WM³’Ûz¨|R»Ì82#«wÿУ£†Ø*`ö+äg%Æ×âfÞU¼ýâŸßÑ©(¹k…ÚmÆ<‘ô7i>ÅÓœ<‹È;ßRç-ÓnŒKÞû’uÑ™—žyôÎKø„úÅÜ7˜©nRµúåÞL$ò·«Z AR•\ÑÂ2ËBPÓd­Ý?ø¬ F. ?’ǧ͒¡ø´ÜZø µ’ËúfÁëóÞd=bݼ7ë¤{WµÝ­äç%%£÷D×më6môÞú™ù*ŸÚnžqdÆ"ÚŸU_ó‘šØ¡2Vy‹•wD2Ï·ç‰ðòtý·ÆTxÇ(–¯á¼·)¯Û̼õNƒè…à:–Ô®%MÇßp¢¾„tZFÁ¦Þ¯ò”7ÁeǺÆå@ ÔËÂŒ˜")¼wÏÎèÁ(f&w¹¹² C.7oöX¹ËÌÝÁ+sÕ Ë}0Tæ¾æ•#!—äç%%%·E³³^IdúÏwÓûLõŽ2ÿð>½xU'çí£å°—O”ƒdtýÊt6ä[ä'ó|‹Ê÷zLÇŸÑqNélvB÷™h£Ñ9Ê3›ÿ¡KÛÛ/¯Ï¡vSç•üòç:ü õ«û*ÃAÂ3t‡‘\§…?!— G4H:øõm[¢GT.Sn¸×Uºz5 7Nìͬgzè26+¢ËŒLáï#êæ•ªÿZ,—us’{"ÿXuekêc5.F 0=’?/Se–w¶D9;úb ùn ߨÿîw ‡è‹‘#û’±ób‡©Ä~ÔNQüSÇ7•?3 ©$òN—‰ÎOULnMÈ'*C…wªP%$<½”ä4¢—sRÈå$\¹ “Þ²ùiþ'cÈ#»’´ W‚{0¬0s»^"„\Î&—ù[˜{Ÿeds>×- Þ»¼ä¶h9•#Lù¤oŒ\`¸ B.œÐ£…#ÆU¬Äø†æI¹–áñìN‰ÐüI=ÏÌÿ$?Sçs<ÍoJÑK•™oÞº¡ñÍÀ9ôØŽ¶+ñYâD7ðó9Š× ï¸ï<ºXžò&·É—¿°Ò9¼ÌŒµ ‰Ek%—ÙtNqɃ¡szëIçÑè¼ÅÆÐþR‰•¿|Ç´Z>·Ñ[Èå6_€J.GãÊmö²dÍC.—l@ vÇú*¸*˜“GO«Ð›£>b|uدÏþjÍ™2{[éë´BcÛ]…\nóeØ‚M°ÛÜÃ&4¹Ü¨0    à'¹Œ™Q=ËÕ³êz¬Áïf¨î ç 5 ¹\ƒAî¸.B.wÜ¢C   P^Ëåx"¹Œ¹   Ð2Ë-C† #¹\Jˆ€\ŽÂçå#¹\¾1G ÐtXG¢éˆÑ€@€är•¦FhåãhÚµý^Ô±l —³q«m-sy|/„hWÃñó4WÛA¤Ž»¨’ÐÖuž*è;Nr¹p¤M4¹¬àB.7q’µÐt+M´­hT0¼Á›Ku¯äå½Ê8ôUGÒ—PBÈå*Í µÍž»¶îƒw=~·¿òìÕ'‰úÈe<37Õ ¼Ëã›U,‰ZNß\þÝ ×¹å ôÇ4.”2™ûë LZóMù஄ïqù eœÅ™Ÿð¡q´Î›è„ãËÏ‚» Y´]ËŽ°ãÞrëz…µ·Å$7ä·#”¨Èå*2/—]míbmv5©pÙÕG.kíbýáê?W6©QóêìÐyKšãnÚ1•¥6åJsK–YþH$¬×¯·›! ¡ÉìJCÓïß®'f.®Ðp„´`h¼¢‘:Oò”ço&¡/N̪Ô*Âïfe»éÁö€\n/ÿ´Ö½ò7¤‰MAìæ.Gå²6›æbKJ×M.‡„/í I=7’¹–qFšêÙh´”+#=£ZJnŸ‘ïÞVx¹_¬\~UHâÆŒc¨¿ÌüÑYÜ=š'ª^;Œ?Ì—™Ôx… ÑÜ’[5Î!¹\¥±4%¬Ö»yä²$O£„€ —]½•VB9åÊbk„t³0þò3:ÍRå,ä²õ-+4ŽÑ¯(ü· ¡îÌSŒ¯ú4õ|t¢€@ @.Wiô —Ë|ç½iÍeà¹lÉeÃóF@½ò×,oUl—\ŽÊ©Ÿ. W&Z|$ÑM/O¯¡,cü—ÄM£_3 ÿ:daÚ÷NBï·;†[ÒW!åCtš•áþ@JHr¹„ƒtÉJ°äl4¿Â´ËfŠ•V}ä²zÀ«g¼ù‡–2ÞO­“¦vËk˺SñhL¢þ˜ºÄí‚+…"&D#µ¿î4Y°PX’Ë„ã픥ϼþ3×”ßtWüyË›ãkqöúŸÚ)˾;Ù\?%ÊÕ´Ã|#α’Üâà€@Ù@.—mD8x¹L5CÉæGºI&F93˜ë#—[?;¡*ZÏœ‘ƒåq¦]ž`B¶‹<Ú0 @.c>Tär±cŠJÛ ¬%0CÑIQ@@ pË…#…Á¦€\n:b4   ÐOrs¡z —«7fðŠ% Þm•ÿ.¶uX¨Èåš xGtr¹#†j€\®Æ8ÁK“ä2怀€@Ë@.· 5*Œära(a@@@ Fr9FŸ—ärùÆ€€@Ç€\îØ¡íàŽA.wðà¢k   P6Ëeø'¹g„   €\.$Ì´är a£)¨;Èå¶Í€…‹–Œ¾éæ!C.§?„NXÛV«Zu½'Uf‹l¡%)¹\’€   PËíåaÃGL˜0aYßϸqãFŒ!ñƒ‘ºz¨Œu^bJâR[Ê@.·;z€\nøOŸ>½»{Ì”)Séû™yòä¡C‡Ž;vLßý1tèµt2ê /p!—£+Tàâ[fWÈ[¸   Lr¹=ƒK©£Fݨ’1è=?I&9*_õBÇ¡U÷»ÜžaÎÑ*ärx¨   E€\.’f’- 'SV’¸2£zCñùÕÍÄ þ"#i¦¡0€€€@Ëy赺n4ºl:äƺ˭°í!ºœª‚€€@‘ —‹¤Y[•-#º\•i?A@@ 3@.wÆ8&÷ÂJnN®ßÖ HÆh+~4  õ"¹\¯ñîŒÞB.wÆ8¢   P Ë•&89€ä2&€€€@Ë@.· 5*Œä²FyLß—lè|ê0í0ž¤¶¨Ê ÛÍf¼µÚå¿°Ýlã•­–„v±–‹µ&ñ?µLÔCï8Fk¥º‘¿|?£Ý‰ÈïXS’—,'–öú¹\ÎY¯8u–ËîÃI.BL…¢“²Ù½ÙþG;h(Š[j»©å‹—æõºXËrkò’©äùòÙÚÍV«XÏ%Ö„~F‹E Hœ)U™fôHnS^²(hŶX¬µ¤>B.'áBáR¨§\}±ö hoaæ¤úÈ2å=©â¾º°YKU·ìèÂ!ÿÝ)Å8“dßlÚlÅë¿Õ#…×Ó¯(7׸Û/æ»AÈU~½ã+oWù£‡X»ç ºpt^Y(¼þ„Æ‘¹ÉýÌ0?“n‚îdÓ]ö^/Öõå½:¬“©|ÜòÖ0…þiVQ~š,ûæ”ó^¿ÞòÌý$ä¿ðÖ”‡³9è!;Ì}†¿.ô…É_wI<3\×ÞëBrŸdÆE2ÿ“®Ç<…!—óÐCÝö¨¡\f ¡äçù§Ž{/s¥’y›voʧš+¼²@h?䶥ϘzŸ.Vù¨b3YY|/F +Þ×3̧¸äbÖâÆ•/®œüCŽIøhõà} 焆°Lh¼L•–4j¡‰dɦ|ñV—Œ—×¾ð>ÃØOšÏÌí¨þ†Æ´¨vCc$¼Íz¯ f"EçUžv%ó-µ¿QÎÂ;€ðÚL*¹œ„ …KA VrÙ¼Jž!}Ò7Ñ[ÿb¤€Ä¹Ü´üŒÊVÅÍüqucÓÅ¥M û•ŸÿäVö£Cf|£ ]¼2s Ê?¤üLYàGþN”ê§ü¾šWÑ™ìºÄóÉw^¥ò •7™Kæ¿÷‚b®ŽÔë1tÁØ_÷¢æÇÑÏÂò¡y.áì'Ìí…ç“ó¾”yþ[ BnðîEŸVò 9CIÈå ÐJWE¸íˆ°Xéºç8T+¹Ì?“„bˆ¿Y‡ÌQ}ÉÈÍ RŒ¿Ÿ ÛŠjYþ1ˆ^³ÍæºMáÕz¹¬ž—™ë-Ã@“ÈáÝÉ+ƒBs’Ga‹m”ËI¦Ž]fù"”e©öS+j?zƒ•Ü£C½JÆÅ¼%7s¶íxè U”ÿŠ*¹\Éd; -}ÓÍC†\N+‡ô®P ‹ ic±ÊeuÓñ>*BϯŠZˆÊ/ë¾/‘ ÑG…w.ñžDÛ•`±JàDÛ éõÔÇRùzðK|–¨$;¡y’ÊAâóE+ÉçУ=ç½Nù`þvG*zÝ çUÔUæúõÞdøò 1~ õ§Ñk±í¬åžÙVªÙ(fºn¸£™z_•\_[‰î^/E]!þÑq Ý¥38&™?fÈåTbÅ”6|Ä„ –õýŒ7nĈ»9õnÎê[S¦žrÙûˆU7D÷‘ãžçï&®ýìd웳_%:ILç­Çªú§Ð¾×ŽUݵï>cÜ®™O;¦<3.^ ÞQðâÒÌOCý“´ËŒ¯wºœ½¨%˜~¹pB~8?£Øë•WºyçstÞJ®wÆÉè|v•ŸnÑl:³ŸÖ½Å;?%÷÷Ò ],®ÿI“Jß{½øF½Nz¯8ï¸H®;ÍŠ÷S2^…_®KnúÎ`fλe¸*S«@.§+ üôéÓ»»ÇL™2呾ŸÉ“'uwwO›>-jZ]ÖeÜm®Íê–)]¸’ºÎr9:IZ\Àºmµ¸õüÍUÝÿüò[Ãü a@ á·¦lÆÍZËù&[øÙ9—‘\ž0áN}\¦“QCr¹L%•5¯Döjåhëå)¹ÜÞ±EÛ땼õªû/ïi JJ"Ó-pM€Ô“@˾®C.·a‚]ze×È‘]]]#ô1lذˮuE.—µ)W.»FÜ8tÔ“ö€\n/´  µ"¹Ü†ážå}à©“’g¡ûrÕŒkŠñ'ª`BÏ'æQa٠ɹŸÞçnè1í‘9šú1Ï A6z.«]¬¤EáCÔÛhèñlBÍóè¸[Fšägôšú)Ñ.B©Õ…Þ¶¼×…;+˜{W‚w£×EôÞº©òsŒ™¹‘ ojÎfÍë"Ä™é—÷£ÐõºïE»íKË’+rYB eÊEr9tg·žFÂûuèv)y$‡dó¨‹N&ïíUx‹ ùì6*N'Ýî3øÉÜÜCÔËP2ŽQ® ŽW»ä²z¨Gçj¨ŒðÙoʈ(/d¡Ÿ^éÉ·šŸQíbµÅ÷‘¿^ܶø3¡¶¢·,ùeëÉQV®cÞ‰-™Ѿ07« Ýäû½F¬n ¯ kfF§œdžðr¹y×Qôº†\Ž"BÒ€\6ïŒÌJx¿6o”’ÇXȬ·n†û¾÷‘f =ö¢²)$£¥-¢·û ~ÖY.Gå ÿì”K¢Ð¸HÆÝ”•ÂkJ2%}—4'±#Ÿöѫۮ’ëB"ͽvA&)j×S÷Þe±Ú Ý',ÿÎã~e’LƒòËeá< ’ÌsI™Ì‚r93:TlºÉeu—Ñ?ÖYøx“ܬ]éà6rƼšµç™Û"ÓYå¤nŽ·ÏÛqÞònsZ1xÇÅí¾¶ä#£ù' 3ŽÖã„÷ßûxó6­Ŝѡ´`š¬x­ìÎw\¼þ˜j ©9$öCW_ÔŽ÷ñÖŠÞgS1t3±°¸Î„®†§æÃô×úHÞßÃü »—€÷òô޾üú-ê¾gىηÐ|fΫôo~ÜCýâý´`ò÷ÏÐ&:"îè„îçÑ9æ-¹œ[aµæÍKGaæÚdˆÙ…»ÕM.gc(¹±f³ÜìZÕõ¼d@#•j݈uR;©/©ó¶¨ò`XIËär“ÀJÍ’V>tè@ªb¶¶³–6Ö´rË…£Í³ v±_© ïo°ÒÎË (2ð¬´è/íÎ0j^¥æCiGr¹ÍC£ärªb.³\nPD—[M€€€(Ë- *õÂ<¦NìVrY®˜•Vv³>ã~Ê|Dý7 ÒßšHR-]‘‰4¥ò!—[:kÑ€€Ô›ärëÆ_’µ>vÿdeðr™‘­©ŠÖ’ÝB,,–‡;ärz¨    Dr9 W®Â$…÷îÙ=xÅ,£Â’VÄ·yµŠ -7þOdÇŽ\#Q…Êyr—«Ð?ø  •!¹Üº¡"üú¶-Ñ£-rÙ›Qˆ’&¾ÞÔ‘<Ü!—óÐC]$ËI¸r&¼eóÓü!ÑÊ–´õ¦Xh‘ª<– _³‡òZ’˜4¢ËI³Ñå$\(   Í#¹Ü<¶Ëî«~÷ŒýÂÆUêˆ&.3¯÷%ib‰º•̖✇;¢ËèY[ d°Ðâ*Í^=´+.µk,ÚÕn‹g5W`O›= „S`¯“¼jW»IN¶«p çÆ+Ûd€\ÎÆ­°Z$‘…ZÙÕ¯Ö™PÔY‹¾#È„“CêYŶCú›7˜bÝärQ7Ü¢ìd¸òTl;Šv9Юv[?ôòžÊKÛ‹f´Û ›’^·«]‰oÍ.SžWÑçfcÔ>ärQs (¹+Kœ`² L„xÒì2µ’ËæþÖ=.´¼¨ŠªîÖbšp‡RG&Üè¬×«¼iд`<\Ëf¼Ð „ìxç¡ÕY4©_faÕŠäñcù©ÝËÌÍlTÎ9»f]ø<Š$Κ-ƒÈÞq'oܼR¬‰”:^’yè½.$“ÊòÓÉ<©Ã¼ÊÉÁºo0·,k%íš·;æaš:C÷Ÿf?¯;Æ>är›‡²ÀM°!—Û<–…6oæ.{Ÿšî]8¤Lyä– Ù‰Þ¦] a=ò-Yf5í}$‡,˜Ê&ÕNH¬¸ç½Â‹á¬>r¥s´EKºeæfÊVëk>ÎùðN ·:3^ÖGÑë •³—OtÞºWMÈO^•ò …°H”nÒu¢*t ZŒé¦wºF –|^I®æúâïT-¸5^Ñ«4ÈåΙ Ë3–øCT.ëÛ½30e¥+JÜ’|yÉÚz0è&¢Ò¤(¹µ¯¦šôjh^®y…i’š„[jùÿyì0?z†d"ãw’GE‰åI”­dªð2…ŸKŒ?¡ŠQÙòÇ‚í{†ò0¯\ìÂñÍ)—“ÚeîÃÞo£—- @.cT@­’1”,–˯¨DàÀÑÇs¼ê¨Ìu=ÉfG¢ô×9gW%'•ˆlI£²•‘SÌc8ú8÷N3ÉäΟ¨oEÍŸ?Bý•¡Ìí5Ïuu Ì+÷z]¡ñm»\ÊzI¿ª§Úä1är›À£Ùê,—½·?cðj¾è£1*;¢ Òûì‰Ê«/Ž…7“?¿$J…ç™G.3ã•*“ÊØ®wÚ4C. å~Òü±æ /‰ø $:Ï…rYrýF¿ø8¾?¯¬¯Iþ¡é4$íJîcÌýSrÏ^ª9žÒXr¹µã»T7¹¬î°î=Ô<©?Õ']M`>¢å™ðžÙ„õXµÌZž[½°ü7fnngC݉ e/¢7³ @ë)R6.˾ûdÆÝ’Gî˜jÅ/oWÂÙû¬>€…œ]Ô<ï< UÑÌÝ)'±ãÿ 7^1Ëû½$­~ñ·‚šÏ+ïum]/¡‹ÑêÖ͵ÃÜ:²ÝǼ·Ö¤û­ð‚íx9!ï 䲜J–…@ årYÐ7Í¢îÝEÙiZG W«/Õò6a:®hµFªyÞ6Ïrþ)Sfßò÷®¢ —+:pµvr¹3†ß¥Ëе¢ìdhºyU¼ñªæ5—Çr…\ÍÓÍΨ[¡Ájª«M5žmªtä},ŠrÖ‚\.ç¸À+Žä2怀€@Ë@.çB]àªÉ¹ühr城ø6’Ó ärcS   <Èå\3„äò¡C’öäSJQ’æyq™jMÒ¢U&§ºu[Ìir9à ¢ €€€@6ËÙ¸©¥ä²\1[2Q¨£Å¢ruò(Ü~NƒË9ÕA@@ä —å¬þ R/ÌcêÄn%—%ŠÙÕˆ^õlž%Ñè wcؼ^µeÖÊf([Æódw@.'ÌZÈGrYÊO’µ>vÿà³2$9ÚF¡º‡d·*)»Œ.Ö‚å’tŒrË Õ¹ Veªóè£ï  Ÿä²”!Iá½{vFF1·X.K”w,TÕr™.Èe)wë«S Ùš²Ùö<¡m¼UÚè§`„Q@@   —¥ÐI¿¾mKôËe>é"tÙ+—M+I«PFød«!oFG¶¤íÐØ ºœ$ ]Å,ô‰åÊ 4½Ê8,.C§ÇÅA@ &¹,J:xËæ§ù#5C¨‰£/ÆÉ…o ä²(ä²tžõ—»ø–ÙêO¶Ãæ?­¿u-¯Ô …Zùóæ§ÞåôÍ“–©ÐŽŒ³ãBt¡ÀyHï¦rºb  Gr9aLÝWýî?ú…«Ô!YN®L×ã$¹¬³õ²Ü·œÜÆ ¯hݢˮÖJZ£ÓâÏUÕ^¡|tõ±Û¨µ®Þu5´YLØ\hª;j1ÏùÔÙ‹ò  •#¹œkÈH"˵²j‰Y "´0EHžºÍ3ºcnp:$XCä·`u!/çG¥†rÙ+I½R•W¥–Àed"“„ $óy IrY(ÁUwxW‹UØ|sÝMP@@ ¬ —sŒ’Ë’¸r®fPy ÈeÅ£-r™Q½m‘Ë. ¡ÔN HC(ã> µ%¹œkèk² v.FM¨ ¹liD+[ƒOÊÄ,eM„ä{H¼ e·[Œñ?Yg¢éŒÈæØM˜à0   P.Ëåx#!PC¹¬ó,>ZÉ™ J¹º"I¢°ªk9ÎÛÑ ™Z3[»^ nëQåª3Ÿ¡í¯ÄŽd®¢ €€@€\î€A¬]j(—k7ƹ;ŒÜ‰Üa@@àÈeL…ꨕ\Å•«7lð@@ªIr¹šãVo¯k%—ë=Ôè=€€´ŸärûǤ€\N%†òG ¨…¢å¿Á@@ ö —k?*r¹‚ƒ—A@@ ª —«:ruör¹Î£¾ƒ€€@‹ @.·xöæÌðBg·Þ_³y–óû¦-@.¦@@@xËgÈÂEKFßtó!—ÓBÞ­§CûQ»6Ë)—sng-Dgƒ\¶€`Ñ´l µ@@@@BrYBÉ.3løˆ &,ëû7n܈#$VrÊe³‰æ‰ÔTË©å% ¢e —3Ëåè6Qø(  u#¹œ<âÓ§Oïî3eÊ”Gú~&OžÔÝÝ=mú´¨!R–TÆ [gô?]m-‰.ë2¼4gBÚL2†®å¶b‰f·dNR:Ëe7œZNÚ):i\P@@:’ärò°þìœËH.O˜p§>H.Óɨ!¡\E‘årY5äJs}ÞÕèºQI+!ÝF£L²¨§\†½šÙÜ$T>ÛX €€t<Èåä!¾ôÊ®‘#»ººFècذa—]14jÈR±^Q«…¬ åµo4ìU±¡$ ^.›‚;$ŽåÙØQb¡5”Ë¡r4Ø- !§F©3*‚€€@µ@.'×äÉ“‡:vìØ1}?ôÇС×Òɨ!‰\öf5”A.[:^wÖ+»]­…“T Vr™Ï6Žªáh“<2›“æ! ƒ€Ô„är–¦Ô‹Q£nTÉôžŸ$CÉMSezg™å²©ÚC¡q“fóÂ̵’Ë ©7ô+9)—ˈ.g¹ €€@ @.gd 'SV’¸²š%‘ËÙ^õ“è{‹f(å##ôþj5”ËJ1KÞÒ‹–AîrÎé‡ê  u#¹ÜºwÍx­%F Ï]&û¦JΜ»ìV´Äw³—Å ŽÔS.[af&¬ßós¥³û‚Ê­» %j€\®æ¸åöºIqßÜ~‰ ÔY.k@¹¢¹‚B   ›ärn„Õ4¹\òq»ø–Ù%÷@M@.×d ÝlAšDkh"ºÜÎh@@@€@.cTä27fÇÓøTþ»zãA@@ ¥ —[ŠBr¹Œ0   !¹,¡„2å"¹\®ñ€7   ÐÑ —;zx;´sË:°è€€”‘ärG>ñ —1C@@@ZFr¹e¨ÑPaê&—ͽEš·Üró,6ðu5änèX‰æY–xØìÖ›m_ÒÇŽ/SÔ}£(;lÈåv‘ïÀv%;ÒíºÉe “B&OE4oô›gY‚ºÙ­7Û¾¤(S˜å‹Êy¹œqÈ.Z2ú¦›‡ ¹œþšp÷µV,ª˜µî²µyuþV —ó3ÔÜmJ̽Ž7k%­iæGV±{¡b©QmïæÛ–c¦©å£þ[ÑDÞ¾ú¢©zzñj7¼ö™9Ú_k(ùÙ%ñ߫ܓ¡~IÎ{g©ÕD¶~ñãåWÖ—L ‰œ’;sêîx'­ù)ó…Í2å–Õ®9©t]wþ[>„îÑó!Ë!Œ’Á²lFï?ÞÃaªÃ@.gÐaÃGL˜0aYßϸqãFŒ!´R’½ôšäF“̺l]¶t€+ ̇„prºšÆz´DåZ¨¼¥JÝç®WÖx‹¹>„Üfºc©æ*w,úäæý1U{H—DÇÑ^QÎ’®cV­Tþ^‰&ŸZ¡ê^?½/3^ ®¢æ§w:…æmˆ^žëν(\é,?¡;Uê¼’O!‰ÛÑk jHr9yЧOŸÞÝ=fÊ”)ôýLž<©»»{ÚôiC®  í´ç=oU÷þS3¹A]0?bvŒºçÚQ|ôy¯ŸnüÛKrY(Y,µ—á‰bÅu ©òÔ 516ze™¦$Oߤ¶B:˜ñŸ—/.R¯?ü·o!e¹jÕu •—œ·d–;49û;Ff1þGç˜Y€çÉ(fWëK¦®wJ‡¦¥å§[WxÝy+ …¦·Sê^ÄÜOÜé3Bn¡‹Bx 'Í®!ÈåäAÿÙ9—‘\ž0áN}\¦“C¼ÞÕ„Y !Ij©^×1¹j÷ºê…%…™ºTR}š­ ËÖs+ô¤‘Ô£’+äŒä|ÈOF&JøH†2$—ytBýšZŒÑ(©%ãw „mè2‘Ô É>áTqqI5¯æºˆŽ…ë¼p&x/Cæn#—ËÂ[ßµ¤^dhU:ärò˜^ze×È‘]]]#ô1lذˮ*1Š[uCbFm …¸jˆ‰.›ž„b½¼šçÒÈeó©Ãˆ$ác5ª/­G¯wªç”ƒ¡g[´ ¡v%þP™‹Ê£¨c%«¡¨dÊ'ɬ¨ŸBÝòGÈßËÓâí3^!I’ÑQ™uF]Q¼úâræ¯5eDÞ¨‹©ËÜIÌFùŽçƒÛV¨u97þÌO!RÉSe:•äròÈNžáO:Ä-÷ —%3!ZÆ|ÕOÝèõõ¤Ýèå¯}¦QFI0NºÚ‚oW˾#Q8^M£OZä÷ŸYÓ¸Û®Û_oy |WaxçO]ô¼©…üM—’úeÉÍ<Ü ŸçrÅÌLBkÊE¯»l×µ{Ó´𱿠Hì˜s[x}ÍàMEï«9çaÔ> t0Èå,ƒK©£Fݨ’1è=?a&µËZÞXaæ¨\vF]ÎЖ<Ãû@ ¯gtY8¸º˜ü±šj9µ|yÎV,Ô/¾¿Þ+Ãú¶ÀĉMÕîJ稀~ÍÙÉÊ­åío6ž¡ùý-P³{º  P1Ëe°Á#O Cyfþmú:_ÆþíS å²WÒ…ÔX(  Ž2噡*'¦X¨]Ka›}×U¼'…aKƾÛ_÷;Cn™•|Ï ‰øvñäÙJ¦¢—mÒ÷·¢o$° RËRRV¹…‹–Œ¾éæ!C.§?„&,Ëür™G ¹¬ø$/™* ìj>oE¡šdtRHΚ͹*VÞ‹öÊeá׌ r9D @žò)Êò‹’ m'¹œe† 1a„e}?ãÆ1b„ÄŠ\.›ÖêEQ…\®®\–È\¯¼ É/^uEã¸Qé\`t9C€ÖýR”C<•?Q)l¹mUa8ðˆ$·Y”f€\N¦:}úôîî1S¦Ly¤ïgòäIÝÝÝÓ¦O‹’ËåPtYuŽºÑj%—•€PÅû·W¾è’¦Ú3Oæ‰í…ìHÎ[bÆÏœýÕß(\mçåi–w¡™21„”¿²àn–ä5g‚‡n6O³-æ;› Ód΀‚\î€û3ºIr9yXvÎe$—'L¸S$—é¤ÄD“o1^mKZï˜2µ’Ë3jèHGÈó½«# S Ir9yX/½²käÈ®®®ú6lØeW •Ò’WýaýS[på²›’Qç$ ÈeÉdCB@.'cœež—ÜÂBvø¹âZöÚIuF÷Ôê¯e'Ú/]]Ȧ_¦·ú[“·Ë¦®K©_·äò‘á&™?z„Æ1Ô/‹¿é°¤]wJ7I«1ó3õºs=4!¸_ª“8¤^GÙæ¿{ŸÉ0o“®þ¾g^•æõÅß%WÓ/~ª ïK¸13ÜåºOºw¤TnÂ[«{…&ÍçfÈåfP…Íæ€\vï×–\0UHt0¬;¯ûÜ5›êŒÑ{¥°b¨¿’ΚeR»cÕÕÕÝ?¼òÅíã€õàdÜæÛò(*4Lòó¡~ñýjVkÜ]2´Ë¨ùtåeY¨_Ió‡7bêWæþ¨kI÷ -³„×E¶û€|¼„×÷ºf.ÌÐE½?ð7"o¿ø{ …Õ—¨ŸÌ“%:„ÜB÷«(æBŽ>$ —%”P¦\ —­JÎG`è¶«înúǼQº'y¹àµ“¤Ørö1ÃÓ7:é½Ü¢~ªæc‰áÌ(÷£BŸ¼¶=ƒÝóV§,ßBó*U.{!d˜·ò~Eg?.9òŸ‡c ~z¯ßÉ$´Z÷^nÌ}†a–®—ºè<”ô+‰ºöù›ªú44U¢lùKØ…émˆ¹~CöSï‡I÷óžÉ̇ —§¼ 䲜J–…ä²uÃòŠæþÂÜ1SÑG¬ä¾In_xiÈÌTÞŸhw$r‡/£šqŽ>#™g!Ï$s×$.…f ;¼Œ‹Î„è¸ »)œ–Bk©~w%ó‡cYÈÐÁÔÎ¦Ê£ÐØ%ÍÛ ó':©¬ÛKj¿B£«Âû@èNžÄMâ¤Ü¯KEq Ýâ$óSR&³Ž\ÎŒÛFrY£§»ƒ÷ai2ùãÜûØ6[>†M£Þ¦>Ï$·ÔÇ#C%¦BrÇ}„XCÃÜßS?2}pë&=HB…åç%%­Ù•SLyï|c„¾p3½óŒö+I¦X³ÑxÞk_>?åBª<ŠrðÞ͘‘’ÌáÅ+ñ-õ>æ½CÝá§“÷ÓB®÷Ãèôæï0Þùæ_ÉÉ¿^FÝΣZ —óÐCÝö¨›\Vwýc‰æ‰.Ó¬Õ„û‘z®‡œan|úF)¹c†š`Úõ‰úc=#S»ÆŠ·§ªEkȼíJ ¸Mx9§öËõ£–q©¥64 oWZå™N%ñäÕa΋ËÛeÝ¢5Xº-ùx…®P« É ¸^Eï©ó?zýêÛ‹ëh’¸ %w˜Ð˜÷7ëoïGBDf¿rÎ[ï­CÈÍõ64…üMÔîTtç3scqj¦AÉu$÷訅 @.gF‡Šm#P7¹œ tèIŸÍjy6Š¥(™X>IýmÁƒ¹ÜRï0©å+N&¨ô€\Nk.Èe~¼ßËK1räDgCõ®óz¡§•~äu ¦Î„ÔòEù ;m'Àü¯BÛ}Krr9  ·ŸieÈåö<Ú€\®ÍPwJGë •i¬.¾ev§Œú  Õ&¹\íñ«¡÷Ë5tt@@ÚH br¹&R©¢äM×$Ñå’ÏC¸  P+U’Ë40J-á§Îjr}"£&n‚€”Ÿ@ÅärùÂC(„är!a@@ò€\ÎÏ@ x®\f–m/¤yw#Þ¬w9­,I[õe¼Úå¿°ÝŒ`!Ó5‘¤> ¹åñu©üSËg€Ÿ42ØUij»-àV ж˜‚\n v4 –\fîeMºÍe6›¹bás¢]ž´«ÝT€!?›í³íK8äñ!OÝfû&±ŸZ¦Ùý­¢?íbÒ®vSǨ#ËC.wä°¢S•' å²¹Æ»7ºàÞ@Í*„Yײ£Ë›Ô”ÙÐGLœÃòÇ´àµ&*ÆíªÕ_Þÿ¨«¦Y×Ã9‰?^ jk¼tI«õ(—ƒË“ÿ…à$‹|&¨’©Ü¬©m.7¯K¡†¬KÛí”9.¡ÁÍÏÁ½xç•÷¦á½Edá})™¹B-¶Ìü‘ÌsÕkï­Æ½ßº×of>Eµ²cõ=ÊYxkŠ^hU)¹\•‘‚Ÿõ"9ºì•>úñ`ýa=ÝǤy÷wo¦Þ!qŸ¾Ö£%ç@zíë“ѶB|¼ÒÄ|¬òݶ"É—·_ŒüJ¯N2Ÿ‚¼–²ž»Þǰ;å¢6%3$•3¾|sü|«Û„ä:õÊ—¤yèΟ $óDÂÁ;¯¡›?xƒ¡ *:'CÜòÌCÉõÒŒv½2·IÜ$×rUÊ@.We¤àg½ä‘Ëên¨ÌËeæSW' …Zô±f^¾XO¯LñòÉ,_\Î…<ÎÝG©Œj]"òÄŒf©·nt\¢½ËÙnT–…ÔÂÎ{Ñ1–C©·Šw¼„ó6³LLºÒ]¡qwU Wà g²ðNj4Ô´äöhÝL¢ýÍPÞëFN;Þ«É}RxŸ#¡‡K†K¸ZU —«5^ð¶.òÈe†ó`àõD’hÝ‹ókåèã3*Ë$Q"U…2EòX =•£}±Œ›BY2^Ñ!rHíKô:Om—ŸÞü%ãåÌ{寨”Œ‹÷; 3o[&—SÇ%ÊV2“³ÉåèÊåïœg&†¤|h£÷è„ÌvDÍ&A.yaÈå’Ü«)fÈeþVëÞ.y‰“á¡î}ò¥ÞpùÇgÈçècƪ•wÂòч}Nyá>&•Áh»iåµÃë¼(þ«U·TþLùTá›$k$Z*ÏX¤ÎŸ $cê•ïÖhfã&¿Þ•ÞùãÎ+á4‹ö‹±#éo’Ì5{‘³Ýèý!dŸ™oÿ¨†\îø!F+I@òªŸº{êóÎîž·nµîSÓ´£ »ÆÕIÞ®÷yßdF¨_ª; ë±Äûo>tCµš³žÇ™¹¹ƒèí/ÂÜGš·¿QbÞ^¸MGgŽp\$êÜ;Žº#ÞAÑ4¼~2wáÐk•‚ìm‚1΋5Ó¬ëQ2,’û£ð&c¡Œ‹2ÓeÉumº!,Ï™ePr?Œ¶ëNÎè¼õ¶+±#¼?ðöÝA‘L¤J—\®ôðÁùŽ%ÐyÛ”X÷èÐ3¬$#êz[Ç:Ø>€Û>š˜çͰmÛ¶X†\n v4 $—CAʲ=N’¢ƒ˜Á…(Û|(¼ƒ%1ˆyÞ‚þÏL ß»týÁÇVï§ãÑ•ûZÑ8X¾÷þeû蘵tïŒÅû阶hï¤{6n=Hµžß¼ r¹T£ g:‡är³ÇË–5›0샀@ÇPr™´ò¦×Þzfë[Onê¥cÕ ‡W>ÛKÇŠ ‡—>Ý8¯ïY°®—Žykz\qhö’ÝT뉧ž…\€Ž”‹@ä2k¹æ¼Pr™âʤ•׿ػê¹Ãth•¼d}}Çš†P¦ãᕽ.?4çñ=Të¡eÏ@.cf@S(¹¬÷937DÕíy·0«0›šN»û¦ªO]ûúÃl~š¹¿&I³_.«dˆCS†FA@ÊJ@ÉåǞܯ‚ÊË7ôÒA*Y‹×ö>¦ã‡õAÑåoD—§Ì[ ¹\Ö…_' £Ë®üU"ؕ–ŒÖRÏúƒ9oîB²_”?nøËÓ_ïîÊü¦ÜÞï'©>W|Â}#”\~xåFêųý©ëz÷J%ÏYÞ;{yôJ.OxàIÈeÌ$h S.‡n(@k AëooÀØì€)½ö]©å{äì,ãLù¯æ— «u¯M¦]¹ó(   PiË•>8ß±¢r™¶º¢‰‡ä².#—Cƒ•¶’QtƒÁ^á+ {£ËQnWQ@@ Ã(¹L‹`4Ò0ž9š†¡’1(®¬‚ÊtÌZÞK‡ú[E—ÇÝ¿†~Ë_IÂBr6yÐ&H’ËV²A(JjjA¯¬d’1©£Ëyä2£†•Ùgó$uEäÔò¼j׿#Mm·Ü2 î¼*íâlm»Su°ÑkAÈ9jÇ *[­ª3‡ÿ<%—7¼x`ÖÂ÷/Ù5{Énó 3ôVŸ:¦.ÞCÇ”…»'?¶ëé÷Q­‰®£ßò(’Ãl)è&ØdHøÀˆ6Y”hCÂeð§]>´«]áÐÔªX…Æ¢W 1Rà )ÊŸlväµä% „S ©ªû_ Ѝ\žÿäË𛸨%µ!—3ÐCˆp¯+÷¦ 3'mÏa…®µ[:¾âF­¼ö­òf÷ø&¬~… «¯VÔÇ:ú§ðy`V7«äéoˆ§—õ(s»!;Öœ Íf¼Ìæ çf»9\ÿÍI¨\Íì‚5ÄÞë4ó%½QZ~Fûkò vÏk˜ú#ëz—´ëí‹uÑY㫽 ]/ÂëÈk‡gË£;èÖ­)dœï¯u³ÜÎÜ„9|¡[¨ÐxtBvp’¼¯ïÜ}÷£›FNyúÊ;×_:n v?yјÕt\0f:èŒ>.·nääg·ïÚ¹ÜÁ]k3’Ë8@@@:†€PX C Å@@@@êHr¹Ž£Ž>ƒ€€€ @. A¡€€€€@ @.×qÔÑg!Èe!(¨#Èå:Ž:ú   • ÐÛÛ³w÷Î]onßùƶBŽm¯lÎ|hÈŸÝ;wcäž…±p‡C½ÎÜ ¦by:خޅ. ÈåJÜ.à$€€Ô‘@C+¿ñÊ7Þ÷ßO»ô˜žU’ãÏ?á~wûž]ÛÜoJ9NåÖÙdz¹\Ç» ú   •&@A\ÒÊ_½ð¶GŸx¶<Yûü+äÒ…7Nt£Ëåt8]gwéärêTAy6 õIqåGVl|«\?‡Y±sé”ÕáT|ÝÁ`ï —Û|Á£yT”%L‰‡÷ÒÑ÷ÓS†£§çо=»È1·;åt8ZgwéärêŠò   m&@ÁZR¥‡?KsØ»g×›;^óÊåR:œŠ®³;Èõr¹Í<šH% ÔçûØÇÇ üá çütÿ~zoÇë¯meä2ï°å-ý3§KT½#Êfw°@Wù)áý”ïärêŠò   m& äò¾}{úŽÝÞƒä—uÞ=ª›áüÞ½»v¾¹V:cär©Nícgt04øÞA.·ù‚Gó   ©úå²Ê»¼GŸ0ð‘{&T7Ãù½{wî|óµm¯lbåršÃäFS}Nêfgt0Ä“ïärêŠò   m&Ð/—wQP„Ž÷ aúˆÎ›™ª˜[^Ÿq »–÷ìyóÍ7^}íåX¹œì°òÁüä¼Ù)¾ËVÉwÐâ¯]5ÝðŽBè¤iдšüðA.·ù‚Gó   ©”\VZŠ„NèÐ:É*@çÍ3êŸÖI}Æ[Ømq÷î7ÞØñÊ«[9¹Ì;r@y¢?Íæ|´–YÀõ„|hFMìÞ&õÚ,²æíZ´wË©W(ʃ€€´™€’Ë{ö¼AÇîÝ;¢‡’›f13*©?2ËxO’ËŽ¶¹k×ë;^ßúÊ–ç˜è2ï°å’×סón÷•çê¼ûÛEZH]³®ÿ^Â!ìòq4û›Ú;Èå6_ðh@@@ •€’ËJôŒ$­TIý‡õOó¼YØÒdÞævîÜþúö-/¿ô,#—y‡-¯ÌV,Ǽþ„œ×}dj©ºæo·Mê wP´«Ú /œ¤qô½¶Ï÷r9õ Ey6Pry×.ÒÊ;vî|Ý{–²Îë3ÖGæ?Õßî™P+úü›onß¾mËÖ9¹œê°6.ô‡qÞ¥¡Œ›UÜêf¯›ÔÁР˜îY#âÅb–ap…8ð½ƒ\nóæA@@R ôËåF¨˜â‚Þ£O øHŸ±>2ÿ©þvÏhS®YõÑ›onÛ¾í¥­/nd¢Ë*–)wØÛh6磵T[¡Þ5©ƒ^ÎÑ“ÚÏP§Bç‚Ö^þüðA.§^¡(   ÐfJ.kJZÇ{(y¤Ì2Öyú§þÔü[ 1 ¾ñÆ«Û^{qËæ Œ\ævÛ ¹Äøc±úBÁô]THù1ÝP%™!óªªè~$ìär›/x4   J@Éå>­óZIZãµW6½´ùiF.—ÊáTnÝA¾wË©W(ʃ€€´™€’ËÛ·mݶm ”4L·ñ ^mhåg^xöIF.—ÇáTVÝÁhï —Û|Á£yT{v½ñ矿ð‘EK7?¿î…çžÜôÜZú£9ðüÆÕžZ>ó¡‡È1·;es8•Ugw0Ú;ÈåÔ+åA@@ÚL`ÿÞÝß¿òö“ÑuûÄéëV.hû±våckŸ˜?eÖÌÏþtØ¿ÿþ—NÙN%ÖÙŒör¹Í<šH%ÐÓsèàÝß4鿟v)%?”ä ¸òO®ðàž·ÞzËêQ9NåÖÙdz¹œz…¢<€€€@Y0-áC§„Þfp©³;(ŸÜƒÎú ó8Æú7ýSn %A@@@@ Ã@.wØ€¢;    E€\.’&l€€€tÈåPt@@@@ HËEÒ„-#`Éåÿ?ëæ|„Üx¹éIEND®B`‚ivy-2.4.0-rc1/doc/images/xooki-toolbar.png000066400000000000000000000146131226750426600203370ustar00rootroot00000000000000‰PNG  IHDRÇP"öjsRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< pHYsttÞfxôIDATx^í‰WמÇ3Á{gÎÌœyç$y™$g’·ÄÄŒã$Nóƒ ‰K0€‚‚(‚ÈÒìû*;(â‚Æ•ÍAQPh”UEvqEç[}»‹êÚºšFhxÝçž:Å­[wùÝÏýý~÷Vqë_,¶ýç¯ù÷Î;ï¼æ Ùë*ÆÆF]³`Þª^wp 1F ¥üÛú,V*ÜżWz= ÷j++é饤|CJ"Ó°¨jzE&‘ªÊ·}£ãHØìµçðé³Ì€ú*R¨¢¥j¼ÂD¼ûF7nÅóœª*º^!T>|Uñð¡ê|Ç+V@$‹ ŸÈ¸GCÇ‹J_?ãÄ“>‘ñ¼T5]¸pÑÎú†ß.–Dƒx\%ñâD®:äJ®dõæé&K„-ª³ŽŠƒuûPu¤a8¿aøHãp~ã0¡êf¾¬Àí]ïðøÞþG½ “?}J‡!Õ9âI‚=°Kûï_Óx›<†T‘ü)EeïÖ> /“ç¶ÿÎÜ.šK×Ù;Òû”™’ ÖxSÅ[oš3æU–”]“š;z›:zA¼³_ÞÑc½â„:v*hS$p Lꡪͮ%+ûí·õo¢Â€âXbaŽx–”™²6KÚ¼<ÑÞ,ÇÍ×ä6tÀŸtBä{kSL÷œ\¶çä»ëR¥ùÆ6½±Ì‡'üa“HÉ¥¿ýæVVŸ7mûòåÕmJësÿ¾É´QÀ™,€J£GÑèx¢ïbûU:f'åv£Nò!GFNXd8ú'Ë[»@Oke,7 ¾¾¥GÞÒíx YdÜ—˜­hýÁ¢ÿ—$ÜûÁ1"4ãÒwQv%5ÖT¨þ¹¤ZyRZm]J"k¬—FÙI¡êí5ÉsÍu<ô¶m²tª`Yr:zœ#F¤ÎÆ+–!uõ×®òûåÐXëJCÁ‰ªØ¿n¤ âê*d¥§To]DR[ýRªV7tåÕы̓ü"9®" RŠQejÖjfÞk½¾_p^bj&NÕÙºœ2K*”Zd—Yàˆól*'TX"[«‘ª?Ù$¼¹&ñMÛ¤7mß\“„?Y`‰[@`´`[ŠIÐYHqG ɾ9|©6¸V·_RÁç=Jå¹Çª"^ÚûÁ¯.SŠ*î*¨¶cIÙÞ'µR~¿²î¨“ûuª?‘T<Ž÷‘RÄ›˜öZÚ2C‘‰©¸üÒoõb?›ÅûW#$œ3OºhG[@•¶ãàÙó'IÛ\BŒ\dFÔQó·¼|ùRÛ¬ éÇG“€ª«·Ž*abPåý¿Ý}÷ÆGF†R´•€¾S58Ôí—dJ«(Z]¹†Î½V[¨mk éÇGúNÕ‰’ФTæ1ÎÁsŽŒ ¥h+½¦ª½K¾7î[†ùÃK¤#ÞURÁVm[kH?>ÐkªrÏìQSTð«®•,Í Ë¡ã#&C)ZI@©jn¿á÷&F,Sè—hÚ;ЩUk ‰ÇGzJÕðð‹üóûÙCQáÒÞØo;Þ1JÑJzJÕ½û·}âŨòŽýº¥³F«Öô‘ªá—Ã'Ë"ˆísÅ¿y©«(úÏÝÑ_7¶]1JÑJúHUw_›òrµÅtu?Kf佸¾åŠV­5$ è#UWª±Ó™êJuîõe]ÓÅñ“¡­$0aTá)Þ‹ÏŸ>zþâ|sºÒCû¢ó6ŒX=óìvÇ|Õp¯R¤µ(¢£«A+‰ë.  jèIÿÝÖŠ#çý#³mRÍø9í„ÛŪì=M ¬±íº‹LµÚÉBJý3¨Bb!`ÑÎô^ÆÒ]L†´’ÀP•uÊÓ5d.ÑFc¹õ–!¯1•€V±OU'K#<">§©Ò¥ö†{_“À§.9OU=ýíQ¹ëˆ?®cíui¹á^ èØ/@–£àE¹Êæ¨Ò[²'U%ÞšÚ—°Ô@•ª1–À‘  T±LÇ.;èªþþþ¡¡¡gϰî3¬íËÜ`IÛ±ŒŸ]GM+EŒc[Ä(rÅ-RÚ5&i„ê†øÚÚÚ–––¾¾>€5i¨ÂÊgÎioV«^GŒmž$7:O™sHOÿI>L†4ÊŽ·’Œ77D”••¬GA]iñ„é*¢®&)U´ˆÅ;˜y•ô«Ò¯ŽŽ*­f|("::`AcÁN&ª W¹rgeæhf …5ø˜Ý̼Ä‹¬ÌEÆ4«ûyóª/sQCª¸eI§ŸV`ÙÙÙÕÕÕ0‚/^ŒÖ–*ÞÒ8••uóæÍ)E•hF¯ÑÔŠÉR?“‘*–fÕ¨ T©yмˆË”×qæõdIgŒU,³«Ñ™ã¶QJ=y}vÜh JU⯑ҨEL›FƒËõ%PöÔ`§E{TÈ* éª ¤ŠWíI§Š;çж-Ú‚8eu•ˆ(Yj@ȱV5Ó(òÔH‰FWFHW±Œ”¶ˆŒŽé©c™þ -Jâ.pûŒŽçBÆäIèªÐì‰[í¯pç€Ü k$ƒ™›Hbî¹þ“¸êâõÅ ô”ÒU¥#„‚Vñ£+ewiT*£ÈóuÜÂ;h§”®’"5¡q¦­ƒ,¥,Óè?XBJñŸŽ*»#d_t„C—Ûõ,¡º, .=n¸—_ª dŒ½&=UÜ!F$0‰ý*Ö(ÃKxõ/`à5 <3Gà ?%à¹ÛÍzýW÷Í~û}½÷îúÇÊ¿iú6 &+§!F(ÿÉú& Wq7Ý»}¹âtþ±´Ä”ˆ¨Ø È˜Àˆè€øÄH<<Ž“„z…y‡ï öÇ%mCDLrC>ÈPÛ_BRôèʪ'rCžÚVé32ÒcãÃ4WF!@Ç]V[ÜÌâÂqKrJœùº¿·y_V¿oeg´/À‰W “õ­=U/†ŸÇäntYìè·h‹÷B{¯›<æoñþ¢àd BX’cAardŠëVï/ìvÎÝäù™"PÀÕùv;?µó0¶ó0Â-8·÷Zxê\.^ðÐêw¥¼Ô'Üæ7Ïy¢%ŠT†çrÛnƒœµª •žrØ»XceìòYç6cƒûl{¯ÏbÓw]»VáòÓÆ]ó‚ã6ûE®Û-ûqg ydÊŽŠÊ+Ü:LÊ7Œ¹Š T§Y9ÎvðŸµÕaæVß™8þæ3Í7fE}ãõûÚ»{â(o¨ŒÊÜh¿ï“mH¦Hà [üfnñ¹ÙwÆ6ÿ9þ ?¦Û}âBtiÅ¡ð´õˆÏ.ôíííÅkCÒ•Õg¶ïŸ«,…”ÈW.URú*3'r»¿ñõ[¤Wƒ¤êà—ð= óŒúÂÈÊæàŸñkK¥ODZHðAKî—;l16Wæî8ÂØÐ›»q|HºÕÀ£‡Ò+ƒÍ½°q—²h¡²8éU¦>yúèaoëù«É‘9¿Üi)G‰ø¯LÈÇ7á;YÚOØREz4¦Ôkª¶~RT‘ÂÛütKÇÍ«· ê›/ݺ[Tv=ëÜ•„¢«)—oæÕ5••\OͰv š¹íÀ4‡€O$AsÌv ™Cú5ç÷ÝEC'¸ÕP¬èE:"ô¥ÐÖHôÆnä„N,3’7_’^™+Õù#|óì™ÃSÉ€óžþºˆúæËÇ‹e÷R;¯ªrÛÍëõ*[UÇcŸ~ÇÀu¥¼·‰?¼É-l~ÂáͧÊ"¯×¼ÝPTsç|éµ ì˜½=hºcÐ Š! Åêûªá?§!V)}‰M¶ðf4L®ÈP­/9LŠcǧ]Ÿócîà%^«Ä#[U@Ñê ñ퇚Ÿ( aåÙÜq³äZ†OüÿÑíòÿüì•lÇ*E&ÓèU”$8ÍÚ±[}ð¶›§´Ü8zhWäÿ8Ît ù9Éà`ÍÖ(Ênp ýT£tgOì7j–K óx e¥dè'Ub Ê} &º¤TÒÀ|FöJåßßK µ=±K°Ç8Ɇ:©ªîì´5k¤¡J~‰ß'Ý~±*GÇÍ¡õ’*ÅpUØûZÈçÀ&}PìðÓ!ˆsWá6)ü0¥Û$ÜÁ#O=®ö½a¡N-¯92b×”½Èg y]!ª˜úL‘æz¤oòÀ¾cäðP%¼#azá(BP{øœ¯WÔb„Çn†A©jRb˜o ¹Ôc#ß÷–‚;+þRå< 榫§™·U7ä¿Sú_f„ÝôšÚªÝÇïm0uÛä›°T(sºDôGB¾½ª”æUØëâe‹®ŒâªÄ^T~ÑNý^¹3r¼4'ïÌ^Ö¦˜”¯©2 ¬§YÒêmHá=£*Sa•ÁxkÀGÅ•©\Ÿã~wÃΈÏRâûc·vÞ^üòe9UªüÝBç•Ue‰K­£ëò£jdˆ+© H5Ç´Ž¿Ãxô™ò.)¦{ØwÏ'nÄ›¨Ú–¹úù‹§hãÝÖ«˜M <’€e‘e”²¸L×~JPE­,¨½ÌhÓþ/ÝÈ!TaÒ§Ø—vÓãðÌÕ°}D.;Ñ9>–Ä–wFÆ”fˆQrÁv,gˆo‘Ožp!†yºZS€9#Œˆ°oÇ;‘4.½ž)Þ…0;Bç«·Qp3z…oj\r-γ¼&GØ|‘æ)¨Ì1YbÐ/]u y…¢ÙÆŠ•§Y…¥aðŸˆ\Àf.EA©+)œ(p…®’+öÇÆÞën!ó'ö|„ùÄ›ˆÌz0Ê1¡\‘åÓІƒ£ƒZ`j‰•¡Èœµb5á3aðu0r„ÀÂD8嘣º'¤BjdZª˜ðRŸ> ª Ï ãÎû=Sꜹ¨Á¬†ÌÈ7ñ;tº,=¢ ‚;Uáð1¾(‰#ÜpÖäÿ~w#Öœ`A•cfX¡ ]wø7޵R_bMûeF%×Ò„:3&ˆ…j††PÅ„I}•á\y"É zvÞi£z$\iØq¡ÊÀ¤Lך³ýtU!FRV0÷£¿\}ˆÒUêP…©+1áÉÓ_o5ƒúÍ=í½-`Y"ï|À¬.æƒ1¹¿ÚïÿKFᎫ5ùøŽ £tU³r/ÿÚ¦2­ D »ùøé ¯(1 ñ,?W•„^§‡ÔUHÆ*IFÆBf„­¼…:‹ŸÊŸyæjŸMdJk.é…î}÷‘-NX#„Y=à…ap¶ÃwËps–Ä…¹-:è¹ãÅ!¨–¬ÚÈ™_…)H;áJùª|°&‚õ )܈§Ñ#ª^¾ɰ†íþÙ1ø* “*¨(ø’pØŽlÞêÿ‘Òò›òÓÄb¨+íÊÛÇ(Dš¢B2÷ð,#ÝÀ^ÝQ÷ÊYÞ>eØ7Hù.¬`Uæ#D¤"žùµ:<gy“xI})˜Å";C5à.ß<Ĭ D‡U4å˜nÈO·tTǶ§Õß»_{³þ V°ˆ$ñÃŒïq`xHGG$¥Q…eîÐLk…j1U{Ô-?~Òz:ÞAc ·ê[.·Ý¯õ_ê8ëᑈ,[Å Uê Ù‚¾‘ñVêE6ü°ÖŠç'ü®1w¹(Äèì•xñÕK¼1§ÊMý[b¬ÜTuÃ:)zñ,—Ð뱌¬Ý1ø¾+õ²Äü-tð4KÐCÐUp-²÷ÄÜ‘{㾅ɃÃJÞÔ~c ®‚‚*¼”ˆWí ~vG-¾T•Ã|œ¯‹ k† m×à¼>»¯ªîwp5Ù%˜ólDµÀpç•*¯°‘Làw‹Íá™9„íO\†I»øøFGú'›ñó-@9Þb%yÂ~¡¥ 0šÌœá}Ch˜¾àf< ëÁã®ð8¹K©ðâGñ±x“Yºêÿ­«„8CLIEND®B`‚ivy-2.4.0-rc1/doc/images/yed-step1.jpg000066400000000000000000000060051226750426600173510ustar00rootroot00000000000000ÿØÿàJFIF``ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ†»"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ )»¸=(,@XÉ.Dz>…{…ÛIÒk»MW·K¤½„ùï4‘¼L¿>B”`Û›yœã#9zï†5)4í)‘ííàºÐ4ínê6ÿí°— µ‰fY‹ ð§ž)=€ï,|)go ·°xÖù]ÑmnnmZÑË3ؖΖbÃväÔgÚ2è2ÜÞ¦‘$‘»Ê²Ù,ÑÆÓ¸C€w(ÉïœÕûíÿP–îu°ñÍ.™µiü]y’±ÁÛŒu!1Ž‚Ÿw¤]‰µ{ƒ¦Ü\oÕã¼¶û5ÂG(QkeÓqÛÁ× WŒŸLñsËùбZ‡öWzRÛCâ=Jm*IEÊÀ‘Ù5³00‚ ¥{íÆÜüØÏ5KÃZÄúþbúݨðî«b÷–ÚQ¤w Ÿ/êU•2‚S•c¥ÐtÍF+{)î*$2XC',îÁŸj$!mŽp$dO—ø‡AÔl¥Ð,&•aº¾ð ÑÒ¸…9Ñâ ¼¹Á8û™|  diFmÊ̓F–°mì< ¦[ê0A¨Zøn*kµ&XfòÈÄjÔÈ®æ8$•%@«:ι¤Á­êw*\ê'S¶¿²ž?e,Dج.[!JÇ&æ8“^ž.õqô:Ó^kV3GÚm³ ŽXƒA‚ÊWæ;pFHmÅùÍjÒçV½Ò,¬-íÚk•×¶ {¸$%Ô2¼Q±Wà€6’~\¨äöê$ë,õKíßMxÑÛj7¬×/$Ò!ßo4W?fPêJ¾AEI«yçѧÔì­®Þ{Ëx¦}»c’@¬Ù`£òrÄ©æzw…¥>ÕìmììßRÿ„JÛNÙ‘[ “‰x;ŒY$€p9;x××#0ë6Ry¯µ› ¸Ù$Rñ$mt)ØÛ¾q·Äœð@=Š( Š( Š( Š( Š( (´P»¦É©ÞhD@%¶‚öI.`­g'ž~iqž¹ìqÇ^h:Ÿ‡á3²jóÞ-„.xŒ_fcº Æ;`äpEzi@H'·JÄñn­{¡øgPÔ¬,Òæ{x$” j Df,ÝÈùqÉ$ €K ‹^½Ÿˆ-íwÙ‰õ;IídŒ¡o&írvFsŠ g¨ÁÍs)ÓîtëOµÜ×-׌¬æ-vñpo"$TQòg=2NN¥kZŠèú¡ª2—[;in ÿ{b–#ÿ®;_Ôõ4Ûûmi­e“N›LÔdšÎEý¨3ü¥˜¢$ç§aJ[ •åгµ’ãÉšr¸(s¹'Ç|rpR@Ô&¢5 NÕ<¯(^[Ep#-»fõ Œ÷ÆzÕ˜&†æ(ç‚X副äxß*Àô#×5 i÷š?†ôM-Ö d´µŠÚå•Èdx%>_›,ÁÛÁ'¶›m ¹SCñ,ÚµÕ²Oc´7Ö†úÆD¸ó ±œºí]‰#8‡ÌFx¬ÏÙÜj:‹YYÇæ]OáÝR80Rdf¶ É »9«~Ðu=>ëN[ß² }*Á´ûSŒÍ23Gó8*!N<“ÍA{¯Ù/ÄÝ>Î×WVúuÌO$I+Âè„’X¤¶ .}+ZQýâ²"ñF›4—·+l‹i9Ñ`„»¥óå0: ¯Î:7¶È´]Aµ{;ólÑFúãß<,êL}…àç‚Ká°¤ýüúÖ²øŽÒHí|˜n&–ãÌÄ1ª—O)¶K»$}Ö88$çž3OÃZýÖ¦ºrߥºÉ¥Ã¨DÐ’L¼“ЃèàvÉî$£á?êZUÝŸö…Ýýרôÿ²y—Aå–ÊgbÆØ~ïƒ#d‚ $Ž×h÷üé6SÅ:€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Ì×tÏí¯êzW›äý¶Ö[3fí›Ð®ìdgÎ3Zt›Aë@ú­Õlîtù™E•Õ¬°L› s¼6p]Ù9Èä`榑£ÞZ]ÝÞêwðß^\Câ¶òPGr ®æÉÌŽIÏ~€q[{EÀÛü7Ñ·1>¤§“z×6“µ”n²$‰Ô`¥ÜΑÓi>xroìÆ—LÓ ÚÊÒNcÓbE¹RÈU@ÚGS…Çñ]¾Þs“ùÒí­+ <ùþh¡bû=®—É5ÉyJŠ@bšRáB·mUc?.+A¾é¹†;M}§÷cûÛúto_¯¿Z·©ëXÖîõk±¹¸`I @$ô^N}jûXÜù3\E“ZÂåå¼¼ýHÎFÁäqÍOo¤]I"‰âšÝ$·’h¤xˆ3&zƒÈõ­Þ2ÕF–†j„ìã}Îy®-XBNNGSëJ.m”† £nvôïŒÿžµ­=Õ´QK=´ÑG0ݺ• •'¨äsî+Ó~ø§ný=0ϸ•ž#3T©ûHÁ2©`½¤ù9™ã~}®ÖP©µòXcïg®}kB?¼:4úT&à¹pÓH©ûש »<&W§¹÷ϹoÚfý¿Ë›ÊûwØ6áwyŸiû>qŸ»¿Ÿ]¼ã´4õÔôý“A ¶²‹´ÅÓ<’FR1Ÿ˜©ˆ”’K{VȽ´o,-Ì'Í•¡žEݹÕ†ÖȧÐÑ Œb ©+zŽY[”¹œÏœ<ëS–U<°8\qÇN;P&´Pa·Œ `úý}ú×ÒÜUY5cÕ­ôÒ®fž gR+¶6OãûÕÆ3Ðûeÿ¬‰ëì‘?Ù/ùÏâÙ•ƒ!¾ð#;¾´‹-š±w £¡õã¦Gqú×Ð0ø“I‘aó¯ µ’{™­aŠæTå’)Z& ù¾eãò;œU{/é3•†îúÊÎñŠÖ[•I²y!)Á;Š1’£4ÿÖ>¾ÉÊZÚgŠêZñÕ¤s-¼Vöq´VðAUŒ1˘±,p2I纔Ñõá¡]µÝŒV¾~͈ÓDË窎0@ÈSô¯¢8ô£Ò±Yí>Weî¿2Þ[&ù¹ßü1óI¸Ô \ÊÙÜZC¸³x“Ôæ“δ$ˆH$ŒÁ<ÿ:ú_ŠÕqZ*Kï%åMëÎ|Óö›o3ÌÂïè#ñ'Û¡þóßf¾’£ÒõŠ;:KïöG÷Î{Ç?ò'_ÿÛ?ýµäúmÒYÝ<²o*ÐMûÏ ?@X~íZ†u«)4û»¯ôy¶îò¢ÚÜ0a‚XÈ«|,ш\ê\Œýèÿøšó°ªT©:sêμM ÎjQìyí¾§m¤.Þh¹·µšÕ#THdùËç*GšxÚs´r3Ŷ×,V[ù£[†k÷–i£P!fŠd >c¸fn[ Âôæ»øUz?üüj_÷ÜüM'ü*Í8ûN¥Ÿ÷ãÿâk¡âpësB²Ù#Îu«ë[ùRXƒÉpÅš{–ˆBe$÷Eb££Ï=2{ò.\uéLyþ«ð«toùùÔ¿ï¸ÿøšßÐü3oáû'´´k‡GÊL¥IÉvÇ ¬qXª¡ìéÜÒ… ‘Ÿ4Îcþ[O²ùßÙúgö¿öÇÛþÛå3Ëûoûwnòþ_LñœsT4ÞéÍcÇ‘:'ØäšApˆP¦Ñn¸Ira;Fá•;0Þ“ögǯËþ4¿e>úy‘è\á#ð¾£cám J´cj#¹¶‚ú[–l/ïD±.ó†v7‘à«Í;ÓڻY@˧̲!8“ì±Û…›nB—…ðpp8'"½[ç søñ¥û)ôÓüh÷…sŒ¾ÐµmV×Ä:ÙÛÜêš:Ø$qÜ<ˆ’qÉbŠvâT퟽ÇͧiCþ­BëdÉgm6máž|±©–D\cÆs¾Kœ›5Ö}›§ßçØ/ÙOL>?ñÿ?̳µaêþµÖõÝ>ëP³²¼²µ¶¸ŒÃs $hH`¤Ò7ÉÎy¦º_²ŸGý?ƲŸGý?Æ„šØ2?."óâ†;f¶¹I­Ì)}qmµÄò/îâÀ˜mœa°Ùü#šÏö‡ˆ4¸ µ6Ú•›Ç%ãÊëä¬×7¯”2$eI*YFpa¯Mû)ôÓüh§‡ãéþ4jj*ÏÙO£þŸãGÙO£þŸãK•ZгöSèÿ§øÒ}›Ùÿ!þ4r0+ÿú¹âŠ¥ss*k±iÑŒ}™¦gt,r@àš±²ãþ~¢ÿÀsÿÇ)rŒ³úôúÕøÕ'û¢¨Aþ½>µ~/õIþè«€˜üV.«vš…¦“¦´Þ\Å-Àžê3$qG@ß(e,ÄÊ€ Ê$瀭·YºžºˆŠD¹šÎò ù7vÛ|ÈÃcrüÊU•°2¬Èª©Ê®‘s5†¬^[‹;#¨^^ÚÙ´vñÀL¿1Ø‚<¬m±,ÛVÓâ>‹y¤j7ñøðòÌÑ}²Ðádm¨|Á1ˆd†à¸n:|Ë»N? ÛÚ’¼²åPmÃO)^ϽÎ@±¦érØy­qª^ê3I·÷—EÕÀ ªI9Û¸äd€åÓÆžU¬ZÍæ­¥Ãe5ƒêpé^o¤·³‚Êl.â`a—q}hë:Ó4K+½J í`»óä†'DB2æ7‘do”†ØªÎ¨o–£Ô<e¨Ãö7Ôõ´ÅYVŒB(DÉ ØLeÀ +íRÅW€ ¹¯xJ{íyÔol~Ûkö;¿²ù¿‡çŸ1n<É9]§æ9'€Æ×|ncðþµ5­õ“Åô6W²ˆš9n-ÖRB€ìÃýL„@_Rét½mu‹‹Y¬nôûÈ${{¯,·–å‚81³® GÎ~^@€~×a}k¬jwSAqq$6ñÄvâáæÔùa‹ùs0ÖPY¸8\tÑipëÝjJÏç\ÛÃnà‘´,m#)g?½lóØp;–î(Å-XÅ¥¢‹˜£´Q`Âü3øƒoãý åx~Ï©YíKÈ€°;Y÷[kpNF9cÝÖ/†|/¦xKD‡IÒ¡òíãù™›—•ÏWsÝŽ?@L Ÿò<§ýƒßÿCJÒ¬ÛÏùSþÁïÿ¡¥iV/rÑ$<\'9çµ_‹ýRº+˜ÓÆ-('ho”‘†#‘‘œŒä#¶Ô-®æº† Éi(†uÚFÇ(²Ï_•ÔädsìkÍü;à›ÛNÒoiP^¢Ú·š×Æ;ŒÎmtôÜrN[tÞÝpÃ&Ÿá;è´[åÕ´‹éõ[ë[C-ý›Ú½Ã„†Ú9-Ýæo›/³+!<’vШnÅ-bxbÊ{Z[ÝØÙYJ¥Ûìö0ˆbŒbÀ̰A`†âpO¶è¢Š(¢Š(¢Š(ªZ^­c­évú–™r—6w ¾)c<üÁAäAäUÚ󟄞¿ðG†¥MFíÞòùÖYmCîŠØ€FÕ±€Ì88P8\ ÛÏùSþÁïÿ¡¥iVF§:ÛøÖ7d™°qˆ¡yßNÊ «_Úq϶¡ÿ‚ùÿøŠÅ§r“)éò€`u?È×Yú¤ÿtW'¤ÈV©þFºÈ¿Õ'û¢µêI%FØ#¿j’¹ßišž¥öSbæHSx–×ûBk ìqµüèA”1µ·äò«L Ó€9 ZRG?5yî™ã-JöòÕô­6C £Y[´—rGædñn$Ê2ÅÉùy9[v^+×õ[¸–¥ÚÇwuœ(bkŸ%ÚÉ.Ù̉(YWï 9 €Aï‡cý)ÁÁæ¼ïMñε¬]Z^[hñÇ¥3ÙÇ9‘ã´ñC&|Ö•+ç¨ "mÅ@ á*Oâ_ÜèÍycεõ¼¶ÖòD-ÿÒ­£pe&Uaq‚NŽwpê…-r©«ëx¦ÛMÔZ {i1-“°¾B]Ê:ÊD!¾Iä!ÚÍ“·ª Š( Š( ˜”úJçðá>^Ÿò ý•Ð×?ÿ3úÿØ5ÿôbWAIÇéòƒê‘®²/õIþè®OHÿ¬Süu‘ªO÷E@’³5=HÖ|£ªév7ÞQ>_Ú­Ò]™Æq¸gëZu‡âMfãHÓ‘´ûí FâQ ¥—äùï‚ì<Â0¸$n»Ž¤ `^—HÓ¦Õ"Õ$°´{øP¤wM ™QNA øÈ3p=ME…£¥Ý­ÜzUŠÜÚD ¶™m<€@DleTp ¨WÅZ+éó_­æma°R’O)ø¶påÉÈøëÇNEQ²ñ–Ÿ=­Ü·1]Âö÷³Y„³Jfd–DVÔýé+9 »`Îp4¢|3¡2^£hºk%ó¼Sj˜¸`Û“œ†$ä瓚~§¡húÏ•ý«¥Xßy9ýªÝ%òóŒãp8Îä)³x†Â-j±´“ḆFˆ¸‘åg¬{[_Ì!m»NCmÁÅñ úLk'‰¡²ÓÄÒˆmE¥Ì—FY ³lÇ’„6å%‰Àä€@.ÍáâÌYÏ£iÒÚ‡YjŒ•+m#ƒèè1WiçùâÖ7ÍóüÏ,nó6y{óýíŸ.zíã§™sã Íî„÷r"[$­$ÆÚ_(ùjZEI6í‘”+å–•±.§â'I¼[;©§7-åí† YgvÞ%+’x‚SÇ@œã# ¦…£ÇyktšUŠ\ÚD!¶™m<1€@DleTdŒ MHÚ>žÖënÖ†·6©…v¬,hÀÆ6ª ô JÇ“ÆÚ<7!wt‘"ò’ y嘻™²ÆJ•û<™x`Áp35ßô+Au-Ì퉦—ɳšSA2ª!1`«Œ8S”qÕN/ÚhFŸxo,´«k£Àf†ÝÌj 3´Pp6JÒ¢Š(¢Š(¢Š(ïEèŸÿ™ýìÿú1+ ®þgõÿ°kÿèÄ®‚”vÒ?ä+Ôÿ#]d_ê“ýÑ\ž‘ÿ!X>§ùë"ÿTŸîŠ:%ak^ƒ^Õ4û«Ë›¥†Ée+ ½Ä°+íMѺœª‰’·ã»YÚž¿£è¾Wö¦©ecæçËûUÂE¿Î7œd~b˜¤Ÿ. Ñot½7ZŽ(o,¤Óä7vÏpRÛ|Æ$Œ™AvL±l…N7ð­êcìÚ” ömBMBÇ͵i<¹%ó|Ñ.$bþýöíØW ’Ø9ê7 7Ê€0áðÌCÃÇJ¸¸wg¸k·ž1´­ÃLgÞ€î,„VÜ0mÜç#Nð,Ö¾&åÅæœ'7ÎñØiÆÙeeŠå 6dr]¾Õ’Ùþ;äv[‡ãK¸dZãîü ý£Ú}Þ¢’ÒÝÏQA¶u’åfY HX©Qö‰J#äÉ8;©_x_IJx†ÃX]ONšð\D¬ë§²EIØÜÈg,äµÀ0ÆAäfºÝK_Ñô_+ûWT²°ó³åýªá"ߌgˆÎ2?1ëWOPz‘@•M–¹iªH<‘Kö‰SÈÀyÛñó|ªZõˆ[9¬}{Â:ŵ–¥g¡±¸“[ŠæÚêI C)$óJ™ÌÈɵH *Ë …u½#w±ª¶w¶×ð¼Ö²y±¬ÒBÇixÝ£qÏ£)öÏJ·EeOâm ÛT\úΟ ]PZÉr‹)fÆÑ°œääcŽr*ÆŸ«Øj¢car— *»Ær¹hÒEÁèÀ¤ˆr29ëš»E&áK@Q@製sÿó?¯ýƒ_ÿF%tÏÿÌþ¿ö ý•ÐRŽÀqúGü…`úŸäk¬‹ýRº+“Ò?ä+Ôÿ#]d_ê“ýÑGP$®+Å‚h¼S£Ý-αi YÝÆ÷:^žn™YžÜª0òeÀ!Xçîõí]­F:SÍ´­/]³ðíÿœš•¬–ïal¶K!ŽÞØCiö¡ f8(ef`Tùd;1iÓ]¹œG§ÍªÅ¤]Ë5³\4ë40º[»ÌÆAæ+/•x¨òd‡’0FãÑ[¿#š1ƒÆôÇZó+ãâY-~Õxo¦žk©6éVl&tŠNÛˆÿãÞ?1&tß”u”3m9dÐÑá׿á8–KËÛþnî<ë±Oäý›.!ýëKö~žIýÒy™á¿å«Wz@äñÜÿõè#ž¿¥pºýæ³áé5ëË+w¸¿»ešÉ†›=êËpÇÊ Ä|Ðì |Ÿ½$d—ÚÉ­õh¼7$òj²KyªÜ£Èÿh‘¬í–âcŽ(Y%u8@6œíLhw óŒœçš$óúPZÞjÓý¶ ç×äÖ¡ÓGöRÅä1ù¿i¼H^hòUC*AÍÁ9Qóóéô].÷N¼²º…u$kÍwP[ÈÞYZ!n^éѼ¦%XHuQœŽNóžÙ`„\½ÀŠ1<Š¨Ò„™T’£=H˜Û$÷5(Àçò SMÒ/ÛÄúýçö¦£enÚ”R-¼qCå\¨µ€—Œ¹©Sµ‡Ý8ÁÍp¶~%m»^˪YÁ1ŠK¹~Éy4Ò\}†ÅT‘né7U¸‰+¹Ha»n=”)ç'éK´ç9 J]e<[b·Ï¨êýž?´<‘Ïg¡ Å• ¶¸/!è d/Áe_“¾¦'Áü)ôQEQÞŠ;Ð?ÿ3úÿØ5ÿôbWA\ÿüÏëÿ`×ÿщ](ì¤ÈV©þFºÈ¿Õ'û¢¹=#þB°}Oò5ÖEþ©?ÝuJä|s®ÿeYØØÅ¯Zè—Z”æ(ïî<¶êˆÒ3ì“Áرõ2©ë€zêªöI¨Ã~È Ì1<1¾ãÂ9BÃ91§=±ÇS–Ä9¯tÏíK=2Òm> VõÖüï‰_Íß`FCºy.9dËpvóŠþ0ñ´¶Öšæ.¨ÖWqZê­7Ço$„oò–0TÆëòHì@*0ÛzßøEt#P‡ì™Q…à»Wýâ;Êì:ñ–žSÆ1»€1VóÁz¡q,·Ó:Ëæî…o&Xs*:H áe‘òÁA˳g$š|O,÷ÇLµ°µE¸¹ŽX$œ¢ÇH$.‚͵àTOДaY2xûQŠÚÛ:r\ݼ­lm¦¸¸‚h#ƒ*´ví& Jæ0¬°lÝÒIáÛ{»iõûLz¤Klé‚›mÕd~g™÷ Þc¢Š‰ü#¦5ºE¿Q-3$çS¹3.à7(—ÌÞíRSvÜ€pH ¯õ‹‰ì´E´I¬eÖfXCOÚ“6Päy€FW!X䆩ÌÒ|JϪZèöRê:Ä“<Í=ƧÙ½§—örU“ÉŒ‘¶pà I$ …%“©›I±ŸLk[F–Jª©C`ˆ.6lÛ…HJੌ`U=7ÂÚV“vníb˜Ý3tÓÝK3¶ñl´ŒÄäAç ^1“@Ôßå[¹m`Òã¥dû¾léÊ5ÌPo2< c÷ñ°1ù£çî–Äå׋­,¬ì-~ÙkäW–¨:Û–c‘]\DK³Ê. 8¡mÿ‡º=Ô`[›f B·s•†$ž)š8—~"É@ ÛŽ˜­[išmÌWпÚ#IΖw–F-¹Ü’ÄùQŒ¶HÀ  zN§±£Øêvë"CyoÄk ‚º†à‘œÄÕÚ«aa™§[XZDzÚÚ%†$,[j(À9'SV¨¢Š(¢Š(£½w þgõÿ°kÿèÄ®‚¹ÿùŸ×þÁ¯ÿ£º QØ?Hÿ¬Süu‘ªO÷ErzGü…`úŸäk¬‹ýRº(ê•©êñéÞTIm=åäÙ0Ú[mó$ Íó2¨UÈË1%Fw2ƒ£XÚ®zÚ¦¯¦ˆ%½µŠ[q̆8åŽCoUа1!k \|Á•"ø‚Ê(솦é¥]^¹H-/§‰ev]®Á+÷IûÃ8øäu? øŽ «}A’;ë‹w‚2í©\Kö© õ£™ MKeÄ.̱î BWQ¤øoR‡Åo¯_HÚán ÖðÊÒÙÖÑ+]Ã¥‰!pX f€:ÀÙìik'Ãz\Ú?…´.á£i¬ìá·ÄNÒÊI€qyÀ­j(¢Š(¢Š(ïEèŸÿ™ýìÿú1+ ®þgõÿ°kÿèÄ®‚”vÒ?ä+Ôÿ#]d_ê“ýÑ\ž‘ÿ!X>§ùë"ÿTŸîŠ:%&áK\lÞ÷ÅZ@Ãúnºñi·ò­üŠŠH{nT²:ïÉÀÎÑó°¦w¸{þTÖ¼²ÿ_Ö¬K³ÓõûS¾Š{é /¨Ýé"4m ²ÊàÆ›¢B’& ÜË{ÝwÄ0Üë6Q<÷Z:\Þîk~.Ñâ-k  ]™w!'6„0;ÍÀšPÀ×—éšßˆ/îllbñ%•ÄWë¼´’;ÒÛÜ»§˜°EáåÆTÅO/¹X)“Pñ>­ Þ¹¶¤—W0>Ðm¦ìì¢7ÆZVò̰̱—s¿|$‚¢€zfáFàkŽÐ/.5OjgTÖá0~ú5Õ,nÙŒN"Ž2ÊKüè›FÐYZ¹Aª "Êx¼:þ†ÞKˆë\ÒâŽÊÕT¤çcÈDè®­c,"áT*’€z¨žq$ 2yѪ»ÆæUb@b:€J¶|CSîÏ?•xüÚî· ÓÞ BÆ9®-l¡¸Ô¼ñ1À%Ô Iç<%ò‘.ÿ+c—ù@ „oéíåÕþ³â,U¢‰í^Œ&¨æyS`ybO‘ 9‰S>nåùZ<záQÍs²žT‰ *v 3QÏrÄ;’zòK=[RÒ<á»_Ã-§—{q}w¯ØçŽ8BÙ—0HªÃt‡Ëuó>Có|¤zžµu~m Ö5¨ì¯†¥¤ˆ´˜Õ"[Åi-dyBJž~(++d6@=Ozç­2K˜ax’IQgÙ³]°X…õ8V8ôR{W›ø–= þ$Êúí߆¡tÛ<&µl’;¯s¸BÌë°àrpܕ㌚î½yý©kq§örÏPÔ ØÎÁµÚÀþZ¨˜ïUŒòØo7 W¯¸RoÇ?—ùõ¯(½ñMô7—–Ú?‹`ÔìGÙ<íJ{‹XÖÏxº-™£…‘2a~to¿‚À‹ö¾#Õþ…毢à¨X4©¢yîs;¨•ÒX”É–ªL°„ÿ–ŒªS=*ŽôQÞ€9ÿùŸ×þÁ¯ÿ£º çÿæ_û¿þŒJè)G`8ý#þB°}Oò5ÖEþ©?ÝÉéòƒê‘®²/õIþ裨Tdtçó©+"}Fh¼Ua¦*ÇäÜÙÜÜ3;ƒFð(ú~õ¿!ø°5 dÀ)vs‘Á®fûÇzfŸ¯\è²A<·ÐÄÒG ¼Ë$ì±v$K!1Pq½1Ÿ™sbãÆzMäÙÅ>£#ùB±˜Ù'yäŽÌpŠ3!ÜGÊÈA;€ ÛO­7«vô<ŸJçׯÚkXj·~EØ]‘¼¹Œ¢î]­2\œ3ƒòãdÜÑiº–“æ›U™ž]»å¸¹’y\í]ò36ÐI!s€Y°95¡´Ó ™¦·ŠG†HÐ3E&ÒÈHû§i##§sRÐGz(ï@ÿüÏëÿ`×ÿщ]sÿó?¯ýƒ_ÿF%t£°~‘ÿ!X>§ùë"ÿTŸîŠäôù Áõ?È×Yú¤ÿtQÔ +UðûêWö—ðê·º}Õ´R¯j!;’C`D‘¸ët¶«+YñŸ ¤/~n‚Ìá ³šq¸²ªƒå«m$²œdœ Óœ^†ZÚñ5+áomu-äVºòVYV@ížg&Yð p úwƒÖØÚÉ7Ù5eûY¹± ˆ§dd"0êAccSˆÂŽ ‚:H.âÞ)ÐH©"‡Q$m}U€ û I¸P'wà+K‹ ‹HuMFÕo-ÞÞùá1»Wi‹ï‚ÓLvýa¡w4Ý!4¹n¼‹‰ÚÞyZe¶}¥!vfy »¾gbÇs6 ãбm¦i÷7÷’yvÖÑ4Ó>ÒÛQAbp98ð9¢ÆêK»8çšÎ{99‚vBëÉ%—ž¼×׊ÏO YÇá‹Md˜[ÚEpK•ó¡Úc~›KEnFÒG Ž*¾•á(tÍ]õWÔooodówËqåÞbÀ§"4QÀ¶Œ Ôç9®ƒp÷£p N?Z,Öeõ=BK{Ž;+Vh¼»xÒheTF†mãfc€yÉÝV4¿[hËm†¥¨ÃiÂ$¶Y-ÃÅF®ä&üíŽ0B²©ÛÈ!›:0ø‡O¸ÔΟÚå”;!•,æ0\îp_/ ‚¤ná^¼V˜`hŸ B4MMµÔom?±¶}–â,ÉòÂÐüÛÑ”å³òõ銯¨ø(jv“C>½ª¬—V¦Îòtáî¡Ë•VýÖÕÛæ¸NœàcsUÔáÒ4{ÝNá$hlí丑c¹TRǑΨ«›…q~¹Ô5Ó ÄØðÚËqqö?´ó^x¤IFJé–žVÏœÀt 26kÍáyî4ùígñ«)¸ÂË,‹lÛâÃ/Ë0ù[N㓳qà :(­†Ÿo¦iöÖ‘ˆím¢Xbq;Q@P2y<×Ò­QEw¢ŽôÏÿÌþ¿ö ý•ÐW?ÿ3úÿØ5ÿôbWAJ;Ëé–Wj0Èèy céõÒEþ©?Ý‹g£jvבÍq®=ÌJ~hšÙwn£ó­¨¿Õ'û¢o¨V'‰,noô¸a¶Ì‘5 )ñ¸ $w1;žOeV8öÀÉ­ºŒÀéÿë¦uáë¿;Å—±X¤—ZÂ$^fÙ7Úù$¢5s°;lp€¬Éü¨bøsÁ.®‹¬è~nÚþ˧£ù[ÖÏn"ƒ÷i–Žàü w'–çÓ:äuæ”ð =RhÉgð—ˆ.´©VM.K­Rm ­î.µ?³ÊË)²òö[LÌBÒ±Þ$ÈÁ—'~çˆ|&D—úVƒ ÆößJ’‰I¹Ý)iÀ$òd‰·D”N2=îú}(Ç=?1@~I¾Â/ôˆnDšýååêÜí•LížIÃ6æXØ èÎÍ€K¿à­QÑöý²ÜÁçiVFç §Í¾oÚdlºC˜·9ûØœq×q‘ÓzQÓ¹8ëÅy–©¢ø­<9†ôûké ·ÒæÓ¤`ö¢ÖåE¬©‚ÇÎY ˜r8Uà °ø^þâÑ-´}6yEµ«6[AjÓEvÅ‹I,·?:å¼¶ßÞX;¦½±#ùS¶ŸZñöðýα¤kK¤h>EëÝk)>¡ûˆþÞŽ×Q¬;ƒo?;Äq"ª+9ásßèúz/ˆµÓì`±Òeµ¶ò¡¶UŽ38y¼Öؽi‡-Ž@Q“Ž: GnÔ¡yíŒP¨¢Š(¢Š(ïEèŸÿ™ýìÿú1+ ®þgõÿ°kÿèÄ®‚”v¯ÓñΛú¤ÿtR·#ñÎ’/õIþ裨Wã½@,Zvˆ.u[oí\Í6• Ïs ®K¡‰X¯ï r9î;*®ÐD÷)rÑFf4¨,ªÄú«?º=0<”øÖh¯añ ¶›®—^[fH6Ë :£É ãBˆ 3‚@#£ºÖüOkâh4{£¼Ó´.F(TWŽñØüòXƒj Ã»ÒtØçXZ,áˉV —$î9&YNé£ÿxÖG‡¼ £øqä–Ú丑ь­mEv‡UÚ±FŠ$nÛ¸‡ œ` ½fúóZð¼žÆæ]R-6[‹ N6ê nïä®à€Kcv ldçÚø£WŸÄí§ `‡S–+[)ÒDw‚Úá~Ý$²·«‘`R¹e%6< @û ˜ƒÈ6y>oåùco™¿Ìߎ›·üù뻞µ^ã@Ò.ÍßÚ4»¾Ù³íFKuo?gÜß‘ómÇÎ(€×üA«ëžñ=œ/cmö *ëíŽð<ŸiÃÝ@|±æ/•Ÿ³3 ™1æÎÒ[NxŠmRá¡ÐãšÄÜ]ÚZ£I &Iaó@Û#LY‹´$mòWhbK„·Oyá½þÚÖÞ÷FÓn`µ_.Þ9íQÖàm@F`(Àì©$д‰/.îßJ±k›¸Œ73t/4dQÎ2À€ ô  ^Ôîu;+“yq—–×Ñl^ÔÀáŠ2´¸áÞ¬T‚0HäôNÎÆÏLµŠÒÆÒ [d$$0F¨‹’O@’O×Þ®PEPEPEPGz(ï@ÿüÏëÿ`×ÿщ]sÿó?¯ýƒ_ÿF%t£°Ñ/w㻘¤¸˜Ccam41,¬‰ºY.BʤÈ1»;HÊà“ž†/õIþèªo¥i¢{{…Óí<ûyáB»£i28È,I'yÎjäG&º(ê•Îø›ÄØdl“íÏÚ5¿²[®Ü|†MóÙUÇ*²ü¼ô9¬ÝN ^_+û*öÆÛ2}ªÍçÜxÆ6Ë;õÏn˜åNX ñ§]3Ť ™­ã™ÕYcóÊ$ïLd‚w(À$ u׋ô{#r·2]ÂÐ8B¯c8i ‘cýÐÙ™F÷A”Ü>uõϲð4:v&™o}!‡í¶71´‰¹•m–ÙB’ÂÛ¯ÝÓŽyûχ7Ö’Gy¦Ï§=Üoi/ö~É¥îÚVšæO4ÝDÝ,YˆÁ P_wâkXü/ªëv‰$ÃO·–W‚Tx$ ‰¿c«¨d$`ò½Aé<_£ÃO4—q,Šdo2Æu0&Jï˜Ì)•l4›A Äj(¼2ÓhÚÕ–¥x&›YßöÉm¢ò”n…aýÚ±b¸D^¬Üäô z‡…u-N;¡q«ZÔ¬†Ÿ©4v,ƒ.ß$O”ø™Á-ævœ @5µmRkk‹{ xîu+”y"ŠYL1ˆÐ vibóF‰f`1Zž+·Ó-® Õ ¤ÄO{%¤rË,kæAv~ì‚Û>R@Á,¡®kšÕ O°GwRÀ Ì|2C.ß29#Ü»”ìSÁ‘¹[Oø{ö-ZÓ~ßn§S°’Ï6ö~Tpï–æLªo?(ûNйà'^xÒºñTðizUyÅì–ÓÊmeòT$¹ .eƒÆ¨bFc ã§®Z ^A¬YJš¹Ó-5 B;sh|ã$ÂmÀËæmÛºw#ä žIê3@ E&hÍ-™£4´RfŒÐÑÞ“4f€0?æ_û¿þŒJè+žÏüWÊêÿú1+¡¥€åôèÿ‰µ»«‹‹¦m>ý-­£[©!¶…ÈhÔ„cºW9`O#žyªøßÄVšÅõ´ŽØa¸xã_"?•CݯW:‘Í­ÜzUŠ\ÚF!¶™mÐ<1ò6!ÆUpÄ`qɯ׿äbÕ?ëî_ý ×¥—S„ê55s)F+”Õÿ…ƒâú ÿäÿøš³iãßïû÷&ªGjþo´›Ù<3Ëó>ËÝÝvçgÞÇ8¨ÚîðÛÃh¶1Ï,i,Ñ…\ƒ‚ù;ÀxÀç~ÛPX\@ú¾™4Ѭw7S«o`O¶‡ûªO÷K㨮~ZvþÑšsJúLµ'|Y ºƒ#£e{hÁR:ƒ•ê;úS—Ç>-kg¸]D˜‘Õ¼ˆ¸fÝ´}Þû[ÛŠ“T’ÆkÛùQì^Õšéçså™ZmòŠŸõ…Ôýß—®ЧYtôIã˜éÇOkÕ{(ãxUDSyeúž¦ L ã?0ëRÝ.])«9·ñcñïŠæ•"‹Qg‘ÈUE·Œ–' -4ü@ñ@äê˜ðF?öZŽk«;iwA!·Š)b’àÇ*Ê ‡É?»ULíÛÂü{55§•½~×ý–í?ñ1Ûäô|G/oõ‡÷6ìwÅij;ºh›Ïù…<ñY‰¥ƒÔ…/öhð Îvã±ü©müuâË«¨­ ÔKË+ˆÑ|ˆ†XœÊñøô¬»~סÞÛG5²Ln`‘Vk„‹r…”7°ïžµ½¡2,šY-q –ò¥ÃM057‚|Ü(2 ³ÂçÁQQŠv¦®8¹¿´Qÿ…âŽú™ümãü¾íJÞ9ñjÛGruäÈìŠÞDG%B“ü>Œ)Ö¦ÍY¡žúŠÇ!`{t‹nX?ë¾ðÏNû gë²Ú=œ1ÛP­ÔÌñG(}¹ŽN@Q‚ÊÀƒ·€)Æ4¥5MœÒ¿1gþŠ?è'ÿ#ÿâhÿ…ƒâú ÿäÿøšæh®¿ªÐþDcíªw:oøX>(ÿ Ÿþ@ÿ‰£þŠ?è'ÿ#ÿâk™¢«PþU÷¶©Üé¿á`ø£þ‚ù?þ&øX'ÿ Ÿþ@ÿ‰®fŠ_V¡ü¨=µNç®ø:þëTÔì//%ón$ÓfÞåB“‰ÀOjï«Î>ÿ®Ó?ìqÿ¥½"¾jºJ¬’îÏf›¼ÿwñμ§Qøi¬ßêww‘\Øç™åPÒ8 33òõæ½Yú~#ùÒD?tŸîŠª5çFW€ªRM$yü*wþ~´ïûøÿüE'ü*½sþ~´ïÆGÿâ>•ìUÆøªûVOi6:lš¯—=­ÔÒ&˜¶ža(Ð*’n~\1º`ò8àã¥fXŽëî1ú#ÿ…U®ÿzq#þš?þø£þfºN>×§ßÉ?øŠél5íjoÛéQ«ËK"Ý&¡´ìzyÓ¡þ§ùÅ/ü*½t.ôüž¿½|Ÿüs=ëkWñ½Õã=¶ÉZîÚ[ ˜å!ºˆ^ÁfF…FÖ¯1ù «78Ûºý÷.l§wö7›«G,‰40¼óB¡$§HñßøU:ïüýiß÷ñÿøŠOøUZïüýiß÷ñÿøŠö:J?´±ÿú#‡ð¶“>‰­Ùi×/M›6挒§3« dÆ»ŠçñÿòÿØ5ÿôbWC\.NmÊ[³¥.Ud1Ïʸþt‘qº*;»fº¶xVâ[va6¦Aÿ±ÿ æ¯ÿ“ÿˆ¤ÆoÕf°·}BöLÜÃÆûÊŽP°ÇNLiÿ|ûšÉÿ„[þ£š¿ýþOþ"øE¿ê9«ÿßäÿâ(»ÓxwL{ã}äÈ—fqpfŠy‹m0J°ÊyCò¶ÀH$Qsáë ­f=YÍÒ^"Æ›¡¼š%uFfUtF àn¼GJæNr4Û+ŸíK|ín¬<ÄàHê§ø;n5¹ÿ·ýG5ûüŸüE+žÐ$bZÞè ‚8ÕoîÀ¢D”>"¢Œ€q°Ç9ðŽmÒ —HêìÿiŽút¸mÁAÝ01€‚Äaû«†ÿÂ-ÿQÍ_þÿ'ÿGü"ßõÕÿïòñîÛmL´µ»µ†Ê¶»ÇÌÆÀF‘Ù÷BìWÒªIá "d‰&K©V41·™};Óqm“ÿ¾@Y°²nP€'-ÿ„[þ£š¿ýþOþ"øE¿ê9«ÿßäÿâ(¸Íal÷ðß´`ÝC¤™<#”gèrcCø{œáÛx öv6Ö6Ö/ ¥ºÄ)u(YP³1IFïÞ¦]þY7†0Ʀÿ„[þ£š¿ýþOþ"øE¿ê9«ÿßäÿâ(¸—Â$÷ßk–Õämò9î%6û¤FI‘»ËË+¾NÞK±<“VôÝÏIóM°™¤—hyn.džF8äfm£-…Îf#œÒÿ„[þ£š¿ýþOþ"øE¿ê9«ÿßäÿâ(¸ÏÿÂ-ÿQÍ_þÿ'ÿGü"ßõÕÿïòñ\‚Šçÿáÿ¨æ¯ÿ“ÿˆ£þoúŽjÿ÷ù?øŠ.AIXð‹ÔsWÿ¿ÉÿÄQÿ±ÿ æ¯ÿ“ÿˆ¥vdÂ~¿ö ~;ÿ¬JèkOðìz~¡öß·Þ\Íå4 Ü2° H'¢Žê+fšÿÙivy-2.4.0-rc1/doc/images/yed-step3-2.jpg000066400000000000000000000073501226750426600175160ustar00rootroot00000000000000ÿØÿàJFIF``ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÄý"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (< LÐÑEQEQEQEQEQHNÿZ€y ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š( ÑY>(Ô&Ò|%¬ê6Øóí,gž=Ã#r!aúŠlx8'ê pþðÞ®øwNÖu.ËR¾Ô-ã»–kØVb ŠªïjŒà(ÇJÑ·ð/†–$[ÍÇP¸]^À³Ë+z³8$“×Û§aRŸøKþ…mÿññ5ÅV²z•„ÿ„Â?ô+hø/‹ÿ‰£þoÿЫ¡ÿà¾/þ&—þÿЭ¢à¾/þ&øAü#ÿB¶‰ÿ‚ø¿øšÇ™w`'ü Þÿ¡WCÿÁ|_üMðƒxGþ…]ÿññ4¿ðƒøGþ…mÿññ4Âáú´OüÅÿÄÑÍæÀOøA¼#ÿB®‡ÿ‚ø¿øš?áðý ºþ âÿâiáðý Ú'þ âÿâhÿ„Â?ô+hŸø/‹ÿ‰£›Í€ŸðƒxGþ…]ÿññ4 áút?üÅÿÄÒÿÂáú´OüÅÿÄÑÿ?„èVÑ?ð_ÿG7›?áðý ºþ âÿâhÿ„Â?ô*èø/‹ÿ‰¥ÿ„Â?ô+hŸø/‹ÿ‰£þÿЭ¢à¾/þ&Žo6xKx[DÕl"ã´ï n¶:Θ$’K}?PòmüÆ.ËC»ryÀ23ØJOøAü%ÿB¶‰ÿ‚ø¿øšCààŸøEôAî,"üvñZS¬ õÔ,t€óN®oÂA­›YÒÄ%¾Ÿä[ùŒY–6†)väòpe`=€ô®’»¢î®HQEÀ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Ÿñ×ü“ßÿØ*ëÿE5tÏøëþIï‰ìuÿ¢š€6äÙ®j×Å7è?ÚóémµÇlJÎϸH÷p ²“@ 0IÈ1ïX¾³µÓeÓþÓy%¶còå[ÛtB0iä«’p1åFÝK!“Ä÷ $v©`~u°xLä ³µÂû2T \ü¹º0RÇÅ7 >œ°Áws5ˆ‘n7²ÜÄ$.»vŒ§î\È$ò€sW£ðõ¤w÷k‡¸†õ¯ZFe̲˜Z›Ø÷Wß$>´€Ùm’oôKûA2Ù&ó·ÇÝ{ã¿ Éç7î•aâÍKR†ÀÁ¢Áæj6?n´V½ ÆÍûÈ+̉··g¼ÓŸÆ‘¾—ý£mfò[G¦EªÜ+GÈÀç,nHàqÖ´ôÿZiŸÙ>L“·ö]ƒiðï`wF|®[e¿r½09 ‚]Ú_ÜJe’ÖúÖC 6ÝÊ$Ã$‚ûäÓ÷žOÍl÷Ð^iþ]ÌÙ¢Ž)÷‰EĆ(bÖÞ¤ÈA=´t}V]JmFíÄÙ\‹vU“x$Å™ÞøvÎ:–ƒì·×?;Ïs ¼[Z]ЦDe!I Bzº¼uÊø{K¹ÓRúKÉ„··?hƒ»iòÒ07m\ñ=\c¥òÛ@á¿ù x¯þ±ÿéµtUÎøoþC^+ÿ°ªéµtUèÃáDQVEPEPEPEPEPEP\ÿŽ¿äžø—þÁW_ú)« ®Ç\ü>ñ ²î¿ôSPÏsE"œŒç ÷¥¯ Ð(¢ŠZiàp:{RÐzP#‘¯cøgÞ3Yϧ]:Z¨ÚŠQí€-×s|íÏ€:’šì-¨ø‡MÒžæò y-.®Ú\<,dF…WæB Ícއ=+e¬íßQ†ùãh†!GÜFÔrŒÃLiÏl{Õ+ÿiÚ”1Åt·±ÝÑÖêTuÞNá½[vÓ’6çn01€+K Ã³j>ѯnf¸±†i1–dþ¦µª8bŽÞ‚TŠ5ˆ½@ÀÝ*J‡¸ÐP8éE€(¢–€0ü7ÿ!¯ÿØU?ôŠÚº*ç|7ÿ!ŸØU?ôŽÚº*õ!ð£6QEXQ@Q@Q@Q@Q@Q@Cwk í”ö—‰ ž6ŽD=X`ƒõ¦¢€9x4Ù@–öž ±–ÀXÚ÷Mie*8'@Çßh'¾O5GB¸ñfµ iº ÕôX~ÙkÇ—ý•+lÞ¡¶çí<ã8è+´aÁ#­súµ¥¯ÙtmjÎ+I†Ë¡\“±YfO”g€AÀÏÏR•׺µdŸcñoý4OüËÿÉ4}ÅßôÑ?ðO/ÿ$Ó¾ÁâïúhŸø'—ÿ’i~Ãâÿúèø'—ÿ’«/c>ÈwC>ÇâïúhŸø'—ÿ’hû‹è9¢àž_þI§ý‡ÅÿôÐÿðO/ÿ%QöÿÐwCÿÁ<¿ü•KØÏ² ¡Ÿcñoý4OüËÿÉ4ŸbñoýôOüËÿÉ5'Ø|_ÿAÝÿòÿòUañýt?üËÿÉTýŒû ºö?ùèŸø'—ÿ’hû‹¿è9¢àž_þI§ý‡ÅÿôÐÿðO/ÿ%QöÿÐwCÿÁ<¿ü•KØÏ² ¡Ÿcñwý4OüËÿÉ4}ÅßôÑ?ðO/ÿ$ÓþÃâÿúèø'—ÿ’¨û‹ÿè;¡ÿàž_þJ£ØÏ² ¡ŸdñwýôCÿpyù*³ôéü[¨Þj–ÿÚÚ$bÆém·®—+Ì1K‘þ1þ·†{ài5‡‹±Î»¢ãÛG—?†njö‹¤&ÙÐÜÉs<òî.%t²vß÷èVæ©àñoˆ®£‘­!Ò #ȼš+oU'qVÚ¿{#ûÜ“‘Y6:M½Ï…5íVV—ÏÓÚÕbU`ù²l;¸ÉÀé‚)ÇBPçOMßk~hªÔRå~‡ü1ö”_óçmÿ~…ÚQÏ·ýú™£ÞkùK Í«—ÆÎNp;ÇŽÙ­Ë_\^ølÜ[ÆçV]U¬M³Íc s€ØÜùÀ=3Ç«©^-&×ü?p†søS2?´¢ÿŸ;oûô(þÒ‹þ|í¿ïЩí|%®ÞÙIw›+DŒêCVb¿x*’ˆç =¤Õ4‹{xP¥iõ%¹iCµ|©Fь󻜓G¶£Ì¢ÛvùÙ½~á*³v{\‡ûJ/ùó¶ÿ¿Bí(¿çÎÛþý ½?„oKЮ­äŽæãWi+hÝ )SÇñdñ’xÂc ƒYÚ®‡¨è’Fš…·”eRѲºº° ¤ƒƒÔgŠp­Fo–-__Ãp• Å]§aÿÚQÏ·ýúiEÿ>vß÷èWI?`Gðì°ÜÉ-¾ ¶†ñK8à7NÀ:ŒsYW ÕdºÔŸN±–[+[»‹xÝÝ7È"vÁsÎÑ×5”q˜y=íë§‘o U+Ù”?´¢ÿŸ;oûô(þÒ‹þ|í¿ïЭø6mQ±kÔx4»‰$ŒL%DweFl n[§8¡ô8ÊÃ:ÔškÙî,Þ8më»g÷¶gvß|c¿J¿¬Pçtù•Õº÷¾žºlOÕêróÙØoöœ_óçmÿ~…ÚqÏ·ýú™Š1[ò£.SOûN/ùó¶ÿ¿Bí8¿çÎÛþý ÌÅ£•)§ý§üùÛß¡Göœ_óçmÿ~…fbŒQʃ”ÓþÓ‹þ|í¿ïУûN/ùó¶ÿ¿B³1F(åAÊiÿiÅÿ>vß÷èQý§üùÛß¡Y˜£r å4¿´âÿŸK_ûô(þÒ‹þ}-ïЬÜRbŽUØ,iÿiEÿ>–¿÷èQý¥üúZÿß¡Y˜£r®ÁÊiÿiEÿ>–¿÷èQý¥üúZÿß¡Y˜£r®ÁÊiÿiEÿ>–¿÷èQý¥üúZÿß¡Y˜£r®ÁÊiÿiEÿ>–¿÷èQý¥üúZÿß¡Y˜£r®ÁÊiÿiÅÿ>–ß÷èUÍ.9µ«ß²ÚYÚ»»Æ¢‚Nz8îE`ÅtþÅyª¿LYý(†¹1õ^ :ÑZÅ\ëÁaã_ Rz6‘ þš2C]è`ûÛÏÿƪ´¾Ø mCC_"þ3]Äöúí‹ÛÚ¹‹Wsª»ü· ×чùõ\oC§é–ñé±Ê×:’1k«…oÝ©Çúµñëÿê_†ŸããovÞŸðOµ§Ãx O‘ó_µÿ¶9ÿøúóÀZù³ÔüçÒÕH–Ú&È,,d°<by8¢¸ÿ¯üNÇØl¿ôš*+èêah⣠õ#¬¢›¶›£Ã…èóS‹Ñ6…ÓTd>º_^Ûkþ.Ôµ˜mž4žDòŒÊ»ÀX‘BqÊžý)žð6±¯i?j²¸²HÑü²&w;U»)þð­õøaâEñ÷¥ÿßÉ?øŠôëã°Q­yÍ)Fëï·ùGÕñ2Œ¹’"Ö|Ieª7Œ1m{jòZ=·ÉlÀï àÅHÎIœv¬Í6úÊ×ÃzÖ•x·cûAíŠImHSʹÈgN¼½ëgþ—‰?çëKÿ¿²ñ‡á‰ü½i÷öOþ"¹!ˆËaMÓUtvÿÉmnžHÑÓÆÊjn_ñù‘xsĺv…jöé©­ôW>|1Å· f)ó„ÝÏ sÈÀÉ©£ñ>Œt¶Ú©Dñ šÔj‘ÄY²¤9ó1˜·ìÊ 8‘ÕÎs‘·Ç~µ»ÿ ÃÄŸóõ¥ÿßÙ?øŠ?áXx“þ~´¿ûû'ÿUJ¾WJ\Ñ©ÖÿŸù²g tÕ¥/Ëüˆô¿Zé‡Â²k™&ÑÚéeP«±’c’CnÎáé·=Edk7ÖwZv¤é°]¥Ž•¨’]ìJÒ8bHB@sÜð;íÿ°ñ'üýi÷öOþ"øV$ÿŸ­/þþÉÿÄUG–F¯µU5»}ÿÍýât±®Ï—M¿/òD ã ¬üC¥j|Rˆìô»kã›g(\¶0O0Á89*ô>3ÓặÔ^ÂúKÝ>ëQ–Ê4(#‘ndfi'+Œãå øÔð¬ÿÿÍ¢â±ñoÀOø›MÒmü8×Ö÷ò\èŸiDû2FË2Ì9's)Lþ¼@þ&‚_ [ZcPµÔH]-þÏ©GPù¥u29åWŒôçš±ÿ ÃÄŸóõ¥ÿßÙ?øŠ?áXx“þ~´¿ûû'ÿD§•J|ð[íݱÇëñ/)ÆyôyõÙÿ°ñ'üýi÷öOþ"øV$ÿŸ­/þþÉÿÄW£ý¯ÿŸˆâú†+ùN3È÷£È÷®Ïþ‡‰?çëKÿ¿²ñ°ñ'üýi÷öOþ"í|üüAõ Wòœg‘ïG‘ï]Ÿü+ÏÖ—ÿdÿâ(ÿ…aâOùúÒÿïìŸüEÚøùøƒê¯å8Ï#Þ#Þ»?øV$ÿŸ­/þþÉÿÄQÿ ÃÄŸóõ¥ÿßÙ?øŠ?µð?óñÔ1_ÊqžG½G½v𬡊þSŒòhòk³ÿ…_âOùûÒÿïäŸüEð«üIÿ?z_ýü“ÿˆ£û_ÿ?}Cü§äÑä×gÿ ¿ÄŸó÷¥ÿßÉ?øŠ?áWø“þ~ô¿ûù'ÿGö¾þ~ ú†+ùN3ɣɮÏþ‰?çïKÿ¿’ñ¯ñ'üýé÷òOþ"í|üüAõ Wòœa†¶¼5ûˆõ—é‹ÿÒˆkdü/ñ!ñ÷¥ÿßÙ?øŠ–×áÇŠìnö÷úZH»° õÁÐñ\˜üv…©B5RrMxŒ6&¥ ¨´þâýŸ‰í´í¢±VQŸ+5Ó•NÁ=3Üÿõ±Ÿâ?Yk0Ï,5e;&0d‚G÷¿Ï ¿á ñüõð¿þ âÿã‡Á~1?òÛÃßû>/þ1_ <Ê<¿X…¾ä}´3º1Ÿ?°•ýWݾÞGšøíÓãb9û —þ“EEZøƒá½_@XgÖ.­îf½g!âvc•Ûœäï +ï)8{jœ¹’ŠWïm?Cåo)NR’µÛvõÔõ_…ò)Íÿ__ûJ:î«…øQÿ"¤ßõõÿ´£®ê¾?4ÿ|©êvá?ƒ¢¼úÇâÝç‡ô¾Á ê··Vñ^@ì‚'xA•O|­Ä.IpÎv0­Ôñ¥‹B“5ìqÜD³XTÿNFtE1áÎÜ´±ÞlÿX3Œ6Þ3 é(®oDñWö¦¹{¦Mi5¼±Ë ‰$k*DZpüœ¶ûŒ¹RA#²cø™§$sr›cžT6Q4°Àæ#mo1.ÒÈ©¸ÀÀlò0ÑfuETÓµµK8ï-•ͬʒA+ÈȬ ä›`Aã'ŒÑü_«ÝxrjéÒa"Ú¢Á£MžDP©$Ó|ÅwÝ>V,}Eröž$½¸ð6­ÉjÝ^µŠÉ” ¦— x!Ë.NFFFr*ÿˆ¼Kgá«xe»ÜLÅWEŒ òòº >‹»qä€B±€Ù¢¹M;ÆÖ÷··_¸šM?íVñA{%cTžZ-ûˆ%™åÛ…hÚX(95#ø‘¦j@G¤ºI3Ol|‘¸’."‰ŸlnZ2  FÉ)ÃYÛQ\ÝÏŠ$²ñ§cs§ÍöK[[Y!•64³HñªŸø˜*®B€UË6’ûï2xW\Ô­í^ Ý. šK[ ¤Ç*Åæ*¶Æ*AVCò±á±r`:+”y7¶Ñ\[ylb¸K‹eù¤)5¼Q¢“´ms8*X.UÑŽÐMZ.¶. :v¡öÔgk<°*Ùœíb¬ÍÄeØï)!€,CEq:OÄ2äi·®‰y©›Ë’5Xæš4eA?šÀù‹Ê«(ÝË|­ŽÚ•€(¢ŠQEQEQEQEQEQEQEQEQEx÷ÇŸøõÑ?ÞŸÿiÑGÇŸøõÐÿÞŸÿiÑ_g–¹ÓùÿéLóªÿ_×Dtÿ ?äT›þ¾¿ö”uÝW ðŸþE9¿ëëÿiG]Õ|ÞiþùSÔéÂ'7oà&Úxã3~â+8ÑŽÍßèNß¼þTJçø„h8Ú0'‚ìV…¯/dŽÞ%†À3'ú +£¨7a¢ˆþóú±œå·t”W ÍÎn/ZC4— ©jbêi^I®|ñæH®‘,‰¿"·“ù6•#PqQÙxÏL†!§jZ…¥ÄJ±­Ê™öaˆ¦2¸"Þ&'nrŠê(¢àAimöHÌBy¥Œm&}å(\n?3t$–,IcÏ@('‡íÃú~Š$›ìÖ?fò˜°Þ|‡FMÇäÆ3€;ã­E!˜KáxS–ž]BôEiäù7?»ó“ÉuxÿƒaÆÅ¯ s“Íá£7’÷Ö§5Ì[Óí9Š9 /³|YHÔ&5;”p·h¢â9}?Àº~š"ŽÝA­Õ­Ýíä•Lr´Æ‘6ä0£eJî<6åDðøFÚ+hm£¨IilБ[¬R$ˆ€†cA—ÜØ 1= î5ÿ†íµ BâòK«¨Þh!ˆ¤e6«C)–)FTêìN *{©£þ»gÑ5M6{«©Î¨®·wNPK!hÄ{¾UEP0 | NIÙ¢•Æaj>ÓuQµ'ó¡º1lß ào¬»H º´à‘ÈP0Ç„mƒ‰Î£¨}µÙÍÅâȉ,êâ5d;T*‚°Ä3F bz)ÜG=¦øFÛHÑYj:„V±,"Ku‘ÎÑF‘«»ß±ÆVU;yR ÐÑE!…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@=ñçþ=t?÷§ÿÚtQñçþ=t?÷§ÿÚtWÙeŸîtþúS<ê¿Ä—õÑ?Âùæÿ¯¯ý¥wUÂü'ÿ‘NoúúÿÚQ×u_9š¾Tõ:pŸÁ‰‡«ˆ_Y´K»‹˜­Êæy<™ä‹î´<Ÿ,‚p qïT®`Ò“SƒOµ½Ô®¦–3+´:•ÁHcÛ•f>aêvþð=Æok]®­euœ÷Э¼ð˘ÿ¢ ì ‚«6Ò­2ÊkM;ÃqG;h žr|Þƒ ÿIò«Ê¯-¡}º?ø&ª-Ô[ZúÝký2¶¥|bðo‡.®íí.ÒEŒ\I©L±À¡í¤ ÒÈѾgnp .8b îoôÛ+û{-{öPOyËŸ"?µyÅJäF«ù7 ©‹eA½8*Ks[_XøkACyf‰¹žÑ®ÄemÜ7É$žª6²d6v=MK¶Ñ/â»i&?gŠê3mi¤Í ¼¡>J ÛýŽmÍ.àxºek±Çd_k¯ Ov¶ÿg²ŸíÌÉgæ@L¡ˆV˜)Œ3‰ß [-çô>g/†_ ê/j‰Ÿ+ê0}¢%{a™RA#däpXI9Áå˜àáñ…c G¥YÁ§‹û©,!kY®Ti3™dšÕT£ŽØÔíÚÄç†ýäu%÷†´yÿ´|Á{ûû£/ËapÛ"ýÿÀù·ï½ÃGÚoü²Ê>½©èVz>™©A¦è³ÛjÒ…IïÙmaÙ$SK¹ØÆÄn Á™›?xæ ÿxjÓÃWÝŽ‹s9µžàÇfEÄÌÀŸË|Æy”s<Š7s­¯»^µŒÖsÍms§]=´ºT÷øŠxÈÚ»Iãy~LgznÉÖt»­JÓQIµY¡žúÁ¬o¥·Ñ&!‘ ÁO)Im½d Ëï6”.„€Im®xn÷UÕì®´‹UK5&YþÆî²³Oq ÌCs’Î0»·´Ò*îÃýSSð´¶E¼"þî+…†ÓØNÒw‰œ7úK16%ewÚÊ[5½Æ£ ¿º)3yÁF“;š+Û‹¸ÎGÞ@K)P2ãaV_13$º@Iµ û‰æº¾¸µ¼ŠtM.T†GtÐÉ.-–0D›‹‚ŠÆ€wTQEHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( øóÿºûÓÿí:(øóÿºûÓÿí:+ì²Ï÷:?ý)žu_âKú莟á?üŠs××þÒŽ»ªá~ÿȧ7ý}í(뺯œÍ?ß*z8OàÄ(ª+¬Ø>•iª,ù³»ò|™67Ïç2¬|c#%Ôr8Ï8«ÕÀtR=JÖ[™mãwyaŸìò‰ˆGòĸ'c)ÏL3“Š·@^[½üÖ+&na‰&‘0xG.ç§&7ü½ÅP³ñ&—v–öòÌZ\ù2Ik,qOŸÝÈÊL¨,6“•†@&€5¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ª——¯l@ŽÖkƒŒ‘“È{U[}h˨Ei-…ÔPv¼ˆ@Èã;Jêö3u`¥Ë}MZ(¢™ QEQEQEQEQEQEQEãßã×Cÿzý§Eã×Cÿzý§E}–YþçOçÿ¥3ΫüI]Óü'ÿ‘NoúúÿÚQ×u\/Âùæÿ¯¯ý¥wUó™§ûåOS§ üœÝ¦ƒq‰Y³¥[K%õ¢`qq0"Ns»åÌÍÏíXyb¹ êih!š Cí­úfžÞºu¹…ÞTh@•ÈT•„’°nàvÇ©Ñ\77<ÞóÁ—‘^jpè:T:g™~Ó[]Àc…M’#aÞ6ÌÄýÞ7îÉÅ«ïý¯H’ >™dÓÆÓÙDÖÞdÀ+üËæ¶'sGÌ„’ð8wÔQp8Ïhš¾‘=ÉÕbÛþ‹°•a.nÙUv…DrEŒ*€WFV»mªZxc\†ÛN½ÓìL»0OsÖ yÙˆc*üÛ© @ß"¶zE\:»ðÅôö÷Jš3ÛØ»@.,bš)¤žDy“¯šLR–g‡æœnab¡Õ 3LðÖ©mo zƇý«"ÄÐYâæ ,\NC¬Ÿ!‰LoÜCä]ªµéQp8]#Ã7¶¾4“R¸ŽôËö«‰^ï}²Ã,._Ëp_´I´4cc€¦A!êŠ)6EP0¢Š(¢Š(™ŒrrÓ$ Ÿaœþï²j?óÞüoþ.¤¢šb HæŠâuÕ›bV2œe»k?VI$Ötµ‰•\»à²–êß°#ùÓ®õ½;FÛP¹‰vüŒÙÁo@k,ø‡KÖuý6; ¡3£;0ØË±ý@õªö¿-õìbêÛ“™_·S{ìšü÷‡ÿ›ÿ‹£ìšü÷‡ÿ›ÿ‹©(¥uØØìšü÷‡ÿ›ÿ‹£ìšü÷‡ÿ›ÿ‹©(¢ë°ý“Qÿžðÿà3ñt}“Qÿžðÿà3ñu%]v?²j?óÞüoþ.¦‘B9QÒ›E&À*_Em‘Gº7³Æ_î•Àaýêš’ÛþCp×´¿úuPW¥°ïìÛÿùý¶ÿÀVÿã”fßÿÏí·þ·ÿ®wSûT^-“T½“ÏÓ!»´²,µ™âhÙù–Ê;&RÛŸý^Ï”à†î+[.Â2³oÿçöÛÿ[ÿŽQý›ÿ?¶ßø ßürµ¨¢Ë°wv÷¶p¬Ïso"ù‘¡Q)!œ/]ç×Ò¥©õ¯ùÛxôjÔD´w<{ãÏüzèïOÿ´è£ãÏüzèïOÿ´è¯®Ë?Üéüÿô¦pUþ$¿®ˆéþÿȧ7ý}í(뺮á?üŠs××þÒŽ»ªùÌÓýò§©Ó„þ BŠ(® (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÆÔõ[Û=F²ŠÑ ¥äí×?9òf*(ç9‹’p Ä’›5RïOŠöæÂâFpöS™ã F Þ<:bFôä ·@Ïimt\[Å0^žbÇçM‚ÂÎÕËÛÚA‘‚ÑÆãÓŠ±E;±X(¢ŠC (¢€ (¢€0¼G«iv“_Ù›/³[E¼Á,nòÝÈN(C(FcµTáÉgoj–šþ¡6¥i$‚×ìºÎ  bh|ïÞ7Á¾Îß.ÅÆñÉÛó_Õt 5MJÖù5BÍí•„QÀ°2n âHÛçÁÛžÀ1¹²[ønÚßRK¡utÐÅ<—PY±O*¤ß¾@Bï$ù’pÌTo8 †#f¡¥®©Ò¬¾_‘"e"gÁ,„}Ð}åSQN.ÎàÕÑ’h3jê’éêú„)²+¶ÓœÊ‹Ï û2ÌÜÜúÕÏí«?úyÿÀIøš‚Š¿h» ÌŸûjÏþžð_þ&í«?úyÿÀIøš‚Š=¢ìdzŽ£ݪà Ü3™¢ i`H¤òW€jJ(¨”® Xñï?ñë¡ÿ½?þÓ¢?ñë¡ÿ½?þÓ¢¾Ã,ÿs§óÿÒ™ÁWø’þº#§øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:î«ç3O÷Êž§Nø1 +ËôïëW~ðô.ðÿjËuköùÄccÛ»Û°vv[ÈàûÜc NÖ‡ãk«Ý>ÚâM1Í¢µ”ÝIr¦F{ˆ d*Š€1 8÷®ã”^3s¶¢¸]ÇW—Ö–I4òOä[Å4—Q2i-çç®)}ì²ìVÜU4¬¼g¡¤>¥odâ¶Y[F²8 Ër¶ìà ‹Ž™9Ûמ 0:Š+ŒÓ|y%ì6RÏ¢Mn—1YÎÍö„qw/åEÓ’Æ@N1,n$7îêýÖ¹¨Úø¶òÆ2÷Q¶K i•-L å;I8bLŽ„ä"ôÎ6ž™ä°%Àø{Çw—°éòi·WŽðZ%åÔpÊO,1¹`#Aæ©mÒ!váwXÓ|muq¤X]¦˜÷ìÖ·Ér¢DšáamÅBd :üË‚[Š¿0,Àí¨¯7_xˆøgÃíö(Eþ¡œÉ4·|ä2ÛÇ)uXØ&ö6ã?+³|¬¡¤PÕ€(¢ŠC (¢€ (¢€ (¨%¼µ…öKs mý×p OEVþÒ±ÿŸÛûú¿ãPcÁ©/ÚÝÈÞÍ)×i1ÁíNÎÚ94½ÕsBŠÂÓ¼+T¿µ–ùŒxGO´H:Àã§ ­Oí+ùý·ÿ¿«þ4YŽ-µv¬Y¢«iXÿÏí¿ýý_ñ£ûJÇþmÿïêÿ+Y¢«iXÿÏí¿ýý_ñ£ûJÇþmÿïêÿÍ7V÷ V â•€ÉሼT´QEE5ͽ¾ß>x¢ÝÓ{…ÏçBW-WûNÃþ­¿ïêÿÚvóýmÿWüj¹eØ9‘jŠ«ý§aÿ?Öß÷õÆí;ùþ¶ÿ¿«þ4r˰s"ÕYu 'p‰ynÌÇ T’:³I¦· Üñï?ñë¡ÿ½?þÓ¢?ñë¡ÿ½?þÓ¢¾Ç,ÿs§óÿÒ™çÕþ$¿®ˆéþÿȧ7ý}í(뺮á?üŠs××þÒŽ»ªùÌÓýò§©Ó„þ L˜¼5¤C PÇiˆâŠÖcð–Î^×øX“ïß4ZøkH³°û ½¦Ëo6 ¶yŽ~xDb#’sÀ†?®Þs“j+‚çA“eá­#NKe´´òÖÚUš!æ9Úë·“Ïî€^~½y¨Áº}-†ÓÉ0§&Ôhvùo·v €Š»ÏÌTm$¯»E&/ iÃ1Úb8¢µ…˜ü%³—„uþ$û÷Í_K;t¿šùcÅÌÑ$2>O(…ÊŒtàÈÿŸ°©è  k hÖ¯jÐZº%²Æ±Ä.$ò–£<{¶»¨Tð,6/?(ÆLžµ+6ŽKXtËF·xm’LŠ`Ù±·´¥ üŠ¥ü½æ<¦îõ×ÑNìF4þÑ®llìäµq ” ooåÜH+FàV ÐÄsœü½y9Ù¢ŠC (¢€ (¢€ (¢€ mª-²:üͺF|ä dç)³Ïµ¼—¤PÄ¥ä’F ¨ d’OÞ ÓõM?V·k6þÖöm%´Ë"†À8%IÁ{ÓNÂ4<ÕþëßCü(µ9·Ïý4ý ÔUiâƒtÿÙº­´¹%QâŒò„÷>´ùÚ[\ŠÅ]+ú[õ±¡dá|A©äòEÐ㼕©æ¯÷[þúáXZŸ©Z=Ôú­äw7Æ›@QŸaýãÛÿ­±C“cŽªíX—Í_î·ýô?Â5ºß÷Ðÿ ŠŠWeX—Í_î·ýô?Â5ºß÷Ðÿ Š£žx­­ä¸¸•"†%/$’0UE$’xô]gÎ8SÈÇ'ÿ­QUK½SO°¸¶·¼¿µ·šé¶[Ç4Ê3d ',rGÔQ©§Ë©K¦Çj÷ð®ù-Ve2¢ñÉLä™yÇqëF¬ t–ßòƒþ½¥ÿУ¥¤¶ÿÜõí/þ…U?ˆRØ/|@–:ŠÛꤧ S,p=þŤ²T\ÙgA¹U”Á#kmGñE¶±q QÚ]À—VæîÊY‚m»€̉µ‰QûÈÎ#|ãŽõRÕ5›7i¢ kˆçƒPÜËul¡‘¤‰Wi $Q˜:|²`«mùëøsú–›q¤­é´hÚci¶Ï ¬ír¬aýã©U@>P_åùµÖQEŸ­È;þÛÃÿ£V ©õ¯ùÛxôjÔ6C[ž=ñçþ=t?÷§ÿÚtQñçþ=t?÷§ÿÚtWÖåŸîtþúS8*ÿ_×Dtÿ ÿäS›þ¾¿ö”uÝW ðŸþE9¿ëëÿiG]Õ|æiþùSÔéÂ!EWÐQEQEQEQEQEQEQEdø–Ñ/|?uo)½6Ï3ìH¯&Àà·ÈÀ‡\¹6¶åÜ¡X <7q{qgrnžêhVr¶“ÝÁäM4[–tÚ›Hs"‘rª§;ŽÍQEQEQEW=ã1uokæÙîes<0¦ã¾QlùGÞ @ üÁHä:(‰ñ]½É¸ñ)iu+êú"XÙ˜`y¦àvPDc÷ÑüÎUy<ü§…½Ïö–™`m.–k-núúvhD!—í[JFÆ'ÏåRXdä ­ŽÚŠwTRBí:MİȊɔ r ýàº*Z(M­P5r<^ÐNçþø‹ÿˆ£Ÿô¹ÿ¾"ÿâ*J*¹ä.TG‹Ïú Üÿßñbóþ‚w?÷Ä_üEIEòTA$3̪³_ÜHÕÊŒT‚:(=@©è¢¥É½Æ•øóÿºûÓÿí:(øóÿºûÓÿí:+ìrÏ÷:?ý)ž}_âKú莟á?üŠs××þÒŽ»ªá~ÿȧ7ý}í(뺯œÍ?ß*z8OàÄ‚ÊòßQ°¶¾´“̶¹‰f‰ðFä`8<ŽëS׎ÛÙ‹'Ò4k¨mf×aŸI?%ôfkhcÂH6+`$”®<°¤É»pÅm[ø6þÇCÑ`µ°ÚãL5hüå-té-«\–Ä™.#PNÀ®UMqXÜôŠ+…Ò|/!ñ-­ìÚOØô¨¾Ó%­‰t jÄZlSlS—Ši@€$1Ãô<á›ÝüÍwêÎ-|«¹å{aÜÙRdQù’ò®CÌC€ý v!X³ûfÃì_kóÿqö¯²oØßë|ï'n1ŸõŸ.zwÎ9«SL° wAeO‘ÎX€8œdòz’p5ÄÿÂ7öŸ²÷íÿÛ¿kò¿´$ò|¯í7w•¿ËÿUócÏmÕ“¥x7U´Ž-Ö÷­v’Ù›Ée’Õ#ºtº‚G•|µ.r0yˆpí‚ÈI»¼·°…f¹“dm,pƒ‚~y"=Y”~<Ð÷–é ‹I‹™¢y£LQ 9éÁ‘??c^C§é©®ÝéöºtpÜIokz•ÝŽ¢¯çÌ·vo$äÆß#:Ç#%e}‡ lZé#ð”–~1šêÛA‡ìb+¨,Þ)·W†ÛnÖS¾%2 ¡”RA‘›1%ØA¢¹i2i6÷qÿf=„,Ëå‰Vä~KGnL9çÔ+0X|›¨©QEQEQE™>½cÔÖÍö§– †Îi’¡€Ê©Ã×½ ñ‰hÕ–ú0Ia:.æ!T(É r{Òi1yš¶¶éõôžµâ(¶è±Ÿú}³ÿÒ˜ëuN:#.iY²ÝQX…Q@Q@Q@Q@Q@Q@Q@Q@=ñçþ=t?÷§ÿÚtQñçþ=t?÷§ÿÚtWÙeŸîtþúS<ê¿Ä—õÑ?Âùæÿ¯¯ý¥wUÂü'ÿ‘NoúúÿÚQ×u_9š¾Tõ:pŸÁˆQEÀtQ@Q@Q@Q@Q@Q@Q@§J™/.n-ukÛ_´È$’8–]Á27ÆÇ¢ô’éwW+]kz„ð¤±Êbd€(á×%bQЊӢ¯ÚHžDT3ÝÛÚãΕS=3QéY\N!ŠáB2<š€çí}KTQEQ@Q@Q@Q@Q@Q@Q@=ñçþ=t?÷§ÿÚtQñçþ=t?÷§ÿÚtWÙeŸîtþúS<ê¿Ä—õÑ?Âùæÿ¯¯ý¥wUÂü'ÿ‘NoúúÿÚQ×u_9š¾Tõ:pŸÁ‰åÉâ ?Áž ¾Žk+Ï*×̲´ŠÆA!i³˜Õ›Í;ú`€ªIl’Ká¶¾dÖ|QªZ[j“[jßñ2‹ûAdÓvD~Ç QÎa¸Û·ÌŒpÎJ;ó.="Š.j“_Aã ÇQ×\Ç äïòâZI¡¼_,eI ˜B¨$·ï[,Í´®Oü$š®¡{oeyt—ÜOirË‘ºÚD¿µQUDN§tM$¬¸\·wõº(¸OŒcÑÓWŠãS›B•ÄRÏ_!q¹¾he`B??>É !xcBËÄ—­ª<ß]CåÞYCi¤]Áûé!’+s7˜í—‘ãYÎÖÜ„唨‹P[ÙÛÚÍu41í’êQ4Ç$îpŠ€óÓåEz}h¸gkã pÝI—ÈñOšY0¥´ð. Ir¾PX^8ævdw˜¦ÅÜq’÷µo_Codš‰íeÓäi³¬\ͪ³(‹lbc ÈNù~âõxÎc}Þ‹E¦—5ÍÆ‘e5àAu$óÑÑC•°®œðÀßš·E†QEQE2YV˾q:’NüÍGçÜÐ>ãþúÿ‹©d%BŽ»”àãéÈ©|×ÿgþùÕºˆ« ^M/Úì—åTÂΨÝÛ‘‚ȬýFÒÚÓZÓ$µ±ŒHYÆ!EVa±ûñüëj-u18û‰Ðc»Vv¦JëšQÎ÷ê3ÿ,Þ´åŽö3qïmIüûúÜßQÿñty÷ô¸ÿ¾£ÿâêךÿìÿß"5ÿÙÿ¾EF†…_>ãþ÷÷Ôü]}Çýî?ï¨ÿøºµæ¿û?÷È£Íöï‘F€Uóî?èqÿ}GÿÅÑçÜÐ>ãþúÿ‹«^kÿ³ÿ|Š<×ÿgþùh_>ãþ÷÷Ôü]Xe(ÅM;Íöï‘Mf,rNM'`¢’gYÒ­åšGV|!Q€ïýáRÒ[Ènúö—ÿBŽœnÌRØfo?èsÿ}ÅÿÅÑ›Ïú\ÿßqñuwâ A|btá,v|o ^eÞ•pâåÛ’à2Ä€îD]Ù&MÃoÝÝÖV¼±ì-{˜™¼ÿ eÏý÷ÿFo?èsÿ}ÅÿÅÖÝrǰkÜÁ’iáUi¬.#Bê…ËF@,@ž¤Tõ>µÿ ïûoþZ‚¢i-†™ãßã×Cÿzý§Eã×Cÿzý§E}vYþçOçÿ¥3‚¯ñ%ýtGOðŸþE9¿ëëÿiG]Õp¿ ÿäS›þ¾¿ö”uÝWÎfŸï•=Nœ'ðbQEpEPEPEPEPEPEPEPmÞ»eg¬ØiNÎ÷w¬U5ÈŒw 碂#p;’ ÄiVn§§Ë{¨hײ²¼iä NJ˜&޹‘}8´¨+Yðõž¹åý©¦Rœã?¥UÒ¼!¦iëynnURÌ“ gèoç[ôRåù­©Ÿ±§ÍÏʯÜ(¢ŠfEPEPN¯®¦½å°½šÚŒ÷71"ùvñŒå˜³Ø Ī`NW,·ñ%µÆ¤–¢Öéa–y-`¼`žTÓG¿|`Þòäå”)ØpNW5üEi­ßÜCoii§Üi[I¹†âñáiÛ<#m‰Á‘ü\òîW‚Ó@Ô!Ô­#Úý‚ËQ¹Ôcdc,­7û³Ð/ÚæÞÙØ8¾V#¨¤¶ÿÜõí/þ…-E5µ½Æß>¥ÛÓzÇçN.ÎàÕÑ%ï‡ÒûQ[‰µ ãj%Žw°Þ¦–2¬’¥× ˆv«*’¹ îmÛÏfXÏ·ýú_ð£û2Ãþ|m¿ïÒÿ…iÏlΆŠç¿³,?çÆÛþý/øQý™aÿ>6ß÷éÂŽx…™£­È;þÛÃÿ£V ªË§Ù#‡K;ue9D ƒùUš‰É=†‘ãßã×Cÿzý§Eã×Cÿzý§E}~YþçOçÿ¥3‚¯ñ%ýtGOðŸþE9¿ëëÿiG]Õp¿ ÿäS›þ¾¿ö”uÝWÎfŸï•=Nœ'ðbWkñÒïÃú&¢– Nêf³.7ÛotS#÷؈Ccæóbé¼V–›ã=QÑ­â}¢U„ºÆ’4q´±£ÆÊ(PÁÔ!`»ÊàTpÙ› ÍÙøë@¸¶‰¤ÔaYÚ(¢ŒHß4‘¬ˆ‰”™•ÆÅÚðØ\«¤šþ•%¼—^$Ç<6æHÁe/(ŒÆ0š>FGÍ׃…ašTV—Œü;¨ý›ìš¬2¾PÁƒ`Á.âqãÌù3¿å¢ûÄb“Qí3so-´p!“‰–á–8ŽÅów©ê@Œ¶@.ÀnÑ\ºøÚÊKj¤V—öbòYîeòͺnOÝ\kQEÀä/¾Ù_KtZåãŠæy]„kó,RC:2Ió.§—qïíÆÄƒÂš”ž ·Öîu¨eºŽX‘l¶Ç²4¸B¨<ÌŒ­É9fl0'B¯WE`ai^þÌþÃÿKó²´ÆÓÿÕíósäüýNßõ=9ûÝxçvŠ) (¢Š(¢Š(¢Š*kOøò·ÿ®Küªç%ñF­fßfO ]̱‚Es†Çû´Ô”V¿•ÿ#*“P³“‘{Jµ‚yu‘äVDafuþì§£ýiÿ=¦ÿÀ™Ʋü:×RÙÜ\ÝÚ=¤“Î\Dç$ ª¾Þ‡µlSr.:«‘ÿgZÏi¿ð&_ñ£û:Óþ{Mÿ2ÿIEñöu§üö›ÿeÿ?³­?ç´ßø/øÔ”QÌ#þδÿžÓàL¿ãGöu§üö›ÿeÿ’Š9‚Á­½¹fG‘‰R0Ò»þŒqERnà.µH!•¥òü‰ +&Hdî‘ê:š’ÛþCp×´¿úuTþ!KbC¦é«p–í4¢wFtŒÞɹ•H @Ý’eöÜ=j½œz¡quoe¨-Ìö²æ8uv…²FÊœ©>‡Ò«Ë¥,_¬µ8­¤&]2î9îæù–¾Zdð£ ä(ÀÎóŒ–'Â×"ãÃPIgw èÚ–¦kwVrm€TfJ?s'Ì…—Ï̹Úì›#¬þųÿ§Ÿü —ÿŠ£ûÏþžð._þ*´(¢ì,ŒMGN‚ÒÕf…®ÄÑMÌŒ0dPx-ƒÁ5%O­È;þÛÃÿ£V ¬êtw<{ãÏüzèïOÿ´è£ãÏüzèïOÿ´è¯­Ë?Üéüÿô¦pÕþ$¿®ˆéþÿȧ7ý}í(뺮á?üŠs××þÒŽ»ªùÌÓýò§©Ó„þ BŠ(® (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÉñ(»ÝCcs ½Ìû IfœÁîíUÈbàüÅx=* °Kkë6Šh®m.¼«…’þ[ÅÞcG$—æ+µÓŒ.î;™àŠæÞK{ˆ’XeR’G"†WR0A‚íL³²´Ó­ÒÆÖó²#‹““…I?1ÑE†QEQEÏxá¯cðV±5óÙK œÒ™b_Þacb·ð’BüØ'Æ ½ G<\ÛÉoqK ªRHäPÊêF ðA¨ñ]ÅȸñÉwué"_YˆgxÕf&à–uRƒ÷1ü®x<|Ç%…ÅÏö–™~nîškÝnúÆuiÜÄa‹í[DNÅ#ÈæPàäÍž®ïKÓïî-®/,-n&µmöòM »BÙ(HÊœÈôG¥éñjRêQØZ¥ü˲K¥…D®¼p_#å^3ØzS¸‹u ˆo¢¹‚8¤ÛÆUä)÷Šœä)þíME Ùܸ¿ÚWÿóåmÿMÿÆèþÒ¿ÿŸ+oü oþ7IE_´båûJÿþ|­¿ð)¿øÝÚWÿóåmÿMÿÆé(£Ú0å"»¸½¼…a{kx×ÌË Ùˆ áºlžµ-TÊM+=ñçþ=t?÷§ÿÚtQñçþ=t?÷§ÿÚtWØeŸîtþúS<ú¿Ä—õÑ?Âùæÿ¯¯ý¥wUÂü'ÿ‘NoúúÿÚQ×u_9š¾Tõ:pŸÁˆQ^Q¢x‚þÓAÐ`MSìÒ/öM´VgWó­d[mótÜ¿3ɘNÏ—hÈj¿oâ ~ßCÑnnµO=õ]2;»‰¾Ï-šù¶¨ò&#žGbû—(rµÃcsÒ(®IÕõMGͶÚßÚt¥ûL‹z"‰Úö8Å¡u8yeŒ•\aHÆñ¼×5­VüJúÊmö¾mŤS $²›+û¶U…<œeÁIß+Á;\’ÀwTW[麭ÄOmhާÃ,ñÚ[¬ yÌ&Y!‡v~SöTŽ=ç9[¦àѲÕg‡W¼½kÔ°´ÕÚ «PG´vî׿g³©U8mPo<rh°§Ex–˜×M©7ö·úeÍÕœ‘C5¸3ýµ0/äœJ[©|4‚~îÞ³T×5=.í&×üˆìoÌ&êf‚ ®Ȇ]¢GŒÁ¿2°U7á±Ë>P=Š‚ÊGšÂÚYt³7’Ðä2v6Y?Ý<ކ§©QEQEQEQ\å¶‹§jZÞµ-ÞŸkpâí<Ы<ˆŽ2GNMM¬x{H±Óá¹¶Ò¬¡/m6ɺ+ ÜFèMl©­ÌùÞö7h¢ŠÄÐ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šñï?ñë¡ÿ½?þÓ¢?ñë¡ÿ½?þÓ¢¾Ë,ÿs§óÿÒ™çUþ$¿®ˆéþÿȧ7ý}í(뺮á?üŠs××þÒŽ»ªùÌÓýò§©Ó„þ LÙ´+H_Íö©% ®#{ÉL!—O’[ËÈ vðÀ7^kJŠ+€è (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2bMZÃPÔ$¶³²¸†êu™Z[·†"D ¨O^ôë÷Öµ+x­e°ÓàíJò%ó¹9UÎÊ'n:޵©Ehª¾Äry…QY–QEQEQEQEQEQEQEQEx÷ÇŸøõÐÿÞŸÿiÑGÇŸøõÐÿÞŸÿiÑ_e–¹ÓùÿéLóªÿ_×Dtÿ ÿäS›þ¾¿ö”uÝW ðŸþE9¿ëëÿiG]Õ|æiþùSÔéÂ'§øÅ.üu6—ý¡döÏ,ö°Û£©™d…P’Pë–ûP%†ÜE1¸¼k~nloNŸåØ]é’Þ[F&Vó÷Il°îùw«4îDà'šØQÖ.`šU¦–°bÎÓÉòcÞß'’ÊÑóœœSÉçæ¨/ƒt‘¤[ Hb0«yÒf8Ë+ŒîýÚ«"²ÀB2»rsṓaãkíNî->ÏCÍùóÄ«<ïqÄ ’dˆI´­ÂóåçpÆ â߃uûßVòh’;/>²òëÛÅ V@òܳ.p °Þц¥ ÔQ<(‹1aÒ,­4žH2‰CWÛƒ–ÞÙ<¶í­?F°Ò¦¹–Æ#í_™;ycb]©©…U( 3ÐQ Õ¥þ£¥M®MwªÞêkiŸkëjÏ2[”fhâ|óHÎøIÛÔ5ûÑáÜ’ÏTÒ [Ê:5”@%FVe†:¨ç# ©tk £½àÊÞʳNC°&ETUu åXÓpAPG<Ôi é©¤]if{[µt¸ófw’`˴rvárN@ 0]ÈIã{ñ¨èñ8†8àóưj‰$Hî”™Û že¤§.TãËÉ`4¬¼o$¶÷òÞéomýœ±Ü^®]–ì$ý≢œ©‰P¿wî–o’·gÐ4«™d’âÍ%2În$Êîaò *N1|¸Æ;ã<ÔÞÑ­. Äv®Ó;DòI5Ä’´­c³åKœÎ0˜û‹ƒ@2n|U©[k°Ød;Ý], ³] X‹‹¶ Ì‚ºïÁ`2v+ûÉ4ߦ§{¦ÀºlÐ.£åI –EÜ!–äG`¹‰¶q·'”ç9Q«†´‹[»{˜m6Ko·É"GÄaD¡UFp åq€0«†Â)£ x¡KWŒE6ñÂyn_ÎSäH¯4A£ ¸•DHÇvô‰Ø:K¯ iww7rZlº¹òüÛˆ$x¤&0ÁX:U‚».àA*v’G߃t ÛAkqa¾)¢tó¤r’NdÃ~ñƒ38gÉ Å I¢è šw‹äÔ|Bú|zM×Ùó[-ØŠbÄX1rc,ŒYä¨* ;zŠÍ‡AÓ`Ôüp¸›sHªfs;gs¤DìG9l²€NæÉùŽt©00/ïõmMVº·ŠÞábŽ8c„€<¨ØòÈNrǽIg¨i¶°Ý nú\][ÆÑÉY^dFƒÑB(³¿ƒMÕµqu èón–HÚ+)¥V_"%ÈdR:©{Tº¾¯i¨XEkk Ó5å«Ú|èYãf%™O'µu%¶šiÐŵg®¦µQ\¦áEPEPEPEPEPEPEPEP|yÿ]ýéÿö|yÿ]ýéÿööYgû?Ÿþ”Ï:¯ñ%ýtGOðŸþE9¿ëëÿiG]Õp¿ ÿäS›þ¾¿ö”uÝWÎfŸï•=Nœ'ðbW7¤øžãQïf´²ƒKMÞtÂü4¶…Wq[˜ÙDÊ8e ÅX‚2ÁòxÃMYmKÆ’ÎÑNo#{V·A ²ùŒ²¨;’Ã<Ÿ”Šá±¹ÐÑXÃÅZI·yL—HêÊŸg{)–á‹FØJyŒW9 FÿºØ ž7±ŸUžÊݤKh|ùb•´Ó˜JÝœ:ñnS·c•,Àê(¬&ñ–2O-ÿ“m"iá’8äVu@èì :ntË©*)$ [M{M}"ëT3:ZÚ+½Ç› ¤…]Çtlƒ· ‚2Ad•ašTW=/‰%ÒÇŸ¯Ø¦i"ÈðÊ“™Øl¤e•U~WØŒß)uùnÎÝÌ»ñ¾‘lL“y–Í+‰¥*ëåİM0™A\È„BÁYr­Î Áì#¤¢ KËw¿šÅdÍÌ1$Ò&åœôäÆÿ—¸©é (¢Š(¢Š(¢Š(¬fÕ5)u Ë{=>ÖHí¥X‹ÍvÑ–&4~‚6ãç¯jYõ bÒ8¦ºÓl–ž(XÇzìÃ|Š€€bà°=E_³‘èØ¢Š* (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€<{ãÏüzèïOÿ´è£ãÏüzèïOÿ´è¯²Ë?Üéüÿô¦yÕ‰/ë¢:„ÿò)Íÿ__ûJ:î«…øOÿ"œßõõÿ´£®ê¾s4ÿ|©êtá?ƒ”¼ð}Æ­4¿Úº”2ÆÖ²ÚyöÖb©"tdÛ,»Šºüåö„UÞ€ÛU?á]ÛMjÐNú}²HÎ%]+MKEdkyáþóÿ¿'$‘ò€e‰í¨®³s´ðSX„¸´—H³¿Šuše¤¬ùÉÏ}îvÌÿòÐBà 6éæð­íÕùº¹ÕÒC"Ù™‡ÙpKÛÝÆÒ „3 1),ÄÝE\B?ËåiðM©£Ã¥¬0Ø„¶*Âæ‚R%%Èw"Þ5ܡ˧ •ÐmÝ5ØnÛ϶Õå-,X+„0G \ƒžDdäcï{fµ¨¢àrú—…ou½>æÏUÕÒtò&ŠÑÒ×ËhÚHž/6\6$pŽÃ ~fù~îÛw^ûOŠíµÏµíò|¯ÜùyÎĺO½žÿjÏOà÷ãvŠ.„´oì]Éh<‰%•¤ò‹î1Æ0£‘¹!HàJ–Éc»E†QEQEQEghÑoÕ5Æÿ§Õù/ Yñ${tT?ôûgÿ¥1Ô:‘y;Ou¥ÙO3ãt’Û£1ÀÀÉ#=2/h°Ê’Å£éñÈŒ-#AÇ·U#£2åvhÒ¢Š+P¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ǿ<ÿÇ®‡þôÿûNŠ><ÿÇ®‡þôÿûNŠû,³ýΟÏÿJgWø’þº#§øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:î«ç3O÷Êž§Nø1 (¢¸€¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ǿ<ÿÇ®‡þôÿûNŠ><ÿÇ®‡þôÿûNŠû,³ýΟÏÿJgWø’þº#§øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:î«ç3O÷Êž§Nø1 (¢¸€¢Š(¢Š(¢Š(¢ŠlޱFÎìd’p QX£Å:s(d‹Q‘¯›pêÀô!‚G¸¥ÿ„žÇþ}µ_ü\ÿñºÓÙTþW÷í!Ý4V7ü$ö?óíªÿàªçÿÒÂOcÿ>Ú¯þ ®øŠ=•Oåp{HwFÕ‹ÿ Eüúêßø+¹ÿâ(ÿ„¢Çþ}uoüÜÿñ{*ŸÊþàöîª+xžÄœ}›Uüt»Ÿþ"´í. ¾µŽæÚE’Wr:ô"¦P”~%a©Eìɨ œ ÖIñ‘fC¨NªJù–ú|ó!#®ƒøJ.[!¶–浓ÿ ·üøëø)¹ÿãtÂAmÿ>:Çþ nøÝW³ŸfO<{šÔVOü$6ßóã¬ÿà¦çÿÑÿ ·üøk?ø)¹ÿãt{9öaÏæµ“ÿ ·üøk?ø)¹ÿãtÂCmÿ>:Ïþ nøÝÎ}˜ùãÜÖ¢«Ù_A¨[ùÖìY2T†R¬¤uO û±PÕ´cNáEfK¯YÅ<¬w³¼gml¦œ)ô%€}©Ÿð[ÏŽ±ÿ‚›Ÿþ7WìçÙ‹ž=Íj+'þ oùñÖ?ðSsÿÆèÿ„†Ûþ|5ŸüÜÿñº=œû1sǹ­EdÿÂCmÿ>Ïþ nøÝÄVA”K£± ¾ãOž$ð2Ì€ÄÑìçÙž=Íj(¢ £Ç¾<ÿÇ®‡þôÿûNŠ><ÿÇ®‡þôÿûNŠû,³ýΟÏÿJgWø’þº#§øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:î«ç3O÷Êž§Nø1 (¢¸€¢Š(¢Š(¢Š(¬<­pEŒÜÿÀ lV?‹äNÖÿëÆoýÕÓø‘3øY±¦¬2éñ;EžJ‚zš·äÛÿÏ¿ïYš$›´x ?ÞÿÐCâi¼¿]gRƒMöE-äÓù>Llá]•ÿ†M¥¶Æý¹âº*6¦Õú™Á.T;I×ôMgOkë*8©éÐ&L,gûë,EG_œeCλᵰKæÔ´‘fèΗxü¶U`ŒCgeR{©¯6¿·Ò¦¶:V‡âm/YKùlÑìäkypb¸‡iX TVŒD$ó3ÎÈÐd*ñ´Ú.·mu•±Ó¥¼•o.^)ÚX¥œ «>Ì«•‰›>_#zc8ŽgÜ«#³´Ô´Ë½J÷OHâ[›ILMª‚øŽ) (êT £ö'é›+«xî-ÖÚh%@ñÉVWR2#‚ï^xž»Ñôˆìíî¦k¶º··‚êÏ1È-ͤ6Ó–oàÂÄò¨ÝñÃ÷ŽúÃko½¼qà H8ãPªŠp¨æ}ÂÈ[¨àKI˜C!‚qÅ`xU‹he‰Îo.ÿô¦JÚ¿“uÉÏü²oäk Áç>Cëuwÿ¥UI·E·Ý~L•üO—ù÷éUü øð^…ÿ`ø úùkš°ÿq¾•CÂn?á Ðùÿ˜}¿þ‹ZÊ ù~¥Kâ_×cWUÕbÑô{íNá] ³·’âEŒÅQK2@έgÛx¥ ÃÁ©Ø]hî¶ïr¦ùáÚÑFTHÛ£‘Â…Þ™ÜGÞã88ÅP}»ÂÝ§Ú ·óì'‹Î¸}‘Ǻ6»(ÎIô®,éÞ½¹¾Ó¼/ªxz5Ô~Í?Ù,nÒ){i˜SÌÑpJãË*\+jwèx£C‡L‹S“ZÓ“O™öEt×H"vç…|àŸ•¸±ô©.üC¤Ø]‹KÍVÆÚäÄÓˆf¸Ds‚Kí';@V$ôùO¥q£ÂÚ•½˜šÒÞÖ=AîbF­reŒ”C}¥Õ̃÷JLoÆùËË‘ø.xu•—e«Ú½Å­Ëîî-â…¡H”*Z#yl3*Y¾]Ã!‚ÎàvZ&¹iâ ÏV°}Ö×q S$¹ê­‚@`rÏWüÃX²»Ò|)¥i·Âsgk»˜$.±B‚ U<€1ÆqÎ2u÷ZW J9Õ|Bê ¿úMjÖFŽs©ø€ÿÔAôš ר©ñ}ßCb—„_n‡'©¿¼ÉõÿIVï˜kð«cEgþ_¯ô¦ZÚßïZÉû̘ü(ÈѼZ5{K{×Ò¯´û ˜£– «Ù-ÂIæ¨ +0fÞ0p ëž6Ѽ=,I¨^À›åXI7)G-Ã+0nes€p€“Œ®îgÞºÑôE°>ð¼7?`[9ocs!¸ûªæTòP² /ó#;}á [ËÓ’ÒK³r"yædkŸô«[Ò‰È; îbqUW(ôO0Ö'Œ¤?ð…kõá?þ€kO½bxÁÇü!šØÏü¸Oÿ¢Úœ¼‰ŸÂÍCÔÒRž¦’¹ÍOøóÿºûÓÿí:(øóÿºûÓÿí:+ì²Ï÷:?ý)žu_âKú莟á?üŠs××þÒŽ»ªá~ÿȧ7ý}í(뺯œÍ?ß*z8OàÄ(¢Šà:Š( Š( Š( £¸·ŠîÚ[yÐ<2¡GCüJF©( G,| k“·YÖQ{(š#ÄÆOæhÿ„ßþƒš×ýü‡ÿWSEtýr¿ó3?cO±Ë oÿAÍkþþCÿƨÿ„ßþƒš×ýü‡ÿWSE\¯üÌ=>Ç-ÿ5¿ý5¯ûûÿ£þkúk_÷öþ5]M}r¿ó0ö4û·ü ÖùÿÞµÿaÿãUÐØØÛé¶1YÚ«,Q͹˜’I$÷$’OÖ¬QYÔ¯R¢´ÝÊ8ÇT€ŒŒV"xl@¢;=cTµ·^šTƒ|lqíšÛ¢¢2ka´™ýƒqÿC±ù[ñš?°n?èbÖ?+oþ3[4Sö’þ’"þ›1¿°n?èbÖ?+oþ3Gö ÿô1kù-ÿÆkfŠ=¤¿¤ƒ‘M˜ßØ3ÿÐŬä·ÿ£ûãþ†-cò¶ÿã5³EÒ_ÒAÈ¿¦Êš~›lÑBÒÈÎæIe•ƒ<Ž@8tpÀ«tQRÛn줭¢1ßÃÊ&‘í5MFÉ$s#EDSq9$ˆÉÉàãšOìúµÊÛÿŒÖÍ^Ò_ÒDò#ûãþ†-cò¶ÿã4`ÏÿC±ÿ’ßüf¶h£ÚKúH9ôÙýƒ?ý ZÇþKñškømn—y«ê—vçïÁ+B« ô;"S¡­º(ö’þ’D)9$úÒQEAg|yÿ]ýéÿö|yÿ]ýéÿööYgû?Ÿþ”Ï:¯ñ%ýtGOðŸþE9¿ëëÿiG]Õ|»¤|Eñ…dlôë˜âˆ¶ò *ÄœžAì_ÿ…½ãúGÿ€ñÿñ5ÃÊj×ÄN¬d¬ßŸùF²§ME§§§ùŸIÑ_6ÂÞñýcÿÀxÿøš?áoxÇþ‚1ÿà<üMsaWþxþ?äkõ¨ÿ+ü?ÌúNŠù³þ÷Œè#þÇÿÄÑÿ {Æ?ôÿãÿâhþ¯üñüÈ>µå‡ùŸIÑ_6ÂÞñýcÿÀhÿøš?áoxÇþ‚1ÿà<üMØUÿž?ùÖ£ü¯ðÿ3é:+æÏø[Þ1ÿ ŒøÿGü-ïÿÐF?üÿ‰£û ¿óÇñÿ úÔ•þæ}'E|Ùÿ {Æ?ôÿãÿâhÿ…½ãúÇÿ€ñÿñ4aWþxþ?äZò¿ÃüϤ诛?áoxÇþ‚1ÿà<üMð·¼cÿAÿð?þ&ì*ÿÏÇüƒëQþWø™ôógü-ïÿÐF?üÿ‰£þ÷Œè#þÇÿÄÑý…_ùãøÿ}j?Êÿó>“¢¾lÿ…½ãúÇÿ€ñÿñ4ÂÞñýcÿÀhÿøš?°«ÿ<ò­Gù_áþgÒtWÍŸð·¼cÿAÿð?þ&ø[Þ1ÿ ŒøÿGöçãþAõ¨ÿ+ü?ÌúNŠù³þ÷Œè#þÇÿÄÑÿ {Æ?ôÿãÿâhþ¯üñüÈ>µå‡ùŸIÑ_6ÂÞñýcÿÀxÿøš?áoxÇþ‚1ÿà<üMØUÿž?ùÖ£ü¯ðÿ3é:+æÏø[Þ1ÿ ŒøÿGü-ïÿÐF?üÿ‰£û ¿óÇñÿ úÔ•þæ}'E|Ùÿ {Æ?ôÿãÿâhÿ…½ãúÇÿ€ñÿñ4aWþxþ?äZò¿ÃüϤ诛?áoxÇþ‚1ÿà<üMð·¼cÿAÿð?þ&ì*ÿÏÇüƒëQþWø™ôógü-ïÿÐF?üÿ‰£þ÷Œè#þÇÿÄÑý…_ùãøÿ}j?Êÿó>“¢¾lÿ…½ãúÇÿ€ñÿñ4ÂÞñýcÿÀxÿøš?°«ÿ<ò­Gù_áþgÒtWÍŸð·¼cÿAÿð?þ&ø[Þ1ÿ ŒøÿGöçãþAõ¨ÿ+ü?ÌúNŠù³þ÷Œè#þÇÿÄÑÿ {Æ?ôÿãÿâhþ¯üñüÈ>µå‡ù—ÇŸøõÐÿÞŸÿiÑ^eâ/ë>)HV¸Y„ŒxSÆ~èè(¯{ BT(F”Ú¾Þ­œò—4œ»ŸÿÙivy-2.4.0-rc1/doc/images/yed-step4.jpg000066400000000000000000000244761226750426600173700ustar00rootroot00000000000000ÿØÿàJFIF``ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ½©"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?¾ñšµ«ù1[Y¡X£‚2 ±~ycϹõ¬ó=§–cÚ›3¸ãòéï^çã?á¿8ç÷xúù‹^F¶ÎöS]_.V2¹ù²áÈÀôù~õõø,Êi6¡Ê®xœ#„íÌÌ´ZnCµ>A…ã öô¡®mÚ@çiqœ1Žõ²º}ëÁ ëgpÐÎþ\R;dcOsx¦Águtc[ky¦i ,aåFHë€A>™÷®ß¯S{¤sýY®¬È‚=P.:`žô,ö ( »P’ / žk›;‘*ÆmæÞÒ• Ì㪀yÜ22:ŒQR_i·Zx·kˆÏ—Tª8{5¡ÛK,ç‚’›Ôðë=kû>-ImDõ G´™Ý ;‚x#Ÿsš¨.-De@‡’ `~Uô$~ Ñ%Ó%Ô£Õô÷°‰ÂKr·(bV$³€~eã=Å@|K`——k=Å´V6öv÷bùçUÖg‘W“À»wÇÄSsT•Ù«ÊäÒ‹ž‡‹›a “ ¼tlsIçÚy^VØöwoý~y¯¤¡–˜#žÞHæ†UˆAWR2ÁƒQ¿‡L¶IæWeyá€Òȱ¯R8ËŒûzôªÿX×JHŸìŸïŸ;}ªßpo”•Wµ_I¬]$÷&Ö(„PÃn…#‰A'…çžA^èúÍ´zêé>[ý ¬o¸²*áÄÄc, ?¸|€ 䛊‘xƒE¸³7êú|¶ÁŠÖå nU.˸2<ð£wJ™q\”-PÖUd×9óีùjcÆ6ÅY‹Yú-î•¶×—(I[ïpp2zñùkß_YÒc»¹´}NÉnmc3\Bó xcî¤åWž0EëZM¼–ñM©ÙÅ%Ì­ $è¦Y¶²('– B:ÑOˆ#8òÊ’r·u3ç´Z‚¿* £ …û£Àô ÏhÒ Ædvâ£9ã¿à+Þ´i:þm}íš¼‘@óÀ— æÞIxXØâÝ•'µlG43<©±»DÁ$U`J1PØ8èpÀàö ÷«ÿYÓÙ û%Þüìù±å³‘·:Fçù—<Z_´Züü'Î>~>÷×Ö¾•ÇÓñ¬¯íû?ìß·ùrù_nû\.ï3ígÏ^>»{gŠ?ÖEÒ˜¿²]¾6|ý$¶rÿ¬HߌÊ Mý¡üõ?™¯x¼ñŸ2›;›kÙ`»¶´¸ŠÔ˜ZY–/Ÿ*A$à¤{Óá1ð§ý Ú'þ "ÿ?Ö$ÿåØdÿ}xçþDëîqþ«òó¼ºÆâËû*êÒîK˜|É£•DƒåW`ºÿ|b½“PÒ³dú}Ý×î&+»Ê‹cpA%ˆê=+~èç.5ÆAßôó°XšTérMës¯FsŸ4{$zÕ­¾46ÆK{††4A² ¬¯—óòƒ´À-áëÝN×í·v$,Vo…žÒ0TIæ$Žè¹RÈO&Âs¶»¯øUz>0'Ô€öx¿øš½õŸR?WˆÿìµÐ±8[Þïî2öŽ&wN{Ë.~Õz|ñËH•Ì¡R$ùa°þä }ìgŽqµ+¨o ”Ê'Ǩê0»PÙÉÜ' c§5éÿðªô|ƒöOúiøQÿ ¯GÆ>Ñ©ãýøÿª¼,Óp ÏtVøh3áÛúûoý+KSðôš¤úð3Ç:ž•‚Èö‡Ÿ¹ˆã#.9;V¶‡á›}Éí-Zåãy ¤ÊPœàØô§öVô“Û§ø×‰’©ZSŽÌï£j/tqhZÝÞ²šôØ%üK%ºwŠ@‰p„´ÞX(OÚ˜ãc}ÁÏÍ•£ÿ~¥’]¢ZÏxì·”½’ÜÛLf»•аÃö €:í`²òŸEû)þëþCüx£ìÄõWü—ük3K™öQM…¼77?j¸HÕd¸òÂy¬-´p¹983ôª>#Ò·4`R®m¤‘'G&Gu#9U#ÁÏ’~ŸãGÙO÷dý?Æ•˜\ó­_áÔW7÷ ¥Åa¦X\À±H°@ƒä^Dϱ@ Òcî2ò03=ŸƒçmVÆþöÚÕ|›ÈçxåÔ./™–8§D“¡æ(Q´«6I ûì§û²~Kþ4}”öW@¿ãOP¹æÞ!ðv·¬ÜΞ|.íA.%Ô&ÛÍiö`¾ZlóQKƒ¸„,F\ŠéL»ÓõÕºÒí¬M¤¶¶öo Jaû2Dòc „>D¤;1´sÏ/ÙNÜbLÀƲž8“§øÑ¨\à&ð̶ÞÓó|É¥èÚJ¶ ´æ\@Èðe~ð0¤àîÙŽøétM>m?Ní‘ï®§»‘ !¥nX)#%…\òPsŠÚû)þ쟧øÑöSý×úáÆ•˜îVþœóþx®;þ[O³yßaÓµÿ¶>ßöß( 6}·ÎÇ™Á¼¿—ëÆ@滯²ŸîÉúe=q&}N?ÇüâšLW<ÛNð%í¥µ”'ÈÍ€·Š+‡¾¸ŸÍHç†G!äƒ"¸»$ À/Íó·ü!Þ'ÿ¡VÿÀ¿øšúâÎòkë‹ý iorР1o-…S×pÇ'ÓÒ®b_ùþƒþü·ÿ¡63›Ñõ­n;íuI´éÆ¡s-¶Ë[W‹Êd¶íÍ#n¸#nÑ÷³ž0{¸Õ ÿdWöím¯xJ"²ªÿiJÀÉ"3>ë{¦$”ù~ó˜¯@„~éû"´I'¡#ÉÀÍcêÚ•âjzNœ`Šúî)gÜÆdŽ8â(äVRÌL¨Ü£Ž~P­±ŒŠÏÔôˆõ*D¸žÎòù7vÅ|ÈÃcrüÊÊU°2¬ÈSʤ01ìü\F°ºÝ”ój‹+Ã#ÙŘNÅÌ™'ä]—ØbpC(.v— ñŬä¿ömìV²iòêV·3< Ìì%”™r™!`LÎ0q~ÓÃvvð_¤“ÉuSG$²0-9”Ä]Ü÷¿r€… €P¼í—nßRÅíãÇ¥ØÛ›m.çIZÅ$L’…Jx¾W3nîHxË?ˆv:§šV™}¨\Iço†Ö[fò¼¯(¶\Ì#n'ŒŒßxƒ‚µñŵ쒮kuª;¸{hm¢H™ ò É™dPGúD}v·Ï§ij»¥xN 3W“U}FúööO7Ì–äÆ7y‹ž hñݳœŒR²ðŽ— #MÔõKˆ•c[”13ùbb)‡— -¢bvç à€H °ÒÒ>˜¥ Š( Š( Š( Š( oÇž%›Â ½× ·Žáí^br@uiQXdt;Xà󃃃ҮøÄ>(ðýžµ¦—kK¤,›Ð«)«=AqÁÇŒeþ!Ð,|O¢M¤jJíg3ÆÒ¢6ÒÁ_nz€J€qƒ‚pAæ¯Co¥´vöñ$PD#*¢€(„[­BÒ×ÄsZGØî&o5æ!Ñ„kÈ]¤Ç“×=:×Cçk?ô ±ÿÀ¿þ×^Kã]FÒÍüEš“Û\²Ìb‰u ÜJ`~í\+òU9àsÀ¯kòíÿºŸ÷ÐÿâªÃg+³RÖ|I¡Üɤ]XÅa;O$—rÀÛÁŠX¯—,œÊ8SÎpkÌ)þè®cLñ6¨êÚ[]ù“H~U18=Æ;WM<¤#û£âï¸4HN++TñŽsµÐºyçGxãµ²šá™P¨cˆÕ°uãï Ô'å®;źmÍ߈t›ÅÓ5Këhmn¢i·ÂÚDwx äùÑ’¸ò2GN:Uè/5‹{m2 é#ŸÉ¸–Þ$SWi5Ü­‚0]rsÆF+@ýëÏ5móQÖ>×7†žâî}JÂîÖúSnͧÁ@d„±}êAŽcˆÃ)2pIc\ÌGö•ØÒôëÓU²Ó^Û[¾´–ÚF½•n-L¡˜3eäX§À¸ »s߀b¾¿·Ó4û›ûÉV¶Ñ4Ò¾ ÚŠ2Ç$àÜÔf·g« E·ž²E·|76Ò[ÈÎdŠ­´á€l`•`¿†îàøkâ *ÚÒí%½·¸[KK—·VBð„ ²X¢Á8RGÌXœ³-÷‡ud]IL³êïuöW734Q¼C*»Ú:¨D;ƒM´àó\¨U,Ün9éÇ©ªöú…½Ô×pÁ y-%òg#c”Wž¿+©ãŽzäb¸7IÔ4m]5‹mt°ÿIŠßH¶xKT‘mqòù‚%Röò± ç™AÆKíÇÓ|©ZøjæÊM$G©ÜZXdÀÏäŪMi¹‰Ë7“.‰· ÍÉÕ·ãÒ«géë^wáϵ¾µ¦\\X]Gcl—o7RÀ .Ík±LVábQº)\*î°ä‡8_D(ÔRfŒÐÑIš3@ E&hÍSÕukÁ¯µ+˜í­UÑYK°Q“Øe†Iàu< µ»5ÊüJÐo¼QàCEÓ• ÕÓÀ«½¶ª231>€}xã'ŠÒð¶‡ÿ׆4ýí“ÞýŽ//ϘüÍÉè;(Îy€2qšL\ý½ì†±ï~(>þâÏû#Ùäh·}§¶œg8é[:Oü… úŸäkÈõÿùõ1ÿOrÿèf½,¾…:Ó’š8ñu%§¼?Oý?òkÿ°¤ÿ…¹ÿP_Êë?¦Ìךw89­m>t;æ¼ybÛs¬‘À%q”—#–^8ÏSÐq^”ðXxFö8㈫.§kÿ lóžãíý…/ü-Ïú‚äßÿaX·:.™,QÌóm!„HIQaäÚòJ«•%¥$ýáœôÉj̼Ñ-(–Éî...®|›eÆÅ ¬L2X)?ë ƒ€!¾P0p,#Þ,·R²êu¿ð·1Ÿø’uÿ§¯þ“þæÿ‰'Nãèñ̾£}ŽKø®å–Õ"s¶.K«Â1¹£LdMºvà›îÒX[ØØêQÀÑÜ<ß`’idª†Wµw*«´•#p²Ý3Žiû-´‹i[¹ÓŸ‹‡tOn.úãiOÅÏú‚sÿ_ý…s1h¶SéÿjˆÌÈ«8‰Š³U¹,»öŒgÉêw!°*/I°ÔgÚ[Xnfö¦IË6ÿ”6BÄw`²œ@Éä«öK7Êôk[¹Õ‹eIÿ‰'çuøÿsÞ—þéí¢ä×ÿa\.¸1gkÛþ˜'ÿ^³qíœ{f¶† (órþ$¶zf•«k¾Ïsk r'”ˆìöêg>]êp¬pA##Ó«fÓôù¬,£Ù٬与æé\)—!»xV,<É0§i;JäH~Ç ØJ­kntGâñÀ?؃¿jíÿ|R‹§þ€ƒÿ¿û ånô›+{k´Kn-˜O&Jl’p8x#èÈùGi—IÓmõtCyo$FÀ»ÅHÌ§ìŒæL:€~o˜sœ‘Ðô~Ç kò°uk^Í!ø¶ODÿɯþÂ|[ÿ¨'þMþ&¸«ø,cЬd²y%-s:¼’À±7 6@É#žçñÉ­#‚ÃÎIñT’l÷¿ d¶°{h>9Ïð'ÿ^º W?á`köý+¡¯Úž¢ØãôŸù Aõ?ÈךkZ³6¿¨É“~ñ½Ô¬¬¶ÎCçs^—¤Œê}Oò5ÖB£ÉCþÈþUцÄË'(­Ì«QURMŸ=Â9®sÿmG§üú¿øS¿°uñ‹û'SòÙƒ2}šM¤ŒàãÏ'ó¯¡HÀã÷¬­SUšÒâÞÆÆÖ;­FåXâ–_*1ìûX€  áX’À2ñæ³{ÅÿQsÅ“MñTOÇg¬£Åþ­’)AO”/|ª£ŽÀ Š]ÄSçÎÓ5Y2Ìç|6Y¾ór:œ žø‚½ŽÛÅÚy¼‹M¾o²êÏ+[›E &dQmŒÌ»fóÁ Ù`»\.E‡ÄHoF‡rÖ7ÑZê|·2Æš}̲$‹öríL´x™¾p¥It)fMkȇõ%üÇ\Xø¶ñJÝZës‚»q,r·û€MoŠ…²[}‹Yû:glB)BŒäœ‚Aõú׳hÏy ´wžo°,ÑDï.E3(1«0e–ïL™s]¤¿˜ò¹ôÿ][Éú^¥)–U–Y$·‘žB«µrHì Æ1רbìOùžgöf«¿g—»È“;víÆqÓcÓŽ•íVž#²¾Õml­?Ÿk%È,’!Q—”Û¸3ÊX:^NøŽÓû]LE9.žÍc 7É2Îm¯8ù¤H0-´g fRZ( x$÷gˆ_1,GIÔ¼µbÊŸf|q’=‡åMÿ„s\ÿ 6¡ÿ€Ïþîv­vú€Óuk8-/d…® ×xåJ«üņRéW:OÌc«ûV¥­Ê`£{ÜÀð·ÞÖì"ÿúWA\÷…G:Éÿ¨‹ÿè¸ë¡¯)y©YXãôŸù ÛýOò5ÖÃþ¢?÷Gò®AÕí®µ»h¢Šø9'K‘z¬È®î˜S6ŒROP$#5“«i2ÝOoar–º•²¼qK,FXÊ9Rêé¹r D`C)œnVÕ'ZúþÓM´’îþê KXð^k‰h¹ ±àd?T=‡†ž·±-áší¢n[ÊÚ²É)€nQ»äU[uP¼œc,[%¢Ñ|/&“q¦3ßG<]”Ö¨ (Æ0lÞňg †ÝÑqÎņ«¦ê©¿N¾µ¼M¢@Öó,ƒifPß)é¹gÕÒ­žüq@nàytÛ]95Xä°W²šåZÔ‰¤šÙ!T(ûðˆ~Ï*U-†äm̳ð–±smgpßgÓ4[_²é’ˤöòDͶgóýwñ 9àNÎõï`P†Á¤"æh^d@§,ˆÈç§Dã9玜Y oLðÌÖZùÖî¯Ò{Ùq:Å¤Ê ÌTµQ‚[%‰È‹ÃqÒWíÖ3ÿgýˆý¢çOßrŸfòþXdó’åd®INî;å?—jp\ ÎÐ4ßì_éºW›ç}ŠÒ+o7fÝû.qÎ3Œã'­h·JÇ­dPŸIð¾Øè¶öÐê×ÑÞý–âÚæêiç•n<ø%cJUwJÉ1« ã ‡ÂÖoue©Ãe©éu%ݽ½Õ vŠIÝË%[æ‘‚áW‚XóWî5Í.ÒE侃:d~uê#oxi|²®XeA#ŒžÙ«pM ÄfKyRUÞÈYIVÜAˆÅs74íÓ@K(­`ŸMxÞâxm6½e·–ÏŽr|ÒÜäõóL¿ð%´Ãeœ°Gm­­¬6w6æâÝ’8*Ê¥Á•q0 hѲqŠé®o¬ìDòê fžU†6@¾d­œ"ç˜ö“D7ÖsÞ\ÚAuo%Í©A<1Ê¥âÜ2»”®G#8Ír:_‚ÞâÇO¾µ±¼Óm­oDªmU ‘®.£™Q!%¶¬~V0xLÎÛšwÃý NÓ®-á±µ·¸–âIÖòÖÕ"–?ôƒl“‘·VÎÂÚ†Ú2‘´²LFâ~wrìy=Ù˜ûgŒP?‚%½ºð~•¨êß]^ÚErï2F» Ƥ¨Š6ƒœg'ž¦º­acm¦iöÖ6qùvÖÑ,0¦âv¢€dòpëVhŸð¯]gþÂOÿ¢ã®‚¹ÿ õÖì$ÿú.:è) 8ÍþBÖÿSüuðÿ©O÷Er?ü…`>„úúW_ú¥Š+*; $ÅcêÚûiš…­Œ:Uî£ss³*Z4CjFP1&GAÖUàdÖ»tãõ®kÄ:ö±g<—wV°Ácu™gtðN+BUR2Ž#;~SŠØF’x—Fk}6vÔíbMMì„ÒˆÚà0R6+a‰ù—Œg‘Oµ×ô›íFm>ÏT±¸½ƒw›m Â<‘í;[r‚HÁ ÷8®CÄž×µ}ôè~ĬÊ8`¿¸²‚ݾu[ÍVRŸº|ªl 3&§Ôüy©øz=)7ú”òH2Ûc¹[µ\/aö”$dñ [ohwWº’Ǫi­aao²ß­âƒJò.Æ9‘å¯~wŽïËâ} ‰$Ö´äy`7Q«] /ÒÞbóÊmV;‡Ð×9.…â+¿Kk¥Eumö"Ñ/dt—b]£n“É8»ÈÂ6JcŒäCmàÍAæVšÔ5ÌöW,ªÌB2j3]È íä”*ž7É šî­î!»·ŠâÞhæ‚T‘°eu# ‚8 ŒsRÖW‡ôé´½>kyÙÞöîà$²ÜI"Ž@ä+€}óõ­Z(¢Š(¢Š(<ÑE Pih¢€ (¢€9ÿ õÖì$ÿú.:è+Ÿð¯]gþÂOÿ¢ã®‚’Ï|?¤[[k–³G%ë2“%äÒ/Ý=U˜Î»è1äGþè®AÐô›]nÖk}.ÆUŽÙ#·EaÁè@®îû”>ª DcÊ1æ˜}‡øS˜ñ\–»ªéš7Ž´kNþÒÊ&Ó/Is2Æ mHb=céZéî'†ÚÚk‹‰R("BòI#U@2KÀÏ'§5)6ß÷éÂìËùñ¶ÿ¿Kþjacw¢i¶‰kkwD™ ·I$³rÌI$±$’I$“š°u;_[ÿßb¸ìËùñ¶ÿ¿KþgOÒt×¾_Oµeç!¡R:jNã;í7½ì÷Ø£ûgMÿŸëûø+NÑ4—×/£}.É‘m `¦Ý¼¹=;à~U±ÿö‰ÿ@}?ÿ“ü(Zˆ“ûgMÿŸëûø(þÙÓçúßþþ þíþ€úþ'øQÿö‰ÿ@}?ÿ“ü)êŸÛ:oüÿ[ÿßÁGöΛÿ?Öÿ÷ðTðhŸôÓÿð?ÂøG´Oúéÿø ŸáF Iý³¦ÿÏõ¿ýülé¿óýoÿGÿö‰ÿ@}?ÿ“ü(ÿ„{Dÿ >Ÿÿ€ÉþjŸÛ:oüÿ[ÿßÁHu7þ`üS?áÑ?è§ÿà2…!ðîˆF§ÿà2…CÂl®5†R EÈ äÝÇ]AkekcŽÒÚxÉÜR$ õÀúTô ?ÿÙivy-2.4.0-rc1/doc/images/yed-step5.jpg000066400000000000000000000751151226750426600173650ustar00rootroot00000000000000ÿØÿàJFIF``ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ¾:"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?Ëñ.üUªM<’;iâOôkVáFv’¹ ¾ Éç©ã¨Åsøô·'Þ1T|)c¡ªé–SX®n"…Êà0 Àg¿5ØK þ&{Ë-F -2ÚîkI] ŒLveŠà†Qž:ö¯¿u(ab©½,¿à/RZÓrZëc߯üz[ß¡L:”_óçmÿ~…kÞx>ýï`µÓì¦,,"ºæ¸„¦X°Ü®­´!#åÉÉÁ¬ûë—w7°EbD¶,«p²J‘ùe³·ïœàò+Hâ(5~e÷£«ÕNÍ2¿ö”_óçmÿ~…ÚQÏ·ýú–º¡{§Kk3A fYB\F])»puÅX k‰„†Ä‘³ìÁeFi7©e;AÈäŒsŠ·VŠvr_x*3}ö”_óçmÿ~…ÚQÏ·ýú±¡ø.{éÚ^®¦.ÌÀ=¼ñ¹ÌjÅ€*X`ƒïQé^ ÔdÖ,mµ; ¼«¨ÞEK[¨ Èr™¶’ Î2{VrÅaÓk™m–»}̵…¨Õì÷·åþf_ö”_óçmÿ~…ÚQÏ·ýúèü5«É¥&¥öE[g…®´È£Ë…'qQ‘ÈäzÔ–M½Ï„õíVV—ÏÓÚÕbU`ù²l;¸ÉÀé‚*ÝjJ<׺ºZwnĪo–Ä?ÚQÏ·ýúiEÿ>vß÷èTZfy¬OäY,/6B¬r\G99ÀPì ;f®Gá-rSlÁ‰¸í£bdșܧŸ—O\tª•J1v”’~¤ª3jé2í(¿çÎÛþý ?´¢ÿŸ;oûô*Åǃõë[ofÓÙ`ˆ39!`¡¶–ÚJçø€Æ9Î*á½Xg6 mÓÿ´ÎeN-¿ç§_Ó¯µ%ZƒWR_xý…E¥˜ßí8¿çÎÛþý ?´âÿŸ;oûô*oxyü<úrIuíyf—XÐìÎr8c‘Ó ÐóŒàÖ6*©Ê#Í Q3¦àùe¹§ý§üùÛß¡Göœ_óçmÿ~…fbŒUò¢yM?í8¿çÎÛþý ?´âÿŸ;oûô+3bŽT¦Ÿöœ_óçmÿ~…ÚqÏ·ýú™Š1G*SOûN/ùó¶ÿ¿Bí8¿çÎÛþý ÌÅ£•)¦u8¿çÒÛþý Oí(¿çÒ×þý ÍÅ&(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-¿ïФ:œXÿKoûô+7ÆÍ>T5»½+Ü"ÖB>h¥†BÈ}ØÈ϶x¨_Ãl:ÞècþØOÿÆ«¶’öÈk×°ê"ClnfBÑœÉs†÷ǧóèc¹Ñ­t8§¾ÖnVæØ‚¶PÛ¾ ÖFCd}Õ¯¿<—cµq左߉÷PáÜ ´gÍw¶»úiýzu}&¥áfMON½·8ŒÜXM­÷‚:²© íÎ*vž¸5ÝZ|~ðð³€_Xê_k¯ŸäE—æcæÛ™3·9ÆyÅp¾ ùü#¨¤ßZ軚òéó_â5ía¤³<1ˆ®mvÓcÎÄác€ÅN…&ì­¿¡ÞøVê; OM¾”3EoqÌrB°'üVí®­k ç‹/þÅ7™¬Û_C …MàÍ!)¼îÆÆpO¶j¿…ü ¬kÚOÚ¬®,’4,‰ÁÎÕnʼ+}~x‘Gü}é÷òOþ"½|V'ê8Õ­úž,)b—½N:^äÃŶ$–sÚ] WÒl¬ÚA ·›»©&P©Þ9`# t5“¨x/4ïDÿÚêóY´R\¬!•apO™³jŽ ÿZÑÿ…eâOùúÒÿïìŸüE!øcâCÿ/Z_ýý“ÿˆ®HÔÊâÜ•MÿÍ>ÞHѬ{I8íþV%·ñv‚Útêq£iiíoj#ïlænXíÇQÇ>§4 ñLþ.Ðut³™¢Ó4È,¤WÚ ²‰•Á|1Å· f)ó„ÝÏ sÈÀÉ­#[6:WŠuøâ"Ñï%ŸMû^Òëy&F6©'¤£þ>µ—ÿ ÃÄŸóõ¥ÿßÙ?øŠCð·ÄEƒ(°è|É2?ñÊç­S.©wíUåkþšéÿÖšÆBË“E·ãþdsxžËû%ŠZß>­&†4RÌÉäªxXå°sŒuïÞ¤¸ñ6”tË‚¶º“jxpè *Çåg ’ẟNƒ½/ü+ÏÖ—ÿdÿâ(ÿ…aâOùúÒÿïìŸüESžTÕ•OÇðØ×Ó»‰‰âBÛW“IxádµÓ!²”:(LÆ[HbNw Œc©ÏþG½v𬡊þSŒò=èò=ë³ÿ…aâOùúÒÿïìŸüEð¬ ñ‰ÿ–¾ÿÁ|_üb¿<–SºŽ"ùþ:x³šNÎt%{.«OMt8íE„ÞÔû¨¾´ÿÑwæ²ãÍ÷{6½ào&{›ÛÝ#ìÖ‘<ædò‡ ’B¤j¥°1“ù׌HA•Ï«ú̦”0øPŒÔÜ[»[kêxxüCÅc'_•Å;hü•¤>ȧ7ý}í(뺮áGüŠ“××þÒŽ»ªùÌÓýò§©xOàÄ(¯>±ø‡wyáýo°Bº­íÕ¼W; ‰ÞeSß+q ’Gœ3Œ+uk[Xå‹ìÍ.ÍÏÁ£v×o›çÏa†QÔ0€é(¢ŠC (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2|Qÿ"–³ÿ^3ÿ趯’_ï·Ö¾·ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µôÙðeëúXzI|(ÿ‘RoúúÿÚQ×u\/Âùæÿ¯¯ý¥wUäfŸï•=MpŸÁ‰ÍÛø#I¶†Þ8Ì߸ŠÎ4c³wú;£+·ï?•¹þ!6Œ à»…!kËÙ#·‰a° Éþ‚Šèê# Øh¢?¼ßþ¬g9mÝ%Ãss›‹Á–Í%ÂjZ˜ºšW’kŸwAœñ$ž_~Ñåi.ºù“57=6ô0õ+ãƒ|9uwoiv’,bâMJeŽm f–Fð;s€Ip Ã_s¦Ù_ÛÙkÞ²‚{È®\ùý«Î*W"5X÷ɸ]L[*ýéÁRXÛšÚúÇÃZ hË4MÌöv#+ná¾HÁ$õQµ“$€³±êhú]¶‰ÛI1û’øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:뼋ûéç× p¸'hlò÷«ÆÎ$㋨Òo^†ø(óRŠnÅÊ*¯öV­ÿAù/ÿGöV­ÿAù/ÿ^OÖ'ÿ>å÷/ó;=”~?äZ¢ªÿejßô’ÿñejßô’ÿñ}bóî_rÿ0öQþuøÿ‘jŠ«ý•«F ¤ú0\è%¯Û®í!¸H U‘óyOó­©JU/îµëÿg8¨uOКŠO³j?óÆÓÿÿˆ£ìÚüñ´ÿÀ†ÿâ+^Ió!h¤û6£ÿͨÿÏOüoþ"ŽI2ŠO³j?óÆÓÿÿˆ£ìÚüñ´ÿÀ†ÿâ(äs!h¨f’k0í"D ᣷@IÎ@ìåRˆ5„àÏ9ñÂçG$ƒ™ E'Ùµùãiÿ ÿÄQömGþxÚàCñrH9´R}›Qÿž6ŸøßüEfÔç§þ7ÿG$ƒ™ E'Ùµùãiÿ ÿÄQömGþxÚàCñrH9´R4‚©c±’rOá”/5à-h‘º e¤¨ä€{ùÑÉ æD´R}›Qÿž6ŸøßüEfÔç§þ7ÿG$ƒ™ E'Ùµùãiÿ ÿÄQömGþxÚàCñrH9´R}›Qÿž6ŸøßüEDe•&û;Ä¿i$E|ƒNsŽŸ+víG$ƒ™QIömGþxÚàCñ}›Qÿž6ŸøßüE>I2ŠO³j?óÆÓÿÿˆ£ìÚüñ´ÿÀ†ÿâ)rH9´R}›Qÿž6ŸøßüEfÔç§þ7ÿG$ƒ™ E27,]]BÉmu88¯ÐŠ}KV•âùµŸúñŸÿEµ|ßxýkëÈ¥¬ÿ׌ÿú-«ä†ûÇë_M‘ÿ^¿¡Çˆø×¡ô—Âùæÿ¯¯ý¥wºOß¿ÿ¯ÿ¢Ò¸/„ÿò)Íÿ__ûJ:ïl?ÑÚèËò‰fò6*çóS^fbÿÛjz—…þ JšóM¬x™%–GHu$H•˜‹öKvÂú Ìǹ'½r–><×.nž?ìø&ótÿí{d†0]íVH÷ÔJÏ#¦Ë¨Woh(eÆÓ¼Œä``çŒ ‘tí.´Ie7Sù¤Ý[[¢ÈM»ß%H,J!9% â¹9—ss/k¶¡ ®˜ö6ÐÞ}¦âÎêâÝæo †<”Y>cÊÎŽXN n3àñåæ¡á—Ô!6WW:†ŸieàÈÚbµ‘”ÈÊ'ñ·!:pk¦}@›F´Ò.4ëK>Í ·º‡ÎT»WÁä/ëÉ«Yi7¢ö{+InÂ* ÞÎ\:ÄgÀ`;Z9—p(økËhßÜý¦ê]>b-¹²I-‚2Ùääàg®¡ªÞi°¹°Š ®Y¬ Hçb¨Þl±Ær@$pçœuÁèw,¡Ó´Ë8ìì-à´µ;!‚!.I' I'ñ¬ÖÒ–ûC²²ºbžK[Lv:ç|.’ßÈöÏN´›@eC㤛PòⳞešÖÙí­Un în|ÈŸs„VE·l‚F ¸É8³ñ+]Q»Ó쮦º´²šyU¢ ¶²)‘e Ù Ë ˆL{€ØX¸cjéï©ÜjV³ÜY^JñȲA* ‹æ‚èŽAa<»Ű–0]øOº±¸´ûuô)wnð^´7­u¹¤}ÎqÁó&•ð›Tï*AL(WÍŸ´[ï6ƒ Ù¹É7›ß$a·¯–ʸØÿ3"©ÛÁ;—v>¥ã=ZÛÄš…³ÀÆÞé-¬ì¿²®$kÇ6é6Ï´«ùQ±ÜÃ,¿"®â®ŠÏ@KA§‡P»Þl“­š‚’BÌíÀÙgsµ™”Èjí'ðí¤ñjHÒÈ­uã:ȹŠhÖ Œœcå0£aƒAÅ6ÿâF‹¦êWÖ7+:ËiÒm ù<¨ÚFU‹˜>TbÕQ°bK¾<·µ½°†H'³Yn•%K¸O˜ð¼3´O©'s¼B0ó3P´š€ôýLK××ËlÏréoÂâkˆåIˆÉ,fvËÚx]ªJ›z·„tÍkRkËã#ï‰axDª¨è#¸7+u'B:.1ƒ’àO­LóéÖò<2BîŽÍ…K!0¿Êv’2:pHô&›â~óBM6KK?¶y÷MШ&F`šVòÀë'î†áÜ$¿±¹–ÊVCq$hÊÒÈèϖ˸ã$‘ÐÏ@*ÕæíÖŸq#ö7â ®¸,bxð}±#tÇ })Ü]Lh•{w¦Îò»¬–òDþZ2D,ŠÊ#ýÄD |»p¤/ËGü úd~DV×vÖpËm:ÚEp¾Y’,FÌNY¾H‘ –ÛœoÃR¸É|;ãíÄú„–z|Û¤ã>lOæÆ¶£³G÷“å#|Ý2Üø“RKý~²N{…šÙâcq*ÀÌ’º¸mªrµ ¶à£,›ÎËÚ>€š6Ä‹P»šÚ„¶ÒÊž]¼cU lPBìàü͘çðͼ÷¥Ü%„îd¸ÓQãû<ìNX°+¸<²«cÀï}ÅÀbøÎÚTÛéÚŒÎ/d°†1!¸š6:Æ]‚&mÄ…Ç—F*|UÒm-‘µFò¤in†R q,Hí®®ÌDG*ŠÌ?(%AÝ Ûý†;xnî-å†ökè.cxÌ‘K+HÏ€ÊTŒM"á”ð}@5RÛÁV– ¶ÇSÔ­•÷­ÁK¥g¸F–Iv4Œ Œ4Òa••þnX.®™¯E­%é·¶ºŽ;Yä¶ifŒ*¼‘ÈèÁ9ËS9éóÁ‚§‡›/õOýIc¦Ç¦YImnå•çšà—uÎéeivã.q펽iºM´Ö¶¬’…V%8Þ§¤hPiÜOtU°ñ.| aâ+øþil!º™ \ΊHŽr~óª9f2-~"éêQéVSß$Ñ\‰ ·1K"Í€æ,žH]“'~3µrå6ìü-t˜´·×u+‹("Š;h¥6ÃÈh™Z'R±‚YJ)‹)þ j8ü o ójk:¬zy$7Bæ6bÒ,*ä«)Rp¥J®ã´ &ÅqŠ¿ü;&­iaÏ™ö¯ $¾dk†™U¢[0”î*…FîHÚÛiè?ŸP´³Žm>êóRº·I– uUìöÒ¸Üò`ôC1QÆÞ[nýk? Zi³D4ûË»K$ò‹YE:ùr4h¨…˜ƒ' `€áX' å·G¡x7OðýÔ7“Ü;ÃnmÔK*WÊ·'s‹XÿÞ à;þÍ2O"[h/®læ–Ú¼Š݉'òÌjÀËòJŽX®Üg~®HÙñGýÏýjåÇï »³±³‘aÑ­¥³˜»jy^ÜD¼B!–+ Ç3`áönÕ½¬ÇWK€«å‚¹>böY¯ûCó§q2¾«¬^ BæÆÂêÊÇìV©ywy’5Ì@Péÿ<œ³@6âV¼u¦6íÍçG €¿º»²o´ZÅïC(Æì4,¸ ¸ä¸¶î££}¶án­¯î4ëÀž[\Z4E¤ŒB0‘YH’ \¶ ÀÀžÒ‘/¢ò‰·¾²[)á3pñ†•‰-ÅØÎ嘱$œõÉ*ãßŰɩ[é·Z}õüò¬ko?”Ä+G3«“²í?g”uÝ•äAªñNI¯Yj.–HòÝJ±.ÈbI¦…äc» 09Ú2äU[ ÇÂQ»›©µ{éu0èÑj Ð b²*¨QŒŒM0ùŸÞx]¹°ü=‚+ëÔ…Úé·6¢Ýãû^÷Zk‰fŽBÀåOžp|Áƒ†%‹q<iÞÇ5­ôßb󦹚+p±ÁO²¼µ¶ÿDÔ&¸•aE1ZmY¦’Ý'T_™€%-µ6ìVb̾ŠåÛÇÚ Ô´ûA#ì¿XZ Ø¢óqåâ6a+¹FåB ’ _l– »ºÒ|#vñÂ$Ö|¿´S…Ýk$Çg<|È9ã?Z,IEsÞ"ñ–™á‹ˆcÔw¢H¥ÚRñ¢¢ƒÉÙL„rJƇ2î’é¶±»ÜyÑùRÜ$èS/@¬Ï+¨$„*ƒƒŸ:.>qJÀnÑ\…§Äm"ø"[[ÝOró¬ olðÜ1fŽGBZ)>KŽXmÆ[jüÕ¥«ÞjßÛÚ~—¥ÜY[ùö·Iuló«hTDÆ|Òs“ÐS°´W y4ÿ!_ËO–Yf•âH£b@-æ!BrXà°*Ût4Y5X§ÿFžÖâÚ_&âÚ}»â}ªàŒÊrŽò±ûØ8 |‘Ùý§aÿ?Öß÷õÆí;ùþ¶ÿ¿«þ5ÐÑG$Bìç¿´ì?çúÛþþ¯øÑý§aÿ?Öß÷õƺ(äˆ]œ÷ö‡üÿ[ßÕÿ?´ì?çúÛþþ¯ø×CE‘ ³žþÓ°ÿŸëoûú¿ãGö‡üÿ[ßÕÿèh£’!vsßÚvóýmÿWühþÓ°ÿŸëoûú¿ã] rD.Î{ûNÃþ­¿ïêÿÚvóýmÿWük¡¢ŽH…ÙŽ¬®Ñƒ+ ‚A“âŸù5úåýE]Ó?ägÿ\ÿAKÅ?ò,jõËúŠÉ«;µC¼Qÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýkér?àË×ô8ñô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄesvþÒm¡·Ž37î"³ìÝþŽèÊÄíûÏåD®ˆFƒ£%ç'=càí?OÒ›×MžÒ}ÎÊ[uºÂ¨>î0EºgŽíŒqƒKðvŸ¤Çd–ó]0´'Ìe9d´ (ã`ÏûÜôâº)ÜG/tûk{Kh¯u¶¶kY|••BË-¸Œ$òä±"•ÎÎ26[“ÂðÿcèÚu¶¡{iý‘³ì×yfO–&‹æÞŒ§*ퟗ¯LVí\oPðt:¥¤Ð]êÚ›µÍ©´»•8Þæ<¹@ÛP°ÈØÚ6pûÇ;ørÞóUÖ./ …­¯íVÓÊL†d*D®X`«8(‡ Œç ]Ú(¸Ðøx-Í­ÕÞ©¨_\ZÏçÆó´`«’=»Qq‰\äÄã$…?TÐΣk}§{asm°«ÚˆŽä¡`Dˆã¬kÓëZŠC0¿á´†I%°»½°™¢Š1%¼€‘±¥mÇx`ìÆy  ’C}ẠÁv1.Ô¼½Uû, ˜V†V–)Tlá•ØáGîÀÂìÚ%î# Kð­¦—ª¾¦·w·Ry¦G¸6æ‘` xñî„€2À6…Mð¶-¢²Ôu­bXD–ë"¢#Wv ¿;cŒ¬ªvò¤¡¢•ÀÉÒ4$Ñö$W÷³[C‚ÚÚW_.Þ1Œ*…P[TrÌëËgZŠ(QETšGß¿ÿ¯‘ÿ¢£¨ê†hä•ཞ+oeUB3€;©=«ƒI»“#‹áííÅÛ[kSÝÃåX´Þù`É-½ÓÜ1’ ~bqæ|ÌL²3!k¨ÐtûËFÔîïÄÝj7båá‚C"Eˆ£ˆ(rª[" ÙÚ1»ã%˜¼ÿ ÏýñÿF/?è'sÿ|EÿÄVœÑî-{tV&/?è'sÿ|EÿÄQ‹Ïú ÜÿßñsG¸kØÛ¢±1yÿA;Ÿûâ/þ"Œ^ÐNçþø‹ÿˆ£š=Ã^ÆÝ‰‹Ïú Üÿßñbóþ‚w?÷Ä_üEÑîö6è¬L^ÐNçþø‹ÿˆ£Ÿô¹ÿ¾"ÿâ(æp×±·Ebbóþ‚w?÷Ä_üE¼ÿ ÏýñÿG4{†½º+Ÿô¹ÿ¾"ÿâ(ÅçýîøŠ9£Ü5ìC¦È*Ïþ¸'þ‚*—ŠäXÔ?ë—õ§+oo(IXÐ '®Åfx§þECþ¹QX·wr–üQÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýkér?àË×ô8ñô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeq–¿í.ü?¢j)a0¹Ôî¡¶k2ã}¶÷E2?}€H„6>o6.›ÅvuÆYü>·´†ÑVó2[Åd¡ü£ËÀð™¿å¢Û[®?‡ËÈÎæÏ·S ÒÓ|g£j"Ú5¼O´J°—XÒFŽ6–4xÃ9E :„,qù@Ü †Yøë@¸¶‰¤ÔaYÚ(¢ŒHß4‘¬ˆ‰”™•ÆÅÚðØ\«™à¯ìíiÚf.¬n<Ï'ñì¶ëŒnþ/³ç9ã|rhž þÇ‹NOí;ìwQ\gÉÛ¿eˆ´ÇÞ8Î7çŸOz4Tx—Hk¸­ã»ó<Ý›fŠ7xp )˜³\)`NôÀ;—9³øÎ+O è:ÝÅ“‹}MRI‚8cl†Ýçgè7…r À' scøp‰ý•ºþ[Oû$ÒY+M›,lI &8˜FNÅä;±ÜA*wlü9öM7ÃVŸkÝý‰³çòñçm·xzgåûû»ôǽ7Šlà½Ô-®c˜IkuötKxd¸’QäÅ!}‘©`£ÎU'nOÌG¨xÇJ´6éo:]Iq=´1˜ÉòÛΑ  „3fwÆÓš£cà™t[–¹Ñµ4ŽUgHîØÌ‘@ÑÀž^Ð’¿fkœd0cóQÚÎÞ YâÓ£žÎ墒y${q ¨/8 îwmù  º~½¦ê— ¤ÎÏ·ÌBð¼k2d ñ3$NWæBG̼üÃ9¶ž&»‘ÚæïN† ,ßÉaÄwFI<ÅœÀ¥ã(0¬à•˜‚ˑ̱øcÁ–Þ¸éá"ƒìÑ5¾žÌ长irLòŽFÀIbTü»d´ðÍÜnÖ×zŒ3ébþKøíãµ1Éæ4æu!s•W üª¤•\œnV4öþ2Òd³µšIœ™ ŽVk{y¦‰K eMâ07°eÚŒÛzarÀiþ6Òîô]7P¸ó­šòÕ.^?³ÊâÙ[ø¤`˜DÈlHûU‚–šƒNð}Æ6É©BWOµ†ØÌ,ÂÜ:FLb@Øò˜Å_‰ B™—¿ ÛQðõ¦•u©ZÊmôá`&“OY a $!܈œ‚¢CÉ`‹´¡ƒ@:X¼Y¡Ëq4+¨"ù ,rÉ"²Fo1 „³mÎvØÛÍÅZI·yL—HêÊŸg{)–á‹FØJyŒW9 FÿºØ¡{àȵ !4Û‹×ý²öæFf[•¸R£$€T\uÁÎÞœðj~½×,ã]^ûO¼š Öh"}76 „t;âi 9"Fþ0T 6ã@:;Ë}BÑ.m¤ß炤pUåXAR@"§ª:6˜š>•Œb±î$AÃ,ňT^rN'K“zŠ( £Óì,{‹H&qpi# qå§Ô•&‘÷ïÿëäè¨ëJ[²%У=ß…mî/íÞ;>ž‘5Ìin£óI®$»€ƒ,r¸2æÆ›ƒ«[´Ö–ä#”‘%³ò¤°C)ÁCЃ\d> ñ…Íñ’âÓP‹e…Àx­ü‡ºš+é.¥t¬Îç<íBeP65ØxvÚí%Ö/îíd´:踎ÞVF’5X!‹°²ä˜‰cÁ@ÖìVEÿì}3þÖ÷áÂì}3þÖ÷á®ÑEØY¿±ôÏúYÿß…ÿ ?±ôÏúYÿß…ÿ »EadRþÇÓ?ègÿ~ü(þÇÓ?ègÿ~ü*í]…‘KûLÿ uŸýø_ð£ûLÿ uŸýø_ð«´QvE/ì}3þÖ÷áÂì}3þÖ÷á®ÑEØY¿±ôÏúYÿß…ÿ ?±ôÏúYÿß…ÿ »EadsÚgü‚¬ÿë‚è"©x§þECþ¹QWtÏùYÿ×ÿÐERñOü‹‡ýrþ¢°—ÄˎüQÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýké2?àË×ô8ñô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeW7Žt[èúÔo1¶Õ®¢´µSÞew+µ‡A´«dç)Á9óΓ¤¢³lõý2ôZ*_Z­ÅÚ†ŠÜÜFÒ嬅@V!ˆGV;I ç-µý2æÍn~Ýkò>ÐêדGbÅX®È„HÃ)Î$JŠ©&©§Å©E¦Éj—ó.øíZeºóÈL䕹ÇcéY²x¢ì}Q¶Óïnÿµö}šÞ/,IóDÒüÛÝTaQ³óuéšÝ¢±¯|Kg¥é }©ÆöS&lf’#q"Ä¥œ W*ÇhÏ pÎ*ðÕ4ö¾{¿µ7hÊ™|ÅfRê ç •V`;…'   tUM?TÓõkv¸ÓoíoaVØÒ[L²(l‚T‘œǽcYøÊÖëKMB}>öÆ íMÕ«]´*.P'˜B°ª¶ÞpåxÉè¬T¤¢±µoèš5¾¢÷Z©›O€Ï=ªNžp\ „ƒ–, g,£¸«i­é2]ÛZ&§d×7Q ­á[„/4d9eÀ'#Ž ^¢¨Å­é3Çq$:”‘ÛD³NÉp„E.åv üªWæðG5ž"Ñ"ÓbÔ¤Ö4ô°™¶Gt×("vç€ùÁ?+qžÇÒ€4¨¢Š(¢Š*þÙm,ío<%päI bÕ^¡‡÷}*jŽÊÆÙ¯^vœ”œ"…Ðå¡èI«§{èL‡ý§SÿŸ‹?üoþ9GÚu?ùø³ÿÀfÿã•^)<77Û¼­Z)?³óöݺ›³c9ó>“[®>éô«6š>§gå…Û]ÚÉ“A$ˆØ$0|GáZëßð&ÁöOþ~,ÿð¿øåiÔÿçâÏÿ›ÿŽUì[?úyÿÀ¹øª?±lÿéçÿåÿâ¨×¿à+ý§SÿŸ‹?üoþ9GÚu?ùø³ÿÀfÿã•cûÏþžð._þ*ì[?úyÿÀ¹øª5ïøŠÿiÔÿçâÏÿ›ÿŽQöOþ~,ÿð¿øåXþųÿ§Ÿü —ÿŠ£ûÏþžð._þ*{þb¿Úu?ùø³ÿÀfÿã”}§SÿŸ‹?üoþ9V?±lÿéçÿåÿâ¨þųÿ§Ÿü —ÿŠ£^ÿ€X¯öOþ~,ÿð¿øåiÔÿçâÏÿ›ÿŽUì[?úyÿÀ¹øª?±lÿéçÿåÿâ¨×¿à+ý§SÿŸ‹?üoþ9GÚu?ùø³ÿÀfÿã•cûÏþžð._þ*ì[?úyÿÀ¹øª5ïøŠvÐýžÒ7nòÑSv1œ VoŠäXÔ?ë—õ{Of}2ÕÝ‹3B„’rIÀª>)ÿ‘cPÿ®_ÔVrÖüQÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýkér?àË×ô8ñô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeyõ‡Ãë»8lsq –Þ+ Øs´ÉÚùøù~îË(vwË>x#ƒEp'c áto]éº ZHlãÝi’<ÉŸš;U¶ ¥¶äó ¥GOœtÉÄz€eÓ×L7‘éóKmym<®bËž-ÔW’²å×=ϊ諸ì:¶ð¯¾•Ú-qjÚ|²º\ÌŠßg«§”¸I ò‹ _-÷Sh ¬ºW^»“Â~ÓÏLÔdÒ|¯´[^9M¶Ùâ8>[tg 2½»WgEÕ<¨^hÚ…•–¡Y&£§ 7¶ Í «Fó:2î,eÎp»núVmþƒu®j#CŠCu©3_Éa2º¥ÔwˆgUMªò¢íG3 ß(S^¡EžðÞ‰>›qyuuC5ÂÇ£q|ÅP¹’l2ç c““» „ÞÖõ[hWÿÙöï§éÏmjð\<‚i³Û†rc]ˆ±À I#‘· ßQEÀâuo jwãW·…4ø­îຳM#)–XÝU„%HǘۤF;òå“.6—…u}GWŽó}¬!¯,ïe w0Qå4[âòÔ*HvXLà·ÝMª²öÔQp8TðEÜG‡mmÍ”ri6 Ž‹•In{Y¸!xWkwËc#~v·"§Ô¼7ªj7vú«ÛY%âùË%µ¦£qhq רyy` `?å˜-ÙÑEÀ©¥Ø®™¤YX&À–°$+å† …P8 Ì@ã¹'Üõ«tQHaEPRi~ÿþ¾GþŠŽ£¨ –îÎ[Ÿ*Þ RY€´Åùq§û¾µ¥7«&GªZͨ[O§éš’ÚiÉoæZÍba ݤT H$c°ËÌJ€À?Yá€òÜëÚ‡‘Vßøßüní+ÿùò¶ÿÀ¦ÿãt]wZŠÉþÒ¿ÿŸ+oü oþ7Gö•ÿüù[àSñº.»­Edÿi_ÿÏ•·þ7ÿ£ûJÿþ|­¿ð)¿øÝ]À©¦È*Ïþ¸'þ‚*—ŠäXÔ?ë—õ£g [ÙA Z8Õ 2+;Å?ò,jõËúŠÁîRØwŠ?äRÖëÆýÕòC}ãõ¯­üQÿ"–³ÿ^3ÿ趯’ï­}.Güzþ‡#ã^‡Ò_ ÿäS›þ¾¿ö”uÞ¿Üýßêk‚øOÿ"œßõõÿ´£®õþäîÿS^NiþùSÔÓ üŒ¬˜üM¢Ë¥Xj‘ê0µü±Ãk '÷²;mT®ì䌌ãÕåúo‚5{m;H·’ÝXÿgÜ­¶äÙÞe·Ÿ´nÀdLû‡ÞûSÎíÜè=2 –âÞ98I:‰‘€#<«Aö D-żs p’(u##FyVƒì@"¼ï@ðmý†ÓXlÕâºÓ<§ó”´QG¤wì.BL­Œ Ü6Ô~ðEì0i˨غþþÞ;ÄûOÊÖ馤l„+`¡2ÿÅÜT`²Ó+&ipiv‰–i-µ ¿eò-e•å܆A„E-÷TžGæ¸X¼/â6»Ñon-¦mJßû<Ítg¶Æ¢%ZG .ò|ܬl±²’rÌ̯»†îçðׂô먦´ÿ+í¾EщâÛg,gŒße)ç>™¢È¢ÇQƒPMð¥Ò ¡ÿk,'°èêr§Ž¸ÁèÀ™/o-ôë ›ë¹<»khši_íE“Éà•Èjž–ûÅÖ.ö¯>“Ú¤­%ÁbËWÊÁòÛœfhƒÁÈ9«7_ð•Σ7ˆ-Í–îÖà,óÉ Wr‡Ê "Vù¶“À¢RŒ¢$ÜYÞê•®—n³];€í±(šY$l…D˜à€' &?RµÕ-ÚkWr¶:KE$m€pÈà2œp@È ô Ön§f’è6qÇ¡Ìñð­¥µÂÛOl6L®ªgiÔm.?u¹}[A×5›{'Õ-õ »HZ`¶¥,$¹;„[T|©YÀ)ótL”XE¢¼¢òÝ Ö­t©Úím/ô×Yޤ²ÜGgß%“æI&   dÈaŠ¿¤x;RÓ¬´Ý–ÓG=µ®“‘ö¼…™f"í±»¼©»þyüŠvü´XH¨òÝ/á±i1s4O4iƒÊ!@Ç=82'çìkÌì|©¥ †h5´´[éš{xVéÖæyQ¡W!RVJÂA»€YÛ:w…Ž›ñoâÐáM>?´Ek,K[dh­Ší\‚ª]n†u‘Ž0ä’ÈÎÞòÞêk¨a“t–²ˆf#k”Wž¿+©ã×ëS×7dúŽâ-aD½šÚúþ9£»ŠH<µO³Ã,@ü26p§Ž™®BÇÀúšZfƒPûAkE¾™§·…nnaw•%r%a$¬$¸°XSª?Û6mû'Ÿûÿµ}“fÆÿ[äùÛsŒ«ù³Ó¶sÅp:ÅŸ‡õF[øtøtvža¦ØË}¤q»Ek¶xòÃËë>Y‘L¥•Nâj§…<"ØépÝxìð5Õ­ÕË‘ù±ÿf˜Ù]C8˜°daƒæ6A Ôì«ÔV¶²^ËvMäñ,r„UŒ&1±Ou'«ÎðåÆŸ¤[ˆü¿.êçÉŒBBgs®8 #(ö b¶´¿ÿ_#ÿEGUOv)öCÐJóò‹ÿˆ£û!¿è%yùEÿÄW“YVÎŽKG[Û¶²–ÈHíV¾rjM“æËå™÷;ˆø[Œ®¶ú'‚þdzZþÊò?±¿´öÙqö/ìðïò¶ü»|ß7;xß¿¾kM;cWû!¿è%yùEÿÄQýßô¼ü¢ÿâ+NŠ4ì3?²þ‚WŸ”_üEÙ ÿA+ÏÊ/þ"´è£NÁc3û!¿è%yùEÿÄQýßô¼ü¢ÿâ+NŠ4ì3?²þ‚WŸ”_üEÙ ÿA+ÏÊ/þ"´è£NÁc3û!¿è%yùEÿÄQýßô¼ü¢ÿâ+NŠ4ì3?²þ‚WŸ”_üEÙ ÿA+ÏÊ/þ"´è£NÁcÆG›O¶–C—x•˜ã© f¨x§þECþ¹QWtÏùYÿ×ÿÐERñOü‹‡ýrþ¢±—ÄË[ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µõ¿Š?äRÖëÆýÕòC}ãõ¯¤Èÿƒ/_ÐãÄ|kÐúKá?üŠs××þÒŽ»×û‘ÿ»ýMp_ ÿäS›þ¾¿ö”uÞ¿ÜýßêkÉÍ?ß*zša?ƒ”QP ÛCiغ„ÛM³Ê˜H6>òmn‡q`:äc­yçI=Tfx–á-ÚT:³¬e†æU 1©²äöÜ=hJ(¨Ìñ-Â[´¨&ugXË Ìª@bReÉí¸zДUmoI½¿šÂÓS²žò Þm¼WÒG´àîPr0H=êõQP[ÞÚ]ãì×Pͺ$˜yrÌoÇð¶ÖÁèpqÒ€'¢ŠŽiâ·@óJ‘¡e@ÎÀÌB¨ç¹$;’IEPEGñJò¤r£¼-²EV£`6¡Ã)Ç¡½I@Q@Eku%”·`ÙÏ*É(uhÊcw`z©©j("»¼–çʸ‚$ŠA r~Elçpþ÷¥];ßBdYþ×oúÞ~qñtk·ýo?8¿øºgömÿüþÛà+ñÊ?³oÿçöÛÿ[ÿŽVºù~$þ×oúÞ~qñtk·ýo?8¿øºgömÿüþÛà+ñÊ?³oÿçöÛÿ[ÿŽQ¯—âÿµÛþ·Ÿœ_ü]Úíÿ@ÛÏÎ/þ.™ý›ÿ?¶ßø ßürìÛÿùý¶ÿÀVÿã”kåø€ÿívÿ mççÿGö»Ð6óó‹ÿ‹¦fßÿÏí·þ·ÿ£û6ÿþm¿ð¿øåù~ ?û]¿èyùÅÿÅÑý®ßô ¼üâÿâéŸÙ·ÿóûmÿ€­ÿÇ(þÍ¿ÿŸÛoüoþ9F¾_ˆþ×oúÞ~qñtk·ýo?8¿øºgömÿüþÛà+ñÊ?³oÿçöÛÿ[ÿŽQ¯—âÿµÛþ·Ÿœ_ü]Úíÿ@ÛÏÎ/þ.™ý›ÿ?¶ßø ßürìÛÿùý¶ÿÀVÿã”kåøZÆ7‡O¶ŠA‡H•Xg¡f¨x§þECþ¹QZ6s5Å”8¤\Ó$f³¼Sÿ"Æ¡ÿ\¿¨¬ú–¶âùµŸúñŸÿEµ|ßxýkëÈ¥¬ÿ׌ÿú-«ä†ûÇë_K‘ÿ^¿¡Çˆø×¡ô—Âùæÿ¯¯ý¥w¯÷#ÿwúšà¾ÿȧ7ý}í(ë½¹û¿Ôדš¾Tõ4Â#+Èt¯ êÐè~°–Êag§K§j@bpÑË$¶áòq’ÈEó:“…!ìzõÀŽƒÌô£¯&¡0¼:é‚k7y„QKæGx²Å±äs]¾dHàa’AE!'Ô#ñ²XF³jðÞ;mÔ%· cIMÝ—ÍAO,EæÈ?.ýà·›^‹EΤÄpA"$Ú¼‘Ê·±>àÌaŠ+¸ã„Œ ì|ƒ+ð|ÙFpû‚“Âë'ı6¡ëÛ[Å{¼÷J™Å“¯2;¿ÌÞiܰà .Ò‹è4Qp8[%šêÕt˜lïb¿·×f»óå´’(â‹í¯#2ÊÊ·ÄÅBI່͒oÝZhvÞâÚÎ{ûµFéæÌHrÀ‰A1ÞC#)lñé”Qp<ë\µÖ“Ä1Cfú¿ÙÒ{[uTk‰´cK'š²*óHå’`A}Áv´ttX5+m#G·–-v-"-:Å/£U¹YQ‚݉ûÐD¿gÈø6ÿË:õ:(¸oöoIe¬ÝùúÒµ¦˜fÒ¡ ó$]˜ /Þwˆ#ä¶áæ+61Õêò:hžwú²Ýù{þïÚ3Ügþ_ŸŽû|ÎÛ«v£š®$Ñ$ˆ\+¨ 2ÊyîÄEÀó½šçصT³ŸZ3·–f–âÆÅ3/š» acóHkFUl°P¤DKí#¾ŽÞÕu[­vãEÝ9W¶¶¼†`ø‡ËUÞä§ü|ó!Æ{cËÏ¢ÑEÀæíüÏøKt¿õÞoö<¿mó6y›¼È|¯;Ëù7ÇÆÜqŸ7o®’£Ž¢y^8‘fß#*€]°'ÔáTgÐÚ¤¤0¢Š(©4¿ÿ_#ÿEGQÔvWÐÙMz“¬à¼áÔ¬à-Pê iOvLŒ/ýªÛV„j²}¢ûR´šö+›]f{»YÌŒ¾ÈÜ*F Ího”[»w‡g&ƒ§Ü]\Yiëm=Ûï¹’9Ѧl“—!2Ç,NO©õ«ŸÛVôóÿ€’ÿñ5­™7F…ŸýµgÿO?ø /ÿGöÕŸý<ÿà$¿üMathQYÿÛVôóÿ€’ÿñ4mYÿÓÏþKÿÄÑfF…ŸýµgÿO?ø /ÿGöÕŸý<ÿà$¿üMathQYÿÛVôóÿ€’ÿñ4mYÿÓÏþKÿÄÑfF…ŸýµgÿO?ø /ÿGöÕŸý<ÿà$¿üMathQYÿÛVôóÿ€’ÿñ4mYÿÓÏþKÿÄÑfFv™ÿ «?úàŸúª^)ÿ‘cPÿ®_ÔUí=Y4ËTu*Ë Á¨ø§þECþ¹QXKâe­‡x£þE-gþ¼gÿÑm_$7Þ?ZúßÅò)k?õã?þ‹jù!¾ñú×ÒdÁ—¯èqâ>5è}%ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¸/„ÿò)Íÿ__ûJ:ï_îGþïõ5äæŸï•=M0ŸÁˆÊ(¯>°û'“¦yOü&þm·öžÜ}«Óí>oý2Ù¿nwþ«Ëÿ–UÁc ô+ËÛ[×áÐô I¯!¹¿½ÑÚâIÞâXå²V`Á[bª;»1 ¹ŠíUE¿£êZþ¯caÿ ?g’+¹ 刎á¥XͶݲ´)`ÒȤ¬eq•#x,¥‚ç Ñ^I£ø‚ù´}SPÊAyyg=Á‘¢Š+E’Æ)(ÞR<µgY3±Wï13JÖ//u9ï/¯÷^Ký›Ù&Š>Q5I /µ£WÜ6‚NÕÃJNÕù(\õê+Ì×ÄúÌ––fÏYI¯n–ØßE$1Ⱥ]ÃÜÛGä@¬ ‰f]²1ÝpÀ«ìô ›§—V±º¹{£§ÞyUVIùmW ÈG 8©É*ÀlÑE†QEQEQEQE l¹–u·‚‘8Bd˜©'j·@§ûÞµ5eØ_\GãT°Y1k4sH›GÌè,œõàHÿŸ°«¦“näÈÓû6§ÿ>öøßün³jóïgÿ-ÿÆë.ãÆrÇâÇÑàÑîî`‚â+k‹ˆ¡™Š<ŠŒÛ‹b‰±i€í8]Ù~ñŠuÛC¨ÃcŒÿÚ{£†ä¾Ï³Ï#h0©àç«|Þc·ËµcrǰµîufÔÿçÞÏÿ[ÿÑömOþ}ìÿð%¿øÝgß&¥ÿ öm»}Ť÷Oh‘[”Ì/n¡A1ÚÂWÏÍŸBµ&ƒâ‰µ{‹žÂ;x5;&Ô,. ŒÐƒ|Õ(¢7ÄÑð¥ÇÞù¸ŽXö {—>Í©ÿϽŸþ·ÿ£ìÚŸüûÙÿàKñºãôÍoÄ:üq›T‰õ[¸"7 fº{C ë *<ÿ0D­´K!'(¬EÍ/Çww:6xšT—Îú}¥Ìò] •&¹XqPЬnæ\ülUùËÁ¯s¤û6§ÿ>öøßün³jóïgÿ-ÿÆë‡Oø”øWÃöPÔ¢±™'šåT̆kxæ.«*oiÐ.Üá˜ìe}BŽXö {˜ÿfÔÿçÞÏÿ[ÿÑömOþ}ìÿð%¿øÝlQG,{½Ì³jóïgÿ-ÿÆèû6§ÿ>öøßün¶(£–=ƒ^ç<Ó]¡ÁŽ×ðšCÿ´é©srò**Znc€ ÒïÝaêúÔúT–³Ko¿NeÛ4èIh˜ãi#û¿ãô ïê7ZœÑÜÍkä[¼êm÷“#’;g¨úþ'³ê´ìcíes¡¶›íÏ·o˜Šûsœdf³|Sÿ"Æ¡ÿ\¿¨«ºgü‚¬ÿë‚è"©x§þECþ¹Q^kVgBØwŠ?äRÖëÆýÕòC}ãõ¯­üQÿ"–³ÿ^3ÿ趯’ï­}.Güzþ‡#ã^‡Ò_ ÿäS›þ¾¿ö”uÞ¿Üýßêk‚øOÿ"œßõõÿ´£®õþäîÿS^NiþùSÔÓ üŒ¢Š+Ï:BŠ( Š( Š( Š( Š( Š( Š( Š( ±çÓ4›ËéfÔWQKˆ¤a¶rÜÂv:E¸n„Œ‚c^ þبcûe̳­¼‰Â$ÅI;Uº?Þõ«§{èLŠ‚Çâò£ ÒE°áþÔÉ# $‘Ë$ƒjáÜ3|Šs•’+Á{ky ±Ïl÷/,w fá÷˸t`͆ÃÀ«ŸfÔÿçÞÏÿ[ÿÑömOþ}ìÿð%¿øÝk¯oÄ›ƒÞiRj0ß´w&꤆7û4ß*9BÃqÉ?/sTôÛé7 =œªå h;™$‘+dDœ/ÊGʼ|£>Í©ÿϽŸþ·ÿ£ìÚŸüûÙÿàKñº5íø…ÊêºA+or«ÛÞÆD†IÙÙƒc#%Üœf\m$W7'†4¶Õ,š).Éíž dÓ®ŒªÐlòÛ{HP¿îÕ †=æ<¦îõÖ}›SÿŸ{?ü oþ7GÙµ?ù÷³ÿÀ–ÿãtkÛñ ™wW…î¬,¬¤´½XÛ­µ·–·HÑF¯¨ ¸l†‚#»9ùzòs¹ýµgÿO?ø /ÿUþÍ©ÿϽŸþ·ÿ£ìÚŸüûÙÿàKñº5íø…ËÛVôóÿ€’ÿñ4mYÿÓÏþKÿÄÕ³jóïgÿ-ÿÆèû6§ÿ>öøßün{~!rÇöÕŸý<ÿà$¿üMÛVôóÿ€’ÿñ5_ìÚŸüûÙÿàKñº>Í©ÿϽŸþ·ÿ£^߈\Çdâhœ´‘°*CZÌCB6SàØ—QHï&ÔpdzgƒŸîUÆší v¿„Òý§MK›—‘QRÓsfsÿ~ë£Ú×ká2å‡qúz²i–¨êU–‚QñOü‹‡ýrþ¢´­¦ûE¤3íÛæ"¾Üç¬ßÿȱ¨×/ê+ît-‡x£þE-gþ¼gÿÑm_$7Þ?ZúßÄÿò)k?õã?þ‹jù!¾ñú×ÒäÁ—¯èqâ>5è}%ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¸/„ÿò)Íÿ__ûJ:ï_îGþïõ5äæŸï•=M0ŸÁˆÊòK[Gð¿…Ú ¯Z­ö›¹Pdþ̸ÝÇ'ç€$%ÚƒñëÔWgAçÍâ)’c¿‰þÓ¢™ak¹·o³IË'˜¨!híÇ̤þÿÕ“V~ ×m­R;]BÊÑL·sÅö­Ößm¯nwF!h¥‘ñ¶?Ý!I˜Ie#ר¢àqž+Óÿ´¼[¢Ãý¦j»l/[ÈÔŸlkûËa¸.O›œtèO=>×:®‚×Úl:»‰–ñ#–öB®dK+5 £˜™–"0ŒÏƒ†HS¢‹Àè>'ºÕ岸¿ÖRÂîu´h4¸áV[¨ä†'ye 3ʻն¯—–#ç*ÇÄþ'¸´WOS5 šapÖ2És Þ5Š?(bI¤’3¿+e«Ôè¢ày½Ï‰|Ekjá.ᙤû\K$‘ˆü”·½ŠÜÌîÛ$’Gb»b€+ŸGÔµý^þÆÃþ~Ï$WrËÃJ±›m»ehR2Á¥‘IXÊã*FðY}Š. ðÞþMLkW·7ÞmÝܶ·rÛ €CæYÀÀ¨p^J ÄñêwÝQE&0¢Š(¢Š(¢Š(®^ó_¾Ñ¼c¦ÁFtÛ™¥[ØÊåÉcg L‡±N¹ÉÆÒüºŠË’ÇHº›PMVÖy ÑËk•ŽR £ˆH¹N91¯=F8ÅiOvLŽkKø‘©Ê— Ömšòíç°Š8¦Û ŸÙí¤@þLR¿™‹”ÏÊWqq¸ ì_xÇQ¹‚)tí2{kuÔ4ë[‰.VxZg·vGˆ‚ùs$1`çp7 »ÞO5ÃèEq4¾sÏmö¨$,Qñá‚•Š<¨;IE$df£—Hðœ×LÚl«ä<2Evó¤HñòÜF  u«»Ø6go­™7F^›ñÞ-K§O-½ÔVI5Ñf‘Ò[…nã>HæTÎ特$G‚›ö<5âËsû4Ýé_`]OO7öƒíVؾX}à™® erX!ùjºè^O±…Ó®BÙùòîv#C·Ë“oC «¼ÅFÒJäV…šèVÙÿf·¹û>ÐÙZþâsåÂveyÿªNNOËד’Ì.ŒÿµjÖÞ!Ƨ©ßY¬—{-Óì±I§Í|*ï æG!Rƒ÷Ž Êß uùN~‰ãûÝBÊÅ#Ñ'žK³ÛE4—q6y,Òëç®ÕU/½‚ñ…ØŒXªl}‡Ã¿Ú?mòu ÞoŸä¥}ŸÌÎíþGú½Û¾|íÎÿ›ïsE…‡†tĶK;+˜ÖÖTšäÜ®¶âÙO#œDóõëÍatSÓü|Úhò.’.,à72\(›¨àh¶ÆÉ p¡òÀÊ—9QŸá¿ˆ7·ðèÖÒiww®ööi{w“çM R"1j–Ý"7aNuÍ+þÒ¯¦¸Ž –S,/g¸ ‰1E8é.Ãõ.ÖbFI¹o¥x^ÑíZ KØÒÕ"Xá uå-BÆÏÜwP©‡`XlN~Q‚Ì.M'Y¸Ô¯'¶“Oû;YþêñŒÁ‚O…`‰ó©F¸íáÐcvõMŠçìWBÓeŽ[K{˜¤HŒ%Ä“"–.K’?xÛ‹6æËeÜç.ÙÐþÚ³ÿ§Ÿü—ÿ‰¢Ì. +?ûjÏþžð_þ&í«?úyÿÀIøš,Âèä5}j}*KY¥·ß§2íšt$´Lq´‘ýßñúw‡u­Nhîfµò-Þu6ûÎɑɳÔ}u’7‰¢rÒFÀ© k1 =ÙOƒb]E#¼›QÃZÍž¹^ƒœ,õ9¬î\Ó?ägÿ\ÿAKÅ?ò,jõËúн§«&™jŽ¥Ya@A àUÿȱ¨×/ê+È—ÄÎŰïÿȧ¬ÿ׌ÿú-«ä†ûÇë_[øŸþE-gþ¼gÿÑm_$7Þ?ZúLø2õýžÇMð¥¥Þ™¨øcíÆÂÕ.NŸd‰ym¼+4²¿˜ÙØ¥™‹ ]ʆ+¯Q^_§kwjzžÝwË´šþGMGì€ýªT¶³ų¼óœâ-­&ÌÆTQ¢x£ÄW÷º9ŸR²¥ŠÈý–YBÉv’CË*°—™åÖDE1üÃù,=BŠó¯éRßx«U»‡NÒ/ÞËI´Á¦ÇeónK€uÃáNøŽÑ•ëSŬÏk}¥¶¼÷ övÖVrDQ¤æ¸ ¦õ$Ã’_ªaCÝRhaEPEPEPEPPÇöË™g[x )„&IŠ’v«t ½ëSW'ªê—ž$‚Éu=VÆÖu¹–C¦X ©Ñmå|™HP$~p9#ž•tÒmÜ™_Ùµ?ù÷³ÿÀ–ÿãt}›SÿŸ{?ü oþ7Xö~,Õ(N¥¥AÙå´±ÔÙ.0ñ]ΰœG ­i㌀ýìÀÝ_Þ4¸ºÑtxo`óµ{¸´òƒx_´¤ðù7 µ6ùwGg#ŒoZÓ–=…¯s û6§ÿ>öøßün³jóïgÿ-ÿÆëð·õJÞÂÊ;íFæÑ&y§¹H"B¶¶R1;cÊ«“Ð9Ýè§äбøŠ5MNÒ=?D¾šÆo³ &Ì^34qÈ§ä¢ «*-*‘†À8]Ç,{½ÎƒìÚŸüûÙÿàKñº>Í©ÿϽŸþ·ÿ­Š(å`×¹ömOþ}ìÿð%¿øÝfÔÿçÞÏÿ[ÿÖÅrǰkÜÇû6§ÿ>öøßün³jóïgÿ-ÿÆëbŠ9cØ5îcý›SÿŸ{?ü oþ7GÙµ?ù÷³ÿÀ–ÿãu±E±ì÷9æší v¿„Òý§MK›—‘QRÓsfsÿ~ëWÖ§Ò¤µš[}ús.Ù§BKDÇIÝÿ gxwQºÔæŽæk_"ÝçSo¸ü왑Û=G×ñ=ŸU§ck+ ´ßh´†}»|ÄWÛœã#5›âŸù5úåýE]Ó?ägÿ\ÿAKÅ?ò,jõËúŠóZ³:üQÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýkér?àË×ô8ñô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeQ^yÒQÔ´‹mWÊûD·©åçoÙof·Îq×ËuÝÓ¾qÎ:šµ[[ÇooE J8ãPªŠpªJ(¢Š(¢Š(6 ÆHêéRÜng_>òYR6l‚QŠ¡Á#* pH­*( Š( Š( Š( Š( ©Úý†ÛVšöæþÕxá‘a‘‡–ë aò‚Z%÷}ÎnQUr‰«”¦·ðýƨ5 ½3ïYw")qµÞ!ò;«†e$lL•qœUŽ£§ÍnncµÓ´óain¶“ˆÅ nb n!ˆ˜Ãd¶á·FŠ¿h» ÌÎÒì<3¢ÏÚ}•Ì2E’‡É¸l&ÈcÇ ÿ ¼#þêNc·Ò¼/hö­¥ìij‘,p…ºò–¡cgî;¨Tð,6'?(Æ­{EØ,Éÿ¶¬ÿéçÿ%ÿâhþÚ³ÿ§Ÿü—ÿ‰¨(£Ú.ÁfOýµgÿO?ø /ÿGöÕŸý<ÿà$¿üMAEÑv 2í«?úyÿÀIøš?¶¬ÿéçÿ%ÿâj (ö‹°Y“ÿmYÿÓÏþKÿÄÑýµgÿO?ø /ÿPQG´]‚ÌÆdâhœ´‘°*CZÌCB6SàØ—QHï&ÔpdzgƒŸîVµ·×&gìQ[OVM2ÕJ²Â€‚0AÀª>)ÿ‘cPÿ®_ÔV½dx§þECþ¹Q\­ÝÜÕh;Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾—#þ ½Cñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×zÿr?÷©¯'4ÿ|©êi„þ FWxRKK 'C¼ÒfÑnõ°/45ˆûZbÕÛý ,¤Ì»Â©SåîÆw>ËEp&t_aâ½QæšÊï\…lX]f)¢™aÒ㕘Á;|È#L”` ²îÝ€—í5Kã(Êj}Í­”Rj"¥ÀšóÊÈ#`Y6…ó Y|µb²z \/ðιy¡Û®¥åÜÇ›®•¶?ô«gŠ6}¥|ÆÛ¾o™X(òykd“Åš¼ze¼öúÇŸw4Vòjý™'þÌ®mÐÁåÆŒ‰g]ŽL‡Ëà‚ >¡P]ÙÛß°ÜǾ5–9€ÉLA&ˆ³¸ð½î¡°iš|¢(I¥éâÖ'¶’dI§uf`Ï rr±«‚Ù‘E…Ó¼Q%¾ª¿kվס´Eo~Qí²¶h´j¾ç¹EXÆ[Ë#”šã,õíFßÃ÷š§ö¿Ú5Y%[Çóa€´NtV•dU6å—h=Äxîû½¶Š. ¨êú¦—ª¶™{­ùV­öy®u3Qý‘d[œ…Ü *o‚%_09ýá‰*Fïƒõ½Wéw{79ººŒ¿ÙÌT¸‘÷mÊaT 6HÇ$œšÒÔ4è5;u†áî‘·ƒmu, œËFÊHç¦qùT–vvú}¢[[G²$Î%‰$ä³Ë1$’Ä’I$’Mz(¢ÂŠ( Š( ±üMO£¥ExÞîÕYd03Æ#¸­Š¡¬ZÏy§ˆí„M2O ʲ¹Um’«HŒ…ÇCUi&LÕâÈàð¦†ymN?[Tÿ fioc}­ÛZÁ¥êíŽ$ £6ð“€8êMYMC]Où„é§þâ/ÿÆ)ºt7kq¨\ÞGR]Ü DpÊd Q§Þ*¼ü„ôï[JO•Ý’º²/ÑEÎjQEQEQEQEQE‘âŸù5úåýEkÖGŠäXÔ?ë—õïÈ¥¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zúlø2õý,Gƽ¤¾ÿȧ7ý}í(ë½¹û¿Ô×ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¼œÓýò§©¦ø1EÆiþ1K¿M¥ÿhY=³Ë=¬6èêfY!T$”zå¾Ô a·GŒnüû'gEq7þ'ñúާ§iv±[ÞÏföÓ=ï&fvȾQØì—x¹Ý•PûºµÍÔÚ½–kröfæ ®^ê%V‘V&‰v¨pTexR1– ®Â6h®Bj±ë2x~Ôoai“íRÎ VXÒÝÃHœ.BŠr˪¬v^¼Ô/µo éú–†·KÚÇ;¬"!r!tÜ~i1oÜS;Ž6ïÇͶ‹ÐÑ\Lž.“L·¶µ¶k­jêf•”ÜÚM ±"÷,É Áó*•ýÒŒ2s‚õÿá;¼Šîê$Ón§šiÃÛÛO ªÖð‹kWeq R¸pó÷\rFá…³¾¢¹»oêZ›Júf‡º(|¸åKËŸ³Ï¯H¦ÆTJ›ŽíÃ…bl] ÅÚ¬ÖzL7ésª_éÖRF­pyâBìËä%-É Ѝä°õÆ7Ž®6ß:hÛ¢ÓmZæþOµ$³Å*Æ6åÛ6ìS!C¼c8kV¹º›W²Ñ­n^ÌÜÁ5ËÝDªÒ*ÄÑ.Õ ‚L£’ F2Á”°4W!‰5Xõ™Ã®Ðnüü]yçI¯Ed}‡\ÿ Ü?ø?øº>îÐnüü]kÑYa×?è7þþ.°ëŸô‡ÿ‡ÿ@ôVGØuÏú Ãÿ€Cÿ‹£ì:çýáÿÀ!ÿÅн‘ösþƒpÿàÿâèû¹ÿA¸ðñt¯Ed}‡\ÿ Ü?ø?øº>îÐnüü]kÑYa×?è7þþ.°ëŸô‡ÿ‡ÿ@ôVGØuÏú Ãÿ€Cÿ‹£ì:çýáÿÀ!ÿÅн‘ösþƒpÿàÿâèû¹ÿA¸ðñt¯Ed}‡\ÿ Ü?ø?øº>îÐnüü]kÑYa×?è7þþ.°ëŸô‡ÿ‡ÿ@ôVGØuÏú Ãÿ€Cÿ‹£ì:çýáÿÀ!ÿÅн‘ösþƒpÿàÿâèû¹ÿA¸ðñt¯Ed}‡\ÿ Ü?ø?øº>îÐnüü]kÑYa×?è7þþ.°ëŸô‡ÿ‡ÿ@ôVGØuÏú Ãÿ€Cÿ‹£ì:çýáÿÀ!ÿÅн‘ösþƒpÿàÿâèû¹ÿA¸ðñt¯Y)ÿ‘cPÿ®_ÔQösþƒpÿàÿâê ÍV¾³–Ö}fŠUÚÀYãÿg  >'ÿ‘OYÿ¯ÿô[WÉ ÷Ö¾·ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µôÙðeëúXzI|'ÿ‘NoúúÿÚQ×u\/Âùæÿ¯¯ý¥wUäfŸï•=MpŸÁˆQEÀty¯èú|ÞMî©em.3²iÕ>„ÕøK|9ÿAí3ÿÓüj”$öDóEu6h¬oøK|9ÿAí3ÿÓühÿ„·ÃŸôÓ?ð)?ÆŸ³Ÿ`çsfŠÆÿ„»ÃôÓð)?ÆøK¼7ÿAí7ÿ“üirK°sǹ³EcÂ]á¿úiŸøŸãZ6wöš„}•Ô71gápËŸ¨¡ÆKt IìËQToµ/Le[ýFÖÕ›•Ì©Ÿ¦M$›Ñ ´·/QXßð–øsþƒÚgþ§øÑÿ o‡?è=¦àZW³Ÿasǹ³EcÂ[áÏúiŸøŸãGü%Þÿ ö›ÿIþ4{9vx÷6h¬oøK¼7ÿAí7ÿ“ühÿ„»ÃôÓ?ð)?Æ—$»<{›4UKSOÔÕšÂöÞéTáŒûâ­Òi­Ó¾ÁET¾Õ,4ÄW¿½·µF8 4?STá-ðçý´Ïü Oñ¦¡'ªBrKvlÑXßð–øsþƒÚgþ§øÑÿ w†ÿè=¦àR?g.ÁÏæÍÿ w†ÿè=¦ÿàRž'^Óð)?Æ—$»<{›4Sc‘%dƒ# «G­:¤ ¢²î š‹þßÐ{LÿÀ´ÿ®Iv'ž=Íš+þßÐ{LÿÀ´ÿ?á.ðßý´Ïü Oñ§ìåØ9ãÜÙ¢±¿á.ðßý´ßü Oñ£þï ÿÐ{LÿÀ¤ÿ9%Ø9ãÜÙ¢¢·¹‚îžÚdšWƒ+b*Z™^(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾·ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µôÙðeëúxzI|'ÿ‘NoúúÿÚQ×u\/Âùæÿ¯¯ý¥wUäfŸï•=MpŸÁˆQEÀtžŽ)íµ"åþßs’ âig~UQôº?²[ÿq¿ï¶ÿå¼ÿ&ª¾—×ú>Zê·WmYJ3²}¿#žšN7h§Γ.§.›Êב&÷ˆHÙŒ÷Á 2:€èN®mý’ßûÿ}·ø×a¡ø†ÛSµñ ¯j×SÜ.¬–J‘Ï壯fó l"Xâ9XÁ³ŽAv'޳ÑîÿáÐî Ó>ʯk§E<Ÿm+öùêÐÂÞjfEتë’~Ø÷(ÍgÏ.åòDZìNÚ|z„6 X\Í“F›Ÿ”BŽzpdOÏØÔÿd·þãßmþ5çÃ3›‹‹©-ÓBÒ’ ©mVC]1³xØ¢6À¶òÍ€JŸâÁb+®ð´S jq§ £>€WMº¹=÷øÇ_öŠÜäKФܩÎþ_™-%8ÛúÐèꇇ6ÿjx‚R È/–0ý xX/Ó,Çñ«õ› j!ÿ°Šÿé4>¾Ÿª4ŸC¤óMbCã"{Ój’].ÛÎ{Ò5\¡_8 ;ÆÑórØ$Z[«†±ð­Í¥Ý¶¡$wR·ö½Ü×R^»Bb’âGŠeˆ¿—½”ý° œâ®¡y¦4דèÞÔ,ìo#¹´Ôf¸’ËɽfžÒ%¾—r‘6&f?,„’3¿k‚$©uá+Û3NŠM"étøã:}²Y3–o/Ë•¡—u²\ùG«î|É@=BßR·ºžîdÝ%¤¢ÆØåÀç¯ÊêxõõÍXóMq> ÐeÐ.5”›Oò¤ž[y>ØdI Î-ãWÜàf¬¬K*äÈX ±Ç[º•ÀÅ¿#þ[ª}>çyŶH6ç鹿3Z5—xsãM?þÁ÷_ú2Þµ*jtõ3´Ð§Æš“²†h¬-¼²‡sÏ»]«ùWGæšætóêßõãiÿ¡ÜVîê¶öù %ñVœº¼šZ‹é.b•!ŧÏ$hìªÀ4Š…ÊêNOóŠÔší`@î‚êŸ"3œ³N2y=É8šácÓ.!ñž§w6‘­ËÍü3Csi©­Â!BdˆN»°ÈÙÊ6@‘U.|1uwfÖóh¨öÓÜZ´òL²-•ªÝBò[c´ª_ ¹xòþìQn.3Ðlu+}KO¶¿´“̶¹‰f…ðFä` œGu©šL©1Ð×5à›tŸèÚ|öažÚÕ"š“‰Ã¶P•;›-œäîÉÁÈ­Öo”Ò¸iª0©yvˆEU¸=€~¬ÿq¾•“á¿ùËÿ_÷¿úS-k?Üo¥EOúŽ +ø<ªx7F* 4–PÈä²Ì}É$Öö¥o¦é÷7÷ryvÖÑ4Ó> ÚŠ cÉà•á6ÿŠ7Bÿ°}¿þ‹Z_Z\j^Öì-#ó.nl'†$È£`O’:ÖÓ~ó" 6R·P†Á¤ÅÌÑI4iƒÊ!@Ç=82'çìh}JÞ=B“3E$Ѧ(…ôàÈŸŸ±¯>ñ‚îd»´—Ô^&²–+ƒ6 ÷ Ëö‹W1 ¸v\¼qʸ#cpƒX:Ÿ†oì4Û6ŠÎê+_´,qÃsu I{§íAöe c˜Ãc%‰ÜÛDÜ£ÙüÓIæšæ|+c.Ÿm}þý›i=×›iaò³G寥vÆJ.]d|)#çÉä7·R¸:@UÔµôE ‹¨ ª: ÛÂÇRÄþ5«Y:9Χâû/þ“AZÕ>/»òlex£þE-gþ¼gÿÑm_$7Þ?ZúßÅò)k?õã?þ‹jù!¾ñú×ÑäÁ—¯èrâ>5è}%ðŸþE9¿ëëÿiG]Õp¿ ÿäS›þ¾¿ö”uÝW‘š¾Tõ5Â!EWÐròø[P†êy4½y¬ášF•¢k_3 ıÃ^2Iç=i?áñý £ÿ[ÿWSEt¬]T­Á‘—±‡ôÙç?ð©í¿ç®‰ÿ‚ÿã•»ÿïˆÿèmøßüzºš(úå_/¹{Mœ¿ü#¾"ÿ¡·ÿ$ÿQÿèmÿÉÿãÕÔQG×*ù}ËüƒØÃúlåÿáñý ¿ù"ßüz´tM´¦¹žâõ¯/.v‰%ò¼µÚ»°äž®Ç$žµ¯ELñ5'W·¢iF.è+m&ú;ë›7SŽØ\¸’hæ¶3)p¡r0èGʪ;ô­Š+(ÉÇbÚOsì^!ÿ å‡þ ÿÖ4þŠæâK‹ˆ<3,Ò±y$“Ãá™Øœ’I›$“Þ»**½¤¿¤‰äF7ؼCÿAËü?ÿ¥ûˆè9aÿ‚Çÿãõ±EÒ_ÒAÈŒ±x‡þƒ–ø,þ?GؼCÿAËü?ÿ­Š(ö’þr#.ÇJ¹‹P7ú…úÝܬF„Py(ŠÅKpY‰$¢÷íZ”QQ)9nRIle^iWO¨5þŸ~¶·Å(–5T±^)nýê?±x‡þƒ–ø,þ?[4U*’Z ‘ßbñý,?ðXÿü~±x‡þƒ–ø,þ?[4Sö’þ’"1þÅâúXà±ÿøý!±ñþܱǶ˜ÿü~¶h£Ú?é äE]:Á4ÛíRG—igy]Ý‹³`tË18«DdëE ÝÝ”••Œ}VÓíã´°Ö­ÒÒ ObddAÀRÂUŽ”éô½ræÞK{_M–T¤‘É¥3+© ƒ>#µnQWíeý"yÈYx'û:í.ìWö·1çdÐh!r0pÂlŽ ký‹Ä?ô°ÿÁcÿñúØ¢i/é äF?ؼCÿAËü?ÿ¤6>!ÿ å‡þ ÿÖÍ{IH9GKÓ¿³ ›Ì¸7™§”¦À͵TarpªŽ§¥^¢Š†Ûwe%m ¯È¥¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zú\ø2õýµÌ÷ª+Áázk¿ô Ó¿ï—ÿâ¨ÿ…é®ÿÐ7Nÿ¾_ÿŠ£ûå÷‡ÖaÙžõEx/ü/MwþºwýòÿüUð½5ßúéß÷ËÿñTbâ|¾ðúÔ;3Þ¨¯ÿ…é®ÿÐ7Nÿ¾_ÿŠ£þ¦»ÿ@Ý;þùþ*ì\O—ÞZ‡f{Õà¿ð½5ßúéß÷ËÿñTÂô×è§ß/ÿÅQý‹‰òûÃëPìÏz¢¼þ¦»ÿ@Ý;þùþ*ø^šïýtïûåÿøª?±q>_x}j™ïTW‚ÿÂô×è§ß/ÿÅQÿ Ó]ÿ nÿ|¿ÿGö.'Ëï­C³=êŠð_ø^šïýtïûåÿøª?ázk¿ô Ó¿ï—ÿâ¨þÅÄù}áõ˜vg½Q^ ÿ Ó]ÿ nÿ|¿ÿGü/MwþºwýòÿüUظŸ/¼>³Ì÷ª+Áázk¿ô Ó¿ï—ÿâ¨ÿ…é®ÿÐ7Nÿ¾_ÿŠ£ûå÷‡Ö¡ÙžõEx/ü/MwþºwýòÿüUð½5ßúéß÷ËÿñTbâ|¾ðúÔ;3Þ¨¯ÿ…é®ÿÐ7Nÿ¾_ÿŠ£þ¦»ÿ@Ý;þùþ*ì\O—ÞZ‡f{Õà¿ð½5ßúéß÷ËÿñTÂô×è§ß/ÿÅQý‹‰òûÃëPìÏz¢¼þ¦»ÿ@Ý;þùþ*ø^šïýtïûåÿøª?±q>_x}j™ïTW‚ÿÂô×è§ß/ÿÅQÿ Ó]ÿ nÿ|¿ÿGö.'Ëï­C³=êŠð_ø^šïýtïûåÿøª?ázk¿ô Ó¿ï—ÿâ¨þÅÄù}áõ¨vg½Q^ ÿ Ó]ÿ nÿ|¿ÿGü/MwþºwýòÿüUظŸ/¼>µÌö_È¥¬ÿ׌ÿú-«ä†ûÇë^•¨|hÖu6êÆ]>Ác¹‰áfU|€Àƒ›¯5æ¤ä“^Î[„©†¦ãS«0«QNWGÿÙivy-2.4.0-rc1/doc/images/yed-step6.jpg000066400000000000000000000513701226750426600173630ustar00rootroot00000000000000ÿØÿàJFIF``ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ¾:"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?Ëñ.üUªM<’;iâOôkVáFv’¹ ¾ Éç©ã¨Åsøô·'Þ1T|)c¡ªé–SX®n"…Êà0 Àg¿5ØK þ&{Ë-F -2ÚîkI] ŒLveŠà†Qž:ö¯¿u(ab©½,¿à/RZÓrZëc߯üz[ß¡L:”_óçmÿ~…kÞx>ýï`µÓì¦,,"ºæ¸„¦X°Ü®­´!#åÉÉÁ¬ûë—w7°EbD¶,«p²J‘ùe³·ïœàò+Hâ(5~e÷£«ÕNÍ2¿ö”_óçmÿ~…ÚQÏ·ýú–º¡{§Kk3A fYB\F])»puÅX k‰„†Ä‘³ìÁeFi7©e;AÈäŒsŠ·VŠvr_x*3}ö”_óçmÿ~…ÚQÏ·ýú±¡ø.{éÚ^®¦.ÌÀ=¼ñ¹ÌjÅ€*X`ƒïQé^ ÔdÖ,mµ; ¼«¨ÞEK[¨ Èr™¶’ Î2{VrÅaÓk™m–»}̵…¨Õì÷·åþf_ö”_óçmÿ~…ÚQÏ·ýúèü5«É¥&¥öE[g…®´È£Ë…'qQ‘ÈäzÔ–M½Ï„õíVV—ÏÓÚÕbU`ù²l;¸ÉÀé‚*ÝjJ<׺ºZwnĪo–Ä?ÚQÏ·ýúiEÿ>vß÷èTZfy¬OäY,/6B¬r\G99ÀPì ;f®Gá-rSlÁ‰¸í£bdșܧŸ—O\tª•J1v”’~¤ª3jé2í(¿çÎÛþý ?´¢ÿŸ;oûô*Åǃõë[ofÓÙ`ˆ39!`¡¶–ÚJçø€Æ9Î*á½Xg6 mÓÿ´ÎeN-¿ç§_Ó¯µ%ZƒWR_xý…E¥˜ßí8¿çÎÛþý ?´âÿŸ;oûô*oxyü<úrIuíyf—XÐìÎr8c‘Ó ÐóŒàÖ6*©Ê#Í Q3¦àùe¹§ý§üùÛß¡Göœ_óçmÿ~…fbŒUò¢yM?í8¿çÎÛþý ?´âÿŸ;oûô+3bŽT¦Ÿöœ_óçmÿ~…ÚqÏ·ýú™Š1G*SOûN/ùó¶ÿ¿Bí8¿çÎÛþý ÌÅ£•)¦u8¿çÒÛþý Oí(¿çÒ×þý ÍÅ&(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-ïУûJ/ùôµÿ¿B³1F(å]ƒ”ÓþÒ‹þ}-¿ïФ:œXÿKoûô+7ÆÍ>T5»½+Ü"ÖB>h¥†BÈ}ØÈ϶x¨_Ãl:ÞècþØOÿÆ«¶’öÈk×°ê"ClnfBÑœÉs†÷ǧóèc¹Ñ­t8§¾ÖnVæØ‚¶PÛ¾ ÖFCd}Õ¯¿<—cµq左߉÷PáÜ ´gÍw¶»úiýzu}&¥áfMON½·8ŒÜXM­÷‚:²© íÎ*vž¸5ÝZ|~ðð³€_Xê_k¯ŸäE—æcæÛ™3·9ÆyÅp¾ ùü#¨¤ßZ軚òéó_â5ía¤³<1ˆ®mvÓcÎÄác€ÅN…&ì­¿¡ÞøVê; OM¾”3EoqÌrB°'üVí®­k ç‹/þÅ7™¬Û_C …MàÍ!)¼îÆÆpO¶j¿…ü ¬kÚOÚ¬®,’4,‰ÁÎÕnʼ+}~x‘Gü}é÷òOþ"½|V'ê8Õ­úž,)b—½N:^äÃŶ$–sÚ] WÒl¬ÚA ·›»©&P©Þ9`# t5“¨x/4ïDÿÚêóY´R\¬!•apO™³jŽ ÿZÑÿ…eâOùúÒÿïìŸüE!øcâCÿ/Z_ýý“ÿˆ®HÔÊâÜ•MÿÍ>ÞHѬ{I8íþV%·ñv‚Útêq£iiíoj#ïlænXíÇQÇ>§4 ñLþ.Ðut³™¢Ó4È,¤WÚ ²‰•Á|1Å· f)ó„ÝÏ sÈÀÉ­#[6:WŠuøâ"Ñï%ŸMû^Òëy&F6©'¤£þ>µ—ÿ ÃÄŸóõ¥ÿßÙ?øŠCð·ÄEƒ(°è|É2?ñÊç­S.©wíUåkþšéÿÖšÆBË“E·ãþdsxžËû%ŠZß>­&†4RÌÉäªxXå°sŒuïÞ¤¸ñ6”tË‚¶º“jxpè *Çåg ’ẟNƒ½/ü+ÏÖ—ÿdÿâ(ÿ…aâOùúÒÿïìŸüESžTÕ•OÇðØ×Ó»‰‰âBÛW“IxádµÓ!²”:(LÆ[HbNw Œc©ÏþG½v𬡊þSŒò=èò=ë³ÿ…aâOùúÒÿïìŸüEð¬ ñ‰ÿ–¾ÿÁ|_üb¿<–SºŽ"ùþ:x³šNÎt%{.«OMt8íE„ÞÔû¨¾´ÿÑwæ²ãÍ÷{6½ào&{›ÛÝ#ìÖ‘<ædò‡ ’B¤j¥°1“ù׌HA•Ï«ú̦”0øPŒÔÜ[»[kêxxüCÅc'_•Å;hü•¤>ȧ7ý}í(뺮áGüŠ“××þÒŽ»ªùÌÓýò§©xOàÄ(¯>±ø‡wyáýo°Bº­íÕ¼W; ‰ÞeSß+q ’Gœ3Œ+uk[Xå‹ìÍ.ÍÏÁ£v×o›çÏa†QÔ0€é(¢ŠC (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2|Qÿ"–³ÿ^3ÿ趯’_ï·Ö¾·ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µôÙðeëúXzI|(ÿ‘RoúúÿÚQ×u\/Âùæÿ¯¯ý¥wUäfŸï•=MpŸÁ‰ÍÛø#I¶†Þ8Ì߸ŠÎ4c³wú;£+·ï?•¹þ!6Œ à»…!kËÙ#·‰a° Éþ‚Šèê# Øh¢?¼ßþ¬g9mÝ%Ãss›‹Á–Í%ÂjZ˜ºšW’kŸwAœñ$ž_~Ñåi.ºù“57=6ô0õ+ãƒ|9uwoiv’,bâMJeŽm f–Fð;s€Ip Ã_s¦Ù_ÛÙkÞ²‚{È®\ùý«Î*W"5X÷ɸ]L[*ýéÁRXÛšÚúÇÃZ hË4MÌöv#+ná¾HÁ$õQµ“$€³±êhú]¶‰ÛI1û’øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:íٜʰÂå`H Û@$àúμœÑ_QyšaôR}›Qÿž6ŸøßüEfÔç§þ7ÿ\<’7æBÑIömGþxÚàCñ}›Qÿž6ŸøßüE’d-ÉÕ¸V¸ŠŒ°]ÑÊ[œ ŽôD——,ÐC”ã*d˜©#±ÀSG$ƒ™¢“ìÚüñ´ÿÀ†ÿâ(û6£ÿͨÿÏOüoþ"³j?óÆÓÿÿˆ£’AÌ…¢“ìÚüñ´ÿÀ†ÿâ(û6£ÿͨÿÏOüoþ"ŽI2ŠdnXºº…’6Úêpp_¡ú–¬3+Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾›#þ ½Cñ¯Cé/„ÿò)Íÿ__ûJ:í£8Õ¡ÿ®èI\OÂùæÿ¯¯ý¥w Ÿn†l ‚'\–’WÈ×—™¾Ôõ/ ü‘éz¤×ºŽµo* KÕ·ˆ¨9*má“-Ï]Ò7LpÖ±mþ$h·7vágI-°Î¥¢,±ù‹Èê®ZMêÌ%Áw|¹VòøzHµ›FÛ[¾·K«„¸žÑ>ÎbvTHñ–Œ¸cPpþ1U ðu¥‡ïa’Kï&Â[ k+Û…û:ÀÛ1 OÊ<°7ÌA;‹áqÇsräÞ-„]Éig§ß_ܬ²F±Ûù@H±ˆüÇVwU*¯*Æyݼ0ÇÊHŒxÛN›G¸Ôìẻ†+‹ktX•U§iÖŒ®öP ÷ŠãŸNbƒÂžF™¥Ã©qocnеý·•¾mûZVe:åÝÉ ¶GÞäåŸðƒé‘ù[\]ÛYÃ-´ëiÂùfH<±19fù"D*[nq¿ EÀ—KÕî5ßèڥݿÙî.ã¶šHÆ1–e9\3|§¨ÉÎÎEI©j·šG„l®l"‚k–{(9ت7›,qœ 9çpzÙh‡JðþŸ¤[O%ÌV~TqÉ;Ç¿ËFhPp£3Ç9<™äÒ–ûF³²ºbžKÛLvH¹ß ¤€wãr}³õ§}ÔɇÇI6¡åÅg<Ë5­³ÛZ"ªÜÜÜù‘>笋nÙŒq’p*=gâVº£w§Ù]Muie4ò«DmdS"*ʲA–˜÷°±!pÆÔþ ÓßS¸Ô­g¸²¼•ã‘d‚T"ÍÑ2‚Âyw%‹`1,`»ðŸucqiöëèRîÝà½hnZësHûœãƒæM+á6©ÞT‚˜P®2ÍŸ´[ï6ƒ Ù¹É7›ß$a·¯–ʸØÿ3"©ÛÁ;—v>¥ã=ZÛÄš…³ÀÆÞé-¬ì¿²®$kÇ6é6Ï´«ùQ±ÜÃ,¿"®â®ŠÏ@KA§‡P»Þl“­š‚’BÌíÀÙgsµ™”Èjí'ðí¤ñjHÒÈ­uã:ȹŠhÖ Œœcå0£aƒAÅ6ÿâF‹¦êWÖ7+:ËiÒm ù<¨ÚFU‹˜>TbÕQ°bK¾<·µ½°†H'³Yn•%K¸O˜ð¼3´O©'s¼B0ó3P´š€ôýLK××ËlÏréoÂâkˆåIˆÉ,fvËÚx]ªJ›z·„tÍkRkËã#ï‰axDª¨è#¸7+u'B:.1ƒ’àO­LóéÖò<2BîŽÍ…K!0¿Êv’2:pHô&›â~óBM6KK?¶y÷MШ&F`šVòÀë'î†áÜ$¿±¹–ÊVCq$hÊÒÈèϖ˸ã$‘ÐÏ@*ÕæíÖŸq#ö7â ®¸,bxð}±#tÇ })Ü]Lh•{w¦Îò»¬–òDþZ2D,ŠÊ#ýÄD |»p¤/ËGü úd~DV×vÖpËm:ÚEp¾Y’,FÌNY¾H‘ –ÛœoÃR¸É|;ãíÄú„–z|Û¤ã>lOæÆ¶£³G÷“å#|Ý2Üø“RKý~²N{…šÙâcq*ÀÌ’º¸mªrµ ¶à£,›ÎËÚ>€š6Ä‹P»šÚ„¶ÒÊž]¼cU lPBìàü͘çðͼ÷¥Ü%„îd¸ÓQãû<ìNX°+¸<²«cÀï}ÅÀbøÎÚTÛéÚŒÎ/d°†1!¸š6:Æ]‚&mÄ…Ç—F*|UÒm-‘µFò¤in†R q,Hí®®ÌDG*ŠÌ?(%AÝ Ûý†;xnî-å†ökè.cxÌ‘K+HÏ€ÊTŒM"á”ð}@5RÛÁV– ¶ÇSÔ­•÷­ÁK¥g¸F–Iv4Œ Œ4Òa••þnX.®™¯E­%é·¶ºŽ;Yä¶ifŒ*¼‘ÈèÁ9ËS9éóÁ‚Ó×'š×á^¥qo,ω+Ç$lU‘„‚äyÍ_±ÓcÓ,¤¶·rÊóÍpKºçt²´Œ;q—8öÇ^µ=¬vï¡Ãc{r!¶Xf†Eܬ6ᔎ„u”Ó@Uñ>©}¦Y[&™rßÝÜ!FMäŽçj—EcµïHƒ9$nÇǺ¥ãêZ¼؈ítQ{-¬’ïóŽÅÜrUªù›2'È?xaÝCáÏ [ÙÜÙáiQÚÜíóáK$ .Ó•Ü¡pØ<Œô«¥hRJ²¾™bÒ$¢usl¤‰;‡x4’0=rìz“O™w…×¼_â4­~Hì¾Ë§yZ•­µÊ¼qºIsé'œ]Ø´$í)\“¸„ËXOëpǯËV?cÑâ¹¾—Î2¼“»¼O)Io—rÛŒ6HCÀFRvO¥hR^]^I¦XµÕÜF ™šÙKÍvÆYpÁãR}‹HÙrŸb´ÙtŒ— ä L¬ÌÄ?0-$„ƒÝØ÷4s.às°x«R—ÄT tÑg¨êW–IÜ.#[a:³Žpáš%$áv ‡-¸tºÅΜéàÿè©+&ßÃz|^#“[–ö{‹†—ÎTxa@¯±£RZ8Õßlnè7³`7®Ô½>|Öf"—1fÏ[ŽþäRº Z®±x5 › «+±Z¥åÝåüFHÖ72C§üòrÌXpÛ‰X"ñÖ˜Û·76þêîɾÑk½ D£°Ð²à.ãBà>ÛºŽöÛ…º¶¿¸Ó¯ymqhÑ’0IÂEe H$erØ 3xSJD¾‹Ê&ÞúÉl§„ÍÃÆV$¶wc;–bÄ’s×$«€¶þ-†MJßMºÓï¬oç•c[yü¦!Z9\˜Ý—iû<£®ì¯  TˆrMx‚ËQt²G–êU‰vCM4/#ÝÎÑ— ‚ªØ`®>ÜÝM«ßK©‡F‹Pf€KE‘UBˆÄdbi‡Ì„þðóÂí͇áì_^ Ô.×M¹µïÚ÷¼êÓ\K4r*|ðƒæ 0É,\ ‰ãûHžö9­o¦û5ÌÑ[…Žyâ.ĹÎß ä ³U>ò­øü_i&­o`¶—Ûn®¥´‚ëËL’D²Fs•Úbeù€,yPÊ ÃÁºxµÖmüûš½¼¶óŸ52ªòÏ!+Ç7/Œç€¾„š¾ÔGŠ`¼•¢ƒM³¼žòÞÔ  ´«*¿îü´Ác)rYäÚAT±¢àt0Ý^Ÿúl?ô«½¼‰-Ë0P]Ëó¯#j_Pi×2Ggk-ÍĈĥ‹€>k9nR3’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeW áß^ÝéPjZ¤žbÍk‹m‹so™edTEžW1¾YÂŽ€çvB‚kϱÒwTW)eã?:öúÞm6ôË ÓF¶ÑÁûèâH`i]ÁoŸkÌî÷JÔvß4›ë UwG¼Xó$‰Z6™U£Cÿ1‰'(¬£w-ò¶˜Ž¾ŠÍƒP–O_i¬©äÛÙÛN¬ÜZG™XqŒD¸ã¹ü9ís⎜ڵ” ·R´µ¸’“IM& aüиRw2ª2îRņvtW/}ã½3M·‘ï`ºµ”4b(n|¸ZU9GÜ*"”âFF0T æÉñÐMö¸þ},Z¬ÿ»ŒI#0KÖ•7 ÇÙ0nç† ¥˜ŽêŠç‹­ƒ˜¨}µÙ½›F‰,êâFW˜*‚°Êq!F* Ptô}Zß[Ó…õ²L‘eˆ,ñ˜ß1ÈÑœ©är§ƒƒê╆^¢Š(¯-­Ü$×0ÆÄdp?ûNÃþ­¿ïêÿ$Z”6> ŠÞU½ùŽÞ" `0K‰rÜôÛ3ÉQi|K`u;û)[Èû˜gši#DP‘Ã#7-»hYÓ-Œ ‘•ݪ‚±eoí;ùþ¶ÿ¿«þ4iØÏõ·ýý_ñ­uÝâ yàÕle†ç>D‰pŒ²áÖ3´ƒó|î«Çñ0H¢wG¸–æ(u[$µ•`¸D¸Bb‘›b£~V-ò€y'Ž´ù"fwö‡üÿ[ßÕÿ?´ì?çúÛþþ¯øÖŠkº<—–¶qê¶/uwžÚ¸BóFA!Ñs–\r8àÕ;iZž—o}kq™RÕÞÜÍ˸Ûåù€¶àã98Âî8äˆ]‘iØÏõ·ýý_ñ£ûNÃþ­¿ïêÿjÙêÚn¡quoe¨Z\Ïhû.c†ev…²F•9R0}¥\£’!vsßÚvóýmÿWühþÓ°ÿŸëoûú¿ã] rD.Î{ûNÃþ­¿ïêÿÚvóýmÿWük¡¢ŽH…ÙÏiØÏõ·ýý_ñ£ûNÃþ­¿ïêÿt4QÉ»9ïí;ùþ¶ÿ¿«þ4iØÏõ·ýý_ñ®†Š9"g=ý§aÿ?Öß÷õÆí;ùþ¶ÿ¿«þ5ÐÑG$Bìç¿´ì?çúÛþþ¯øÑý§aÿ?Öß÷õƺ(äˆ]œ÷ö‡üÿ[ßÕÿ?´ì?çúÛþþ¯øÕyµ˜…äVxVæXÌ‹šA u8ÏùÁô4Í?W[½GɆñ¤hfXåA!;IìGùäàÖÿTÒ÷3ö¦¢²ºF ¬29VOŠäXÔ?ë—õwLÿUŸýpOýU/ÿȱ¨×/ê+«;-PïÈ¥¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zú\ø2õýa³æé+—ûFÿAWÿÁƒÿñt}£Nÿ «ÿàÁÿøº/äþà¹ÔQ\¿Ú4ïú ¿þ ÿ‹£íwý_ÿÿÅÑ'÷΢ŠåþѧÐUÿð`ÿü]hÓ¿è*ÿø0þ.‹ù?¸.uW/ö;þ‚¯ÿƒÿâèûFÿAWÿÁƒÿñt_ÉýÁs¨¢¹´ißôü?ÿGÚ4ïú ¿þ ÿ‹¢þOî EËý£Nÿ «ÿàÁÿøº>ѧÐUÿð`ÿü]òp\ê(®_íwý_ÿÿÅÑö;þ‚¯ÿƒÿâè¿“û‚æF«¦[êöi¬ÐÜDwC:ðñ?¨ü¹Ô'Ñ,-´Ç´´³L"Ȥž¬Ç#,OsþzV‡Ú4ïú ¿þ ÿ‹£íwý_ÿÿÅ×SÅ+|,ÇÙë¹>™ÿ «?úàŸúª^)ÿ‘cPÿ®_ÔVœ [ưãÊ`ämÇ÷¬Ïÿȱ¨×/ê+Înìé[ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µõ¿Š?äRÖëÆýÕòC}ãõ¯¥Èÿƒ/_ÐãÄ|kÐúKá?üŠs××þÒŽ»×û‘ÿ»ýMp_ ÿäS›þ¾¿ö”uÞ¿ÜýßêkÉÍ?ß*zša?ƒ•ÂøwÆW·zT–©'˜³ZÅ"ÛA¢ÜÛæYYg•Ìo–p£ 9Ý šî«›³ðzÚéQio­êwpEvÑÊ CDÊÑ:•ˆÊQHÜXà×:,¼gç^ß[ͦޙaºhÖÚ8?}I +¸-óíy€ýÞâÀ©@㚎ÛâFƒs}aj®è÷‹d‘+FÓ*´hcßæ1"Då”nå¾VÄw¾»´›íD³\]O,’]ÜÝjF ]"W@V¿’‡åØP¨Tp/èÞMÚʵKÑ1@·DU#¹’(Ò1#p]x2ªáH\rÛÒƒP–O_i¬©äÛÙÛN¬ÜZG™XqŒD¸ã¹ü9ís⎜ڵ” ·R´µ¸’“IM& aüиRw2ª2îRÛWÚ—:¼š•®³¨ióKpH¶Ë+ª3²“æFäÈݪ‡týHK׺‚Û³\:[Ç*ˆâiã‘% mÉ,fvËÚx]ªJ“@ ïéšm¼{Õ¬¡£CsåÂÒ¬Ê8.áP§20Ù‚ •}Äñx‹P¸eÉlà`¶ö–xÝKU€0€ äH,4Û3GPûj2{Æ‘XЍ7)Vf”f@ìw’X¤_ÓôX´ûÉnÅÍÕÅÄÐG;†-±ä}Ý 37 …h!cñîóÃú ß`…u[Û«x¯ vA¼ ʧ¾Vâ$8g;VêxÒÅ¡IšÎö8î"Y¬ *§#:"˜ðçnZX‡ï6¬Æioà&Úxã3~â+8ÑŽÍßèNß¼þTJçø„h8Ú0'‚ìV…¯/dŽÞ%†À3'ú +£¨7a¢ˆþóú±œå·›'Äk;oSQ·x$KÃò¼VòXaw,ÓH±’l|¬w î\µnø]]xê3BÈö‘OÚȪÊ^'·†`Äs™OaÆ8ÍT‹ÁÐÛM%Õ¶­©Ã,¯#ÞoŽIzD®¸td ÞLm€£i]«òÖ¶›¤ÛéMv`y›í2¬¯çHd ¬QÄ>cÉùcRKI$æI5dÒµ ?ѧº¸¹ÃomÝò¾&rvUDvù˜}Ü ’½ˆ n/­gÓ"ši–ùâO)cØY‰C.$S½ (ä1Vùk6úÊm@ÞÛEc¦êÑÀe³ÔAò¦PÒnÚÛHm¬ Fû¸ÀÎåÉ“ÁšÝËÚ\MukMòCm-Ü·Y“$^{®÷VkY vO4¬VëdIÒ/‹ô&êâ}NÒÖÒ „·W¢E3<)2”rØ`R@Ûš¹«jÉ¥Eú4÷W2ù6öÐmß+íg eQ„Go™‡ÝÀÉ øVάc±7ÝÏ7Ù,µ=M°be‰w3·låpû÷§å®¢çCx¼%g¢ÛØiWðÛE/gzŒ°Lˆ  ó `…a¸I÷qÔïñd ukiu§_YÝO»÷W>RlİG÷÷ìl›ˆÈØÍŸ™~øÙVŠ4q¨µšß@þ\W2Ï2ʆ; Æ$Y?+5N@qÆywðf·sq§O=Ôm¥ ’î[“ «)¶ wË‘m+e±ƒ"¨ùW"œŸ5[ˆ´èe}5LÓ#Óâ–$Ž{‘ öòÆ^EÆÈa…Üb,X3€ÞC®è÷[Ï«c,79ò$K„e—±¤›çu^?‰€êEhW¡ø6[/Yê÷VöŠñ%Ó2¹¯$IdȬ&›æc²á0(–=¥QEQEQEQEQEQErÓk1 È­ð­Ì±™/4‚@êqŸóƒèiš~®·z“ ãHÐ̱ʂBv“ØóÈ=Á¬ÍWL·ÕìÒ9Y¡¸ˆî†uáâQùr?¨O¢X[iiif˜E‘I=YŽFXžçüô¯K‘$ô9yѯ¦È*Ïþ¸'þ‚*—ŠäXÔ?ë—õwLÿUŸýpOýU/ÿȱ¨×/ê+Ç—ÄÎÈì;Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾“#þ ½Cñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×zÿr?÷©¯'4ÿ|©êi„þ FQEç!EPEPEPEPEP/k’™wLŽT)1Ìé3Œí#=OçIöEÿž÷Ÿø/ÿSÑUÍ%Ô\¨ƒì‹ÿ=ï?ð._þ*²/ü÷¼ÿÀ¹øªžŠ9åÜ\«±Ùþ{Þà\¿üUd_ùïyÿrÿñU=s˸r®Äd_ùïyÿrÿñT}‘ç½çþËÿÅTôQÏ.áÊ»}‘ç½çþËÿÅQöEÿž÷Ÿø/ÿSÑG<»‡*ìAöEÿž÷Ÿø/ÿGÙþ{Þà\¿üUOEòÙþ{Þà\¿üUd_ùïyÿrÿñU=s˸r®Äd_ùïyÿrÿñT}‘ç½çþËÿÅTôQÏ.áÊ»}‘ç½çþËÿÅQöEÿž÷Ÿø/ÿSÑG<»‡*ìAöEÿž÷Ÿø/ÿGÙþ{Þà\¿üUOEòÙþ{Þà\¿üUd_ùïyÿrÿñU=s˸r®Ã"!‰"ŒaB¨Ï@:V_ŠäXÔ?ë—õ¯Y)ÿ‘cPÿ®_ÔT”;Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾›#þ ½C‹ñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×zÿr?÷©¯'4ÿ|©êi„þ FQEç!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY)ÿ‘cPÿ®_ÔV½dx§þECþ¹Q@ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µõ¿Š?äRÖëÆýÕòC}ãõ¯¦Èÿƒ/_ÐâÄ|kÐúKá?üŠs××þÒŽ»×û‘ÿ»ýMp_ ÿäS›þ¾¿ö”uÞ¿ÜýßêkÉÍ?ß*zša?ƒ”QEyçHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVGŠäXÔ?ë—õ¯Y)ÿ‘cPÿ®_ÔP¼Qÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýké²?àË×ô8±ô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeQ^yÒQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘âŸù5úåýEkÖGŠäXÔ?ë—õïÈ¥¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zúlø2õý,Gƽ¤¾ÿȧ7ý}í(ë½¹û¿Ô×ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¼œÓýò§©¦ø1EWžt…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@dx§þECþ¹QZõ‘âŸù5úåýE;Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾›#þ ½C‹ñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×zÿr?÷©¯'4ÿ|©êi„þ FQEç!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY)ÿ‘cPÿ®_ÔV½dx§þECþ¹Q@ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µõ¿Š?äRÖëÆýÕòC}ãõ¯¦Èÿƒ/_ÐâÄ|kÐúKá?üŠs××þÒŽ»×û‘ÿ»ýMp_ ÿäS›þ¾¿ö”uÞ¿ÜýßêkÉÍ?ß*zša?ƒ”QEyçHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVGŠäXÔ?ë—õ¯Y)ÿ‘cPÿ®_ÔP¼Qÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýké²?àË×ô8±ô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeQ^yÒQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘âŸù5úåýEkÖGŠäXÔ?ë—õïÿȧ¬ÿ׌ÿú-«ä†ûÇë_[øŸþE-gþ¼gÿÑm_$7Þ?Zúlø2õý,Gƽ¤¾ÿȧ7ý}í(ë½¹û¿Ô×ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¼œÓýò§©¦ø1EWžt…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@dx§þECþ¹QZõ‘âŸù5úåýE;Åò)k?õã?þ‹jù!¾ñú×Öþ(ÿ‘KYÿ¯ÿô[WÉ ÷Ö¾›#þ ½C‹ñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×zÿr?÷©¯'4ÿ|©êi„þ FQEç!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY)ÿ‘cPÿ®_ÔV½dx§þECþ¹Q@ñGüŠZÏýxÏÿ¢Ú¾Ho¼~µõ¿Š?äRÖëÆýÕòC}ãõ¯¦Èÿƒ/_ÐâÄ|kÐúKá?üŠs××þÒŽ»×û‘ÿ»ýMp_ ÿäS›þ¾¿ö”uÞ¿ÜýßêkÉÍ?ß*zša?ƒ”QEyçHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVGŠäXÔ?ë—õ¯Y)ÿ‘cPÿ®_ÔP¼Qÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýké²?àË×ô8±ô>’øOÿ"œßõõÿ´£®õþäîÿS\Âùæÿ¯¯ý¥w¯÷#ÿwúšòsO÷Êž¦˜OàÄeQ^yÒQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘âŸù5úåýEkÖGŠäXÔ?ë—õïÈ¥¬ÿ׌ÿú-«ä†ûÇë_[øŸþE-gþ¼gÿÑm_$7Þ?Zúlø2õý,Gƽ¤¾ÿȧ7ý}í(ë½¹û¿Ô×ðŸþE9¿ëëÿiG]ëýÈÿÝþ¦¼œÓýò§©¦ø1EWžt…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@dx§þECþ¹QZõ‘âŸù5úåýE;Äÿò)ë?õã?þ‹jù!¾ñú×Öþ'ÿ‘OYÿ¯ÿô[WÉ ÷Ö¾›#þ ½C‹ñ¯Cé/„ÿò)Íÿ__ûJ:ï_îGþïõ5Á|'ÿ‘NoúúÿÚQ×WyoªÏ>ëmJx@¡µÞ»ž}…y9§ûåOSL'ðb_¢²>îÐnüü]a×?è7þþ.¼ó¤×¢²>îÐnüü]a×?è7þþ.€5謰ëŸô‡ÿ‡ÿGØuÏú Ãÿ€Cÿ‹  z+#ì:çýáÿÀ!ÿÅÑösþƒpÿàÿâè^ŠÈû¹ÿA¸ðñt}‡\ÿ Ü?ø?øº×¢²>îÐnüü]a×?è7þþ.€5謰ëŸô‡ÿ‡ÿGØuÏú Ãÿ€Cÿ‹  z+#ì:çýáÿÀ!ÿÅÑösþƒpÿàÿâè^ŠÈû¹ÿA¸ðñt}‡\ÿ Ü?ø?øº×¢²>îÐnüü]a×?è7þþ.€5謰ëŸô‡ÿ‡ÿGØuÏú Ãÿ€Cÿ‹  z+#ì:çýáÿÀ!ÿÅÑösþƒpÿàÿâè^ŠÈû¹ÿA¸ðñt}‡\ÿ Ü?ø?øº×¢²>îÐnüü]a×?è7þþ.€5謰ëŸô‡ÿ‡ÿGØuÏú Ãÿ€Cÿ‹  z+#ì:çýáÿÀ!ÿÅÑösþƒpÿàÿâè^ŠÈû¹ÿA¸ðñt}‡\ÿ Ü?ø?øº×¬ÿȱ¨×/ê(û¹ÿA¸ðñuæ«_YËk>³ E*í`,ñÿ³ÐŸÿȧ¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zúlø2õý,Gƽ¤¾ÿȧ7ý}í(뺮á?üŠs××þÒŽ»ªò3O÷Êž¦¸OàÄ(¢Šà:ŠÎ¼×ô}>o&÷T²¶—Ù4ê‡Bj¿ü%¾ÿ ö™ÿiþ5J{"y¢º›4V7ü%¾ÿ ö™ÿiþ4Â[áÏúiŸøŸãOÙϰsǹ³EcÂ]á¿úi¿øŸãGü%Þÿ ö›ÿIþ4¹%Ø9ãÜÙ¢±¿á.ðßý´Ïü Oñ­;ûMB>Ê꘳ð¸eÏÔPã%º$öeŠ(ª7ÚΗ¦2­þ£kjÍʉæTÏÓ&’Mè†Ú[—¨¬oøK|9ÿAí3ÿÓühÿ„·ÃŸôÓ?ð-?Æ«Ùϰ¹ãÜÙ¢±¿á-ðçý´Ïü Oñ£þï ÿÐ{MÿÀ¤ÿ=œ»<{›4V7ü%Þÿ ö›ÿIþ4Â]á¿úiŸøŸãK’]ƒž=Íš*¥Ž©§êjÍa{otªpÆ €}ñVé4ÖŒiß`¢ª_j–b+ßÞÛÚ£š@€Ÿ©ª?ð–øsþƒÚgþ§øÓP“Õ!9%»6h¬oøK|9ÿAí3ÿÓühÿ„»ÃôÓ?ð)?ÆŸ³—`çsfŠÆÿ„»ÃôÓð)?Æâ߯i¿øŸãK’]ƒž=Íš)±È’ƲFÁ‘†UÈ#ÖRPQYw$Ðí'h.u‹fC†ŽK„VPMEÿ o‡?è=¦àZW$»ÏæÍÿ o‡?è=¦àZð—xoþƒÚgþ'øÓörìñîlÑXßð—xoþƒÚoþ'øÑÿ w†ÿè=¦àR’ìñîlÑQ[ÜÁwÏm2M Œ«ÆÁ•‡±-@̯È¥¬ÿ׌ÿú-«ä†ûÇë_[ø£þE-gþ¼gÿÑm_$7Þ?Zúlø2õýß‘ÏM'´SŽçI—S—MŽekÈ“{Ä$lÆ{à @t'×6þÉoýÆÿ¾Ûük‡°ÐüCm©Úø†Wµk©î —VK%HçòÑã3y†6,q¬`¿ÙÇ »ÇYè÷ð‚èwiŸeWµÓ¢žO¶•û|uhao53"ìUuÉÇ¿l{”f³ç—rùcØö'm>=B,.fŠI£MÏÊ!@Ç=82'çìj²[ÿq¿ï¶ÿóá™ÍÅÅÔ–é¡iIÔ¶«!ˆ.˜ÀÙ¼lQ`[yfÀ%Oñ`±×xZ)†5 ¸ž+íQþÝsŠU£gU ±Æ±Çœ ìÉ“G<»‡,{?d·þãßmþ5ÍiÛG‹õ´@ùÌ@îÛç\ŸS…QŸ@+¦Ý\žŽûüc¯ûEn?ò%ÅRnTç/Ì–’œmýhtuCÛµÙ,™Ë7—åÊÐ˺Ù .|£Õ÷¾dŠ ¡o©[ÝOw 2n’ÒQ ãlrŠàs×åuº»³ky´T{iî-Z y&YÊÕn¡y-бÚU/„ܼyv(·è6:•¾¥§Û_ÚIæ[\ijBø#r0N#‚:ÔÍ&T‚èkšðMŒºO‚tm>{°Ïmj‘MÉÄ€aÛ(JÍ–ÎrwdàäVë7Êi\  €4‡UT¼»D¢ªÜHÀ? Ö¸ßJÉðßü‚eÿ¯ûßý)–µŸî7Ò¢§ÆýG…üU<£PK(dr?‰Ùf>ä’kNûR·Ótû›û¹<»khšiŸíE±ÀäðJÆð›Å¡Ø>ßÿE­/Š­.5/kv‘ù—76Ãd ÎѰ'Éki¿y‘…©[ǨC`Òbæh¤š4Áå cžœóö4>¥o¡ ƒI‹™¢’hÓ”BŽzpdOÏØ×ŸxÁw2]ÆÚKê/YKÁ›P{†eûE«˜Ð\;.^8å\±¸Á¬OÃ7öm›Egu¯Ú8Ṻ†‰¤½Óö û2…„1ŠFÌa±’Äîm¢nQìþi¤óMs>±—O¶¾ÿ@þÍ´žëÍ´°ùÙ£òãR»c%.²>‘óäòHÛ©\  *êZú"…EÔÕmác©bÕ¬çSñý„ÿI ­jŠŸÝù62¼Qÿ"–³ÿ^3ÿ趯’ï­}oâùµŸúñŸÿEµ|ßxýkèò?àË×ô9qô>’øOÿ"œßõõÿ´£®ê¸_„ÿò)Íÿ__ûJ:î«ÈÍ?ß*zšá?ƒ¢Š+€è9y|-¨Cu<š^¼ÖpÍ#JÑ5¯™†bXჯ$óž´ŸðŽøþ†Ñÿ€-ÿÇ«©¢ºV.ªV¿à¿ÈËØÃúlóŸøTößó×DÿÁ ñÊÝÿ„wÄô6üoþ=]M}r¯—Ü¿È=Œ?¦Î_þßÐÛÿ’ ÿǨÿ„wÄ_ô6ÿäƒñêê(£ë•|¾åþAìaý6rÿðŽø‹þ†ßü‘oþ=Z:&ˆÚS\Ïqz×——;D’ù^Zí]ØrOWc’OZ×¢¦xš“+ÛÑ4£t6“}õÍΛ©Çl.\I4s[”¸P¹t#åUúVÅ”dã±m'¹ö/ÿÐrÃÿÿÇëEsq%ÅÄ–iX¼’IáðÌìNI$Í’Iï]•^Ò_ÒDò#ì^!ÿ å‡þ ÿÒý‹Ä?ô°ÿÁcÿñúØ¢i/é äF?ؼCÿAËü?ÿ£ì^!ÿ å‡þ ÿÖÅ{IH9—c¥\ŨýBýnîV# B(<”Eb¥¸,Ä’Q{ö­J(¨”œ·)$¶2¯4«§ÔÿO¿[[‡‰b”KšŽªX¯”‚ 7~õؼCÿAËü?ÿ­š*•I-ÈŒo±x‡þƒ–ø,þ?GؼCÿAËü?ÿ­š)ûII ‘ÿbñý,?ðXÿü~Øø€ŒnXãÛLþ?[4Qíôr"®`šm„v©#Ë´³¼Ž.îÅÙ°:e˜œU¢2õ¢Š†îîÊJÊÆ ¾«iöñÚXkVéi „…'±22 à)a*ƒÇJtú^¹so%½Æ¯¦Ë ªRHäÒ™•ÔŒAŸÚ·(«ö²þ‘<ˆä,¼ýv—v+áÛ[˜ó²h4޹8a6GƵþÅâúXà±ÿøýlQG´—ôr#ì^!ÿ å‡þ ÿÒÿÐrÃÿÿÇëfŠ=¤¿¤ˆ£¥éßÙÐMæ\‹‹‰LÓÊS`fÚª0¹8UGSÒ¯QECm»²’¶†WŠ?äRÖëÆýÕòC}ãõ¯­üQÿ"–³ÿ^3ÿ趯’ï­}.Güzþ‡#ã^‡Ò_ ÿäS›þ¾¿ö”uÝWÎø§©xkL66–6²+Iæ3K¸œíUìGe­ÿ Ó\ÿ nÿ|¿ÿYc²ºõ±3© Y±P­SQkT{Íà¿ð½5ßúéß÷ËÿñTÂô×è§ß/ÿÅW/ö.'Ëï5úÔ;3Þ¨¯ÿ…é®ÿÐ7Nÿ¾_ÿŠ£þ¦»ÿ@Ý;þùþ*ì\O—ÞZ‡f{Õà¿ð½5ßúéß÷ËÿñTÂô×è§ß/ÿÅQý‹‰òûÃë0ìÏz¢¼þ¦»ÿ@Ý;þùþ*ø^šïýtïûåÿøª?±q>_x}j™ïTW‚ÿÂô×è§ß/ÿÅQÿ Ó]ÿ nÿ|¿ÿGö.'Ëï­C³=êŠð_ø^šïýtïûåÿøª?ázk¿ô Ó¿ï—ÿâ¨þÅÄù}áõ¨vg½Q^ ÿ Ó]ÿ nÿ|¿ÿGü/MwþºwýòÿüUظŸ/¼>µÌ÷ª+Áázk¿ô Ó¿ï—ÿâ¨ÿ…é®ÿÐ7Nÿ¾_ÿŠ£ûå÷‡Ö¡ÙžõEx/ü/MwþºwýòÿüUð½5ßúéß÷ËÿñTbâ|¾ðúÌ;3Þ¨¯ÿ…é®ÿÐ7Nÿ¾_ÿŠ£þ¦»ÿ@Ý;þùþ*ì\O—ÞY‡f{Õà¿ð½5ßúéß÷ËÿñTÂô×è§ß/ÿÅQý‹‰òûÃëPìÏz¢¼þ¦»ÿ@Ý;þùþ*ø^šïýtïûåÿøª?±q>_x}j™ïTW‚ÿÂô×è§ß/ÿÅQÿ Ó]ÿ nÿ|¿ÿGö.'Ëï­C³=êŠð_ø^šïýtïûåÿøª?ázk¿ô Ó¿ï—ÿâ¨þÅÄù}áõ¨vg½Q^ ÿ Ó]ÿ nÿ|¿ÿGü/MwþºwýòÿüUظŸ/¼>µÌ÷ª+Áázk¿ô Ó¿ï—ÿâ¨ÿ…é®ÿÐ7Nÿ¾_ÿŠ£ûå÷‡Ö¡ÙžõEx/ü/MwþºwýòÿüUð½5ßúéß÷ËÿñTbâ|¾ðúÔ;3Þ¨¯ÿ…é®ÿÐ7Nÿ¾_ÿŠ£þ¦»ÿ@Ý;þùþ*ì\O—ÞZ‡f{/Š?äRÖëÆýÕòC}ãõ¯JÔ>4k:Ž›uc.Ÿ`±ÜÄð³*¾@`AÇÍךóRrI¯g-ÂTÃSq©Õ˜U¨§+£ÿÙivy-2.4.0-rc1/doc/images/yed-step7.jpg000066400000000000000000001454051226750426600173670ustar00rootroot00000000000000ÿØÿàJFIF``ÿáExifII*ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀZ&"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?óÍ ÎÚÆÙ†7˜ÈÎ}GÒº®bQÿ–äûÆ+JÞ8Ñ»6U$úWe¯x=4ýA¸–v\êPÀYH'8ã8Àïïë_uˆ¯KJ1·¢>ea牫-~fa¿Œøô¶ÿ¿B˜u(¿çÎÛþý ­wc-œîÒa)ܬýÔ«ŒôùBœuü*.¡£êúœ×bÞ:$llÝæ;ªF2G^~•Ó ô%UìÿÎÈçöU=ŸR/í(¿çÎÛþý ?´¢ÿŸ;oûô*DОO ìG#É,ÚÓÒÕ"Éf1ïóÓÅ?BðùÕu Ûk»ƒ`–VÒÜ\<‘䯍*Hç&©Ö¢£)7¤wBm¤ºìAý¥üùÛß¡Gö”_óçmÿ~…O¨øSXÓ'°·šÊgžú4QG–ï”#}{œdU$Ñõ9/žÆ=6íîã{uŒŠ8ä®2:Ϊ5)Is&¬'FQvi“iEÿ>vß÷èQý¥üùÛß¡RÙø~[X¾f’9´Ù ˆÛyD´,ž^:ä}Bš¢5K; «;‹InåXãóâdÎæ g­%V“m_U¿Ýɇ±•“ïÿ /ö”_óçmÿ~…ÚQÏ·ýú¥ªøBK#*Y=íü¢ù­"Ø>ÙB©,Êã*HeuÚ ?)=«&-V¸…¦‡K½’%,ÒÝÊ‚:‚@íÞ”+Qœy¢ôû¿1Ê„àìÑ'ö”_óçmÿ~…ÚQÏ·ýú>‰á«Í_XÓ¬dŽ[Xï‹®$„íePKÎ7`ƪ]évñ=ÚZܾœ\ˆ¯Xå\ü¬NG=M?iKŸ’úÿKô±—/7BOí(¿çÎÛþý ?´¢ÿŸ;oûô*9t=^ ˆ­åÒ¯cžbDQ½»†| œ dàÒ­é>½Ô‹ªDÓ,šeâ41ù²†DþóqÀ㩦§M«¦”“³¹/ö”_óçmÿ~…ÚQÏ·ýúÙÉ·Ÿä6;»±Œ{Ô‰áýjF*šEû0UrÙÉ ÙÚzt88=ðjùé÷Dû)yŽþÒ‹þ|í¿ïУûJ/ùó¶ÿ¿B«f_ÿgý¿ì7?bÎ>Ñå7—œãïcx§Ë£jÙ ÙtÛÈí « ÞÝìc#ù©÷]ƒÙ¿2oí(¿çÎÛþý ?´¢ÿŸ;oûô+kEðJêÐèeõ!º´³¬qù;¶¤JÅŸï òÇ¿Z翲5?¶EfÚeê]Ê»ÒÝ­ØHÃä.3ØþF²…z3“Šz­ÿú2凜b¤ÖŒŸûJ/ùó¶ÿ¿Bí(¿çÎÛþý —FðõÖ©yl’Á{ ¤êî.b²’•x$*Œ°ÜUN:)·ZÁ£hWÑÈóK«ùÛ-Ö/™Ln©Ž¿1%‡ªui)r7¯ü?ù1*qæ[ØÏí(¿çÎÛþý ?´¢ÿŸ;oûô*ýׄn¬ÓÃé9’+½bY#òÂQ¡+" ÎNNwƒÐSu/ GbšÜ‘Ý\\E¦Î¶é2Y9ŽgÜÁpJ¦Ò{žj&ƒi'¿¯{~ç±O Q+µýZå/í(¿çÎÛþý ?´âÿŸ;oûô)²xZŠX¢“H¿I&$Flà¹'ð ¨âѵIÂtÛÉÈbB1ÜàT`r@ãØÖ¼ôí{£?e.Ì›ûN/ùó¶ÿ¿Bí8¿çÎÛþý bèÃܽ²é7Í<`3Ä-ܲƒÐ‘ŒŠŠ='QšÞkˆ´û§‚DÒ,,V2:î8ÀǽÔû öró,iÅÿ>vß÷èQý§üùÛß¡Z°ø&ö]#JºÅÇÚµYü«XÙŠþü‘°c,0Tg¦HÁÔôë'S¹ÓîЬöòÛ‚ÇB2ÁƒÜj)Ö£RN0wkôЩPœ”–…Ÿí8¿çÎÛþý ?´âÿŸ;oûô*]O÷v[_HÖ9RD-Ù‰NáÈOÍÐóéUeÐõkxVi´»Øâb¡]íÜ)'¦ ûUF¥)+¦'FIÙÜ—ûN/ùó¶ÿ¿Bí8¿çÎÛþý cè:¼i3¾•|©"f6îx]Çw|¤{Ô3é—öÖ‘]Ïcs´¸òæ’&T|ŒŒ1w¬€™á`ŒL60sJ5iJN)ê†èÍEIìËÚqÏ·ýúiÅÿ>vß÷èUy´­Fßí>u…ÔfÛçï…‡•»îîÈùsÛ=k{Uð.¡a>¹öv7VÚ9ˆM/”Êd.Šçhû¡ÁnxÒ•j1iI­àšûÂ4'$ÚOOëô2´âÿŸ;oûô(þÓ‹þ|í¿ïЪ6Ö·— ok³Ìÿv8³7àOkû Wû[Ze_}¥SÌ0ý÷„Î7mÆqžõ£p‹³dªmírOí8¿çÎÛþý ?´âÿŸ;oûô*(ô=Zd™âÒïdHÇ+-»‘¡¸àCIªKbo£ÓoÐ)o=`cS»ÀÁÏÒ—5>è=œ¼É¿´âÿŸ;oûô(þÓ‹þ|í¿ïЫsxRûþý/V´†æñoVv‘!·fÜ/ÌÃ=y=º¤š³$)2ií…*ëlåX7LsœŒ}jcVŒ¯f´vù­ tf·Lwöœ_óçmÿ~…S‹þ}-¿ïЫ¹¸}V;ÕšÆM?N–ý£šÂcåÁÆ3žµ‰j¨ÊœÛŒu·ê'JQI¾¦—ö”_óékÿ~…ÚQÏ¥¯ýúNÚÊêõÝ--¦Ñ ²Ä…ЍêN:z×Ѽ3-üW—7ÆæÊÒßO–ýeû19#Û¸&Jƒ÷½*•)ÓNS{e7h•?´¢ÿŸK_ûô(þÒ‹þ}-ïШ"°—P½’ "ÚúíTnÛþð¯%QŸ'^Ö|;&™âé|=Âæd–(VB»3ª°ã'| ^ÒŸ2‹zÚÿ/釱•›é±ö”_óékÿ~…ÚQÏ¥¯ýúWд"òïO“[–KÛXÉ`¶GÊ2ùf~ìûíǽe6ª$PJúmÚÇpUas)oºãœöÇZTêÒšæ[yÝ~c• EÙ“iEÿ>–¿÷èQý¥üúZÿß¡Q¾…«Gy£éW«s(&8ZÝø' Œž*þ‹á[ÍKÄÖš%êO§Kr¬Á§ ›;N2Ò)Ê¥(Åɵd¯ò£&ì“ìTþÒ‹þ}-ïУûJ/ùôµÿ¿Bª]i÷Ö>X½±¹µir­ÄM#èEiÝè¶VÓ5K‹Ë¦ŸRIÚxm••LLæv‘p #~8ä•ZqI¾º+kùzhÊM¥Ð¯ý¥üúZÿß¡Gö”_óékÿ~…YÒ<1w©éÚŽ¡"Oogic5ÚÎ`b’˜ú nO>½lxR¸žH,á¹y ÓÅíÂÏg,%Xç÷J%Ûå Ã`㡨–&„dâ䮊Xj&“ÔËþÒ‹þ}-ïУûJ/ùôµÿ¿B«eßÿgý¿ì7?bÎ>Ñå7—œãïcx¥ŸKÔ-mcº¸°¹†Þ\å’&T|ŒŒ0r"¶¼6º3öl±ý¥üúZÿß¡Gö”_óékÿ~…fcÚŒ{Ur¡ršÚQÏ¥¯ýúiEÿ>–¿÷èVf=¨Çµ¨9M?í(¿çÒ×þý ?´¢ÿŸK_ûô+3ÔcÚŽT¦Ÿö”_óékÿ~…ÚQÏ¥¯ýú™j1íG*SOûJ/ùôµÿ¿Bí(¿çÒ×þý Ìǵö£•)§ý¥üúZÿß¡Vl¤—Qº[kM>ÚYX€êI<îkÕÔx*O&ãUq‹%ÿÒˆk*Ï’Ij]*jRI²s¢jJplôqõ½¶ÿã”Ó¤_޶Ú(úßZÿñÊÒ¿¾fbÀ}« æíå ¬1é\ôçZJîßsÿ3¦XzQêþÿø­­on靈‹J·Ãþ´H‹·ÌÌ@‰«gDÔG[M}om¿øåléóý™/$ãÒÏô7®†Ko Ç ?Ú:­Ü/ rHˆ„€YCq„>¾µËÌÒ(5«ïÖÝNû#PΞìz"]Û31ô>IöÕK ;ýTÍöM.ÔˆŽÙQJ§Ó.@Ï:Ö猭´X´Ûköâê)ZT‘¥ÚÈà|ª޶a¸û<º°Á×/Æ?ïÕcÌêa𮺊¿šk­µWÿ#£–SÄbUg÷ù\ä‡õ×OÒ?ð2ÛÿŽUkV†“û;NpŠX¬0Hä¸UrÇ×^s Ï¨YôG6·c4˜ ÈAß?‡9Ä™,"ñŽ•oat×QGyn¯1Pß̶ãªÿžG'ÀÿZqq’æ„m?ÃSß a%Ë9]&ý-ßC…ÒñÝ?•t+àŸ¨ÿ?þLÅÿÅW©šSÂâ%ÉRª‹^jÿ‰ÍFXŠnNœ.™K\™nïNü'ÿ¼}½½*é½°ÁvZw’$×wÿhÔ„°Ž%ùTd€;[çŽÔ¿ð…x³þ€Çÿbÿâ©‚Ý%òZÉD~X88%¹ÝòçîžzTpê6:…üAmo<úާt!Y'ÌÜÒ1`q¼œóMÿ„#Å¿ô?øÿGü!-ÿ 9ÿÀ˜¿øª|جë'ww¬uÕ?ÐÓý©4Õ;Y[¯Ÿùšé®éGQ¶q~Ð4¾I µ¤Ã?9!yŒm$ñÐu©gñ.•}o§&«siÓ¬mSS6òfFËHvÞ|Á‚ò;ØÎü!-ÿ 9ÿÀ˜¿øª?áñoýÏþÅÿÅV–\Ýý²ûãÞÿ×CEW•½ŸàûXÚ“Å:}î¡âk¨îZÌ_^ØMfòÛ³qˆYЍÏ;KqלU¦ñ/‡Šlµ‡»šI,á¹–_.9ü—˜FŽ2»²ÌqÀ8äõ®oþÿÐÿàL_üUð„x·þ€çÿbÿâ¨ö9JéioŠ=¹ ö¸Î´úßgÞâÚx€ØøcOApòkëÿÚ2Œ/’C1`6Œ±Æ3ߦ+¢¸ñ:]øÛG‹ÃÍ%Œï$*¯û癋M•8ÈPx==…sŸð„x·þ€çÿbÿâªH|ã;y¶úl°ÈH¯#F8!ò8&®qˤܕXß_´­ª·áИϬœNšïsTñ†™«ëq[\·êlÝø–ɼ/—ñ[Üi­m-ĬÄ R²—<Äëž•-Þ½ \xR×C¹¿¸lþÌ× °0[ÅW$ÀÀØQ¬p3ŽG5ƒÿG‹èð&/þ*øB<[ÿ@sÿ1ñU>Ë.éYoŠ%{LgZ}-³;;ønÊâÔiÃÚ¬·QÅm¦I¤-ˆ©ò§ÌÙ`Ks“ÀãÃðç‹mm?á û~¡sþƒëj;ÒWÃ?ú½Üç¯${VGü!-ÿ 9ÿÀ˜¿øª?áñoýÏþÅÿÅT,>]fe¯œ{5ú¿™N¾3OÝþËüýRµÐ¼9à[Qºtû=ž¢ ªDí%Ë3¨ÛÀÚ8'q8÷"ø‡M²Ðô[K«­—é×ös¤Fó::¾SoÈAÚÁ¹õx3ÆRˆVM6gH–$kØÊÆå¶®ü Ç\SáñoýÏþÅÿÅQì°2Rö•–­½$»ÊßúSW¹)½gåþFÃxšÎRýuDšî=!tí9­ì&ˆo%¾b$gbWåù˜€}ê®âK],x1!wc§¥â^DZ‚ˆå‘p Æåàg ª?ð„x·þ€çÿbÿâ¨ÿ„#Å¿ô?øÿZ(eÖåu“ÿ·—f¿VýHu1ÝS·É÷Oô:M3SMoÇGMÓáž_/ìß(oÀ€d à©Ü~ñçõ¬ÍWÅÑÞ[xºX®¤Š{ë‹Htñã˜b”‚C(‚¹nOñÍR‹Áþ4€?‘§M˜»Å{\ƒ‚Cò8TCÀþ,PѰ ˜¿øª•OÏwV6IuWºwmúÙí1|¿½ßN–µ‘µwâk&ðÄPÚ_ÃosýŒ4Ö¶–ÎâVb©YKžb ãœô«Æ£k¤Ù+KvÍs{á+k(,£É.Åñ#66¼÷Ï^:gžÿ„#Å¿ô?øÿN—Áž2žQ$ÚlҺƱ)’ö6Ú‹ª¹~ÉàzÔÊ–™rÖV½ß¼¿Æ®*Þõ7{[gø›Pø—IµñÖ‰€ÕøB<[ÿ@sÿ1ñTÂâßúŸü ‹ÿŠ£Ùeï⬟ý¼ºóòOðµÆt§ø?/ò6´ÍsAÓ%ðÙŸU’õôk}BG•mftÒH¥3¹2KeÔr}sô /‚ÒÚé>Á"Ón¯õ(Åäxe´˜îå…Ç>>þÜÁÈ#<} ?ÅÞ'²ÕtýAtûø‡öÙËZ=Á‘{Ia“ÊL`ýÕç=Ï5‹ÿ?‹è ð&/þ*øAü[ÿ@cÿ1ñUj–\§ûeuo´»Ü‡WÊãìô~L‡u[[]GR3¬:TwšlÖqMh’·íÈåÙ‰ã/·MoEâ]Ê“OKбÿbØZ ¦¶¹¬¼…— ²BaÓ±î+žÿ„Å¿ô?øÿGü þ-ÿ 1ÿÀ˜¿øªªðËëK™ÖKþÞ]=u&”ñ”ãÊ©þ­[_¶Ô4¿¬÷iq>«=Ùü«9"YDn»ŽÆ,P`óJÑÕuŸ?†57N¹ŠÖ;¤µk[Hì:e.$Ûd’ß8Ÿðƒø·þ€Çÿbÿâ¨ÿ„Å¿ô?øÿK“/ÒÕÖ?‰tI/É~=Çí1zþï{ô}oþfÏŠu½îÏÅ’Yê-=γ5ƒEn-e]žQ@Ùb»z)=j?kZN¤ž5òïT®ªle· §w’zóòœ#‘Î2¿áñoýþÅÿÅQÿ?‹è ð&/þ*”)eñK÷ëO8ôåÿäWâ7WÿåßàüÿÍšž ‚Â×W½T¼–âtY ÉŠÞEh™±¹¨-‘ó¨=x«Úž¢ú|w½ÔÑ[Eᩬt±lóK#2‘´’Ñ£†%‡%@ã­a[øGƶ’‰mté ” Šò4aø‡Í6xÒîãíZ}ÅÌûvù·É#íÉ8Ë98É<{ÔÖXZµý£¯5gª¿ùJUéÒåTÝïØÚð~¹ èë¦\\ϵÚK9¿‘ìÚyn7“l€Š3“Ð’=ÎfÒõ hž Ôï/Ý¢µ¶Ô•`H$2^n‘@c 3‚w‘ƒr9ÏøAü[ÿ@cÿ1ñTù<ã)V“M™Òe‰ö2±†9m«¿$q×V¥©'%]jõÕmi-?ð/¸Tªb¡:oE¦Ë¸Ôð牬tÃฮ¯eDÓà¾:€X¤* Ÿ“8byàgÕx²Ù,EõÊìðrX*¬rŒ^x{îüÃ~+7þÿÐÿàL_üUðƒø·þ€Çÿbÿ⪥G.”œ½²ÖýWVß꫌Œy}ŸnËüY¼C§\\\F׉<"4Ã+Å!äîÈ?)'¶HWlËlìïgou•ÀK3h9üާ=ºãšÝÿ„Å¿ô?øÿGü þ-ÿ 7þLÅÿÅWM ˜ )¨ÖZÿyyöõ0«]K^žÞ^ŸäWðl×¶>)Óä´‰ç¾É" óŒ8ÀöÉöÆ{WWâ ;kV0ß5¥Ž&‘§Ì¾cí›åù³–7ó/=kŸ‡ÁÞ4¶Ko¦K  $Šö4a‘ƒ‚#‚iŸðƒø»Ÿø“IÉ&ê"Iÿ¾«,CÀâ*óʬmkn¯ø«4£õªP²ƒ½ï°º]åŒz/‰t»aÄš‚ÄË~bÄ…_{«e|ø1Rvúõîšî·msñ"ëÄ~éí’î ¢,™åÇ<0r¤gÂâßúäÌ_üUðƒø·þ€ßù3ÿWàWUÖŽªÛ«l—èˆkéòr=ï××õ4.ï<5Þ$½†â;‡Õ-&’ÚÖ[iaº||Â¥W Ç£wÿdSfÖ´‹Ïøl_4×ZEŽ™m Ì%"Ì¢@NÓ€ØÊäŒäqÏJ£ÿ?‹è ÿ“1ñTÂâßúäÌ_üUBXõ®»|Kµ¾ÿ2Ûŵü?Á÷¿ôŽËBÕ,5ø>ÞÚþ+‹‹/¶¬©‹[ŇBWh*PêzÖƒâM'N¾ðlRjqm£Ú\ ›Õ‚]ŒdSµPÞÁz}ÞãÜ Ø<ã[Y„ÖÚl°J …’ØÑ×# #‚jð'‹#cM  >ÕÀ«QÀó4ë®[[u}y¯ÿ¥hjê⹆ï~ÏËüŠÚž¦š‡…<)dgš[ÛH.MØ‘*^D( ‚pœUÍKR·¹ðN‰¥Å¬½»Y¥Ë]Y„¸ÄìÒ‡Œ|ˆQ±ƒ÷ŽG½'ü þ-ÿ 7þLÅÿÅQÿ?‹è ÿ“1ñU×ÏQŒUhé'%ªÝßðÔÂØ§''Mê­×úèkÏ¯é £Ë+j,ßð‹K¤¥—Ùåb'þð*¥pøÇAŸf6»¥Ms4FìÆáÒŒ¯›RàîùN’G* eÿÂâßúäÌ_üUðƒø·þ€ßù3ÿX:Yußï–¾kÏüÍ\bK÷{y?/ò5¤ñ.–¾ÝåÇœþLz`·p\Ÿß÷Á×׊ÃñN§«.‘­Ä²Ag¤ÛC"eEw†À @ dgëSÂâßúäÌ_üUðƒø·þ€ßù3ÿZÑþÏ¥55Yo}Ñ.qåtÞÝ™Íù'Ò$úWIÿ?‹è ÿ“1ñTÂâßúäÌ_üUwÿh`ÿçì~ôr}Wüî9¿$úQäŸJé?áñoý¿òf/þ*øAü[ÿ@oü™‹ÿŠ£ûCÿ?c÷ ú®'ùÜs~Iô£É>•ÒÂâßúäÌ_üUðƒø·þ€ßù3ÿGö†þ~ÇïAõ\Oò?¸æü“éG’}+¤ÿ„Å¿ôÿɘ¿øª?áñoý¿òf/þ*í üýރ긟äqÍù'Ò$úWIÿ?‹è ÿ“1ñTÂâßúäÌ_üUÚ?ùû½Õq?Èþã›òO¥mhèöºÔ‡ŒY'þ”ÃV¿áñoý¿òf/þ*¬YøOÆr; 9c‘ rÅ-ÌEdSƒƒ‡¨ ‚ʶ; (YUN«£4¥†ÄFi¸?¸ÞÒâð}Η š¦­uãgÌŽ5$N1òØï\v°ÖÞ\‹9 –Ë#º²dàž8ÇjÜÿ„c^ó"éÿø0—ÿ’)­á]qºøO?÷—ÿ’+†Ž&…9¹{Kߣ”l½5:êÒ©Q$£ky1'—ÉÒ¦”ðtŸý"z·ýŸ¨¼SbÎ/ôxP¤‰6åeTƒˆÈêCU‡‡üfòÎ×>‚懷’â5O”a1±Ô®ÑÀÁqÒ—þ{þ„m?ÿÿòEO¶ÃůÞ+¤¶”{%×Ð¥ ­4âúô}ßoS/Ä3Z[x~ÚÎ è.¤Iç•Ì*à(eˆ¾«ÏÈzVþ£(‚{ìœn×uý£Tÿá×ÃOiÊêr¬o]À>»Zr§èACáÿ0»ðüë,¦r.n”bCÕIä÷çŽqfq¥‹Â:TêÅ?9-u¿C³+«,&.5ªAµ®Éö·S§ÿ„›OÑ£ŠÓI†;«vÞI:`Üä`¦E?¯;°$m-¦?øGüKù4ïü—ÿ’)¿Ø-‰Ä¶~°µ¹^c/š3ê¡æeÏ¡ÇG5òï&­9.j´ìŸó-§Žs…„eË Ý¦¶ß×SɵXªŸz*ߊtûÍ*ðØßÃäÝFFôÜŒŽ„Q_¡×”e>hê‘ š…žç­üÿCýÈœ•ÑÿÂE©IâëÝ9fHím¯"€"è·7Õ¢‰É3£yhs!0ù@ñ\çÁøñÔ?܇ùÉ]‰žãIÕ5#káý^ô]γ¼ÑKj#-åG<ªÀb1ÔuÏlWÇgïõ>_’= ðWÏóg?añÖÞÒKNo5®e­#Ì6¸ŒÚ[JÇ2È|Ógivo›Œ…$wVW–ú…µõ¤žeµÌK4O‚7#AÁäpGZ笼g¦CÓµ-BÒâ%XÖå Lû0ÄS\o·9EtB¶öñÂ…ÊF¡Èìì@嘒O¹$šòŽ’ˆµ tŸ 꺕º£Mig4ñ¬€•,ˆX‚2=k&ÇÄ‘Yù÷Œ÷òÜN-í- Òe°•Ü#; \I‚6)l’£å#$àVÖ·fšŽƒ¨ØÉÒGsk,,0e …-ò†çŒñžµÏXéúޤþV Þ#·–ÚÞÞ?08 „ „K$ŽõaŽ˜84 3lÉ+ödäC…?¢Óï/%¿dM:6¸î¨—Ê{xN]œ>|²'ÌUn“S#û6à6žúŠ:ì{D“*·bFU#äÓ=zW7aáè5khntí_O{ PÍs-»<®ÒG)˜˜ÙÃH$–1cÙ8[|BÑ®íhVi"™ÌQ4R’ñ˜‡”¬ŽQÝüø‚…c’ÛI Ån麽¦¬×c2;iV3*RMÑG(d œ©YŸ¯Öª/†íì强º½¸¶œÏç\”-!Æ(@V7 ¡Fø‘ù`I·¤éš-£ÛY¦ØÚVðSÂðÊ«µvTQÚ½XÖÛI _jwh€ZÏx„#*Í"]‚‚UI g'Óf¸Ë}v½»ÓdƒÄ §Íu-ÄrJö^DùÆu•6Ÿ4þðeC†€ËŒàþ™ãS%Y|˜œ$šIb1Dñª¹C";!cïXü¨ùÁRáñu´¯tíB(Y Šy¥[M0B‘H¥·ïýì`íVP_’0Ø‚o„A-Ûߥ΢·—Ó^¬~c*Â#ÚTˆÀŽcy~j¿qá»kIîÕÒÃ,ñÝOf¥<©¦fÉ +¼åǰS°d¶MÍÔühéMå…œÓK©ÅÌ2¨&'žÞ6S—>.9Û‘ÉÀç§‚F–Þ9…ÝC4R,„ºv’2:pH÷5ͯìÁ…[RÔX<‹XŶÍD‘H…sh"ǘ_;~mÙ9é ¢·Ž7™ætP­,C9ï  ž¼=… ^%ÛÚ:ØÏ 7'$ž*yʆRxÏñé\Þâ[ù4"æöÛûGRÕ-Eìvºl+—ØËdË.Ö‘Fww /×Iyq%­£Í œ×r.1·8à»*ñ×’:~Íéš3Ïa§ÛEµ¡Ë¥Z­¥½Ôk$’DB†\"Ë(É%AÈ8,(@Z‡Æ:}ËÃ%´7SXHÐF×êª"æÑ!Va&XK!ÆHÃb¯„¼Vu«-6ÔÅ5ÝâØ[K¨\¡‰R$„H7.àÿ6AP¯8Ï ‹Pø;O¶xc¶šêÚ ÁYLRÎ ì-o<ŠÉºL¨Ê#üûc9¥¥ø^7U}Qõ ÛËÉ<Ýò\ycvõOŠ8ñݳœðYx^&°Q¨^Ëm§J$²¶“ËÙˆ¤ˆ !2íýæcò¯=rhð˜éÿf¸™¡ºW†(…•wÊë#DðÆ7aäY! HÌ‘àâºç¿á‰u 8¨G´¶žêñŒ˜24ÒËæ*ôÁŒ33ã¨h¡9%k¡  ŸêÏ¢iù~.­¢e´‡d“¤mµW’ÛXà óŽJºø‡aex.híbŠØB·5¤’K!ŸpÍÁB…‡ ’CIÀ®‡]¶:^ µÕÑŠx'XmZ5‘Ú9R@…ÆTg$qœsŠÆþÎ}sZ’úm3ZÑîÖ(¼›·’Õ„mšÕW“,VâPw)é‚¡X –Þ;ŽëW eÖ¡kwºZÛ[y;„ů<Ü»8R¶#!й\ƒ“Õ麄Z¥ŠÝB®€³Æé £tbއŒ«+ ‚AÇŒçïü$ÚŽ{i«^Ås ¨n.Ñä*±ÜŒ¨deÜZää`(^.®ƒMÓâÒìVÖwžGy-#»w8e™˜àx`Pìº(¢ÂŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( œ>/Èù}ÿlÿôRQGÅïù/¿íŸþŠJ+ïhŸøcù#Ê[ËÕþgsðn–ÒùœÉ…޵de&NNÒ=?Zõ²ÁýÙð"_þ*¼¿ààΗ©¥³?(8'™xÍz”K²—ËmG–vÞç8õ¯˜Îÿßê|¿$uàÿ‚¾›öX?»/þKÿÅQöX?»/þKÿÅV‹Hú4uÄqËy Aq$%ÂÚÜ8RѲ¶7"œgµs׺l²éò 6ÔÄçoú½fó~ÜÛ7LW~ÜíÝ•ÝÙÏŸ Ršº:±ßý–îËÿÿñT}–îËÿÿñU‰á-R+í1íËÜKbÞO™)>d±ÿË7}ß6ü ®H½I@-t“ºvc"û,Ý—ÿ%ÿâ¨û,Ý—ÿ%ÿ⪶¥­é:?•ý©©ÙXù¹òþÕp‘oÆ3Äg˜¬»èËý6VÖ˜0šNÛ“9Á}§ 8ÉÉçÁ½µM»#wì°v_ü—ÿŠ£ì°v_ü—ÿЬ½ÄPë²ÝB–7ÖrÛ,léyˆ}ÁH'#sí[4\iÙ‘}–îËÿÿñT}–îËÿÿñUç[ý³ÂÑêsÝê†òãG‚ñäMVê0&x‹³Y¯Ì~èF Ïðæ™&£k Õε¯1û|P4cV¸ È΀ççÏF= iÈɹêeƒû²ÿàD¿üU!··AåŽúD¿üUcxZIÖ-Œ²¼6š‡“–W•• ¼]Éfù¤sóŒàprÿ¬‡ýÿý”Ô=†'Ù`þì¿ø/ÿGÙ`þì¿ø/ÿPêš„ZN‘{©\+´6<ò,`*ŠX’p=kÍõÍnÆÂöÊÏ\פ“X™‚݈uy,á³Ìf@8Êes€ üß:åÎ8¨ÅË`nǧ}–îËÿÿñT}–îËÿÿñU‰á]N[Ûy šñ¯ŒkÑ]Ÿ½Š@ÛI(IÜÑ@Û·<”“‹³EöX?»/þKÿÅQöX?»/þKÿÅUjRéZ,÷6êrÌ[‰)çHë{ñÎÝî¹Ç8Î2x®QÕô+[é!“Å× ©@û%¹—Xò€‘I÷ V.0 `íå[?=B[v='ì°v_ü—ÿŠ£ì°v_ü—ÿЬÿÞÍy§È—.Ò\ZÌ`’R yŸ*º·d£¦pÝ»­Z™'f_eƒû²ÿàD¿üUeƒû²ÿàD¿üUdø£Rº°Óà‡OW7׳‹x $|­#‘¸í ²7Û»åÞWwËšáŸZµ6Ö:•þº²Ý›rem@; œ…WhŒ* @çhIZŒ¶ìzÙ`þì¿ø/ÿGÙ`þì¿ø/ÿUtkçÔt˜.eP³Ñʾb1GÚ;w)ÆyÆ3WêÓ³/²ÁýÙð"_þ*²ÁýÙð"_þ*¹¯k—zU——c#C2ÚÜßI"…ÝäÀ€²¡eeÎñ™HÛ¿¡År)­Øj–Ù%´k©%2ksÞ†aÈ’dÆÃ³¦g›Œ%%t Øõ?²ÁýÙð"_þ*²ÁýÙð"_þ*›cwþŸm{eŠâ™€+(#8ïƒSÔ;­‹ì°v_ü—ÿŠ£ì°v_ü—ÿŠ®3Æ·z­†¹¢3Qû<—†x‹Kn²¬H±ù„*ðI&1Õ¾ž•ƒ¬êq« wÄé­”6Ò‹‘o ²1¥R~ñÖ5ÁÈûßJ¾M/p¹Üý–îËÿÿñT}–îËÿÿñUÌØj:~§â;XôÿǨ¼vÒ»ˆ&·ªï‹ƒ±xóã‚+«©jÀB¶öî¡”JAéÿñT¿eƒû²ÿàD¿üU-¿ü{EþàþUÎx¯N{¥ê¢_!íY­ÖãnãledÛ(dDVÇ$€œg)jEöX?»/þKÿÅQöX?»/þKÿÅV$Þ!k›5´·ò­u™ E-»¾ÿ°•ÿY+Ž F´8hðG˜¦¥ð¾•—¥ÈðÅ$_m›íL’çxÊ*)}À7˜QŸ9>c?'­;4µ[ì°v_ü—ÿŠ£ì°v_ü—ÿŠ©kÕ^gñ6¥}&§$vWM„ƒQ¹ˆ$Ig„*G".rÎ}ÉôÉ1rv@ô;Ÿ²ÁýÙð"_þ*²ÁýÙð"_þ*¼çEÖõ¿Ú]®·£ë7qK(h‘o ¼œJK†Ž53´›¢0O—îfuz<Åsoż©,2¨xäƒ+©Áw¥$ã¸!>Ë÷eÿÀ‰øª>Ë÷eÿÀ‰øª–¹Ïk6s‹KpZ0Ï ûØ$Œ/#w¯¿Å%v÷Ù`þì¿ø/ÿGÙ`þì¿ø/ÿ\&Ÿ¬ÝilL( 'æxØ ¦¶~™Îw±H&…%PBº†ëƒNI C ½¸*—,p?Ò%ÿâ©~Ë÷eÿÀ‰øªYÖCþÿþÊjJ›Œ‹ì°v_ü—ÿŠ£ì°v_ü—ÿŠ®^¸Ö.µÉ4ù!Ô‰/iga9%ŒË_9YFpÁUK*íbQÞ­¦³áù¦ó#Ôón—:UÔÿi‘ÿnYرåĆ2U— Å™wTdÕÓ^„Üô?²ÁýÙð"_þ*²ÁýÙð"_þ*±O sA,sC"‡ŽHØ2º‘ÀŽ#iõÆEöX?»/þKÿÅQöX?»/þKÿÅW;©x«É•’ÅbdSÌÒd«}#ŽœçðÆ Uе«¨ˆ㺑œªõlI$¯?wžF}úõ®Wk…γì°v_ü—ÿФû=¹b¸— Ò%ÿ⽪jãåÿÜ_æÕ 6“ÝB“ÛÚ¡†@ —ó) ô8þtÿìËïùõƒÿ3ÿñ5ÂøâÒˆ<(÷wÛctÑÆ†ÌÜæSör@­–Ø’žv«ž€ÔÿtÏAa«0Ùhö’_ïŽÞûE•Y¿s, IGÝê ÉÍu8E+™«¾§gý™}ÿ>°àÆþ&™%¬¶Á^êÙV"Á7E}3IÀÈ8î@®SÃþ,º—â=Å¥÷Ž´ GJ’Ê/"Þ×Ê„}¥ä*©ÎìäÉ ¹æUã¦;ÍoþA¿öÞý•<«°jº”þË÷eÿÀ‰øª>Ë÷eÿÀ‰øª–¹Ÿ[ëkzö~º4ø^åÂ,üÑ+¤ù‡zåv¡F99Î@ÆP3µì[Ðè~Ë÷eÿÀ‰øª>Ë÷eÿÀ‰øª”ãR=ˆ5<êÏûíÿ¡à5kKF°ñŒ‡ÂË,‹,Ä]˜­¿t~ÍÜ }ýI”ó{ ]8ó½Aèwf+A2ÂY„¬¥• Ì›ˆ» Ü?1ëLÿ@ò¼ß7÷~g•¿írc~í›s¿®ï—¼u®Z}>ÀxšÕQPÚ\#Ȳùˆ’1fß—$rsóñßÂÆËû6ÿ„53ý¯´ËäÚd·ãË>z~ïw¶vóZ*KM/óÏ@û,Ý—ÿ%ÿâªô+Íówæy[þ×&7îÙ·;úîùqëÇZ¸~ñÎ3í^p¶6?ØQ7ü!«Ÿí`¦_&Ó%~Ý/ïîéû¼}ÞÙÛÍE8s »ðŠÐÌІc*¨fAs&à@$nèvŸÈúSì:˹.1ä°»‰2¥†ßŸŸ”Ç`Mriö'Ä7ê| klD>E–/>[ýfß›qÏÉÎ8Í]ÎÑ`ðl‹áT‰Ù¢&ëʵ̧ì²ä‡ÝÔ >`ËŸ½Wì—ËüÅsºk{tRÌ% Ÿô‰øª_²ÁýÙð"_þ*–ãþ=¥ÿpÿ*’¹îQÙ`þì¿ø/ÿGÙ`þì¿ø/ÿK<ñ[[Éqq*E J^I$`ªŠI$ðë#Oñ,7𨿷–Ñå­<î ÊÈ#ª>m‡¼õ¨ÕØo²ÁýÙð"_þ*²ÁýÙð"_þ*¥¢‹Œ‹ì°v_ü—ÿŠ£ì°v_ü—ÿŠ©h¢àEöX?»/þKÿÅQöX?»/þKÿÅT´Qp"û,Ý—ÿ%ÿâ¨û,Ý—ÿ%ÿâªZ(¸}–îËÿÿñT}–îËÿÿñU-\¾Ë÷eÿÀ‰øª>Ë÷eÿÀ‰øª–Š._eƒû²ÿàD¿üUeƒû²ÿàD¿üUKE/²ÁýÙð"_þ*²ÁýÙð"_þ*¥¢‹Ù`þì¿ø/ÿGÙ`þì¿ø/ÿRÑEÀ‹ì°v_ü—ÿŠ£ì°v_ü—ÿŠ©h¢àEöX?»/þKÿÅQöX?»/þKÿÅT´Qp"û,Ý—ÿ%ÿâ¨û,Ý—ÿ%ÿâªZ(¸7ü\]ž9ºL“µb\ž§ É÷¢—â÷ü—¿öÏÿE%÷”?Oü1ü‘åu—«üÎëààÝ¥êcilÅÚ æ^3^¥ì‚%òÄ[cQå†Ý·ÆyÎ=kË~ Œéz˜Ú[1Còƒ‚y—Œ×©D» ‰|±ØÔya·màqžsZùŒïýú§ËòG^ø+çù³Äk¿QðòúßL?òJæ¤X£¶…åpÄ"!ˆ'  ’}€$ûç›:¶™.¡%„°\¥¼Ös<Èd„ȬZ bÁ—Þç¯lw¬×ÑuÉ#•nµ[;˜™îmíç²waÊ9'fA¸ §ŒŒs\Tª¨A®§CZ‘hwIñ6§ugp5ð‚ßF˜ÅçRw&˘—s 3ó.zšãto ÝØêí<ò—†)ö‚—2ÂeP‹ “ä¸óšU1ÊNA.Iv‘¦ì«»»†kspgÔgÖ58uI1k|˜#x™ÈDSadgBij$ˆI9¤ösÉ3\ÕÛ75¹ÇþA©/<=öBkË}_QÓÌê‚Xí— 9Dÿ1R‘Œ„@~èÄ?ð\ÿÐÓ®ß6ü\Õ!ROF­ýy4êÓŠÕjQð½ÓÝx›Y3…[˜¬lb` —yÀ<í<2ç’¬§½uµ‘£øzöúô^Þ^]^¬K,—"qý¸ƃ?¼<œžíZõ¬W*HÆræ“hä<&?…´xw[*Çp–“x0™‡{õ­htHñ˜—KŽ@Ãc¥„!”ç‚|ƒôæ©éÚ·¤CµŽ¹`¶ÐÁ´+6›+8Ž1µ72Ü fÇS´zÒ¯ +5Ý+ ç.sÿ·u¿23±WÂßñóâ?û ý$¶­ÙÖCþÿþÊj†‹¥>•×r·77whžD‹ÊBÛ0 1Q¶5êÇœž_—ýd?ïÿ즲“»{go¨Ø\ØÝÇæ[\ÄÐÊ™#r0 ŒŽGô®6}S–Oqc5ì¶rùëqk4*$bYdd*HbÛWò€Ç½Íp¨á°5s„²ñÐUÔ´d¡8ÊŸU8\Ž€‚U…'NM'J¶±IA ãqP sœ*ºƒ8Uì Õ“”®Çea5}55m2[6mŒÅ^)1Ÿ.D`èøÈÎ×U8<`ðkž‹OÕ£›Ê:Af'j]Faõf!ð3ÉòÉë€Üï먫§UÃa5sˆð߈ÖÓP¹ÒµKh­.%½•LË+0ywUpTlÜ‚ ‡ãi;ZE ÛÖ½á«mh‰ÁŽ+°†##Ä$Ic9ÊH™—’G#žÌêÛð-­´6ë,Òˆ‘PI3nwÀÆX÷'©5““»•Šæ•ý©gŒ¨¹·”MnÌH°T‚GMÈιÁÆì€HÇÛxOQK+}-lnDVÂÝb’[¸VÀáÕ·.dùŠ(?'!G œC¢®\„ÕÎ;Á^$†âÎÛJº·[;Ý…Õw“æÈIiA ’†ÞZ1¼€NÖÛØ×?¬xNÛT½û\SY¤+ç² %‘‡Ý•v¯Î02jíè*m¶Çem{Åžÿ„†Ä¤eV&[bYÊn†P®ì6Ó•FÎÓ÷1Ñrñ6ïZi¬#–æîZІ)ÓåHT³¾‡ Iäúú…¤*¸« «œï…¼Ac©ZGa PÛKm ˆàŠs4m €£€]@* À ‘Ù•›¢®~_ Úr-FÞcl¢aq,Hƒ™rȃvH~à[¡f-ÐVWmê7n‡'㦥ͅΥeqvÇ"Å´†9 ’¼P ­¹1þ´ŽXsÚ¹è ±¸’}7EÑ5K{Û¦³»aw}ᢶ»› gr‚@=¹Î{]CDmGQŽYnXÛª014q8VÝ.!ÈÊgžA‡„l4©šm8¥œÌ›Kk+XØ®AÁ+8ȵMYjI‰áËme|e Úžuié·(†yâ}ÄËnp6;c…ïðî«(iWCT·¹:ĉn­½bÉË!Ç8;N{ôÅjÔÎÎÃDvÿñíûƒùW?ã/é¾Ò'[Ûu¼y¡`-ª¤Š~\;?ʪKÎIç°EtÿñíûƒùW-â ßj:­¶·¢^Ek«Û ^S¼×…–PAFÎñÈÛÉMEËÞØæÐø¢þ=ÄÖ:¤ŒÞDW·m&¢öÊ4SIŒÇÊ înV$7›ìz¿câ+¶X´…xÞ²I‡ x=Tyçƒ\ü+Qm¡ÙŧÜŧg9¸ŠVݳv#ÚwcD1VÎÕùÈÞðËø~+Ë‹ÉÒ}JýÄ—2G¹Ë±êIy$l…QóÆNÕ'g¯õåýv%\èëÌî;[8åãš1xÈ'‘eÜ ,òl;¶Ž‹ó¨œñ¯ õìz¢ZÜù6¶Ò[ÁÂÉ5ÃÊñ–6”æ5EËžÚ_W]ð¥ÄױϤN`Šæt‘)PcVpdš-À¨l,¤a‰Ü>mÁô´ Yi7+vóÝ_Þ&Dsݸ&0FT@¨ Ûwa˜nÁÅtÂT ”–仲ˤøsJÓgxÞk;(m¤hÉ*Ì‘ª’ ã#ŽM©y¿Ùw~Fÿ;È}›3»vÓŒc¾jÕÏ}n3‡ðÜVÓkgXÙ|¬Â­Ðžø¦k¥°µÓl¯î¢¶e7N|ÉžTœ@3ÓÜg¨¬}_Ã|Ý9#hÜüÐ1/¸>žÝ»qÀ4 ÝÃyÍÓ$ ec‰²IúŽ€ää[³Öâ:ºãåÿÜ_æÕ%F¿ñòÿî/ójÌ£W¿³Ó,¼ yw¥´w«¾i䢿Æà ± H%ŸÄÛÁa ÑuX ¾’ŠiÛÎeT%Dŀ˯ðäÒºþ@Zý{Gÿ Š¦žðÌwQ]Gáí%."*c•l£ …q´ƒŒŒ`cÓÒ÷3ŽÇ‚Úx’mÅ> ñ®ž,¥ÒÝf’QåÂc[wxä*Jí;IW ù¾Sº?¡5¿ùÿÛx?ôjW‘üEøM6§­ë>2Ù&§*Ü[K*nmãDYP·Pí†#nN€K¾˜¶6Zo„l­4ØçŠÆ6·G;H]Ê„)ó>q€qµ¾î1ŒR@ö2üK¡]ëgKû.§%¢Ú_Ãs4` ³"8$#QÊ’9 ÔÔ4©ãÕ´0úö­+=䊌ÂÔygì³Ã œ9Èç¥u®øZ=sTÓ/_RÔm~Ç!fŠÖåãYFÖà§æ ²à•,¹äšu-döסMæð¾ þ(Ò51â-BH,–o69D;¥Ý³ òF£aÛ–ÎOÊ»p~aÓÐNNh¬å7+_ Ò±êÏûíÿ¡óý^òÅl|aø Ç+K0KA5¸óÙ£pP±äàƒòcïd× Aþ¬ÿ¾ßú®fþÏÄ2iÞ&¶‚ÂÈÇ~òùDß2»©·Ž1…òñü=—œŒàn:Qi=­DÊwŽ–|KlãÇ,È-.Oö‹> ’.|¬ Ø'‘Ÿ“Œsœá}§bD¿ð˜ÿÚÛ¼¯>×å_·çÌÇ—žŸ¼Îv÷ÆÞ+«˜ø‘üAox,tݱÚÏF¥&ÕÞñ¾Nsò`×$`fˆµñ/öDv¿Ùú~F§ö¬h6Hûg“û¬cóœs·?-lšÓþލã1>gö¶ï/ϵá~ÝŸ3^z~ó9Ûßx¯H?xóŸZäÖ×Ä£FŠ×û;Ojbëoöƒgló¹ýÖ1ŽùÎ9ÛŸ–²¢ÒßÈl«gw§Íâ[´‹Æ’1–ÞÕ#džÐ´¯¾o~럟œñ‹š=ÞŸgáw»Õ®ÐZ4+VÉJÂs„Pù‰Úå;múŽúãþ=¥ÿpÿ*’£¸ÿiÜ?ʤ®rŽ/VÔ'¿ÖÉá“}´Ê-¬ËJü”™»0ùI@ÕØÌÄ2Ÿ&¾¯ Í§@·„«qjÊ Ô±’¦ÑÁÈpÙ Âþóå(Ë»å\{­‰æ‰v/š | ÁI€} UÏÐS«UW•$‘62t «Û›IRó÷ÞDžRÝ€O޹:žhÛž›NèÓZ›$QGh©h ªtS«94Þƒ (¢ÂŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( œ>/Èù{ÿlÿôRQGÅïù/íŸþŠJ+ï(Ÿøcù#Êë/WùÃ]jM2Úkhl~Ö÷q  &òñ·ÌÏ8ô?¥z~#Õ"‰#OáQB¨ûjžÀí^]ðóþBîäõêµó™ÌSÇTù~HêÁ¿Ü¯ŸæÆÿÂM«нÿ“©þÂM«нÿ“©þê+ËäGMÆÿÂM«нÿ“©þÂM«нÿ“©þê(äAq¿ð“jßô/äê…ð“jßô/äê…:Š9\oü$Ú·ý ßù:ŸáGü$Ú·ý ßù:ŸáN¢ŽDÿ 6­ÿB÷þN§øQÿ 6­ÿB÷þN§øS¨£‘ÆÿÂM«нÿ“©þ‡Äš©*O‡yS‘þš¿áO¢ŽDÿ 6­ÿB÷þN§øQÿ 6­ÿB÷þN§øS¨£‘ÆÿÂM«нÿ“©þÂM«нÿ“©þê(äAq¿ð“jßô/äê…ð“jßô/äê…:Š9\oü$Ú·ý ßù:ŸáZÚMýö¡Ks§Çi%@ûG˜ÄñØ.1ϯn•—Px‡@½ñ7µ +OÔžÂâf :ýÙcsŒ„n‡o?Q•)Å$: 'Ö/¬mîâ²±ÏÊ¡¯ 0ÈÏîºóSyßüùéÿøÿüj®xwþE+þ¼áÿÐiSäAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨§È‚æ‘­ÿÏžŸÿ¯ÿƨò5¿ùóÓÿð5ÿøÕoQG" ˜>F·ÿ>zþ¿ÿ£ÈÖÿçÏOÿÀ×ÿãU½Eˆ.`ùßüùéÿøÿüj#[ÿŸ=?ÿ_ÿVõr ¹ƒäkóç§ÿàkÿñªzþ¿ÿ­ê(äAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘Ì#[ÿŸ=?ÿ_ÿQäkóç§ÿàkÿñªÞ¢ŽD0|oþ|ôÿü þ5G‘­ÿÏžŸÿ¯ÿÆ«zŠ9\Áò5¿ùóÓÿð5ÿøÕF·ÿ>zþ¿ÿ­ê(äAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘Ìm­¤ÙiùS‘þšÿüj—ÈÖÿçÏOÿÀ×ÿãU½Eˆ.`ùßüùéÿøÿüj#[ÿŸ=?ÿ_ÿVõr ¹ƒäkóç§ÿàkÿñªF·ÿ>zþ¿ÿ¤û6´·Ø´üÿMþ5ï[ôQÈ‚ç6–^"‰p5¼1/ Ýä(ô 'õ¥û7Š?çâü _þG®ŽŠ¢lsŸfñGüüAÿ+ÿÈô†ËÄ2ûGÙ§U!‚=æGCòÀ3]%Œ#[ÿŸ=?ÿ_ÿQäkóç§ÿàkÿñªÞ¢§‘sÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘̶֔`YiàdŸøý~ÿöÊ—ÈÖÿçÏOÿÀ×ÿãU½Eˆ.`ùßüùéÿøÿüj#[ÿŸ=?ÿ_ÿVõr ¹ƒäkóç§ÿàkÿñªzþ¿ÿ­ê(äAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘Ì#[ÿŸ=?ÿ_ÿQäkóç§ÿàkÿñªÞ¢ŽD0|oþ|ôÿü þ5G‘­ÿÏžŸÿ¯ÿÆ«zŠ9\Áò5¿ùóÓÿð5ÿøÕF·ÿ>zþ¿ÿ­ê(äAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘Ì#[ÿŸ=?ÿ_ÿQäkóç§ÿàkÿñªÞ¢ŽD0|oþ|ôÿü þ5G‘­ÿÏžŸÿ¯ÿÆ«zŠ9\Áò5¿ùóÓÿð5ÿøÕF·ÿ>zþ¿ÿ­ê(äAsÈÖÿçÏOÿÀ×ÿãTyßüùéÿøÿüj·¨£‘Ì#[ÿŸ=?ÿ_ÿQäkóç§ÿàkÿñªÞ¢ŽD>Xøº|wx% ²à­”™ÁÀÈü/Æ_ù(z‡Ö?ý”WÛÐþ ?ðÇòG˜·—«ü͇Ÿò³ÿpÿ'¯U¯*øyÿ! ?÷òzõZùÜãýú§ËòGNø+çù°¢Š+Ì:BŠ( Š( Š( Š( Š( Š( Š( Š( £Ô¼Ooám7NšæÞi¢½ÔÒÈù ]к1 [•žxÉ2V¶RÚ£É;Ã9xÙ”·nG¡Ã0Ï¡#½L¶5|;ÿ"Εÿ^pÿè´«7ÿò,é_õçþ€+J¨AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPË¿ä¡êXÿôRQGÆ_ù(z‡Ö?ý”WÚÑþ ?ðÇòGš·—«ü͇Ÿò³ÿpÿ'¯U¯*øyÿ! ?÷òzõZùÜãýú§ËòGNø+çù°¢Š+Ì:BŠ( Š( Š( Š( Š( Š( Š( Š( ¶t¯øòoúè¬jÙÒ¿ãÉ¿ë¡þB¦{ ^ÿ‘gJÿ¯8ôZU›áßùt¯úó‡ÿ@¥T ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(åߌ¿òPõ¬ú)(£ã/ü”=CëþŠJ+íhÿŸøcù#Í[ËÕþf‡ÃßùÙ¸“×o‰ÍͼWèÚ‹E*FÌ ŒƒÌ•Ä|<ÿ…Ÿû‡ù=t:Mà¶Ñ¬mæ³ÔVX­ãG_ìùÎPá+çóTž:¥ü¿$ta?‚¾›6¿á —þ€šýõÿ£þ è ¨ÿßPñÚ£ý§üúê?ø.Ÿÿˆ£ûN/ùõÔð]?ÿ\<îtÝ—Š-àš¾³¹°ŠW('¹xD`í-‚D‡Ú{uÅYÿ„“Bÿ ÖÿIþ5†ú„Mªé.`½DK¼3Ëe2*îã\–P9gQø×_YI$ô3?á$пè5§àRð’h_ôÓ¿ð)?Æ´è©3þM þƒZwþ'øÑÿ &…ÿA­;ÿ“ükNŠÌÿ„“Bÿ ÖÿIþ4ÂI¡ÐkNÿÀ¤ÿÓ¢€3?á$пè5§àRð’h_ôÓ¿ð)?Æ´è  ÏøI4/ú ißøŸãW-/m/â2ÙÝCqm¥á8Ó#¿"§ªwz|sÊ.¡Û ò.Ô¸ “Ž»[ûÈsÊçÜ`€@Ê*…½ì«:Ú_EåNr#•qåN@ÉÙÉ ã­Ï\ ZªÛkÓ]ÚÃs‡¨¼3 ‘t*FAÁ—Ò“inÍ—ý­wÿ@Gþû·ÿã´k]ÿÐQÿ¾íÿøí.h÷R¶t¯øòoúè®J=eÍåµ¼ú]í·ÚÆ’JÑÜŸk“ÑOjët¯øòoúè¥&šÐhÒðïü‹:WýyÃÿ  Ò¬ßÿȳ¥ל?ú­*±Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@.|eÿ’‡¨}cÿÑIE/Æ_ù(z‡Ö?ý”WÚÑþ ?ðÇòGš·~¯ó4>ÈBÏýÃüž½V¼«áçü„,ÿÜ?ÉëÕkçs÷êŸ/É8O௟æÂŠ(¯0é ½´ŽúÎ[i *ȸ‡ ‡³)ìÀàƒØ€j-*îKÝ2 æ ·vNª8YTíuÁƒ§§SW+2ÓýX»³<%Înà û«"Û µÉã&SèMiÑEQEQEQEQTîõK[)DRyÏ!]Å ·’b£±!àg®:ƒûgÍÿM7Q¹ÇÞýÇ“·ÓýqL÷éœcœddõÅ´p40G4-ÑÊ”àädzÍðçü‹OýyCÿ  “f·q÷æ²²Sò•‰ZwÇ÷•ÛhÐ`1žsŠÍÑuXm4:Ú{mE&†Ú8ݳ§8` žµ•TÚV:+7ûvÓþxj?ø-¸ÿâ(þÝ´ÿžþ n?øŠÃ–]†—ü„´Oúýoý'šºý+þ<›þºä+‡–õ5 WIX ½ýÕËHí-œ±ª¯“*ä³(XÆ»+þ<›þºä+h¦¡¨ºš^ÿ‘gJÿ¯8ôZU›áßùt¯úó‡ÿ@¥[(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šùwã/ü”=CëþŠJ(øËÿ%PúÇÿ¢’ŠûZ?Á§þþHóVòõ™¡ð÷þB6_îäõêµå_ä#eþáþO^«_;œ¿Tù~HéÂ|ÿ6QEy‡HVf±þöMDqöY‡˜G‰þGÉì«‘!íû±œutÙ#Žhž)QdÔ«# †¨#¸ QX–Wz••œV“é7÷2@¾Q¸Ya"`¼ù¤,l™Ç=jÇö¥çý5ûùoÿÇhN ¼¼‚ÂÙ®.–0Ê¿*3’Y‚€‚I$ÀªÚ—ŸôÔïå¿ÿª½ýÌöG&‘{n¦ö×2Êð•_ßÇ×l„ûp)0/oÙÏ-Gÿ·üEÛö_óËQÿÁmÇÿZVÙö*Æöý—üòÔð[qÿÄRIµt‡·¢ÈסdXPW – ƒ·#äãå ~³|/qxSIXÑQM¤LBŒ •Ÿ©$ŸÆ´§>a4_´´ŽÎ"ˆYÝÛ|’¹ËHÝÙ¯qÀTôQZ(¨®.`´§¹ž8a\n’W £'$ûÕøI4/ú ißøŸã@tVgü$šý´ïü Oñ£þM þƒZwþ'øÐlé_ñäßõÐÿ!\Ÿü$šý´ïü Oñ®«E’9´Ñ,N²Fï¹]NC=ÅLö5<;ÿ"Εÿ^pÿè´«7ÿò,é_õçþ€+J¨AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPËŸä¡êXÿôRQGÆ_ù(z‡Ö?ý”WÚÑþ ?ðÇòGš·~¯ó4~ÿÈFËýÃüž½V¼«áïü„l¿Ü?ÉëÕkçs÷êŸ/É8O௟æÂŠ(¯0é (¢€ (¢€ §ªYIcäE2à –)UÙ7€QÕÆFFAÛŽ¢®Q@_f×?è%§àÿñê>Í®ÐKNÿÀÿãÕ«EG³aÜÊû6¹ÿA-;ÿÿT6^m2ÂÚ ù­Þ•h ¬  ˜Û;A9'aRrrsÈÛ¢©E-„f}»R·ýÜúT—,:Kg${z‘#)SßoÌGÌhþÔ¼ÿ £ÿ-ÿøíiÑLwW¿¹žÒäÒ/mÔÞÚæY^«ûøúíŸnoUMbÖ{Í?˶™–heQ+S²Er ã!qÐÔ>n»ÿ@í;ÿßÿŒÖ5`äôfæë¿ôÓ¿ð=ÿøÍn»ÿ@í;ÿßÿŒÖ^Ê]‡sF­xþD/þ½¢ÿÑkXžn»ÿ@í;ÿßÿŒ×Eá;I,<3gg)S%¼i<¨ ãÛŠ¸ÅÅ;½áßùt¯úó‡ÿ@¥Y¾ÿ‘gJÿ¯8ôZUÐHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEòïÆ_ù(z‡Ö?ý”Qñ—þJ¡õÿE%ö´ƒOü1ü‘æ­åêÿ3Cáïü„l¿Ü?ÉëÕkʾÿÈFËýÃüž½V¾w8ÿ~©òü‘Ó„þ ùþl(¢Šó¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(­+þ<›þºä+¶t¯øòoú詞ÃF—‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiU(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šùwã/ü”=CëþŠJ(øËÿ%PúÇÿ¢’ŠûZ?Á§þþHóVòõ™¡ð÷þB6_îäõêµå_ä#eþáþO^«_;œ¿Tù~HéÂ|ÿ6QEy‡HQEQEQEQEQEQEQEQEVΕÿMÿ]ò[:Wüy7ýt?ÈTÏa£Kÿò,é_õçþ€+J³|;ÿ"Εÿ^pÿè´ª„QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|»ñ—þJ¡õÿE%|eÿ’‡¨}cÿÑIE}­àÓÿ $y«yz¿ÌÐø{ÿ!/÷òzõZó…–oÔcýï—äÛ™>îsÉ\uÿk?…zçö@ÿŸƒÿ|õëæó™%Ž©òü‘Óƒ_¹_?Í™tV§ö@ÿŸƒÿ|õèþÈóðïþ½yœÈê±—Ejdùø?÷Çÿ^ìÿ?þøÿëÑÌ‚Æ]©ý?çàÿßýz?²üüûãÿ¯G2 tV§ö@ÿŸƒÿ|õèþÈóðïþ½È,eÑZŸÙþ~ýñÿ×£û ÏÁÿ¾?úôs ±—Ejdùø?÷Çÿ^ìÿ?þøÿëÑÌ‚Æ]©ý?çàÿßýz?²üüûãÿ¯G2 tV§ö@ÿŸƒÿ|õèþÈóðïþ½È,eÑZŸÙþ~ýñÿ×£û ÏÁÿ¾?úôs ±—[:Wüy7ýt?ÈT_Ùþ~ýñÿ׫–¶âÖ}ÙmÙÆ;õªe$Ð$[ðïü‹:WýyÃÿ  Ò¬ßÿȳ¥ל?ú­*ÐAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPË¿ä¡êXÿôRQGÆ_ù(z‡Ö?ý”WÚÑþ ?ðÇòGš·—«üËßíâ»ÔôËyÐI®ˆêzY³^ëÿO‡?èýößã^ðßþCšGývÿB5ô}|öqþûSÕ~HèÂ/Ý/ŸæÌøB|9ÿ@¸¿ï¶ÿ?á ðçýâÿ¾Ûük~¨kVRêZõ”ùRÏF­Æ2F0x<‡Œàœs^eÙÓd`Yh~Ô§– (¬®%‹ï,S–8À9ò>aÈãíŸ.:qæÖ|vþ)–i&KÝrÝìqÙ€ b/çBì²+n‘m2Þ`$d4€º©Rì,ŽÇþŸÐ./ûí¿ÆøB|9ÿ@¸¿ï¶ÿã’ßÅ/wtË{®[­´¶Ö¶¸‡–u+ˆZBXHËk°–mÀ‚®ÛˆFÏöø¶½ŽoíϵEÄ: ‡Ï Ü%ÍÊÆg)Ã.Áió\edäæBK°²;øB|9ÿ@¸¿ï¶ÿ?á ðçýâÿ¾Ûükž†×]·òoVã\–æçUÔ ’0ἫQö¦„"Iûµù’Žãø•wl!jdžZ·Ó®…„ß2Ê€6«5ݤn0K2 …–uaò)RZ2e`ÅÔadjÏá ZÛËqqao !y$’VUE$’NœÔká?—¶ÖͼÙ^ñ9;äMÛ|ܰØùFÖô5Íkp^ÝhÞ%·’/M­Ko©!Ž5•­^²ˆ û’Jy~ówÞÿ–µ¡o¥\ͪxSº¶»–ò wPC,ÛØÃl~۳ᆈd`0@Ladhê^ðVn·¤v03„Y.®|¥-‚p 0À'Æ®ÂáÏúÅÿ}·øÕmZìYø¶ÃS’Úùí-m.¬åx,¦˜‰dki ŠY”ª?ÎPFÒCqZ±¸Ó<¡Ø^GåÝZéöðÌ›Úë†zQvDð„øsþqßmþ4ÂáÏúÅÿ}·øÖý]…‘ÿO‡?èýößãGü!>ÿ \_÷ÛoÑEØYð„øsþqßmþ5†›e¦O¨Cel GÊ9Ç–§“ÔòÇó®’±Güj?õð¿ú)*dýÖ jXðïü‹:WýyÃÿ  Ò¬ßÿȳ¥ל?ú­*c (¢€ ­©XévÆçQ½·³€n%XÔ© UšáµxÒëâ¢u -2Ýíà ˆÚYgÃБ ûUÂ<òålÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿT¨®ªù“Ì]ÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*©QGÕ|Ø»ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUR¢ªù‡1wþ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøª¥EUóbïü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñUJŠ>«æÅßøNüÿC^‡ÿƒøªÚµ»¶¾¶K›Kˆ® e%‰Ã«b85ÌVV­è¾ñ^³i©Øi–÷Ö·QÇqp‡•še‘”18Ž<ãÛÖ³©C‘^ãLô*+Ÿÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*°ÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üUðø?þ†½ÿ0ÿñTÐQ\ÿü'~ÿ¡¯CÿÁŒ?üU_ÓaÈãÖŸoó¾×çmò¥ÿU¿ý+ýgÙ÷lùqÓ6³ã·ñL³I2^ë–èŸcŽÌ[É:e‘[t‹hÑ–ó#!¤ÕJ€z…åéoâ—»ºe½×-ÖÚ[k[\ÃË:•Ä-!¬$eµØK6àAWmÄ#çû|[^Ç7öçÚ¢ŠâÃçnæåc3”á—`´ù®2Œ2rs! ¡Eyü6ºí¿“z·ä·7:®¥‘‡ åZµ4!Oݯ̔wÄ«»a V<0úÕ¾t, žù–TµY®í#q‚Y\,³«‘J’Ñ+. ´†xnP¼Ç*d,ŒV*ÃŽáv Š’¼X‡Äöš}Ûé±j°ÜC.¡sc6óH&”Þ\>vÆè£äò˜yÞbÈÐÊû6¾)·Óž÷L¸ÕeÕîu RãËG ]µ¸ÿ"¯˜vÃݰ… @¾¿³Ó,伿»‚ÒÖßgýý£ö¸>Ãåyÿió—åãvýÝ6ãœôÅyÝ®±—¬êÓEcâ FÚÞÞÉôËkØ'šH¥‘®‘䕦8`Îê_… ¾ZIíÀðe¬6‰}s#jê“°š!oÒyÈ—rõr‘œ»(ùw‘’ÖA«i·V_Ûê“YÊá#¸ŽehÝ‹ì08$·Ë^:Ô—×özeœ——÷pZZÇóO $–< ’ã\Þ’uT½ÕÆŸvþgˆì.¬„ÐÈŽ±«YG$†&©T£s(!wò¹' ñ,¦=GE¹÷rŦÞý¦äÁm$¥c{{ˆ”¨U%ÎöPUrTHšè ž«x®-åŽh%@ñÉWR2#‚ç4A<7Vñ\[ËÐJã’6 ®¤dGÎk‡ž  ø{)¹ŠH ŸX73¬ªWý]GÌs*Ÿº†%Õ±…, Qßï¿Ä·_E»ƒìÃg<‘½¶ØüÝÎ%[uËyàùŠÒÊäùb€;ɧ†ÙÏ,q!u@ÎÁAf`ª9îX€r@¬‘ÿÚý|/þŠJæZ×ĉD÷̺UÝŒOÈ^ò3w ¼Òùi‹q³Œ Æä·{ŸlþÅÿ‰—Ÿý£¹~ÙççwÚ<´óqŸáß»nß“n6|»iKáaÕ‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(®&ÿþJ¥ÿ`«/ýu]µq7ÿòPõ/ûYèÛªÚ‡ñžÆ]Þ¶Ö^!{FÞ–˜¸ ™æ@@Û’K")Ëcæt~+û[E²Ù-ÄÑ uósæC vtãåŽC·Ÿ»×šÐ¿Ðmu¿yd™ZöÚ;g(ÀlÎÊËÇ „äç ãÕŸØÀkö—ª‘%µ¥£C.w$c#T9þ6éŽ{}âLßøM ‹KÓnîÅ•›j6ÿi·[›Ñ „‚å@Ý™p3‘ÈÉâÔò$»‚ÐËg¥$†M¬!“Ì<.9 Gœgžz`fô:½¶Ÿako=ÄMcköHgR¾g—…WìSÓ¨íUæðà¹Ô®^iäû¶PZ² yB4¥–BA$ëÎs÷½y=à'½ñ6“iiy8Ô-%û‰ ­ÂþåÝÂ!ÏÈ7u'¦¥PÆ6òÙ5ÜGu w jïg8•|ݪѪ°`Û•sÆޤoÞZE}l`˜»•ÁU•ƒ+pÀ³î^ã"Ðð킳ìWD6öÖ而F vxÊñÔïžƒŽ¹=à¡ëvÚí´òÛI‚ Œ.öó c-µ[åqÔa‡Ðäv­ Èï®Ø6ÇÿF]Tv–¦Ö7Sq<ìî]žfÉÉìÇ@üI§xmÐxïZŒ°ÞÚe“Ï$ n²QùÖuïìõÜì袊à((¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+?TÑ­5e¥ßÌ$˜.¡;e„žêß̃ÜТ€9èõ«­U¶ñŒBÄ,:œk¶$à ü²nNÒzNÚèi²Gѱÿ褢Œ¿òPõ¬ú)(¯µ£üáä5o/Wùš ÿä9¤×hÿô#_G×Î ÿä9¤×hÿô#_G×Ïg?ïµ=W䎌ð—ÏóaECZ²—RÐﬠ—Ê–x5n1’1ƒÁàô;Ë4“%î¹n‰ö8ìÀ± —ó¡vY·H¶o02@]T¨¨Q^^–þ){»¦[ÝrÝm¥¶µµÀ,<³©\BÒêÂF[]„³nvÜB0.·Åµìsn}ª(®!ÐL>yá.nV39Nv Ošã(Ã''2êWŸÃk®Ûù7«q®KssªêPIpÞU¨ûSB$ýÚüÉ GqüJ»¶µcí[é×B ï™e@UšîÒ7%™ÂË:°ù©-2°bê;Hg†å Á,r vBÈÁ€eb¬8îGb¢x!º·–Þâ(æ‚T)$r(eu#x Ž1^_$Í´šµ˜® Þ¾ˆ¶«:¡»kۦ̻>M„b ÿ» ’8ßF³?ˆáÔbK u”Öæ½Ô+6-ýé¬ÂïýÙ;V3„ùr —ç @‰ca£è1Ggaic§Gq)Ù ¤"Y6’p£m¨O®ÐV…xÞ¯>²×š­¿‡¥ñ9¶K%{xî5wZêC*÷ –0 Ÿ1u\|¢:é5;]OOÖÍ®5Ëý{é£yžgf[ å/x–„¤8Ud¼’xaxRYcG™öD¬Àm¥°¾§j±Àì íUõ-[MÑ­ÖãTÔ-,`g²]L±)l€XœqìkƒÐ¬n/ÿáÕ®£¾º¿·Öõfží„’Aûrá¶f4çËS³ J ä*Ðj×bÏŶœ–×Ïikiug+Áe4ÄK#[H˜TRÌ¥Qþp ‚6’Šê*8 †ÖÞ+{x£†$qÆ¡U à8ÅeøNÆãLðn‡ay—uk§ÛÃ2nk¬jdppAé[V(ÿíGþ¾ÿE%mV(ÿíGþ¾ÿE%)|,:¢Ç‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(®GÄ:^©ˆFµ¦ÙøæµK[‹t‘EØÎÈɼ…?ëHíÖºê*£'tösþ… _þÿÙÿñú>Ñ®С«ÿßû?þ?]å¯Ö&+#ƒûF¹ÿB†¯ÿìÿøýh×?èPÕÿïýŸÿ®òŠ>±0²8?´kŸô(jÿ÷þÏÿÑösþ… _þÿÙÿñúï(£ë #ƒûF¹ÿB†¯ÿìÿøýh×?èPÕÿïýŸÿ®òŠ>±0²8?´kŸô(jÿ÷þÏÿÑösþ… _þÿÙÿñúï(£ë #ƒûF¹ÿB†¯ÿìÿøýTƒMÔtÛx¿R„Z™¤L’ØHÅlä…g#åÝç2g{õ¯GªZ¾¯£ÞiÓ©s DXu\Œ=Áä}*gVSVabí•áÍJMW@´º¸n¶˜®T ÈJH?V­ZÈaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP>© ­åÈ¿±¸k Q*ÝF»ƒ¨þ £¯±äs‚5†¼ëy™­@¶:‹äDCf¬u11ê{ì8aèG5¹U5;-GNšÛP¶[‹f\¼l…³Žrç#¶9ÏNhvž$ž8ZEÈ D'–ÇÓ#ó¬ NçRÔ!²ñWˆo5›Ì7:5ƒ'˜ÛÍ» §ÜŠÎ´œ`Ú5°u_úµÏûóeÿÈô`ê¿ô9kŸ÷æËÿ‘ëZêþÎÀDo.à·¸Ž?:@›ÜôQž¤úR½í¬wij÷0­ËŒ¤&@‡°êzáöµ;•dd`ê¿ô9kŸ÷æËÿ‘èþÁÕèr×?ïÍ—ÿ#Õæ×tt–HŸU±Y"F’D7 *±V$g€Ob¥›\ÒmíbºŸT²ŠÞTó#•îQÓ*7NË(ÏûCÖkS¸Y?°u_úµÏûóeÿÈô`ê¿ô9kŸ÷æËÿ‘ëV FÆæâk{{Ûyg€,qʬуÈÜÈϽ55M>Kv¸KëV\FÒ ”¨b@ Nq’H÷{ZÂÈÌþÁÕèr×?ïÍ—ÿ#ÑýƒªÿÐå®ß›/þG«ç\ÒL:™ÕlFž ѸO+9ÇßÎ:ñ×­[‚xn IíåŽhd’HØ2°õpEÖ§p²1°u_úµÏûóeÿÈô`ê¿ô9kŸ÷æËÿ‘êk_è÷n—{-ôcT†9­bº•#‘è`Ï'‘ÀÍ]mWNKå±kûU»f(°”HX(bç9ÚAÇ¡kS¸YŸØ:¯ýZçýù²ÿäzdRêš&¹¦ÚÝê²êvzŒn­si,R¬o( ƪ¥JÆãr9­íx,þÙoö¢vˆ|ÕßœÆÜç8V?@OjÊ׿ä;á?û Éÿ¤WUtªÍÍ&ÄÑÒQEÞHQEQEòïÆ_ù(z‡Ö?ý”Qñ—þJ¡õÿE%ö´ƒOü1ü‘æ­åêÿ3Oá¿ü‡4úíþ„kèúùÃá¿ü‡4úíþ„kèúùìçýö§ªü‘уþùþl(¢¨kVRêZõ”ùRÏF­Æ2F0x<‡Œàœs^YÔZÖ—©O,Z…µÄ±}åŠ@Ç#Ô|ÑÆxëVçžn.%Ž"BòI#TP2I'€ç5å> ðf»eâ˜.îíÚÒVbî] bWî¯\ƒ»ÿ½È"½ ÅŸlÿ„7\þÎóþÝýŸqö³çÌó<¶Û³îÎ1Žs@WÚV±{¬^i_ß[é‘y÷QÞÁ3¤Ïö…eHÑ´ùl×n>P-HβáM{Äé·wW·vë6¦lnãÒåt‰c·‚å&'9*ãz†È;qè”W‘ëmâ[Qâ[Ù5MJâ·ÔœÇ­ÂÆåò™¥òÈ9‰<ÌðßòÔ×Q£É¯Eq|Úm¥ÝÌ šíËÀÂç2ý «Ü#1äòÛ ¥æö°ë_ð”_K©ßj¾O›wö›{{;½¿dÄžVÉD¾Ví¾IByÛ¸<ù†¤¿óèÒ%äšÌWmq¸•QäÚíÄBZ•grÁD‚&VI0Rè•–žÐc¸»¸MMYïQÒêEµ@Ó«œ¸sŒ°cÉ9ï^w¦Ããá2ÜÝk–—}’Þ4ðÔ."‘Ê·˜–Ûi%šA‚®ÅÈGÉ>¼u ZÏÍñ»¶²eÒ£‰œ œ]Þ¥«M˜‚‘ÇóÉ˜Ø ÊIØhÓ4{ O³x´KKkS+ïK(Ñȧcd/]§¸ÛŽÕ&¥¤éºÍºÛêš}¥ô áÖ;¨VU ‚23‚F}Íy}Å—‰RæT†çR°‹í`°X\L^v¾¹bO—,q€TÛn3 ‘¿>¹@Á6¶ñ[ÛÅ0D#Ž5 ¨ `Æ*J( Š( ±Güj?õð¿ú)+j±Güj?õð¿ú))KáaÕ<;ÿ"Εÿ^pÿè´«7ÿò,é_õçþ€+J˜Q@Q@Q@Q@Q@Q@Q@Q@öš?³|[ªiçˆo”jö¸Ž`?}d5Ð×?âŸô5ÓõÅãû:äý0“ä“>Àÿöκ (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*;ˆš{ibY¤… ‰cÆä$cpÈ##¯ Š’£¸‚;«imåÝåÊ…c”8#  ûƒšÃðý¬–ºŽ¤°]]O¦-"7W;yÚUÜ“·˜Æ3€ÊøÅbéóÜÿliº‹]Þ4·ÚÕõ„нØDQ ›c'j‘ä' w“šèôß éÚM±¶³{õ‡1’j7„òÎT.÷;W±‡Å>évú»ê‘@âé‹6LòVa†eŒ¶ÅcŽHšÑš®"h§‰%º£¨`\ž‹¤iÚ?µØ´Ë{8¥Ó¬exíã¥Ì—@¶Âʺúç-ÿä¡ëö °ÿÑ·uá±­È|Eaw6«ay—© [\ZÉk#¢¦e1í» FÊp Ãð"«^è—òêwªîK½VÒùn·¨Ç‡rÙ>SÞŸzë(®&Š8ëMõHim0ë÷ד’Êq ý«ËcÏ?~:Ž8x4múßY²–êÑE´?ÛË+óïâã=ã ôŠìh£çñxWU“Ãú=–-®Â÷:uÄ»ÔùW2-¸ óÊHr28<ò3rÿDÔu .îOûa ¥¶8]Àã#9±£ê×———V:•„VW–ñÅ1H®<å1ɼ)ݵyÌnÇn¦¶)6ö`y¼þ×ÿá¶ÒcÓãEc O+y™c`cw'Iä·#ƒ[šüϬº[{{O»…·®Z¾É¼õã\Üu88#=…ùؼm‰ô­<,rÍo¬^ÞI"Ò¼Oã=jÿGºûU¨Ó¬ból€°–èœn=G#ʱ¯ü65¹ØÑE`øÒûRÓ‘:ß(^¬‹‘*¬M úâºGE‘C+ # ŠDt–5’6 Œ+AïN®wÁ®ÖúLÚ4¬LºDíe–êb4Gñ“ñº*(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬­_^ƒJ– e·¸½¿¸'ɳµ eu[æeUQݘÐu UOøHuOú5ÏûýeÿÉÐQ\ÿü$:§ý šçýþ²ÿäŠ?¶µë“åÚøVæÝÏü´ÔnàHÇýúyXþ_tSPÕ4ý*?P½·´‹ yä ôêk+û[¿çSךÏX4È„#†FÜçê¥*ÞŸá½LŸíÖ1ý¨ðnf&YÖG%ç@?á'’óG¿¾ÏI¤ìÐýwI‚Gº«Qöêñ÷ªÛ鑟ùe§EæÈ?í¬£ðŒ}krâ¸BðÊ’ fBÈÁ†å%XqÜAˆ5^=[M—R“MP´{ø†é-Ve2 õ)œÈí@Oqðj|F¼Õõw¸þDŽƈ’ÌÏ5ë…™˜Ÿ•2vñŒ…ã»Í6Ö /êv¶°Ç izGjUD·x‚ºŠç5;mKOñkV-¨Eqj–·6ñȉ*ùl쌛ÈSþµÁŽÕh¹A¤4nÕ=[N‡XÑï´Ë†u‚òÞKy2u*HÈ#8>•›ý½ªÿЛ®ßë/þH£û{Uÿ¡7\ÿ¿Ö_ü‘\ʧb®KÛõ¤‚âG6²Á$Áòí>IÆr `óƒÆ*ié2O3ß^_\̨=ÙBû;TlU˜ôÉ,I&«oj¿ô&ëŸ÷úËÿ’(þÞÕèM×?ïõ—ÿ$SöU6°] oáó·(Òí…oZúÊHÈó ’@Þg伇<ñ!ã&gðí¤ÇLi湚M>V™$–MÍ! ä9#‘’€ .8¨?·µ_úuÏûýeÿÉoj¿ô&ëŸ÷úËÿ’(öu;Ðá+CBËëwŽk™|Ø% ì·™e;xRÄ`Œ0Ú¸lóVö­}sx“OÓ\-Ðe*|©„^NõÊžLxRG 9ƒû{Uÿ¡7\ÿ¿Ö_ü‘Göö«ÿBn¹ÿ¬¿ù"gS°]A…’Ðý²ô\[+ ¹2î‘ÕÈ.¬H<«Ð `c“áÿìËëvÖÃOO±RráÝìÜ“²1ÇÉžø ý½ªÿЛ®ßë/þH£û{Uÿ¡7\ÿ¿Ö_ü‘G³©Ø.êÁ׿ä;á?û Éÿ¤WToj¿ô&ëŸ÷úËÿ’*8¢Õ5½sMººÒ¥Ó,´éáVæXÞYehÞ ™B…‘É%²N8«¥Jji´&΢Š(®òBŠ( Š( —~2ÿÉCÔ>±ÿ褢Œ¿òPõ¬ú)(¯µ£üáä5o/Wùš ÿä9¤×hÿô#_G×Î ÿä9¤×hÿô#_G×Ïg?ïµ=W䎌ð—ÏóaEW–uQ@Q@Q@Q@Q@Q@Q@Q@bøþÔëáôRVÕbøþÔëáôRR—Âê,xwþE+þ¼áÿÐiVo‡äYÒ¿ëÎýV•0 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9»ø•xêÖà [ëY¤ñxÿ†QÿZé+ÅvS]èIh›ïlÙo-Gs$d8_ø Ÿf5©ey¡co{láà¸e‡ñ+ ƒùžŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ±µ­mì¥NÓ¡[½báKC8Xס–Cü(?2xôf±­Ë ÚéLis«Ê›ö¹>]¼g6R:EêÄ`q’'Ðô8th$&W¹¾¸o2îòQóÎþ§ÑG@£€8š&†ºRÍq<íy©\×7’.ÏeQü(;(à{’IÖ¢Š(¢Š*9á[‹y`rá$BŒQʰc‚9ÜsRQ@ǃM¦á‡0Û[ǪßA$"ŒßJˆ£êJ¨É±4˘]Ó4äš&ÕmµÝFâîG˜–î.v3¡Hx0{ñé^…EQEQEQEQEQEQEQEQEQEQE|»ñ—þJ¡õÿE%|eÿ’‡¨}cÿÑIE}­àÓÿ $y«yz¿ÌÓøoÿ!Í#þ»Gÿ¡ú>¾pøoÿ!Í#þ»Gÿ¡ú>¾{9ÿ}©ê¿$t`ÿ„¾› (¢¼³¨(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Çö£ÿ_ ÿ¢’¶«Çö£ÿ_ ÿ¢’”¾Qcÿò,é_õçþ€+J³|;ÿ"Εÿ^pÿè´©€QEQEQEQEQEQEQEQEQEW=áaöÔô"0,.K@=`—2&=.Ÿöκçõ04ïiz˜$Gvqé“—‰Ñƒ(÷–€: (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (®Ã~Ñuï éºÖµ¥Ùêz†£mÜÓ^³02(}«¸ª3€gR¢¦®Æ•ÎêŠæ¿áðý ºþ âÿâhÿ„Â?ô*èø/‹ÿ‰¬~´»”éh®kþ_ÿЫ¡ÿà¾/þ&øA|#ÿB®‡ÿ‚ø¿øš>´»)ÒÑ\×ü ¾ÿ¡WCÿÁ|_üMð‚øGþ…]ÿññ4}ivS¥¢¹¯øA|#ÿB®‡ÿ‚ø¿øš?áðý ºþ âÿâhúÒì§KEs_ð‚øGþ…]ÿññ5ŸªèZW†ÅŽ©¢iöÚmÂê°8³ˆB³G4é+ª€aò28 bœq*M+ ÇkX¾·p×ÿØš"¤Ú£(idq˜¬ôy=Içjulv4ÝWX»»¿}A*o€j»eÝŠ‘HèÒ÷Sñ8t´ÓE²û5¨bY‹Ë4ºIœõwnìúÃ]"£h¶Ú-£E <³JþeÅ̧2O!êÌ@:´¨¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€>]øËÿ%PúÇÿ¢’Š>2ÿÉCÔ>±ÿ褢¾Öðiÿ†?’<Õ¼½_æiü7ÿæ‘ÿ]£ÿÐ}_8|7ÿæ‘ÿ]£ÿÐ}_=œÿ¾Ôõ_’:0Â_?Í…Q^YÔQEQEQEQEQEQEQEQEŠ?ãûQÿ¯…ÿÑI[UŠ?ãûQÿ¯…ÿÑIJ_ ¨±áßùt¯úó‡ÿ@¥Y¾ÿ‘gJÿ¯8ôZTÀ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+3Ä:kêÚ Ýœ,á“}»Ÿà™HhÛðuSøVGEÔ“XÑlµB‚â¡ê„ŽTûƒ‘øUêälõ𾧪i×vº“ÚIpnìäµÓ§¸M²üΙ‰$Þpqʽÿ –—ÿ>ºçþ¯øÍtW?ÿ –—ÿ>ºçþ¯øÍð™ióë®àŠ÷ÿŒÐAEsÿð™ióë®àŠ÷ÿŒÑÿ –—ÿ>ºçþ¯øÍtW?ÿ –—ÿ>ºçþ¯øÍð™ióë®àŠ÷ÿŒÐAEsÿð™ióë®àŠ÷ÿŒÑÿ –—ÿ>ºçþ¯øÍtW?ÿ –—ÿ>ºçþ¯øÍs;ñåΙáçÕ4¨ÇsfÂI!½Ñ.Ò£èC;F»êáÓèÑëšð/ü“ï Ø*×ÿE-q~ øí¤ø–â+ ý2òÎýøÞ&¹G>Ûáÿ|àz×ià_ù'Þÿ°U¯þŠZåÅlŠˆë_ÙÜé²je½ŠØü‡’!‹‘#mŒÆA î$ÈÈŒ¬ž(¶#Qgv÷OvÖ_ePžbÌ"iBœ¶ÞPqóp2EkO Í‚ºDÚ™–ÚØÛ‹°ò=Ü’ç*™9…’eÃD_Û_Kxå5&Ôg+Õ‘³[…qÚ•=OÝ÷ã—Ýë/ZÞÜÚB,ï![©$‚9eT çÆ¼' Nà#~q·å#vxªö¾3†ö+w¶Ò59îÔ]Ú X¸ ¸®dÀÛ½AÜFr1»#3ÛøgÈþÎÿKÝö-VëQÿWþwÚ>N¼cíyÎ΃<G†²¿°?Òüßì)´ïõ{|ÝÞGÏÔíÿQÓŸ½×ŽOt“ÅÚbÚGw5±³ŽþIcAˆmß;d|pB±ÀáOS¦ñE¬ŒÖkvR ¸¬æ¹ ž\rȱ˜Áù·reEàÎ ΋Á--1oÿvúLMãù<Í a†Wæù Iýï½íW®<3çÿhÿ¥íûn«k¨ÿ«ÎÏ'ìÿ'^sö~¼cCŽOt l¼G þ­5Œ67¾\R¼ëb˜¼ÅÎà@bëЀY@=‰ÈÌÚ¶¹“5¼&ÖîêiøŠÖ07¹¹FI,³äð¼—Zé¼¾ºµ¸´ýè0}ˆ,’¤ŠTÇ+îÄ‘€xR€ü«’qÌ·^HÞÁô)`Ñͤs@«ª”JÊÎ8UmȬ g94½Û~!˜ëÒØJPjÿ`‹lE‹/ØEÏÌw §vî@<6ó¸7ÇpÉqá•‚‡·–MGOD™-7€À2:óSÂ3ÿ¿íµÿÌWûGËòÿéËì»3ŸøqíŽô¾/ÿ5·ý…tßý-†ª6ç¼€×Ò´«=Á,ì£Ù’ÌÌw4Œz»1嘞I=jíW¦@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEòïÆ_ù(z‡Ö?ý”Qñ—þJ¡õÿE%ö´ƒOü1ü‘æ­ß«üÍ?†ÿòÒ?ë´ú¯£ëç†ÿòÒ?ë´ú¯£ë糟÷Úž«òGFøKçù°¢Š+Ë:‚Š( Š( Š( Š( Š( Š( Š( Š( ±Güj?õð¿ú)+j±Güj?õð¿ú))KáaÕ<;ÿ"Εÿ^pÿè´«7ÿò,é_õçþ€+J˜Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@T¿Ôì´´¯nR<ñÛŸòò;U¹$ÿ2x­×?âÛw§ÚK©šæ-BÄ«${#û\ &1È\&O²äô  ‹ëëm6Ê[˹<¸"fÚXú`’I<9&¹í_IÒ>"èÉm5ÕçöjO›‹eVäuè’Pêç¡ÍZñVùô™"·†âYmn,ï#…‰tK„‘‚œa›lmò‚O##æ<1æM6·¨n!‚úüMÜBÑ>Å‚òQ€eËFÇ9ï@4_èÞ´û6¦ÛYEÜD˜-þóucîI¬ßÿÉ>ð×ý‚­ôR×K\×äŸxkþÁV¿ú)k—²*&ýQ\E`ø¦ûRÓíì%°xc‰¯íb¸w˜¤—FUGNC¶XôÇ'#z©êZt:¥ª[ÎΨ—Ü„º)VUƒÆäöÏN´Öúˆ©â[Û‹½¬¾Tó\ÛÚ¤¡CüÙ’-À óÏT~¹ºwÕ¬nîä»}>÷ìëq""¼ŠaŠQ¸ ‘æã€:UÍKJMRÞ{yîgX¥Xöˆö%Ñ· íÎìí<ä|ƒs“IÒ“I‚d3ÝM<¦i®.6ï‘È “µUFTÕ€¿ETŒ+Åÿò¶ÿ°®›ÿ¥°Öõsž9ƒí>K6X¼ÝKOO2&Úé›ÈFTö#±«§ñ¯Q3©¢¹’þ&б½ÄC« Xo{Ž#“ðØ}ii>!Ó5¢ñÚ\ÿ¤Åþ¶ÖU1ÍûѶ}qƒÚ½B J(¢€ (¢€ (¢€ (¢€ (¢€3µMsNÑ„_m•æ$EQ<²IŽ»QfÇ|+?þ=+þ}µÏü^ÿñšd*â.¦Ì2bÒlÄdÿùnwcë±3þè­ê婈p—*CHÄÿ„ÏJÿŸmsÿW¿üføLô¯ùö×?ðE{ÿÆknŠ­>Ãå1?á3Ò¿çÛ\ÿÁïÿ£þ=+þ}µÏü^ÿñšÛ¢­>ÁÊbÂg¥϶¹ÿ‚+ßþ3Gü&zWüûkŸø"½ÿã5·EZ}ƒ”Äÿ„ÏJÿŸmsÿW¿üføLô¯ùö×?ðE{ÿÆknŠ>´û)‰ÿ ž•ÿ>Úçþ¯øÍð™é_óí®àŠ÷ÿŒÖÝ}iöSþ=+þ}µÏü^ÿñš?á3Ò¿çÛ\ÿÁïÿ­º(úÓì¦eŠtBõ,ã’æ™1Åye5³I“´J‹»ž3[5Íx¼¥YK¾=[O(Ý×uÔHqõVaô&ºZè¥Sž7V (¢µQEòïÆ_ù(z‡Ö?ý”Qñ—þJ¡õÿE%ö´ƒOü1ü‘æ­åêÿ3Oá¿ü‡4úíþ„kèúùÃá¿ü‡4úíþ„kèúùìçýö§ªü‘уþùþl(¢ŠòΠ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬QÿÚý|/þŠJÚ¬QÿÚý|/þŠJRøXuEÿȳ¥ל?ú­*Íðïü‹:WýyÃÿ  Ò¦EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\†â]Î=3O¶Ò¯ì-Ç—l÷’[H‘ºŒ)mq]e2„f­ 9Ï´xÃþ€zþfÿäZ>Ñãúèø9›ÿ‘k£¢³öûìç>Ñãúèø9›ÿ‘hûGŒ?è¡ÿàæoþE®ŽŠ=…>ÁvsŸhñ‡ýô?üÍÿÈ´}£ÆôÐÿðs7ÿ"×GEŸ`»9Ï´xÃþ€zþfÿäZ>Ñãúèø9›ÿ‘k£¢aO°]œçÚôï–ÿòPõûXèÛºtúŽ¥/Š›b¶‚ h!¸ºóÃnu•äPƒ€TDÇs8ëY¾¸Õn|_ªK¬ØAczt« ÐÁqç(ýíßñmõàgêkvïDÓ¯µ {û›}÷øØÛØåÜ á°ÜÀàò0kÏ­ohîZØÊµñÔ÷öeâ„YÞj7Z|jó¡ó~rs‚ücŒ¯'šÏÒ¼AâV-+é‘I«éÚ±·ˆvˆ·gϸ̸Á]¼ýìsÓÇ£ØEöÔ·Äû™ÞÛU›ï0\í {2r}i¶z&Ÿaö³[ìþϵ6vß;.³+ÉçýRrr~^¼œçt)'5)ô‰µ[Xm"·¶Ð­u©¢•Ù–A34jÁ€pÄp{ñ¡qâ-KNºÔ,îã´šâ?±4 2(ûTí «I;Y2Xc ô¨žÑ£Óæ°[<[M§Ç¦Èžkól¦sžÏ^zð*ÌúE…ÍÅÌó[‡’æ(á”–?2FÌÈ:ðC;G<õà`¼{…'ˆu?µÇ¦Æ-çö³iÏ3DÆ2>È×!ÂîÏM ŒóƒÈÎD/âr]ÖæÞd+quoyr-dÁ+G‘¸`cå¶ð0ÙÍt1èztFÙ–Ük¨Ý¤fo5‘£,Äœ±Úì9ÏQè1^ é7$-Ñ„–i• ¹–' +—“çF †bI\ã§ /2~éÈã©|>"¿›RÓñ²Ù^j—:x]­æ/’³å³œrÐÜ\älÉ¢iòý§}¾~Óuä¿;|ÓEåìn¼cÉÁÛÈ99¢¾OøH!Õ ¨« Ï:E2åÙ l¹ç 2pOJW€<_ÿ koû é¿ú[ t•Íø¿þ@ÖßöÓô¶é+¯ ð?RdQEtˆ(¢Šùwã/ü”=CëþŠJ(øËÿ%PúÇÿ¢’ŠûZ?Á§þþHóVòõ™§ðßþCšGývÿB5ô}|áðßþCšGývÿB5ô}|ösþûSÕ~HèÁÿ |ÿ6QEygPQEQEQEQEQEQEQEQEV(ÿíGþ¾ÿE%mV(ÿíGþ¾ÿE%)|,:¢Ç‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(9æ[{ygpå#Bì 1g€9'ØsT4 \ëšP¾kWµo>xL20fS¯ÉgäÎqœdõ­:ÇÑ´ûÍ#J’ßK3ê7ë ¨Žk§“®Óó~˜ÁaŒóP¼E%ö¤–siÑ®™yuqa ȹ%ÞXƒï Ñ´~ê@b~^ƒ5¿gci§Z¥­¬6Öè0±CE_ W7gáíJbÕeûÓ,õ ­FV3;Ì%Ê2mÚ3ÉÈcœ/šê蜷ÿ’‡¬Ø*ÃÿFÝÖía[ññWÏ}*Çø–ï?Ì~u»^uâ2ÖÁEV# (¢€9ŸˆVæãÀéóæˆEaq)6ß3lLB“×npNÎ0x$þ+–âksZ)§ÎÑêFÅqïœVœðCuo-½ÄI4¡I#‘C+© ƒÁv¤{h$gxciU5¨,ˆ, ú«‘ßhôªOa߇,ì4ßê¶zDA§ +9•-À æ3NñÆJ¬džüõÔÕM?KÓ´˜Z6ÂÖÎ'mì–Ьj[Ô…š·JNìŠ(¤0¢Š(Åÿò¶ÿ°®›ÿ¥°×I\ß‹ÿäj;WNÀÿ·ÈMt•Ý…ø© (¢ºDQE|¹ñ—þJ¡õÿE%|eÿ’‡¨}cÿÑIE}­àÓÿ $y«wêÿ3Sá¿ü‡4úíþ„kèúùÃá¿ü‡4úíþ„kèúùìçýö§ªü‘уþùþl(¢ŠòΠ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬QÿÚý|/þŠJÚ¬QÿÚý|/þŠJRøXuEÿȳ¥ל?ú­*Íðïü‹:WýyÃÿ  Ò¦EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPN« C©ÜÃx—wV7ЩDº´e°à•!••†@8e8=1U?áÔ¿èr×?ïÍ—ÿ#×CEK„^è{þ½Kþ‡-sþüÙò=ðê_ô9kŸ÷æËÿ‘ë¡¢—³‡d9ïøFõ/úµÏûóeÿÈôÂ7©Ðå®ß›/þG®†Š=œ; ¹ÏÂ7©Ðå®ß›/þG£þ½Kþ‡-sþüÙò=t4QìáÙÎ{þ½Kþ‡-sþüÙò=ðê_ô9kŸ÷æËÿ‘ë¡¢gÈ.sßðê_ô9kŸ÷æËÿ‘èÿ„oRÿ¡Ë\ÿ¿6_ü] {8vAsžÿ„oRÿ¡Ë\ÿ¿6_üGü#z—ýZçýù²ÿäzèh£Ùò ˜6þ }ow¨êú–¨öÍæ@—f%Hßݶ(Ð8-œgŠÞ¢Š¤’ÑQEÀ(¢Šùwã/ü”=CëþŠJ(øËÿ%PúÇÿ¢’ŠûZ?Á§þþHóVòõ™§ðßþCšGývÿB5ô}|áðßþCšGývÿB5ô}|ösþûSÕ~HèÁÿ |ÿ6QEygPQEQEQEQEQEQEQEQEV(ÿíGþ¾ÿE%mV(ÿíGþ¾ÿE%)|,:¢Ç‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(åߌ¿òPõ¬ú)(£ã/ü”=CëþŠJ+íhÿŸøcù#Í[ËÕþfŸÃùiõÚ?ý×Ñõó‡ÃùiõÚ?ý×ÑõóÙÏûíOUù#£ü%óüØQEåAEPEPEPEPEPEPEPEPX£þ?µúø_ý•µX£þ?µúø_ý”¥ð°ê‹ÿ‘gJÿ¯8ôZU›áßùt¯úó‡ÿ@¥LŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( —~2ÿÉBÔ>±ÿ褢Œ¿òPµ÷£ÿÑIE}­àÓÿ $y«yz¿ÌÓøoÿ!Í#þ»Gÿ¡ú>¾pøoÿ!Í#þ»Gÿ¡ú>¾{9ÿ}©ê¿$t`ÿ„¾› (¢¼³¨(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Çö£ÿ_ ÿ¢’¶«Çö£ÿ_ ÿ¢’”¾Qcÿò,é_õçþ€+J³|;ÿ"Εÿ^pÿè´©€QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEòïÆ_ù(Z‡ûÑÿ褢Œ¿òPõ¬ú)(¯µ£üáä5o/Wùš ÿä9¤×hÿô#_G×Î ÿä9¤×hÿô#_G×Ïg?ïµ=W䎌ð—ÏóaEW–uQ@Q@Q@Q@Q@Q@Q@Q@bøþÔëáôRVÕbøþÔëáôRR—Âê,xwþE+þ¼áÿÐiVo‡äYÒ¿ëÎýV•0 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€>]øËÿ%PúÇÿ¢’Š>2ÿÉCÔ>±ÿ褢¾Öðiÿ†?’<Õ»õ™¥ðßþCšGývÿB5ô…|áðßþCšGývÿB5ô}|ösþûSÕ~HèÁÿ |ÿ6QEygPQEQEQEQEQEQEQEQEV(ÿíGþ¾ÿE%mV(ÿíGþ¾ÿE%)|,:¢Ç‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(åߌ¿òPõ¬ú)(£ã/ü”=CëþŠJ+íhÿŸøcù#Í[ËÕþfŸÃùiõÚ?ý×Ñõó‡ÃùiõÚ?ý×ÑõóÙÏûíOUù#£ü%óüØQEåAEPEPEPEPEPEPEPEPX£þ?µúø_ý•µX£þ?µúø_ý”¥ð°ê‹ÿ‘gJÿ¯8ôZU›áßùt¯úó‡ÿ@¥LŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( —~2ÿÉCÔ>±ÿ褢Œ¿òPõ¬ú)(¯µ£üáä5o/Wùš ÿä9¤×hÿô#_G×Î ÿä9¤×hÿô#_G×Ïg?ïµ=W䎌ð—ÏóaEW–uQ@Q@Q@Q@Q@Q@Q@Q@bøþÔëáôRVÕbøþÔëáôRR—Âê,xwþE+þ¼áÿÐiVo‡äYÒ¿ëÎýV•0 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€>\øËÿ%PúÇÿ¢’Š>2ÿÉCÔ>±ÿ褢¾Öðiÿ†?’<Õ»õ™©ðßþCšGývÿB5ô}|áðßþCšGývÿB5ô}|ösþûSÕ~HèÁÿ |ÿ6QEygPQEQEQEQEQEQEQEQEV(ÿíGþ¾ÿE%mV(ÿíGþ¾ÿE%)|,:¢Ç‡äYÒ¿ëÎýV•føwþE+þ¼áÿÐiS¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(åߌ¿òPõ¬ú)(£ã/ü”=CëþŠJ+íhÿŸøcù#Í[ËÕþf—ÀNµ¤€H&Xù¾c^å{¬¥…³ÜÏpÉ.æve÷Ç_jðï†ÿòÒ?ë´ú¯Añ-Åävw±/Úã´;ÞÁþì£Ôc«C‘íÔ7‹™SSÆÔ¿uù#L<œi+yþlìaÕÂîI›cF]dVF~èÈ©§¾–)™ä` ,£¡Ç÷k,ŽJ”c„«c+ò2*Õ܃íSIÿB5ÂèCžÖ7U®\þÓ›ÖOûíøŠ?´æÿ¦Ÿ÷Úÿñ›æŠ_4U}^…ísGûNoúiÿ}¯ÿ@Ôæõ“þû_þ"³¼Õ¤2ŽÔ}^ƒÚ¾æ˜Ôgc…£¯ÿAÔ®Q ýµÿâ+9g Œ‚~d<{:“úPDØò²¤m\ŸÜŒ54Ö„ê³cûJoY?ïµÿâ)?´æÿ¦Ÿ÷Úÿñ›æŠ_4Rú¼;Ú>æöœßôÓþû_þ"—ûJoY?ïµÿâ+7ÍZO4Qõxvhûš_ÚsÓOûíøŠžÖâ{7÷î60uzV½±¼Ñ[Bå.Oûqÿè˜ëÔ£Ý"á6Ùg÷ÿóñ'ä¿áGïÿçâOɬìö£gµr¿ÿ?~KþZêøÚ+³Ü0XÆ]™‘@É?w¥ilö®S˜Çys….Tq“òŽxüëjS•™•¶úú]ÛGso3K ƒ*ÊëÈÿ¾:ûT–ÌZçQ%Ë‘u·$ÑvúWáÛ ‹_´ÞJŸdŽé·¥‚}؇©ÏF>ƒNzý?ýv§ÿ_Ïü–¯N0Ñæäõ4|;ÿ"Εÿ^pÿ襻ͽ·S RþíÎÙ”ç¡æ¢ðïü‹:WýyÃÿ  ÑÚ ÀÜÇ8ÿ V¥EW‡Ê·]·Ó` öçô¨ZîãËRÎ貎ƒi,?Oüz´ÆCB3JUK*2Çj¢nfb ‡erì¥6ä@{“Kö‰¶ÈýÒÝeظ ± ÆVÌQ”c]ƒ¢ãN ¡‹#ã·ù&€)}¢`²eYpPåIŽ Âžƒ­Kj1%Ð-¸ù½}~E©ÄhªUQ@=@hTDEUÐb€3à’T³cbßèûÀÀà®Þ?EXÊö’L‡'%cªŽßŽ?ZœDŠ…cQF2€ zP±„D„ª…Úê(9Ã]\ÂÆ¦R²”YxAPCõüjKŒ,ͪª¯Ùð¼?áWR$QU@Ø»T÷Óô¦4bIE$ã’=Gäh¤w=‚Œ»¦I\`gsœð)Ö²HeÛ,»‹)`O=TŽÜ÷«;>ý«»ûØæ‘!Š6fHÑY¾ñUŸ­>Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( —~2ÿÉCÔ>±ÿ褢“ã/ü”=CëþŠJ+íhÿŸøcù#Í[¿Wù—< {§XÜÛ\ê‚Ù$*ÄÒnpÇåÂò:ç>Õè­ãm ˜ŸøJmÆ}4“ÿÄ×ÍÛ›ÔþtnoïγÄ`h׫*²m7ééÕ2a)Â<ªßùŸI't%Î|QnÁeºä}TúÓåñî…,…ωmA=âTç?˜¯š·7÷çFæþñüëì¬=ïy}ñÿäKöµ<¿ó>’ÿ„çAÿ¡š×ÿ-ÿÄÑÿ ΃ÿC5¯þ [ÿ‰¯›w7÷çFæþñüéÿeaûËïÿ"Ö§—ãþgÒ_ðœèô3Zÿॿøš?á9Ð?èfµÿÁKñ5ónæþñüèÜßÞ?ÙX~òûãÿȇµ©åøÿ™ô—ü':ý Ö¿ø)oþ&øNtú­ðRßüM|Û¹¿¼:77÷çGöV¼¾øÿò!íjy~?æ}%ÿ ΃ÿC5¯þ [ÿ‰£þþ†k_ü·ÿ_6îoïÎÍýãùÑý•‡ï/¾?üˆ{Zž_ùŸIÂs ÐÍkÿ‚–ÿâhÿ„çAÿ¡š×ÿ-ÿÄ×Í»›ûÇó£szŸÎì¬?y}ñÿäCÚÔòüÌúKþþ†k_ü·ÿSÇñEˆ0OÛÇ'þ%²òÎ?*ù›szŸÎÍê:O)ýܾõÿÈ‚«QvüÌúsþN‘ÿCLø-–øY:Gý 0à¶ZùszŸÎÍê:Ÿì|/y}ëÿ‘·«å÷?ó>œÿ…“¤ÐÓþ eªóxóC™÷[ƒÿ`·oÕ5ó^æõ?›ûÇ󦲜2ÙËïÿ"µGÛñÿ3éãm0?ð•[äsÿ ƒÿÄÕ»OxRÙ&ß®,,¾a"Öeî íë_2noïÎÍê:%”᤬ܾõÿȉV¨¶·ãþgÔš7Ä¿ Zhz}´Ú¡Ya¶Ž7_"C† wÖ¯ÂÓðwýþËÿÄ×É»›ÔþtnoSùÒþÆÂ÷—Þ¿ù¾±WËîæ}eÿ OÁßô?ø/ÿGü-?ÐXÿà<¿üM|›¹¿¼:77÷çGö6¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7©üèÜÞ§ó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ÔþtnoïÎìl/y}ëÿ‘¬UòûŸùŸYÂÓðwýþËÿÄÑÿ OÁßô?ø/ÿ_&îoïÎÍýãùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍýãùѹ½OçGö>¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7©üèÜÞ§ó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ÔþtnoïÎì|/y}ëÿ‘¬UòûŸùŸYÂÓðwýþËÿÄÑÿ OÁßô?ø/ÿ_&îoïÎÍýãùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍýãùѹ¿¼:?±°½å÷¯þD>±WËîæ}eÿ OÁßô?ø/ÿGü-?ÐXÿà<¿üM|›¹¿¼:77÷çGö6¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7©üèÜÞ§ó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ÔþtnoSùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍê:77©üèþÆÂ÷—Þ¿ùúÅ_/¹ÿ™õ—ü-?ÐXÿà<¿üMð´üÿAcÿ€òÿñ5ònæþñüèÜÞ§ó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ÔþtnoSùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍê:77÷çGö6¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7÷çFæþñüèþÆÂ÷—Þ¿ùúÅ_/¹ÿ™õ—ü-?ÐXÿà<¿üMð´üÿAcÿ€òÿñ5ònæþñüèÜßÞ?ØØ^òû×ÿ"X«å÷?ó>²ÿ…§àïú ü—ÿ‰£þŸƒ¿è,ð_þ&¾MÜßÞ?›ûÇó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ûÇó£sxþtcá{Ëï_üˆ}b¯—ÜÿÌúËþŸƒ¿è,ð_þ&øZ~ÿ ±ÿÀyøšù7sxþtnoïÎìl/y}ëÿ‘¬UòûŸùŸYÂÓðwýþËÿÄÑÿ OÁßô?ø/ÿ_&îoïÎÍýãùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍýãùѹ¿¼:?±ð½å÷¯þD>±WËîæ}eÿ OÁßô?ø/ÿGü-?ÐXÿà<¿üM|›¹¿¼:77÷çGö>¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7÷çFæþñüèþÆÂ÷—Þ¿ùúÅ_/¹ÿ™õ—ü-?ÐXÿà<¿üMð´üÿAcÿ€òÿñ5ònæþñüèÜßÞ?Øø^òû×ÿ"X«å÷?ó>²ÿ…§àïú ü—ÿ‰£þŸƒ¿è,ð_þ&¾MÜßÞ?›ûÇó£û Þ_zÿäCë|¾çþgÖ_ð´üÿAcÿ€òÿñ4ÂÓðwýþËÿÄ×É»›ûÇó£sxþtcá{Ëï_üˆ}b¯—ÜÿÌúËþŸƒ¿è,ð_þ&øZ~ÿ ±ÿÀyøšù7sxþtnoïÎì|/y}ëÿ‘¬UòûŸùŸYÂÓðwýþËÿÄÑÿ OÁßô?ø/ÿ_&îoïÎÍýãùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍê:77©üèþÆÂ÷—Þ¿ùúÅ_/¹ÿ™õ—ü-?ÐXÿà<¿üMð´üÿAcÿ€òÿñ5ònæõ?›Ôþtca{Ëï_üˆ}b¯—ÜÿÌúËþŸƒ¿è,ð_þ&øZ~ÿ ±ÿÀyøšù7sxþtnoïÎì|/y}ëÿ‘¬UòûŸùŸYÂÓðwýþËÿÄÑÿ OÁßô?ø/ÿ_&îoïÎÍýãùÑý…ï/½ò!õо_sÿ3ë/øZ~ÿ ±ÿÀyøš?áiø;þ‚ÇÿåÿâkäÝÍýãùѹ¿¼:?±°½å÷¯þD>±WËîæ}eÿ OÁßô?ø/ÿGü-?ÐXÿà<¿üM|›¹¿¼:77÷çGö6¼¾õÿȇÖ*ù}ÏüϬ¿áiø;þ‚Çÿåÿâhÿ…§àïú ü—ÿ‰¯“w7÷çFæþñüèþÆÂ÷—Þ¿ùúÅ_/¹ÿ™õ—ü-?ÐXÿà<¿üMð´üÿAcÿ€òÿñ5ònæþñüèÜßÞ?ØØ^òû×ÿ"X«å÷?ó;OŠ­–µã+»ý>o:ÚR…i\â5‚ê Å’ORM訨ÅF;$—ܬDo»?ÿÙivy-2.4.0-rc1/doc/index.html000066400000000000000000000122441226750426600155660ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/install.html000066400000000000000000000113321226750426600161220ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivy.xsd000066400000000000000000000344201226750426600151200ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile.html000066400000000000000000000162311226750426600161260ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/000077500000000000000000000000001226750426600152355ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/ivyfile/artifact-conf.html000066400000000000000000000035171226750426600206510ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/artifact-exclude-conf.html000066400000000000000000000034251226750426600222760ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/artifact-exclude.html000066400000000000000000000116251226750426600213540ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/artifact.html000066400000000000000000000126621226750426600177270ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/conf.html000066400000000000000000000143201226750426600170500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/configurations.html000066400000000000000000000156031226750426600211620ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/conflict.html000066400000000000000000000106011226750426600177220ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/conflicts.html000066400000000000000000000070021226750426600201060ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependencies.html000066400000000000000000000075351226750426600205630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency-artifact-conf.html000066400000000000000000000034221226750426600227600ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency-artifact.html000066400000000000000000000142061226750426600220370ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency-conf.html000066400000000000000000000047251226750426600211740ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency-include-conf.html000066400000000000000000000034141226750426600226070ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency-include.html000066400000000000000000000107651226750426600216730ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/dependency.html000066400000000000000000000442251226750426600202500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/description.html000066400000000000000000000040701226750426600204470ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/exclude.html000066400000000000000000000066561226750426600175710ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/extends.html000066400000000000000000000106541226750426600176030ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/include.html000066400000000000000000000057411226750426600175550ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/info.html000066400000000000000000000075071226750426600170670ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/ivyauthor.html000066400000000000000000000036431226750426600201630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/license.html000066400000000000000000000035511226750426600175510ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/manager.html000066400000000000000000000061361226750426600175430ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/mapped.html000066400000000000000000000034531226750426600173760ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/override.html000066400000000000000000000070761226750426600177540ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/publications.html000066400000000000000000000052761226750426600206310ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/ivyfile/repository.html000066400000000000000000000045251226750426600203500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/js/000077500000000000000000000000001226750426600142025ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/js/jquery.treeview.js000066400000000000000000000162541226750426600177200ustar00rootroot00000000000000/* * Treeview 1.2 - jQuery plugin to hide and show branches of a tree * * Copyright (c) 2006 Jörn Zaefferer, Myles Angell * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Revision: $Id$ * */ /** * Takes an unordered list and makes all branches collapsable. * * The "treeview" class is added if not already present. * * To hide branches on first display, mark their li elements with * the class "closed". If the "collapsed" option is used, mark intially open * branches with class "open". * * @example .treeview, .treeview ul { * padding: 0; * margin: 0; * list-style: none; * } * * .treeview li { * margin: 0; * padding: 4px 0 3px 20px; * } * * .treeview li { background: url(images/tv-item.gif) 0 0 no-repeat; } * .treeview .collapsable { background-image: url(images/tv-collapsable.gif); } * .treeview .expandable { background-image: url(images/tv-expandable.gif); } * .treeview .last { background-image: url(images/tv-item-last.gif); } * .treeview .lastCollapsable { background-image: url(images/tv-collapsable-last.gif); } * .treeview .lastExpandable { background-image: url(images/tv-expandable-last.gif); } * @desc The following styles are necessary in your stylesheet. There is are alternative sets of images available. * * @example $("ul").Treeview(); * @before
    *
  • Item 1 *
      *
    • Item 1.1
    • *
    *
  • *
  • Item 2 (starts closed) *
      *
    • Item 2.1 *
        *
      • Item 2.1.1
      • *
      • Item 2.1.2
      • *
      *
    • *
    • Item 2.2
    • *
    *
  • *
  • Item 3
  • *
* @desc Basic usage example * * @example $("ul").Treeview({ speed: "fast", collapsed: true}); * @before
    *
  • Item 1 (starts open) *
      *
    • Item 1.1
    • *
    *
  • *
  • Item 2 *
      *
    • Item 2.1
    • *
    • Item 2.2
    • *
    *
  • *
* @desc Create a treeview that starts collapsed. Toggling branches is animated. * * @example $("ul").Treeview({ control: #treecontrol }); * @before
* @desc Creates a treeview that can be controlled with a few links. * Very likely to be changed/improved in future versions. * * @param Map options Optional settings to configure treeview * @option String|Number speed Speed of animation, see animate() for details. Default: none, no animation * @option Boolean collapsed Start with all branches collapsed. Default: none, all expanded * @option control Container for a treecontrol, see last example. * @option Boolean unique Set to allow only one branch on one level to be open * (closing siblings which opening). Default: none * @option Function toggle Callback when toggling a branch. * Arguments: "this" refers to the UL that was shown or hidden. * Works only with speed option set (set speed: 1 to enable callback without animations). * Default: none * @type jQuery * @name Treeview * @cat Plugins/Treeview */ (function($) { // classes used by the plugin // need to be styled via external stylesheet, see first example var CLASSES = { open: "open", closed: "closed", expandable: "expandable", collapsable: "collapsable", lastCollapsable: "lastCollapsable", lastExpandable: "lastExpandable", last: "last", hitarea: "hitarea" }; // styles for hitareas var hitareaCSS = { height: 15, width: 30, // custom size used in xooki marginLeft: "-30px", // custom size used in xooki "float": "left", cursor: "pointer" }; // ie specific styles for hitareas if( $.browser.msie ) { $.extend( hitareaCSS, { background: "#fff", filter: "alpha(opacity=0)", display: "inline" }); } $.extend($.fn, { swapClass: function(c1, c2) { return this.each(function() { var $this = $(this); if ( $.className.has(this, c1) ) $this.removeClass(c1).addClass(c2); else if ( $.className.has(this, c2) ) $this.removeClass(c2).addClass(c1); }); }, replaceclass: function(c1, c2) { return this.each(function() { var $this = $(this); if ( $.className.has(this, c1) ) $this.removeClass(c1).addClass(c2); }); }, Treeview: function(settings) { // currently no defaults necessary, all implicit settings = $.extend({}, settings); // factory for treecontroller function treeController(tree, control) { // factory for click handlers function handler(filter) { return function() { // reuse toggle event handler, applying the elements to toggle // start searching for all hitareas toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { // for plain toggle, no filter is provided, otherwise we need to check the parent element return filter ? $(this).parent("." + filter).length : true; }) ); return false; } } // click on first element to collapse tree $(":eq(0)", control).click( handler(CLASSES.collapsable) ); // click on second to expand tree $(":eq(1)", control).click( handler(CLASSES.expandable) ); // click on third to toggle tree $(":eq(2)", control).click( handler() ); } // handle toggle event function toggler() { // this refers to hitareas, we need to find the parent lis first $( this ).parent() // swap classes .swapClass( CLASSES.collapsable, CLASSES.expandable ) .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) // find child lists .find( ">ul" ) // toggle them .toggle( settings.speed, settings.toggle ); if ( settings.unique ) { $( this ).parent() .siblings() .replaceclass( CLASSES.collapsable, CLASSES.expandable ) .replaceclass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) .find( ">ul" ) .hide( settings.speed, settings.toggle ); } } // add treeview class to activate styles this.addClass("treeview"); // mark last tree items $("li:last-child", this).addClass(CLASSES.last); // collapse whole tree, or only those marked as closed, anyway except those marked as open $( (settings.collapsed ? "li" : "li." + CLASSES.closed) + ":not(." + CLASSES.open + ") > ul", this).hide(); // find all tree items with child lists $("li[ul]", this) // handle closed ones first .filter("[>ul:hidden]") .addClass(CLASSES.expandable) .swapClass(CLASSES.last, CLASSES.lastExpandable) .end() // handle open ones .not("[>ul:hidden]") .addClass(CLASSES.collapsable) .swapClass(CLASSES.last, CLASSES.lastCollapsable) .end() // append hitarea .prepend("
") // find hitarea .find("div." + CLASSES.hitarea) // apply styles to hitarea .css(hitareaCSS) // apply toggle event to hitarea .toggle( toggler, toggler ); // if control option is set, create the treecontroller if ( settings.control ) treeController(this, settings.control); return this; } }); })(jQuery);ivy-2.4.0-rc1/doc/moreexamples.html000066400000000000000000000056571226750426600171720ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi.html000066400000000000000000000076631226750426600154310ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi/000077500000000000000000000000001226750426600145275ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/osgi/eclipse-plugin.html000066400000000000000000000125571226750426600203470ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi/osgi-mapping.html000066400000000000000000000233531226750426600200150ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi/sigil.html000066400000000000000000000074521226750426600165340ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi/standard-osgi.html000066400000000000000000000066001226750426600201560ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/osgi/target-platform.html000066400000000000000000000122671226750426600205350ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/principle.html000066400000000000000000000117561226750426600164530ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/printTemplate.html000066400000000000000000000045121226750426600173060ustar00rootroot00000000000000 ${title} | Apache Ivy™ @version@
${body}
ivy-2.4.0-rc1/doc/reference.html000066400000000000000000000055321226750426600164170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/release-notes.html000066400000000000000000000176321226750426600172330ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/000077500000000000000000000000001226750426600154275ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/resolver/chain.html000066400000000000000000000111211226750426600173730ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/dual.html000066400000000000000000000042441226750426600172460ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/filesystem.html000066400000000000000000000125111226750426600205010ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/ibiblio.html000066400000000000000000000110151226750426600177240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/ivyrep.html000066400000000000000000000062231226750426600176360ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/jar.html000066400000000000000000000103761226750426600171000ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/mirrored.html000066400000000000000000000072041226750426600201430ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/obr.html000066400000000000000000000100161226750426600170750ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/osgiagg.html000066400000000000000000000046751226750426600177510ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/packager.html000066400000000000000000000417351226750426600201040ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/sftp.html000066400000000000000000000154541226750426600173020ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/ssh.html000066400000000000000000000114361226750426600171170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/updatesite.html000066400000000000000000000072071226750426600204720ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/url.html000066400000000000000000000070521226750426600171230ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/resolver/vfs.html000066400000000000000000000057171226750426600171250ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/000077500000000000000000000000001226750426600152325ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/samples/apache-hello-ivy-default.html000066400000000000000000000270761226750426600227050ustar00rootroot00000000000000 Ivy report :: hello-ivy by apache :: default

hello-ivy by apache

resolved on 2007-10-21 17:24:25

Dependencies Stats

Modules3
Revisions4 (0 searched searched, 0 downloaded downloaded, 1 evicted evicted, 0 errors error)
Artifacts3 (0 downloaded, 0 failed)
Artifacts size217 kB (0 kB downloaded, 217 kB in cache)

Conflicts

ModuleSelectedEvicted
commons-lang by commons-lang2.0 1.0

Dependencies Overview

ModuleRevisionStatusResolverDefaultLicensesSize
commons-cli by commons-cli1.0integrationpublicfalse29 kB
--- commons-logging by commons-logging1.0integrationpublicfalse21 kB
--- commons-lang by commons-lang1.00 kB evicted
--- commons-lang by commons-lang2.0integrationpublicfalse166 kB
commons-lang by commons-lang2.0integrationpublicfalse166 kB

Details

commons-cli by commons-cliresolved by default

Revision: 1.0

Statusintegration
Publication20051108231152
Resolverpublic
Configurationssystem, default, compile, provided, runtime, master
Artifacts size29 kB (0 kB downloaded, 29 kB in cache)
Required by
OrganisationNameIn ConfigurationsAsked Revision
apachehello-ivydefault1.0
Dependencies
ModuleRevisionStatusResolverDefaultLicensesSize
commons-logging by commons-logging1.0integrationpublicfalse21 kB
commons-lang by commons-lang1.00 kB evicted
commons-lang by commons-lang2.0integrationpublicfalse166 kB
Artifacts
NameTypeExtDownloadSize
commons-clijarjarno29 kB

commons-logging by commons-loggingresolved by default

Revision: 1.0

Statusintegration
Publication20051108231641
Resolverpublic
Configurationscompile, runtime, master
Artifacts size21 kB (0 kB downloaded, 21 kB in cache)
Required by
OrganisationNameIn ConfigurationsAsked Revision
commons-clicommons-clicompile, runtime1.0
Dependencies
No dependency
Artifacts
NameTypeExtDownloadSize
commons-loggingjarjarno21 kB

commons-lang by commons-langresolved by default

Revision: 1.0evicted

Status
Publication
Resolver
Configurations
Artifacts size0 kB (0 kB downloaded, 0 kB in cache)
Evicted by2.0 in latest-revision conflict manager
Required by
OrganisationNameIn ConfigurationsAsked Revision
commons-clicommons-clicompile, runtime1.0

Revision: 2.0

Statusintegration
Publication20051124062021
Resolverpublic
Configurationssystem, default, compile, provided, runtime, master
Artifacts size166 kB (0 kB downloaded, 166 kB in cache)
Required by
OrganisationNameIn ConfigurationsAsked Revision
apachehello-ivydefault2.0
commons-clicommons-clicompile, runtime1.0
Dependencies
No dependency
Artifacts
NameTypeExtDownloadSize
commons-langjarjarno166 kB
ivy-2.4.0-rc1/doc/samples/build-install.xml000066400000000000000000000055471226750426600205320ustar00rootroot00000000000000 ]]> ivy-2.4.0-rc1/doc/samples/build.xml000066400000000000000000000147011226750426600170560ustar00rootroot00000000000000 We are now ready to execute our simple program with its dependency on commons-lang. Let's go! package example; import org.apache.commons.lang.WordUtils; public class Hello { public static void main(String[] args) { String message = "hello ivy !"; System.out.println("standard message : " + message); System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); } } ivy-2.4.0-rc1/doc/samples/commons-lang1.0-dep-report-part.jpg000066400000000000000000000274671226750426600236100ustar00rootroot00000000000000ÿØÿàJFIFHHÿáExifMM*ÿþCreated with The GIMPÿÛC  !"$"$ÿÛCÿÀ9&"ÿÄÿÄC !Ó"1TUV’”•Ò2#At346Qa²³$RqB%Cu¡„‘´ÿÄÿÄ-Ra‘±Ñ!AQ1qÁð¡2BñÿÚ ?ôÕeãdgÞG6yµF])—b8åÌ6¾®þºÔVW ÿÆþ‘/ì ùrU’_ƒ#[DÿmŒô'âÑ´OöØÏB~-ME[µž¬íý¶3П‹FÑ?Ûc= øµ5»YêÁÑ?Ûc= ø´mý¶3П‹SQKµž¬íý¶3П‹FÑ?Ûc= øµ5»YêÁÑ?Ûc= ø´mý¶3П‹SQKµž¬íý¶3П‹FÑ?Ûc= øµÏ%ùhÂ0Òø®&a V/pÊpá3 Sí)œÄ) ˆæÌ*¢jícå׳Å0+Ê£¬´{YÕ)Í«ÔEâB)ê L™Nmà]ã–á`¸†ú·_z±BÓhŸí±ž„üZ6‰þÛèOŬŒ§)˜b;0ʸÔÛ6²šA%Ð3Fª5LTpšÆÔÌ™È\¢ %°g ývµçt#¦ÙàµÄNŒ†Ò‹(ÇÍβ肺FP™Ô)D…5ÀL&¹D:÷RëïV(\íý¶3П‹FÑ?Ûc= øµ›ÂxûâOÛc§é0Î3þ,™ÓCO*¢—Ls Bæ-ƒ¥¾áù«A%/”ŒKö² •¾›†«TÏaŒQÈ GÒKÞ¬P“hŸí±ž„üZ6‰þÛèOÅ©¨¥ÚÏVv‰þÛèOÅ£hŸí±ž„üZšŠ]¬õ`‡hŸí±ž„üZ6‰þÛèOÅ©¨¥ÚÏVv‰þÛèOÅ£hŸí±ž„üZšŠ]¬õ`‡hŸí±ž„üZ6‰þÛèOÅ©¨¥ÚÏVT‘Ÿ,Š,ö¨ÁÕEE3lGÝ”H¶¯çŸÿªchŸí±ž„üZUâ&¤qýèÕ…b0M¿_ C´OöØÏB~-DÿmŒô'âÔÕͦ¹a„†—Ä ¤ 'ÐC®Ù)W¹™åp`U±VC¬R €:ʺº.’ÕŠhŸí±ž„üZ6‰þÛèOŤ9ɇyÁÍï¯Å}g»öÄöŸ³?ìï›íéuuoê¤ ð!&ðØÛ •²ª$ÖD‡9@¢b³XDäË1˜TºYêÅ í¢¶ÆzñhÚ'ûlg¡?©°î.„œˆ‘˜jõ©cc×U%]íÍÕDJ™@®t”9JL£{J` âPÝJ:å¥êI [ñ&Ö(‚2­ºJ¦1@ ÀCårŽð t³ÕŠM¢¶ÆzñhÚ'ûlg¡?ªÕÅ0-0ë éihø–/“Lèªñê$ ‰Éœ¥♆À#Ñ1€l"!¾¢‘ÆØ27fúŽ.€gµ W-õä‘OY_*„¹ƒ1ÃcáµK¥ž¬P¹Ú'ûlg¡?¢¶Æzñjj)v³Õ)öqÎ^mQ‡ÐDêeØŽ²€¯«»ª˜Ú'ûlg¡?•ğò_¤Wû¬+ Ó]õy‚¢¶ÆzñhÚ'ûlg¡?¦¬\¿(mZâ ¨H¼9?>ê –’Ô‘ Rä UHe%-올¯umt“÷«5ÛDÿmŒô'âÑ´OöØÏB~-e ¹G³îcµ‘H²±j!*‹$èâCåDâcŠyL Q Z¥‹pª®ß³KB¨æ95|‰_¤'jDÆÊBæ¹£¸DÖ·çVég«-6‰þÛèOÅ£hŸí±ž„üZÈàžT0f*ÁæÅ ¦DzJÛY¹E%ÝC&M`ˆ'œKѸô€BÕt8· ƒGOBƒf‰¢«•¶ô²"E€Ù¬P8 D~ë…¯K¯½X¡i´OöØÏB~-DÿmŒô'âÒ°SpÓÍò^>Q±Œ³7$X…8”LQ°€Ûú…XT»YêÀ‹©ôh–Õm¡aNûÃ-ˆsßö»þÛÝ1´OöØÏB~-+)ûôOêÍþj±&ßίÐ!Ú'ûlg¡?¢¶Æzñjj+wk=X!Ú'ûlg¡?¢¶Æzñi ]6–Ã3îºx„zp²Mrj e œÁœÅ(å-ÍkÜ@׿ð§)ð3®Å«†’j9ä†OD¤Q„C_:j¤Ýp8”Bà6° ­Ò~õb†ÏhŸí±ž„üZ6‰þÛèOŪ´1n^yÄ14*±MÔ—|Gé rئP ”¤]Â?ùó ‹žØ3éXçtÓuöm¯êHèëeͧŸ6\ùwå½í¾¥ÒÏV(\íý¶3П‹FÑ?Ûc= øµ–Äøþ6Þ*±ÒcçݶfÆM™ÐQ±•\GLñ@âC6b”Ka Žêµ‹p¬{·ŒßâhVŽX¦U]¢»ôˆvä0” e &¹@EBÚùËü­ÒÏV(Zmý¶3П‹FÑ?Ûc= øµVÏáW²¨Ä³ÄЮ$Lª¢Õ'éedõ b q À@7—Ux· ʪÙ(ÌM ùGJ(“r¶~’‚±Ó(B aÌ%)ŠaêÃRég«-6‰þÛèOÅ£hŸí±ž„üZšŠ]¬õ`‡hŸí±ž„üZ6‰þÛèOÅ©¨¥ÚÏVcdgÞG6yµF])—b8åÌ6¾®þºchŸí±ž„üZW ÿÆþ‘/ì °¬B Å7]X!Ú'ûlg¡?¢¶Æzñk7Ê6kƒ>µÃÊÈý]ù#›lZ;œöd6¢„¶kü(ÜCuÈžPp‹ì0–!q4Ö%©—‹QRµQ³¢€çl©N!‘RØn_ä €€K¯½X¡¤Ú'ûlg¡?¢¶Æzñk-ŽùG¸>:VFE' Ê(™#“n²B.óåéÇ9SÀ  bBãq1–7Ò’u;Å쪮њòk*U~Ì€SˆãÑ ˜¢!¸F—_z±BçhŸí±ž„üZ6‰þÛèOŪ²âÜ*wj3.&…3”‘Šˆƒô„äpa0.k‚‚$8:Ç)·nªÃ8þ6bWÆ<Žs†ÓEY/©‘"*™”)³¦©Ë`!DDDB×ëeÒÏV(jv‰þÛèOÅ£hŸí±ž„üZÍòg°ï(8|“ž³EŽžÒÛ¦r—T„1²fÈ"[ŽðßZª¦—½X¡Ñ?Ûc= ø´» ÷H]ª0™VU;lG°æ%ÿkùå¿ýÓÕ_ûŠŸ«sþsÖ¤»êò[DÿmŒô'âÑ´OöØÏB~-MUXºm,7†$gÜ3tñô ádšäÔÊ9ƒ9ŠQÊ[š×¸€ ®6ÝÚÏV(?´OöØÏB~-DÿmŒô'âÕ4>-‰{‚ãÇú[´à§“Y$´ÓPCLÇ0H\Àbˆkô€Ãp'B=Áéb·/ZÆÅžù—tù¹“NÊ auRPéo0[qÇx€ †àég«.v‰þÛèOÅ£hŸí±ž„üZ¦ç¶ úGÖ9ÝôÝ}›kú’::ÙsiçÍ—>]ùo{o¢G`ÈÝ›ê8ºžÔ\·×’E=dM|ªæ Ä Œ†ÔºYêÅ ¢¶ÆzñhÚ'ûlg¡?ªçqnvFs˜š-ÉÓJ‹Çé"sD@ 1€D.þƒRó“óƒ›ß_ŠúÏwí‰í?fÙß7ÛÒêêßÕRég«Ú'ûlg¡?¢¶Æzñj­®-Â®æÆ ®&…^Tª!b›ôŒ¸—Î]06k—)®Ýa¿U]Ríg«!Ú'ûlg¡?—RF|²(³Ú£UͱvQ ZÚ¿žþ©ê¯_ø‰Ÿéz5‰Á%Ú¾<¿`khŸí±ž„üZ6‰þÛèOÅ©«7‹ñ‹,9+ ,$$åf”XŒY3ÀêIçPÂeNDÊ ušã˜,¾Û]4ýêÅ í¢¶ÆzñhÚ'ûlg¡?²Æå!E5~‚±²².Á±bŸ;hƒÄÃT颙– 鉈9E!8˜ jµÅ¸VÙÎbhX·'L*/¤‰ÌA0Ƹ_ú [¥ž¬P´Ú'ûlg¡?¢¶ÆzñiraÞps{ëñ_Yîý±=§ìÏû;æûz]][úªÖ¥ÚÏV("þF}ªWjŒ>e’NÛÃï9IÚþY¯ÿTÆÑ?Ûc= ø´¬ÿî)þ­·ùÉV…i®ú¼ÁÑ?Ûc= øµÒmŒÕsªfpŠG)Z¢ u A°ê ‡¥~¡¦©9Ø7ýk_ó§VpJ-ªêÁ¦¢Š+¨ Êá¿áØßÒ%ýZªÈaÕ” ?,p‰t‰¹Š=Þ°‡õ ÕÎM)ªú€ZÑPë«Ý“>ÔãáFº½Ù3íN>«qö ¨¨uÕîÉŸjqð£]^ì™ö§ [°MEC®¯vLûS…ê÷dϵ8øRÜ}‚j*u{²gÚœ|(×W»&}©Ç–ãìQPë«Ý“>ÔãáFº½Ù3íN>·`âx¯’LE=ŠqüÊí` õôJ73õ.M4 Üpãrb8ÊQÜ«tw€å•Ÿ%X¨ò¨¦ñÄ*1㎠Œ]'*¨±§s5*b‘@À¹AQ8\½,€=ìúê÷dϵ8øQ®¯vLûS…jù{8n äaŒE€Þ\6í¶Qûu*“—MÜA)ÄÙ (,qzŠ oÄAÈreÉn;À™”ƒ2a¹vÑð«Ã£«$»c¬C¾;’¬`êljMÕ|Ã]Ë]^ì™ö§ 5ÕîÉŸjqð«|Ÿ‘S†ÆòI‹ËÉ&Á¯”…+œ54Œ£u[I¸ =Yc¨™”*%;a«Ñ95áÔ^ºéÜša‚áx‡Èì Xªýú—EÎ~!ÊR˜Ç]~š§0“0ŽR^Ö9´šê÷dϵ8øQ®¯vLûS…GÕOÈ©5º½Ù3íN>k«Ý“>ÔãáY·`šŠ‡]^ì™ö§ 5ÕîÉŸjqð¥¸ûÔT:ê÷dϵ8øQ®¯vLûS…-ÇØ&¢¡×W»&}©ÇÂu{²gÚœ|)n>Á5º½Ù3íN>k«Ý“>ÔãáKqöWþ"gúGÞXURë)Îcôé`‘~ˆÆ¯˜zhïÉqæ=Ap¿XSúê÷dϵ8øV#8Ö]üþ&®‰ù"ÄóøßO¬æ)¤×déƒa|º­œ˜­ôÊET 62b—8 ¯Û5ÕîÉŸjqð£]^ì™ö§ 躩|1SŽá¾I¥bwOæYÅÔãáFº½Ù3íN>o—±SŒ7äãcŒ=!„—M+0‘W”vdHuDú*i&{©˜@å0\ÀPØF¥‡äçG`¼c£È©'¸‰ …3¿~*.Š"‚„VxV¥QÉÀÊX¤9B€ÿ*ìZê÷dϵ8øQ®¯vLûS…/—´*rv˜·O“™I`¤c²ýE`Eâ*4":ºº“8—ɦ`°ýõ›?"X©<-„0úª' 2ÙwYRŠŽ$T RÃ!Ž^˜˜ÁqÈß5ÕîÉŸjqð£]^ì™ö§ _/b¥7'1r0x X­AìsY¨-V2‰›H @0Å(ï€ÚÛ„D.6¸ßÔ:ê÷dϵ8øQ®¯vLûS…eÎ>À®$þ’ý"¿Ø5aUX‰eÈ€ÇK¢½#Æ®R‡@wˆ‰,ýGu?®¯vLûS…aN6ß ò «–r•±>&ÄéJŵ€Œ’`ºAˆÓz¹³BéŠÄ;pLSqq×)ÎÊ¥¬0›¦ë«Ý“>ÔãáFº½Ù3íN>Ñu"¼Š˜x¼'ˆ¡ùWĸ–9h¥cqÀg\ÊÍ6b†!åS9mc‰ÉM|§Ëcd!96å¯(XWKÊGÌ© íù¼q2èNñ79ŠS&ØR› !øiŽSeÌ!ÙõÕîÉŸjqð£]^ì™ö§ ·«Ø©Ì°/'˜Š#’‡ÜšÈ¿Š$nÀù‹wèЬ¶Ðuª1•,…8Ü€e3ýåËÒÀ5äW¦šé®†WWé$ËÄVjf ÜDé UÙÊcÊAë!úÃÑšê÷dϵ8øQ®¯vLûS…UÖKÈ©‘ä{ La<0å”ëæ¯¹~«¡: “0ÀR”X©¦. ë€cÃ{Øv•º½Ù3íN>k«Ý“>ÔãáX}H¿ VS÷èŸÕ›ü Õ…UI¬ ½ŠÿÓ¥‹gfÜhÕÀGðUÜ$Þ?ƒ}€G¨Ÿ×W»&}©Ç±Ʋïçð5º½Ù3íN>k«Ý“>Ôãá[·`¦å.FsNÂD•¨½‘`³4ÅÒÆM2ê”H&¦Àa€Â÷.ï¼N®qI(£¯%Ú5Ò®äÌTh¡TH¨bfë€'H@ ™„ Q8>×W»&}©ÇÂu{²gÚœ|+Kª—Ã8Æ äšVB5Âì¡áZJº“håeUÄ’N.ΚÅ*é»0f*åÕL#¹DM©r”„%˜ÊöÄ;|,”¬4œ‹“µXú²N* *:M Ë®e1•: e渆Pìúê÷dϵ8øQ®¯vLûS…/—±S‰§Éf3äÿá8ã@<æÌ².®ùd5–*«(dPDýÅn6û®¹TäÒKÏÁɃXTÓpÑ8üL’Î×Q¡]·s¦ÜÅ(\@ɪÄ"ü†Ùz–º½Ù3íN>k«Ý“>ÔãáKåZÔTäPü’»iŒ¤>B>EŠø¤Ø…«¥%žZœD§Ë±È@9Q?Q€D¢¦6¼‘`yœ77ˆŸb|6e%¦œL$ñ££¬ºS¢TzhàR¨°gí @ jéê÷dϵ8øQ®¯vLûS…Y?"¤ÔT:ê÷dϵ8øQ®¯vLûS…fÜ}‚j*u{²gÚœ|(×W»&}©Ç–ãì á¿áØßÒ%ýVU‡VP0üpt±À%Ò$jæ(ôxÂÔ7Súê÷dϵ8øV:s…ßÀF–k«Ý“>Ôãá]WY/"§'Ä<›M“àˆ,/Ñ,=<œÊÔpTË‘C¨æMCžâ©€T6]å¸ÙH‡+Ü›rŽ™@%#ÌÚM£"µl¤Ë¤‹Q#f\ºI¥‘ØÁpQ@)ƒuŠB»>º½Ù3íN>k«Ý“>ÔãáEÖKÈ©Äñ‡%˜ÎK”bÈã@j–†™pÙwË'¢³”LÈÀ‰³ÙÀAAˆ[ì­NÃxÎ/• SŠ%˜À–#Ù5ÖQeTk³ dÂÀfä3‡æL¡ººº½Ù3íN>k«Ý“>ÔãáKäÕ**aùÂx‹áf¸NEh¥ãcv‚·r”2Îõ2…9Ê%)QÊS UÌ&û‹—§¾¨uÕîÉŸjqð£]^ì™ö§ ©ëQRj¯€ýÅOÕ¹ÿ9é­u{²gÚœ|)%”JZ:XßêÜï$jæÛuÀaÔ!Öpá\ÜãmwðÿµªQ¢äg0ì$IZ‹Ù 3L],dÓ.©D‚a1Jaܵ·ˆ\/p¹×W»&}©ÇÂu{²gÚœ|+jqö*`plo(ðPÑGe†ÎÚ¬AK+g‹—@„TÆ·H B,6 ÷€V`ÈÀòYŒÙò_…p»“@m¸Ry¼ÃC¦ùc&û*ë(tÎ"ˆ ;•Ü`.!¼»fº½Ù3íN>k«Ý“>ÔãáZ½^ЩËq§'øÏaìRfð­¤#]»UËrnY‚ÄYºh…òDL¡tI¿L· :‰sÒâ^G¦Ý²Ãqpˆ@EÆÃÄÍ7AãƒåYú*¤.rÆ! bÝA0 ®aÉ`%vÍu{²gÚœ|(×W»&}©Ç—Éy<òNE±Ú¥I [ ŘZG²p²×t‹¢7I4EGLÜ d\ JA2E ,†‰Œ  L?$®Úc)‘b¾)6!jéIg„§)òìD²'P@TOÔ`(€i]×W»&}©ÇÂu{²gÚœ|*ß/b§ä§’¬U†q\DŒƒˆVq‘鸫•_"C¨Q(@r–«@Æ:‚U¨`Ø Ûju{²gÚœ|(×W»&}©Ç²ú±,Tš«×þ"gúGÞ5®¯vLûS… ºÊs˜ý:Xd_¢1«æš;À2\CùP\/ÖÏ©8ÓçÊܵ‹åW :Å‘í¡ÔÃÑÌ£–ò/Öh¡(“Hé*’gݪÜ ` Û0»]^ì™ö§ 5ÕîÉŸjq𭮤Wr)Ü Ê;ì)"ÈBÍ>òm%žH<|ª'r¢&Sð îSºÆÆÊ"b\jÔ¼!ŒñD»ю«F•‚fyéêÄ#—Ä1Œ‘\¨ œµHÆ!ÓÌcMùtÝu{²gÚœ|(×W»&}©Çµz½¡S‘CòJí¦2xùù+â“b®”–xAjqŸ.ÄK"u@äDýFˆ˜ö:‡]^ì™ö§ 5ÕîÉŸjqð¨ú©ü±QYÿÜSý[oó’¬*ªue’wŽ–/ú¶ÛϹCöÄÝq'XõuˆØxÓúê÷dϵ8øW58Û}ü/È&¤åÿ`ßõ­ÎM®¯vLûS…)(ª†I±LÆM ­zkG¬™ñÓë1ˆö4êN6pÍ]Q]@UÆþ ‚ÿã[ÿˆµOUð›.YH·/Ò4Gè·2†Mp)õ‡Ø@Q鉈€stAÙš¾Ðh¬lk3—¶80X’D’t£çBÜÅÔhmm"ŠÖÊ¡C3{ "Cpd-†ðÛ`C î(â‘áŒi,C T\ €&U€~á( ™ {l9@2…»®¼ŸÄ¿¬³ïôZ›º+)ë¨GO^2z´’8]¦Îu qP”®LPýâ˜KaûÊ&ÝlÃ{98£µZM«K'ªÄ!Lp^ÎT"=b©Ì‘@÷á`ÜbþDš­ŸÞùd*l¨¬:Ql2ȬÕ;C¨²„t…L£¢lùG1„»Â÷Ü"§ò%f‚§N¥¥ž¥îErœÉ5@ëœ&”¢a½·Ø+'ŠHýlLÕVñDPvÔ¥r›(°·Õ ¨ppL½#S±lÆÊa­(Å3ÄO"hgªÎ¨œ‡ú„ÚžçHúºEl©r EÀL 9z!’å“þCUI| ›ê+5«_«³…`F¬Œƒ4‘j"¬áM£ðÉmAŠP1¤bå/æVرÛF¹Ý‘‰ÐL¬LÍ4Ë€ DLa1 ˜ #{\Âaµ„w¬œì¸þ÷/袊îP¢Š(Š(  (¢€McÚmªyívË\ö½Œ–ü¹Âö¿^CZÿqocýÆ?g&̯cÜÃså*¤ÞS L%æ(ï ÃÖª¤IyDZ.Q%š.DâU ™ ”MÒ ¾ÃuÛ1oc¥ec°óÕÖhäæIÛõÁÓQBí ˜ RX˜-üîθÚjmxÿÂ¥µ|“%×ʲ¶°d0”¹†ÅÌ` 0€”¹„3Çu9Y9¦Ž´qQ,¢³™¶E˜ŠEÌÙ4GPÝDÊ$ úÀC.c\¡¬« ¹6ŸïïÏý€¢Š+©BŠ(  (¢€(¢Š9ÓéÂ?S>žVÊlù2Ø£¿6r[þs–ßî°r“>œ#õ3éål æÏ“-Š;óg%¿ç9mþàë++ý˜ (®~|(ÂW–ù9¹ˆ]±‘#«”ÌvärG/Ì' @VL ˜í0Pl%6­Å“mpÖ–Äo“YF‘LVz¹ Dˆ'0@Ö(ÚâÌ*μ̈́°V*uñ`³´ûœú2QpÚ±›t¢©&R™ÓÕÖH-œ«WL¢OÄXâr‚…è$â%å¹\<¾‚șԼkØwGÂNT|”yRje’+óªšlR1ˆìª7PA­Ð9–)Ly¢¸žŒûŽ_"%R¨ƇÕÝ7•vÓ5ŒÔ¬œ•°¸‘Ô¹I]4Ș•#DPÅP„Ö6xœâfj 1 æ0ËLºÃ.=–@ŽŠgd|ÙL‹¿87™C†Ps´¨™Ì¢¹ÿ!‘‹Fa¹ è²q$e˜·JHvè%¢‰ Tª¡ÔD‚¡8ç ŽuÊbœý€N@ù]Ç>\îD-žÙ¿ Aµ³–ýWµÕ|¡lÅr“>WqÅÏ—;‘ g¶oÂPmlå¿Uícõ_([1\¬Ç値¤d67‘­ö'®6ç"ßQ³‘½‘Q]EFýž@ý3?;ÓµŒÇ±;f6äòQ(Í¡hù·ŽŠ†c6AH×…5Ïk†PÞ&Ó»V Âsmq.‰ÄlSY6’¬Qz EH(DÖ0^Â!Ìi,3ŠšÎ¾ØI'ì± eUAò’ˆ‘ЬHåÌ"UJ-Î(wÛ“r †£ŽbÓ-и4ì1rà`›×§`@Xª¦@v`= ᨞⡛2\4báV_àÉ5±Q¹2…a‡ ê¨ÂP„z ˜•š¤PíÄNs§r˜D2Üïüêju¥Ño&éX™v±N‚s ×#c‚¥7ìˆGD1Ì6_A\ƒáçNbPZ gK›áé¨õ ªD£‚‹&p˜ ÝÐ@Å%ÄÀ9DÐa¨u’å5RÀ½C¥‰%\ÎJš9Bm*Ý‘3=Hü¨C‰4Ér—DrÙ¨®gŒ°ÌÜâø*?”ú$ÄŠ,ðcc–hÜ­¾˜ð Uˆ+*"C(`!³pP1D j\…ˆ”ÂÒa^¶{Îé†n–ÔÌŒA $ [€ì™F‚šEÊ–m3¹Œ vj+ƒ`˜IþQdPœÁÈÄBÏáù$gÛ²‚V95¨³`2êÿ­T„Qp+’2©’1® eà1ć&ò“a´âWNbØ:9˜@YƒÑ+¼ÍI¦+¢¢ŸRX©3.‹‚>â¦P;Á °RrL0Ë 8e0ò¸ÉW{˜\ñÌ7w †F+C"–Ю 2ÊÀ[‡?Mä•£¦<ì]6Y©[KÊ"ÕMK à…µ Dt@€L½PÊ(¢€NúŒÏ©™²c›>|×(oÍœ÷ÿœæ¿û‡¬\¤à©ÁLú™›&9³çÍr†üÙÏùÎkÿ¸zÅÊÌ?Õ¢Š+@IF N:„M|ÏÚ6EÒéd7A%Œ©S5ía¹T,pË¾× »\3–L"Àóü J“m²Óx íaÞµ‡3•Lñ4•rê¦C G2J6Lâ]@ÊBæå <”gñ ¤¥eEì€õ}3¼rF­“) s¬©¯b”¥±@Ç0ÚÅ!sX¥0ƒµÈ9PK0åÜü3Œ@âÛ5gWm½œTQ8µHã±ϨÜPÏøWO@Üóó ýséSÝM§dÚ¾šça×Í“KkÓÙóê~]Kê~³ôjÎfm¬TŒ# ¬ef_“qLJS•ºÎOq " ׉wZâiœHÓã„ðÜŒ^&k$€”y¸üI"ñ%H¢G×*"šmRT¤6|á¨r\D¨”uÜå’'K¯ƒ‘ÂϾ˜ý9µõ#G‹Â1)£'ªdó>㔥\æ%Àßh Å8Æ >dÆLdÔvù%Vnƒ—O”1ÁC‰[¦q)@UL.kÌtÁÛWì[¾båM¤U]éªCÊr˜7¢„¸”êkGâL&)5ÆxA(ØÙvOUƒˆRXÛJ‹0Wz¦j¾±²Šë˜ s˜ œJ *˜u>MXº‹äë F>F-ÛH†¨.ÅDÚœˆ”¦H¦LRˆ @DÆû‡®€´™>F„6|—r€_>^µH¾rõÞÖ¸ÞöÊ{åo,3chÝQE²åYwBG›*Ë‘,ŸéÑPGYLý–Âl¦1zëe2|lù.å¾|½j-|åë½­q½í”÷Ê.RQZýîfJªˆå3ó«½Zó¡SŽI錢èåT‹•4ˆäÊ“1Rÿ†;Ž¡ nZÜcÿá¿ÿ5ŸÿÔ•b¹AŠÅÍ úTér<®H¡[ éȪ$K”© $6Âûú@A0ï ´ÑÜœ&„¹À‡I°6Ș¹G*9®9­¼0 å”uüÈ«‰Iz{k©çéõ$æàÓ¢Š+枀¨ðÜûˆÜ;¾–2­Z$ćl%€Qº¡ºáRQNéÕ:ÎvÃs>fÜj9Ø Ìù›q©:+Vç‹nç;ṟ3n5ì?†æ|͸Ô·<[p9Ø Ìù›q¨çaü73æmƤ襹âÛ€9ÎÃøngÌÛG;ṟ3n5'E-ÏÜÎvÃs>fÜj¬dþ=›¢8C O€§}$Îí#¤Â߆™œ °”2€X@,!SÑYnMÕ¿ép9Ø Ìù›qªqI:]Ñ0¼Î²ùu*6(X¥ ­¸¡që˜ÃÖa†Š¶ç‹nç;ṟ3n5BLD‘*ô¸^d*™9õo)ÂP¶µ· Íÿïþ*)nx¶às°þ™ó6ãQÎÃøngÌÛIÑVÜñmÀçaü73æmÆ£‡ðÜÏ™·“¢–ç‹nç;ṟ3n5ì?†æ|͸Ô·<[p9Ø Ìù›q¨çaü73æmƤ襹âÛ€9ÎÃøngÌÛG;ṟ3n5'E-ÏÜÎvÃs>fÜj9Ø Ìù›q©:)nx¶à¬gÉ.~dDÎA&t7‰„¢ûÆ]ÙG¬¢;÷oMÎÃøngÌÛIÑRÜñmÀçaü73æmÆ£‡ðÜÏ™·“¢­¹âÛ€9ÎÃøngÌÛG;ṟ3n5'E-ÏÜÎvÃs>fÜj9Ø Ìù›q©:)nx¶às°þ™ó6ãQÎÃøngÌÛIÑKsÅ·s‡ðÜÏ™·ŽvÃs>fÜjNŠ[ž-¸ϱ:ή‚x~e#¨™ˆSçC¢"è¸)·Cÿ!º›‡ðÜÏ™·“¢¥¹üÚÛ€9ÎÃøngÌÛG;ṟ3n5'E[sÅ·s‡ðÜÏ™·ŽvÃs>fÜjNŠ[ž-¸œì?†æ|͸Ôs°þ™ó6ãRtRÜñmÀçaü73æmÆ£‡ðÜÏ™·“¢–ç‹n3ŒN²‹69püÉ%æ ètÃ!‹mÎ:ÌÒî«ØBnvÃs>fÜjNŠ–ç‹nç;ṟ3n5ì?†æ|͸ÔmÏÜÎvÃs>fÜj9Ø Ìù›q©:)nx¶às°þ™ó6ãQÎÃøngÌÛIÑKsÅ·s‡ðÜÏ™·ŽvÃs>fÜjNŠ[ž-¸œì?†æ|͸Ôs°þ™ó6ãRtRÜñmÀçaü73æmÆ£‡ðÜÏ™·“¢–ç‹nç;ṟ3n5ì?†æ|͸Ô·<[p ˜âu›±A0üʧM2Ç·H@,#Òpcoþ¦þb=u7;ṟ3n5'EE9¥K[p9Ø Ìù›q¨çaü73æmƤè«nx¶às°þ™ó6ãQÎÃøngÌÛIÑKsÅ·s‡ðÜÏ™·ŽvÃs>fÜjNŠ[ž-¸œì?†æ|͸Ôs°þ™ó6ãRtRÜñmÀçaü73æmƨYâuDÄS̨"¢‡¾t7Ž&é8Ü×mÛ€¡`h©nu­­¸œì?†æ|͸Ôs°þ™ó6ãRtU·<[p9Ø Ìù›q¨çaü73æmƤ襹âÛ€9ÎÃøngÌÛG;ṟ3n5'E-ÏÜÎvÃs>fÜj9Ø Ìù›q©:)nx¶às°þ™ó6ãQÎÃøngÌÛIÑKsÅ·s‡ðÜÏ™·¡>'XÏ’\0üȉœ‚Lèo D÷Œ»²YDwîÞ†ŠŽsòÛ€9ÎÃøngÌÛG;ṟ3n5'E[sÅ·s‡ðÜÏ™·ŽvÃs>fÜjNŠ[ž-¸œì?†æ|͸Ôs°þ™ó6ãRtRÜñmÀ&y‰Ö]‘ ivy-2.4.0-rc1/doc/samples/eclipse-plugin/ivy.xml000066400000000000000000000044211226750426600215040ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/eclipse-plugin/ivysettings.properties000066400000000000000000000022611226750426600246610ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** # Unix users, set it to something like: /home/me/tools/eclipse-3.4/plugins/ # Windows users, it should look like: D:/tools/eclipse-3.4/plugins/ or D:\\tools\\eclipse-3.4\\plugins\\ eclipse.home=/home/me/tools/eclipse-3.5/plugins/ ivy-2.4.0-rc1/doc/samples/eclipse-plugin/ivysettings.xml000066400000000000000000000027611226750426600232720ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/hibernate3.0-dep-report-part.jpg000066400000000000000000001044501226750426600231450ustar00rootroot00000000000000ÿØÿàJFIFHHÿáExifMM*ÿþCreated with The GIMPÿÛC  !"$"$ÿÛCÿÀny"ÿÄÿÄ=!1"3AQR#2$6Baqt²4´%SbrC‘cÿÄÿÄ/Q!ð12Aaq±‘á"R¡ñBÁÑ#ÿÚ ?ý5Äg6u¶ßìžÿ‚ñ'Äg6u¶ßìžÿ‚ñó5;Ж^S«<¬Œ£ÖáFKjÓè*"(’ÄÂ"Böìœx&”CQ¯AÃ%_}Ì\ía쫪Ëù…&›aé}MMÅUEW Q{ ª¢-¤õŒì[êË=œ“(A1ú-‚$÷…"%%žëh„HDîª7‡4¶Û4ëY°µêŠLÀ}hSîD Fðò–Ûfk6½QI˜­ b=ˆ®Æ .©?¿äšýSÍFÁ—q1³r3qÚoAÄ7UÙC55BG;¬ ¬öTS“µŸ$ÞNE\鳄/¥\k±ý¶Èa"œT·®¤(kdTI6ðò–Ûfk6½QI˜­ b=ˆ¨Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÈéF-4ºs"„cxDZÝîÌW7ì&p‘ñeÄp û«jI=‘ÀT4EUì« Ç/(âá~¨9 „Lìñƒü|L4ÅizˆµAU_R9ÝUUe¼B ËxyKm³Nµ› ^¨¤ÌÖ…1áD@Ôo im¶iÖ³akÕ™€úЦ#Ü(ˆçe¦ãV«üûùŠ™¹Õåìmad2ë8¯¼YýF2]++ŠãVI3#ABDATì1ÇnS´XÚ_Ô^FÈu–Å£R22mR¾‘éÝI SÖIZÂÌ·‡4¶Û4ëY°µêŠLÀ}hSîD Fðò–Ûfk6½QI˜­ b=ˆ«±…ko…=¾â‡¶ÚÌëã8î`ƒ¶ Ô]qT ÒUTQ ý2¿Ïºöâ ¹[æ06 f¿„GšãN˜1…ÓÆSm΢´¦W"(C[" §hž&[ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "£xyKm³Nµ› ^¨¤ÌÖ…1áD@Ö¥˪çL‚'–‹Ä{_‹—–¹m«ôo [V•:BHJ”%òsnóTAãÆß—69¸¹€–Eí†Éæ¸îÑF\T鈘Ò:¦ž¥>È2ª¨ªS-áä -¶Í:Öl-z¢“0ZÄ{…Q¼<¥¶Ù§ZÍ…¯TRfëB˜p¢ k=Œ)K_ßò(ü”ËØäuoó¹(ýk†›n<÷öæ{y§ø:'pXÒ&6huu˜‰„dã*¢óJÞ *J­ ,ª$¬¡v‰ðò–Ûfk6½QI˜­ b=ˆ¨Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5§ÿÇ•®AÉÚÏ’o'" .tÙÂÒ®5ˆØþÛd0‘N*[×R5²*$ÿ ·‡4¶Û4ëY°µêŠLÀ}hSîD Fðò–Ûfk6½QI˜­ b=ˆ®ÁYR4sƒ„ÛÃÈ[mšu¬ØZõE&`>´)ˆ÷ "£xyKm³Nµ› ^¨¤ÌÖ…1áD@Öîxœ&Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "«žç ·‡4¶Û4ëY°µêŠLÀ}hSîD Fðò–Ûfk6½QI˜­ b=ˆªç€9ÁÂmáä -¶Í:Öl-z¢“0ZÄ{…Q¼<¥¶Ù§ZÍ…¯TRfëB˜p¢ j¹àpp›xyKm³Nµ› ^¨¤ÌÖ…1áD@Ôo im¶iÖ³akÕ™€úЦ#Ü(ˆ®xœ&Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "«žç ·‡4¶Û4ëY°µêŠLÀ}hSîD Fðò–Ûfk6½QI˜­ b=ˆªç€9Ä6'Ïëù/æ'å)‘3~¬ã›Êåÿ©3c˜ò³<:Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5åü,²åÝ|ï¶‘bï¯@ˆÕ@½R‚H«ë›/L{”’Ÿ9:É&¹·™ƒ»qg«íäec˜²¬€!2óf¦Ž¡,ÊÏOÒ¨©è©Á«Àw÷³sr'9ñqÆÚVÁ”BÅŠd²ªªªKÞ!Û˜yzí³BÖŠ‹^™¼D‡Òã>ØÌÉXs ¯]¶hZÑQkÓ7ˆú\bgÛ™+mªµ¦üó4sƒ„ÜÃÈ+×mš´TZôÍâ$>—™öÆfJØyzí³BÖŠ‹^™¼D‡Òã>ØÌÉZîxœ&æA^»lе¢¢×¦o!ô¸Ä϶32VÃÈ+×mš´TZôÍâ$>—™öÆfJËžç ¹‡W®Û4-h¨µé›ÄH}.13íŒÌ•‡0ò õÛf…­½3x‰¥Æ&}±™’²ç€9ÁÂnaäë¶Í Z*-zfñKŒLûc3%aÌ<‚½vÙ¡kEE¯LÞ"Céq‰Ÿlfd¬¹àpp›˜yzí³BÖŠ‹^™¼D‡Òã>ØÌÉXs ¯]¶hZÑQkÓ7ˆú\bgÛ™+.x½>ž“=ËôëŒâÚô¬ ÷µÂ?Öã’yG8†ælÒl\ÎkÙžT!éOÒä* ÄXaTÇÛ$õ):Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5•'s؈ü‹ýaó_ù§ÈüÇ-ít_ôýJüïËþïòI§Ëÿñ[ÈÇ~üÃÈø»Üîk<ì燙9}í2(.2¹vpMe,©–¨ˆ£¡=æÀÞ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "µsÀ3ŽiøNç4í˜ÝsO)lvŽà†sù\¬" ¶ëƆhDç\IAµ¢ ¨•žð7ÿ‰û=¾+»'O'3_¦.]Ø9‰œãl4-¡dãä|˜ºÜ ùl«Œ,¶Ó+ÆÎÞ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "«žXw‘oÈ;>VýR~we™°ê–<¶]|ç2úµoÝeoÒp,=FÔÒBÝ¡¹oá;:NPÝhñ¶xL¹°Ýãoq×RÞ..&K Š`ŽÙ"+=\TU!¨Џ§.®€Þ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "«žRÝrVß/?e™»e69X:pk EÊ×e½–¨+ŠJѺࢵt$TG$¬&³ò›Úàn¶{¶rv̼Î,|%e‡ôÓ׋m¶N4(Ú¶J¤fªB^‘ÚÞ@ÒÛlÓ­fÂת)3õ¡LG¸Q5ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "«ž—&è¿§uëþk溻,üëôé3–öE"Wøõk?ZÌ$Â;¹:b^“’ÂMëåÐH›™ˆ•™ŠœÕFðò–Ûfk6½QI˜­ b=ˆ¬~ó -5¢)¾Ø2Jþ8uS %*ë)=ÄRV¥Ûº/P’¥é™ÉÚöøçÜå¢þ¢Ô1¯ù¯•él°3¯Ó¼ü¶[9‰OåÒ¬ý-0± ë˜yzí³BÖŠ‹^™¼D‡Òã>ØÌÉXs ¯]¶hZÑQkÓ7ˆú\bgÛ™+UÏ¥ò÷ íp7˜l9‡ /S®Ýì7zìf5¤Î@?–YJ¢ëÊñ‹€#˜ò" `ª¨ 0Š%Ä>ïõ›=~Ï—9ŸY—ˆîéOçôç’Û±Ï ÅÈiD›VÄ-*„’°žôæA^»lе¢¢×¦o!ô¸Ä϶32VÃÈ+×mš´TZôÍâ$>—™öÆfJËžEÉøWŠß*ì¹sW¸yŒLþMo•HòYGœd w‘EA,‰õÆ Ö•Vê·wkÈyYœÅ˜û{¶ZÒì¶ø[¬üBÂRÉ,¬_—étŸê ƒKòxöhÉr l4¶¹‡W®Û4-h¨µé›ÄH}.13íŒÌ•‡0ò õÛf…­½3x‰¥Æ&}±™’²ç€W÷\ƒ ÉÆÉMF·Y¥ËÍÛàm3ò±p\Ë<\Æò¿uFªdJ–%UEqW¿t^Eù¿×?óJ~«ÌšÝïý<ô¾Säkùz¯ò_Ë´u<-}Vw0ò õÛf…­½3x‰¥Æ&}±™’°æA^»lе¢¢×¦o!ô¸Ä϶32V\ð ÿá;-|OÁçbÙáØ;,œà5Ô¶¹Ùû¶L¿–¤¦`Ú¼(Њƒmˆ¸¨aðÏL¸<í€ëï?5´ö3ŠÏ¥ÌlwQÓq±RRB%ÈÊÌy G²¿HQl-®aäë¶Í Z*-zfñKŒLûc3%aÌ<‚½vÙ¡kEE¯LÞ"Céq‰Ÿlfd¬¹àþ“áK8ŒœQ>YÖ½‘²Öfè¶Þ»G ,2EÃ33Q R'ETA©Ûš~ïö9;„Ôó>³u·ŽÇ ;Ny-ä€áãã1¨d4ªÒ®=Í<"…ÅËÓ˜yzí³BÖŠ‹^™¼D‡Òã>ØÌÉXs ¯]¶hZÑQkÓ7ˆú\bgÛ™+.xÍ#{Vul·»ÍÂÍÏKu_ÃÄ,fÔ±VÉÇ`aMeQW´Â;Ânaäë¶Í Z*-zfñKŒLûc3%aÌ<‚½vÙ¡kEE¯LÞ"Céq‰Ÿlfd¬¹à˜ïˆe{ÆKé7·‡M"n^""R"*Tsˆm&6A0당Íu7 ‘¤H)×_ÛED%ª ¨ÿ)D"EAT[ÃÈ[mšu¬ØZõE&`>´)ˆ÷ "³ ;VÀsˆlÍÌsƯ™¾j¿!­ÌÁù~œõ>aÜS½§µ~Z"oå#»­áä -¶Í:Öl-z¢“0ZÄ{…Q¼<¥¶Ù§ZÍ…¯TRfëB˜p¢ kW<,Õ| ×1³w7nËly;A”æ­¬|¼¦rUŸí9Dþ_íÝ?I‘¡ m­ú–ÆyCk‘ÏzþiÛí4¦ö24‡®Ó–.VGí›O>O¸§‹ÔqÇEŠ¥MU"PU;;xyKm³Nµ› ^¨¤ÌÖ…1áD@Ôo im¶iÖ³akÕ™€úЦ#Ü(ˆ®xáO½w ç#¸Mòøµƒò®`èZÄËy™V^EˆŸwöÂH:B¤¦D ª=„ÛÃÈ[mšu¬ØZõE&`>´)ˆ÷ "£xyKm³Nµ› ^¨¤ÌÖ…1áD@ÕsÀá=ÉÓ ôœ–o_.‚DÜ|ÌD¬ÌTæª7‡4¶Û4ëY°µêŠLÀ}hSîD c÷˜Yi­MöÁ’Wñê)WYIî"’µ.ÝÑz„•/H$ÎN×·À'88MÌ<‚½vÙ¡kEE¯LÞ"Céq‰Ÿlfd¬9‡W®Û4-h¨µé›ÄH}.13íŒÌ•ªç€9ÁÂnaäë¶Í Z*-zfñKŒLûc3%aÌ<‚½vÙ¡kEE¯LÞ"Céq‰Ÿlfd¬¹àpp›˜yzí³BÖŠ‹^™¼D‡Òã>ØÌÉXs ¯]¶hZÑQkÓ7ˆú\bgÛ™+.xœ&æA^»lе¢¢×¦o!ô¸Ä϶32VÃÈ+×mš´TZôÍâ$>—™öÆfJËžç ¹‡W®Û4-h¨µé›ÄH}.13íŒÌ•‡0ò õÛf…­½3x‰¥Æ&}±™’²ç€9Âzc¾!•ï/¤ÞÞ4‰¹xˆ‰Hˆ¨EPs ¯]¶hZÑQkÓ7ˆú\bgÛ™+%¤ÆÈ&qw9®¢æä"ô‰:ëûh¨„µDå(„H¨*‚.Nå·6ÏþiÐel3°·Z]ƒ:ÝîN±“‘Œ¹,/+jëN4† BªÓDŠ&„Øú”TÀåÃÈ[mšu¬ØZõE&`>´)ˆ÷ "£xyKm³Nµ› ^¨¤ÌÖ…1áD@Ö®xWÒbòö™½f#<(믺óÊŠãï<á:ó¥TAB7 ÍPPE DE?Âø;‹ªøb\“ Ú³ªk3—ÜÓm¬èçb«?8¬¡¥2.¨JvU1;*4mhíáä -¶Í:Öl-z¢“0ZÄ{…Q¼<¥¶Ù§ZÍ…¯TRfëB˜p¢ j¹à¼§ËÛ\ æË˜9ƒo…²Ûgãca‘`à&80Á¦“Ëõ-ŒÚÚ÷´ŠwµÎÖå?’ùQ¼<¥¶Ù§ZÍ…¯TRfëB˜p¢ k€¿§òv6v2æ£ `»”ç@•R…ë”B_XªA¨r’¼Üï[sc¹‡•t{ì†ò6xŽ›Í…Ær]`”fQ [!RDUXE˜•ˆ•˜ß‡|–×*á[/`{m©IÌç¢ôÑ{Œ•Qa»ª‘wU„ms+…‘—žÿ0i€Q²h2qYWG‰Ñk¦&DJ°ˆÚ¥ÿl,=ÊÓx›L?œÂÜçt\'¢Ø‚¢¢mÊ(’¢A$ËC3ë·w©¨£kNžÇ>ÏMÎúnyÙò΋g»ÃÝgk›{; :.)'e°\Qjt%R "ЕHaVx—â'1ÆÏÇÀ™3;«òŒ°.;T5.˜IQ WëØO’³Naäë¶Í Z*-zfñKŒLûc3%n ¤ÝÁqQMÑz•2þòsûÖÿíXã¿ ¶ß0ó›¦ê®ÀJƉ(‹ŽÊ¢vD숰ŸXD•U•ᮼ?ÁÇѤ³Ï¹B{¼ßÓµf_:uõeäôI$OQÔ£ÏnË+ õây§æ05ïá1„Gšã­¿›ÓÆSmΚˆ:€W")PJ¢¡/hŽ&vÚðØ6ÏlóuX}šÝ²© ª!"ŠÈ‘'t_?xT^ZÇMJj[Øl‰õ}¥15ÈMHÀÌÅN=D’„… ÝU{ñÇSµ¹ÛÒŸÏ*fçÞdÉÆÌÎӛظYmb(n›¢Õ°XE[:(V!DHTRî‰'¥Ïw52šÉÇ2±è> º®”ÄQ%UJ˜ùï)Þ%y½¥Åwæ¬ãÉóY¬æœ*v6ºUDíüdgëÝ{§hk ¬\Œ×Û#RÌ}q R‘°nü¡´ÿîxØ­E*··÷øgWºÛãcº.`j?°ÏcS1zޏ>bÙ! ZQE±Dh˜œÁÜ1°Îa¬ë㻄9„ô¨ÔMa¯J¤­Ñ_ò§tîœqÁåöqs‡!só_m¼—²˜Çs§Óe×TÔˆTA }ljR r¾¯ôöòŸ&>]rœBoNëŒÒ 2…*•E±T}"¦B2‰+kV4Oœ~ô §ß0µªÜba°àÕ¬"*"Bª÷^¦s':ålùwž9ŸN[?Óøw¬Übâþ ¸Ocƒß¨›Ž6b.‹Y!$E&ÁaRçµç̬>bÌa½#.éu»|-.~Yf¨äŽVWËôºLtÔM¤ùÌ{:Ÿ¹UöÌøkËnèót˜‹›¯ÀÌå´å§šÇy pÀLY…q PÚ^A)ïÕ+¡ÀW¾ÇõÙ¼Äîж{6±2s±ö9º¶É¯–ÊËÇét_2VÕá!ù|H8 ½‘[ÀáÍ?4šÝFÃ'Dþ3çëvXZìÍn»`Êä2îFXc ”¡@¸¢Š ¨¤=Õ#ø‰¹k9ü}¯)³ŒÖ³o‰§Ûä1´ë6jÂc¦2+bO |Ó ê¸,Q iÖQTâç̺L]þ¹¬Çm¦³±3EZTB¾6Cy‹(¾•6…ë °¨½Ò33’µY_ªõ23SõMÞíú˜ú_Åù^˜§°/ɵdYU±Â¤¤‘ñ â¦7#ä;Ëî;˜ê±ŽÞ&åضiŒY YŠØôš£fˆhfª¤×¥ÕE,_Š˜¥¦ËÙäéÞÓòþNÛ˜eä75ï0á´¸£dx•ÌlàCAœiþ.¬ž?íSσ» ®ë§®Ùdìðµß0)ˆÃù øä-Plw,‡—” ³j¤èr/-ü¿3â»…ÕÆækŽÁ¥Téj&Ð( ¼ê¤ÏW!ã™5à fÆ/ŸÔm—]‰Ë;¶N­ G1üÞüþ_Ê´‡’,!‰!‘‡H h¨ª¤¨3+µÛó¿h›`þ†>\ÉqÓº÷È |»9A“”Í”eôS³WNÄ‚ ®J'$F¸ñw\Ï̧K; 122Ü` 2m–¤0õÉ  B‰sÃ|}¶Ç#;šyƒRY;pÜ<Ö"bNd; 4¤°â‚cŠ/‡ÿÈ[PgáæNç3”±_ß É–®¾-›ìô^{4ÇuÖàhé²…B¤D” Ø8KI…“¯Õ³‡—¶Íۼݭ™˜ ‹®I*¥‘슈)ÙeeUÞOLwÄ2½ã%ô›Ûæ‘7/)ª9Âzc¾!•ï/¤ÞÞ4‰¹xˆ‰Hˆ¨EQÎ&ÔŒçž29—'ã(èp˜dô¥ƒ•²ÈDÝ?„á8ÆF YQ¦×ª ¬2gÓu\+ ôÁKFâ3'IŠÿ5`s¸òeààäá4©ÓP|Ø3UH›"ãB¢B”¢ÊE,øñ;¯£ø‹Ë8yúVöÚþ[Üfaäh÷¿5‘‹òÃE\@Åzζ¢(§Ü\õ"‚ZõÍ™YryO XÛXm#™ —²V³œlIÇÅF‹«w¥u\GÑ…PKEà|&å¼yg+;u±À&O/±“–‰­{¢‹Ž*•DQÕUt‘Væu ¦yH˯Ûíy—u¸ý6ÃÆÊ`i¬Ž0Y²ÈH‘(K¤¨ P+? >.ê¹ïxλ ´¥óºÓÚaŽàs2`I¡PÍi~Yïßn Ä‘u-èE-3ŠÏ&òs<¯ÓgyºËÀÄÆL=nK­ü¾:U°FÀUÈCy]4AX$»Švn8OrtĽ'%„›×Ë ‘73+39ª¹Â{“¦ é9,$Þ¾]‰¸ù˜‰Y˜©ÍVgÝ`sƒƒƒŠÁÁÁÀppppÂzc¾!•ï/¤ÞÞ4‰¹xˆ‰Hˆ¨EQÎÓñ ¯xÉ}&öðé¤MËÄDJDEB*’û˘œgüȜͫæMs؜ߛ°ÏØl›Ft‡Œ8"ä8¿¶¯KÔÕÅyžé¢'î  qLÄä\¼^oÎæFyÌì–ÝÈÅ&° ¢iµôc!.2º,Š)"š*)¸Ss#Zg’wÓýqNmØsž 9{½ž±œœ]hks·rU†Á¿œOì쫈n(‰tÕlHB‡'ñœqyOâw+¦Ç=áÇÏÔlXÆ×¶ò!l3K+\í“«Ô4%D#U!Xäæ©ØÝeo7YÌâd¹™ƒ®Éu³ÇÃÈp ³p eô¼ð „Ž*Š hî9gU·Þcí6,ü×K[—¬,WDOæ2I‚uE·ý8$LA*,¤–|JçhÔóVÕ¡Ýlõ™zîVÃÙbëpp/XîižmÃ/,ñ¥œuVpÜÆD2‚QÛ8Ïö? póò2UþkæbÃÎÖ†§cˆoc¸9Ø@ãä,ºá²Ov—ê ‚âŒ*šœšèq]ØêG˜ù\Yˆû8ÎÝÁëÐÈ4êP °IÔ["¯©fx±pžˆúšL/Ô¶3kkÞÒ)Þ×9ÿ[”þKår­M5Ά5]™”lùkKË;ýx'O#-žŽ[˯l ”“t:$o 4%ê/I„A›·!ó:í ô½ƒØÛDirT1½£$²§u‚4E•YU”U•DžÛé4ÛŽ—êú~Ç£=/šÆi11dX˜I²qȼ¡©äýOÈkW!ò(G2rI çeQ QaÊù"UôJq”?W^s¡çZz‘ÔÛºcŸó¶ïüDÏØåj˜ÃÈ×?® LCÉ3<Æñó\u³J¶ªd$@GÒ?ÉSzÔ½—“ªÄÈÏÂù ÇXªŽtQE ºv*¬¤§e‰ãæN»_“Ÿ‰°ÈÁÅ{3ÿ*û 8ÅÒ„©#dì±å<ð×-§)6ëR~Ÿé¥¥9Éʵ(åýäæ÷­ÿÚ±Ç~8÷“˜?Þ·ÿjÇøò®¯Õü³ÒFsg÷[mþÉïø/|Fsg÷[mþÉïø/©Ü~—†õ¸áJ¹š´¬[1ÕñH™.þØÌù’™¹HÞ·)W3V•‹f:¾)%ßÛŸ2S7)eŽYÊÞjž;jéªaº ¨ˆ‹H52ïüEU|öì¼x¾!)£[Ê%çôQTXõ¥?m%|œ$wñßþ~EÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLܧ†û3+°1p•ÈÎÉV×L†œqUET»6©Oå=â˜÷»­h9×Ôãæµ‰Õ`]hÍ6.É¢4ÈÜU Ð ¢—TWE;Â)sœôáZ®†6õ¸áJ¹š´¬[1ÕñH™.þØÌù’™¹HÞ·)W3V•‹f:¾)%ßÛŸ2S7)«>¹ ¦Õ^\gÉ9‡^/ËD‚j¡†’‡"¨J„’¤¡QfxíËYyøn²ÛŽc;…¹Øc¶Ø²BãDŽä¹e;*~Ú¤T’wíÞ¬nµÇ• ©co[Ž«™«Jų_‰’ïíŒÏ™)›”ëq•s5iX¶c«â‘2]ý±™ó%3r˜èg¹Î¤×dãc»ú~b©?ŽO S´!‡yŽóÿ× ãsFVF¡ì‘Æe¼—ñ°ŸÂ’ù¸m´q{*èvQDôV%e8§©§4×)QRÀÞ·)W3V•‹f:¾)%ßÛŸ2S7)Öã…*æjÒ±lÇWÅ"d»ûc3æJfå<7Ù™Xå‹„¬†FvJ°¼ `Ü4㊪(¢¥ÙµH²)ï°|ǽÝkAÌ~¾§5¬N«ëFi±vM¦Fâ¨^€Uº¢º)ÞKg=8V« ,mëq•s5iX¶c«â‘2]ý±™ó%3r‘½n8R®f­+Ìu|R&K¿¶3>d¦nSV}rMª¼¸Ï’s¼_–‰ÕC $EP• %I;B¢ÌñÛ–²óðÝe·Æw ;s°Çm±d…ƉÉrÊvT$ýµH¨ÿ$ïÛ¼-XÝk+ARÆÞ·)W3V•‹f:¾)%ßÛŸ2S7)Öã…*æjÒ±lÇWÅ"d»ûc3æJfå.pqé²84M½n8R®f­+Ìu|R&K¿¶3>d¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊ\àádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLÜ¥ÎGM½n8R®f­+Ìu|R&K¿¶3>d¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊ\àádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLÜ¥ÎGM½n8R®f­+Ìu|R&K¿¶3>d¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊ\àádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLÜ¥ÎGM½n8R®f­+Ìu|R&K¿¶3>d¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊ\àádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLÜ¥ÎGM½n8R®f­+Ìu|R&K¿¶3>d¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊ\àádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLÜ¥ÎGM½n8R®f­+Ìu|R&K¿¶3>d¦nR–›_Žþ“ ÂÈÍ>®0ªçº³a)T$t¿õ  ¼ ÐU&x¨eã+Ú|7q6;7Xúx†iôÀ‘±ýÂp€ÛT"#W&Õ±È òÔJ.©XÜÖãìæj^Ó\ÇSÍæ »{…â"ƒšÜs½œÍKÚk˜êy¼Äop¢<@ÄPc‡3e?‰ªCÆs¦ã¹8øèpР޼ ©$ö²!ª¤¢¤¢J*v㎙Ow§žwŒf2WÝ'\p’©þÒ*YUQIRb¨šÜTí§7ÿ€uÍn9ÞÎf¥í5Ìu<Þb ·¸Q b(09­Ç;ÙÌÔ½¦¹Ž§›ÌAv÷ #Ä E"yŸH̱3v¬d ¦½°Ê0m¢OY6*€­‰*)¡M«ê,\lRmªtnkqÎös5/i®c©æó]½ÂˆñAÍn9ÞÎf¥í5Ìu<Þb ·¸Q b(0çdph›šÜs½œÍKÚk˜êy¼Äop¢<@ÄP`s[Žw³™©{MsO7˜‚íîGˆŠ 9ÁÂÈà ¹­Ç;ÙÌÔ½¦¹Ž§›ÌAv÷ #Ä E5¸ç{9š—´×1Ôóyˆ.ÞáDxˆ Ãœ,Ž›šÜs½œÍKÚk˜êy¼Äop¢<@ÄP`s[Žw³™©{MsO7˜‚íîGˆŠ 9ÁÂÈà;œFXÕçe#ù @îYsA«‹=ÜDõ—ø…¸ÐTZo[Ž«™«Jų_‰’ïíŒÏ™)›”›Óéé3Ü¿N¸Î-¯JÀ¯{\#ýn1ù'”s‰PÝ›zÜp¥\ÍZV-˜êø¤L—lf|ÉLܤo[Ž«™«Jų_‰’ïíŒÏ™)›”¹ÅâVï+–¾s/1à¶Ë™z­FVkò*¶FÓ$b„ˆ¨ª2)0¨±õN*Èàëq•s5iX¶c«â‘2]ý±™ó%3r‘½n8R®f­+Ìu|R&K¿¶3>d¦nSœs8s—/gj4¹ÙÆv;f³3‘ìZÏÛ7ˆË+Œ?,­0â8é[!WæW¤0!SH†Ìçm޳gºç´¯k¶9Ü­Ê¢xc»æ ÙyùÍ*@"ãÄÑ=*Ø ‘¨U*¥(²8ÀÞ·)W3V•‹f:¾)%ßÛŸ2S7)Öã…*æjÒ±lÇWÅ"d»ûc3æJfå9þ»ž·ò>Ë/`÷é»&vIƒ®Ì•6ú—í6ò›ZÅ$É(xËØ7fˆ¢)ÄNaÏäÍ>ëä´ØÏdçãlw9º\¬Œ|sÅÉ&\ÅGw@uâqã¦:6 âª’ #€i­ëq•s5iX¶c«â‘2]ý±™ó%3r‘½n8R®f­+Ìu|R&K¿¶3>d¦nSœm~"o[ø“™¢×kžÉÄ×mðµobµ ÍÈ'‘öñÜ<•Îoû>8´96VŒIU_PõEGSádpÛÖã…*æjÒ±lÇWÅ"d»ûc3æJfå)mµøìà¦Fh!8Ë*Kžê,bWEl¨)ÞfT¡ L„æxOrtĽ'%„›×Ë ‘73+39ªÌá^ÀÖãìæj^Ó\ÇSÍæ »{…â"ƒšÜs½œÍKÚk˜êy¼Äop¢<@ÄPaÎ+<û¹ÚëC«Ò9û͒ൕ˜Á>Ö5qŸÉS&„Á\‘ÇPDCSB•­J¬Ž4æ·ïg3Röšæ:žo1ÛÜ(1Öãìæj^Ó\ÇSÍæ »{…â"ƒÿ9äïùçSÈø÷/ƒY\Ó²Ôí1³õG™‡œxmg€¸LuÂZSÄWQ¢#Q5inª×®3›pw%ñ˘³å—Ècdá4Zw•ÿ“ý;!qzã’&,¢€W÷ŒžHžŸ #€nnkqÎös5/i®c©æó]½ÂˆñAÍn9ÞÎf¥í5Ìu<Þb ·¸Q b(1XÂÜóVÛœ÷8ú²Ò·©Ñì™×ebä°êädß ÞÄêÝG%VŽÊÒ¢˜#’ÝOG̹ڇlµ±Ök÷Nóä] ^[ÏÚJ5±ÉÞ F_W›q@ˆÔÈ\@ípDYSs[Žw³™©{MsO7˜‚íîGˆŠ kqÎös5/i®c©æó]½ÂˆñAŒË’9ÃaÌ›wËÀÍa$ræqbáã=œë}w¶$€ È)¹ hЍUQ$ùƒ7o—ñPþbåærnÕý9lñrXqŒ„{P_K¢£F¦ÍZGZX/RŠ,Žzs[Žw³™©{MsO7˜‚íîGˆŠ kqÎös5/i®c©æó]½ÂˆñAŒãUñC+v8ÜǪÃd9Us´øO†Kj™÷Ï` TPM[ªv¶eer»7k‡Ã+!òÎÅÍùl­ÞV·Uòz¼œ…Æpq,“hM¶g Q"!jа¨p²8Ín9ÞÎf¥í5Ìu<Þb ·¸Q b(09­Ç;ÙÌÔ½¦¹Ž§›ÌAv÷ #Ä E3,ž}ç NQÝsfczPÀcvþ''!Kõo‘o(ÐN¢ª«ŒØ©8 Š.…è';s¶Ç QˆX9ùÜÈz‘Ùlùs3¬–\îb¼ÞζèzÛV{¸HªÙ’yA‘À4×5¸ç{9š—´×1Ôóyˆ.ÞáDxˆ Àæ·ïg3Röšæ:žo1ÛÜ(1‹ø}»Êßò×Îç6Èe±›¯|™EÝ<\§q‰ÁUPV”ЉE ¶(²Ø8Y'UˆË͹¯ä™|ÛëÛ1ÅT{Ä#„ˆ‰Ó¬¢'©*6 á¦õ¸áJ¹š´¬[1ÕñH™.þØÌù’™¹I¦;â^ñ’úMíáÓH›—ˆˆ”ˆŠ„UâaÚ¶mëq•s5iX¶c«â‘2]ý±™ó%3r‘½n8R®f­+Ìu|R&K¿¶3>d¦nRçŸ=ëv»oü™‡ó:W58úÜÝ—ÉçêË*c' :À½ayèmÚªµ.ö4r¬Ž 7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊFõ¸áJ¹š´¬[1ÕñH™.þØÌù’™¹N%ñŸr6ü«ñ—“-¦»3“w{ ~c:<¼Á–@P^x‰¼Ñ1ÈG™Q@˜Tpk£PnÿüŸúcØZ­gŒ6_Ö<áí¡u6²ÑÁe³Bê"㨪æç`$QYÎÞ·)W3V•‹f:¾)%ßÛŸ2S7)Öã…*æjÒ±lÇWÅ"d»ûc3æJfå9ÇÁ߈›ÞsÎÁw/\÷éÛMBíq4¸Më•Ušc.CòÞa¼PëTH`Šª†•ÔøY6õ¸áJ¹š´¬[1ÕñH™.þØÌù’™¹J[m~;8)‘šN2ʒ纋ãAØ•Ñ[* w™•(BS!9žÜ1¯IÉa&õòè$MÇÌÄJÌÅNj³8F×°5¸ç{9š—´×1Ôóyˆ.ÞáDxˆ Àæ·ïg3Röšæ:žo1ÛÜ(1sƒŠ²8nkqÎös5/i®c©æó]½ÂˆñAÍn9ÞÎf¥í5Ìu<Þb ·¸Q b(0¯7ç–³–ó2›È gTQ¦_r(ÓŽ6SÙH‘U{öEì¾8†ÂÞ;ý5ºÌül×q¶àµ”D¹ (:óh (H¦¢ÓÀŠª²¤%*¾WŒõ4á+Zð©…Ín9ÞÎf¥í5Ìu<Þb ·¸Q b(09­Ç;ÙÌÔ½¦¹Ž§›ÌAv÷ #Ä E"Wq–ÖÁœœ¬fó±2Ço ÇEâVÛwÒÀššª ªBÿ/‰Ç_½Ùm[ÀÇÂ\l\‡Ç,çñ\!TÇxY_ÚR%$(RUªÊ÷Gi§ZSlÓäTœs[Žw³™©{MsO7˜‚íîGˆŠ kqÎös5/i®c©æó]½ÂˆñAŠÎ&fÓk·Ì5ÂLrÛb0þ2ÝÖq[Ue¢¦‹ Ü­WÄökWÌ9Ù»äÇcd¦nR7­Ç UÌÕ¥bÙŽ¯ŠDÉwöÆgÌ”ÍÊs-ÑïySWÊ ðÇ™¹ìnCû]–h&à 1Ë]Qs+ ®«™)&.¶2- ª‹LüXÚ`o?ðéÍ»½[ÿ1°åܬWhCÔiÌ3 ($EIE…D_¿ #€]Öã…*æjÒ±lÇWÅ"d»ûc3æJfå#zÜp¥\ÍZV-˜êø¤L—lf|ÉLܧ,ç®lØóý®Ëž& ó«ZÎ1»·$]Ž8:Ž)EŽO¶àôÀ”0p:´nÍð#(ñ9‡ !vl5·ècàm2×+3ÕiçÔÜꑆê*:ê :aQVÁdp kzÜp¥\ÍZV-˜êø¤L—lf|ÉLܦ÷µZžJÞË/;åZÂ]p3%+ GKº«« rÿ©h*–~! ZÆ÷”0ñ22A6±ŸÚ13Pp •Ä%B^êh±ÝKÊâ„/U\ØÇÓb¥…ÎÚ—ÙTÏËËéüŽ·~¹.ä«Êä6@"bŽ¢¯z J‡ 7cx›LʦÓæëfÓ¹n ºž“Tì¤p¢± ‹ó›ZNQÜ`¶ãÏˈÞSîf嵎Öi†S™#êFJH^pÌ:h—YEDK'Ã^jÊÜ8Z¼×ÃbûxÃ’¹Ì#pK8DDUY¢¢z„W²(ª¯¢z¶èÇcÏxßÙ·¹'·ÙòÖïK°Ú䱟=&Ó)ôDº¸#b«v#1 (Ø„D%@PfÖãìæj^Ó\ÇSÍæ »{…â"ƒgÄF9˜þ#Ý1üR9ÏJþ©WžFPá§aqDs—æ²KåÏ%äEmy•Ta D|yAYADàÃÑk13‹1–žê+Ž:‚æK†Øª©ˆØ»Š"ÁxUã»z[téëp‚•­X­iXíÚ:MÇÛ¦?Š@Þ§VÝ:zÜ ¥kV+ZV;vŽ“qöé⑽šý«žÀñ´ÓàìŸeüŸ™XÍŒ·X$QRIl†QT²ý¸àþ§vÚÇÅŒf1õbKŠ‚!¡j Ú´NÉü–¿ÅÔÓz[téëp‚•­X­iXíÚ:MÇÛ¦?Š@Þ§VÝ:zÜ ¥kV+ZV;vŽ“qöéâzuu¢þ½ïc°`YÉT¸nf ’&*„+ ©(©(ªžx€Úrá†X=«Ã€´ù¾Vö#)"nÝUUp–I¥IUJݦq5úWeüLy4¢É´Ð(¨¢ŠŠ¢x†Ú…OÀ>ÉǶõ:¶éÓÖá+Z°)ZÒ±Û´t›·L‰žšží.{ 1ôì.(ŽrüÖI|¹ä¼ˆ­£Ï2¢¢ê€¬!H("+((œz-f&qf2ÓÝEqÇP\ÉpÛ5U2"Q[qDX"O ¼woS«n=nRµ«•­+»GI¸ûtÇñHñ‰¯Ò¸Ã/â`ëÉ¥6M¦EETUÄ6Ô*~öN6ÅUúW=€ÿbkô®0Ëø˜:òiD “i QQDDñ µ Ÿ€}“mêumÓ§­Â Vµ`Rµ¥c·hé7n˜þ)+#G88M½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ oS«n=nRµ«•­+»GI¸ûtÇñHVXœ Zý.(6eƒ¯`D€U B–Ä;y–ÚDO¸xN=·©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤+ 9ÁÂmêumÓ§­Â Vµ`Rµ¥c·hé7n˜þ)z[téëp‚•­X­iXíÚ:MÇÛ¦?ŠB²Ààá6õ:¶éÓÖá+Z°)ZÒ±Û´t›·L½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ!Y`pp›z[téëp‚•­X­iXíÚ:MÇÛ¦?Š@Þ§VÝ:zÜ ¥kV+ZV;vŽ“qöé⬰88M½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ oS«n=nRµ«•­+»GI¸ûtÇñHVXœ&Þ§VÝ:zÜ ¥kV+ZV;vŽ“qöéâ7©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤+,ÎoS«n=nRµ«•­+»GI¸ûtÇñHÔêÛ§O[„­jÀ¥kJÇnÑÒn>Ý1üR–ç ·©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤ êumÓ§­Â Vµ`Rµ¥c·hé7n˜þ) Ësƒ„ÛÔêÛ§O[„­jÀ¥kJÇnÑÒn>Ý1üRõ:¶éÓÖá+Z°)ZÒ±Û´t›·L…e€9Åw]¡ÖçbclÜwa󌡺ÎÓ ÄGÓü$Tî«ü‹¹*Ø•UVY½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ"?—ôú_éÝx¯^­. ""2**=ìrŠŽ9þ"›—¨¬ª¼ç¤”’|ô0“s ×ò^w,¦ô?P¸Ø©ª ŠöÜ?§yïÇÓk‡W“¬VLñò„‡#¨ñ™º„5[*š­a%VQ;"qíÍN­Ëõ5¸G{ZÌ Ú×´öï=W'ïÔ/ÉdsS«rýMnÞÖ³¶µí=»ÏUÉûõ òY«|—=ÌåínVÁ݃…° ‡„@ÉŽCH¢3T€4DD•X*«åW‰nsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–J6ôKžÀsƒ„ÜÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–G5:·/ÔÖáík0+k^ÓÛ¼õ\Ÿ¿P¿%š¬°88MÍN­Ëõ5¸G{ZÌ Ú×´öï=W'ïÔ/ÉdsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYVXœ&æ§VåúšÜ#½­fmkÚ{wž«“÷êä²9©Õ¹~¦·ïkY[ZöžÝçªäýú…ù,«,ÎsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–U–oO§¤Ïrý:ã8¶½+½ípõ¸ÇäžQÎ!¹‡Y«ýbã˜I8Ï)6#ä\²©X#ÜrVãüËÔ’«Ã­êumÓ§­Â Vµ`Rµ¥c·hé7n˜þ)œ®{Îßjð7š<ý&јÀØc9‹”ÕÈz8*&2*Š’*©(¨¿n>·©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤ êumÓ§­Â Vµ`Rµ¥c·hé7n˜þ)Y` s?,j9‹åËb­½dg'=ü,€‹‚:ÁДAT-UPTUTá›É|¯”ȲZvXhp[ÀÅ"Çe³CeQ©4cf ™U%mAH¦Q½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ#ƒšÎ,1µ‰—ŒÓOÔhQ5î"«Žˆ+âYHþ•–ýË?¡þ‘ò¹½?™ù¿šýK'çºõ§WæúŸ1~Ÿí[©=?ÛšzxâŸ9<4Øz<}cØš|7ro[‹ŸÆ!£î+޶ëhÛ­~Ó‚@‚J((*©Å½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ oS«n=nRµ«•­+»GI¸ûtÇñHVX^o&òîg1ùü7‹/ªÛÆØæ<8Ï<ÜtÞw uÑ£upÀˆzm§L+`á6õ:¶éÓÖá+Z°)ZÒ±Û´t›·L½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ!Y`pžäéˆzNK 7¯—A"n>f"Vf*sUÔêÛ§O[„­jÀ¥kJÇnÑÒn>Ý1üR#÷š}/é¢ÉêõèÑ?ŽÚв*=VQù ¤6ÚD¬ÐR§+3rµíϰ'8ŒæM³˜pCfÓÊ-:2î>K˜Ï°hŠ7mæˆ\l”H…TIDÈVD•»š[—êkpŽöµ˜µ¯iíÞz®Oߨ_’Èæ§VåúšÜ#½­fmkÚ{wž«“÷êä³U––'+h±qõ 1ƒPÓäž^«¦D/›n¶ã¦J²é˜¾ò‘’‘’ª—~ ÞVÑfkù‡_“ƒ|nc¿êÁÕ4ù‹c†9wE–›ôljòª¼ÿém>¯#i¾ý]€ßýFVoI¦†äCê3„KÆ×ººIþ%ž;<ÎKÄÎÊÁÙerþ>[8.lrXÈq‘p1eÄ<ƒîKŽ¢šúdÎWºð¬°™¼›Ë¹œÄ;çðÞ,¾«oc˜ðã<óqÓyÜt4e×FÕÃ!é· 0¯îBå<Ü6±256e¼œ¬•Ètz‹’ñ=ÛŠ„Šã.¸V6Z(QTDšsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYá‰ Ø²ãØØÚ̶•×YpÛ1StTÿ¼$žQIÄ^ê¼+,Ž‹•´Z/ý'å>CZÞ­Š:ký•¸é¶r¿¹HZ‘؆îB§PìãÚ¼·˜»·¶~&3ج;rô4ñ4N L,“ ,ªJW´JÏÄÐ?‘‚¸ÚÇrÁ¤yö( àƒªò!ù©ªä"*öUW<ú¸ÄÐ.p࿬\¼–xX0£ Š¨á ¯r\…B_òÏó¶:ñùKc¤Ð뵆9îäŒìÞÆ%ÊxœÈ7º¸*®º})/áfÅl.òž“–¹WS˘.<æ&«œ& åEp @%DDRI„DŸ¢qÝÍN­Ëõ5¸G{ZÌ Ú×´öï=W'ïÔ/ÉdsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYVXEÊÚ"Ðdè—ûNKÙn:hHû¯–A:7G‰\E…¤V9‡á¦»1®\Áמn>ìö{¿WË ì‰ÂÈÇEù¤>¹š+ŒŒ“‰ûaIª qtsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–U–óI«ÀÒêÙÖëXèã5eDS#""%#32U#2%"#%R"%"UUUáÞsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–U–iŽø†W¼d¾“{xtÒ&åâ"%""¡G8†Òk5jï™fä8F‰*Ÿ]UIVÅê³`¾e°Õ]oS«n=nRµ«•­+»GI¸ûtÇñH˜9Z¶œ$ö¯íæ.íÆ-Ÿ‰Œö+ܽ Ý1üR–Ë|›Ë¼½œyš¬7›uZVYsy¼FUQUœppÈqÚZ‡í´€0ÛioS«n=nRµ«•­+»GI¸ûtÇñHÔêÛ§O[„­jÀ¥kJÇnÑÒn>Ý1üR–ç îN˜€W¤ä°“zùt&ãæb%fb§5Q½N­ºtõ¸AJÖ¬ V´¬ví&ãíÓÅ"?y§Òþš,ž¯^øí¨« ‚£ÕeÊCm¤JÍ*p‚³7+^Üûsƒ„ÜÔêÜ¿S[„wµ¬À­­{OnóÕr~ýBü–G5:·/ÔÖáík0+k^ÓÛ¼õ\Ÿ¿P¿%š¬°Ù¬d=ŒëÍØñœWYYT©(OùúL“¿ßˆÎcÑ·³aÎ’tòssª`ªÓ/£Š=Ä¡N!eS¿dTuÍN­Ëõ5¸G{ZÌ Ú×´öï=W'ïÔ/ÉdsS«rýMnÞÖ³¶µí=»ÏUÉûõ òY‰BäÓK~`ÇèZÏ‘ùN“Õêuz¿2ç^ñ[umÔµ}3i¯§Çn<'.iÇ œF1¦ Âkå_q‚ ’‘Š* —zÍ{oJCNjun_©­Â;ÚÖ`VÖ½§·yê¹?~¡~K#š[—êkpŽöµ˜µ¯iíÞz®Oߨ_’Îvkö®{ M«mƒa¼0m£}§ÔTE ¤mTD^ȈÓ}“·§ÇuàgM®g`¹í²híˆÄUãVÀÊlbÚ­–JIlR¾¥Ÿnjun_©­Â;ÚÖ`VÖ½§·yê¹?~¡~K#š[—êkpŽöµ˜µ¯iíÞz®Oߨ_’ÎØ¿jç±£œ&æ§VåúšÜ#½­fmkÚ{wž«“÷êä²9©Õ¹~¦·ïkY[ZöžÝçªäýú…ù,Ýe€9Âzc¾!•ï/¤ÞÞ4‰¹xˆ‰Hˆ¨EPsS«rýMnÞÖ³¶µí=»ÏUÉûõ òYKI¬Õ«¼Je›á6$ª}uU%[ªÍ‚ù”PÃT–årÛ›ÍÞ¯u«{[²c­ŒíUQ €„„€ÀÅP€ÄHLUHP…QQˆÌMåÜ<|6ðÞy¦s‡`¥•˜öCä @8ñ¸dO@W¨¥Ei¥V²êumÓ§­Â Vµ`Rµ¥c·hé7n˜þ)z[téëp‚•­X­iXíÚ:MÇÛ¦?ŠEVX\ÏËŽbùr؆kocYÉÁÏ ¢àް`t%U UTUDU;gè4Ù¼«‘ÊÏk™+ø%¯<6S¢ÚctÕ±¤Ph°•ˆOÇvõ:¶éÓÖá+Z°)ZÒ±Û´t›·LŽ ‰ c;1µe›Jó P•”SóPTÇETìŠøô𬰹£“yw™IÃÛa¼N¸ÓM¸Ùc8HÓâû*¦Ñ‰Y·BÀS ¤uTG Þ[Ðë9{ñ5<‚ëªóÎäd¹’û樃wt‰Ç DQH•P@E E;·©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤ êumÓ§­Â Vµ`Rµ¥c·hé7n˜þ) Ës„ôGÔÒ`9~¥±›[^ö‘Nö¹Ïúܧò_*7©Õ·Nž·)ZÕJÖ•ŽÝ£¤Ü}ºcø¤Vò¿AÐ|>gdZ\L–ZÃha–@•âqæÄñ'b9êr²Ìþ·4’æÞF7Mˇ|¯Ëú~YÔŽ¯G„8˜‚JU¹¯Ôˆ•H–%V²"qžàs~+€lfjuLü£e¶›cZþ+Mºû®´M¾ã U7 ÕLÍá@²ñÖabg`«» .A› ëJظ‹è©!(¥„Ü$UDUGJQ,¼v’Õ‚£éêBq“¯‰/ÁÅ;˜¹ƒ”µ<чËùú°s':G ¶ºî8Û]E^ëÔpÞJ)šP¥l®jun_©­Â;ÚÖ`VÖ½§·yê¹?~¡~K¯äÐâ3›?ºÛoöOÁx“â3›?ºÛoöOÁxNãô ¼f@åd2šœÓ›Sš£Ë´;!wR v^þ'Àçå¨b’é6¯’‹‚¦Äã¤ÄŸîwENþ‹,'‰íǶöÚ·)ÓÙaëZ¾+kR±ß¼õ[¿P$‘½¶­ÊtöXGzÖ¯ŠÚÔ¬wï=VãïÔÉ'ßUû¾ <~ZQ&“`ªÁ ¶(lNBLH~çdDïëªÂøžÜ{ Ì‚ÊÇeu9 ¶†o)5FVhPvRí”$îüÀÞÛVå:{,#½kWÅmjV;÷ž«q÷êä’7¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$ª¿wÀ#ù·?åXm–²6 ¾¢y ¸.„Œ¶ˆ†DY„S ï=Ò;!q‹´Ùåbèv¹o½‰ƒ™Šf¸`Ú‡]ÕIQÄ#@%&Äz}ÒNʉ “/eè3þ_­“¬Ê£€ëp§è¡ ø/Ýn;þàÇòIâÇô²åbe1ú7Ì2صŠèt®Ø* ‚§tG·î䓯I¹UKoSf37¯9Œ_¬U3vÙx?, Œ´Ùd*}UÔFPP—Ó ’¨ª³ü³”þ^©O%Σdäc©Â"š4ñ¶„±ÚÊ€Š°ˆ’«‰Ûœ½tz9:ŇÖjàv7#Ô?û‹®=ÓºõSòïÓa¥ÅÎ׈¸WmÐD"5”…ÏÕ\É'tãk«•}ý?!ÝFã[ÊúfðórsUÍgƒËdIÐùuè7PEƒ$¬IéTî‹6½ym33òØÈuÀ@Î*·ª Ñ4òЧH/yUD〜·‚é¢= ¹"($À6‚d¨4U@QºKÍÂJOPaRÉÇmFN— ¬lm¦3¨d§uÈ'MÂRíÚHž„DOÜDEâ4¢àÒrÛמ¿`ˆÜŽÄöYNfµ›´ÊÀ,Ué¶ uêB¨7²ôd•=E¡.H\æuzwê™.5¢ëŠ˜5lb`E€IHuÿˆÿœÏã»Ë¨ÇÝOÎäd7ÔtW§T²wT[³ ÿ¸>éÂØÃ ÂÅpyqí»##§Û@ }² B¥(èGÿhþHб¦Ý<ý>iíPCcl¶‡¤ålL ÍEÊÔüË«®oEa†Ä?u{"L Ä$ðæ.Çg°£íYÕü¶§9âeq‚7:·¹ËIÒH¡ŠÂ—«Â£¸øü¬æ“NóúÍŽ&3m6Àä“NÚ ²’£­÷DïÔþI,ä;Ë{ñ_ÈwS–ë$'ŠfM™¶¨ «áUM˜Tópû§Iu–6¯—˜ \ínãy´¦K˜¬îZL¬c‘µhñØE5$ 6†…3k¿•.8¯2o‡Y’ë˜Ç‘…‰‘²t_k²‡DM¦I! Õ J).)ýTl¦ï-徯›ºœ‡_a1ÔÔ›"q£PTn~¢ªë~Ÿ ÔÉ'»[ )?×k;^N¼ AHÆEA&{¤¼Ÿÿ¨ÇòIvoügN\b…O`îÙý~Vk»Prõ†Ë¹eй G–(ª‚Ì…R‚¢¤=ÖþQ!,¼ºþI;³ÂÉÉ<¥ÁËFçPÌU–œ’ª Ê+Š‘;"}eWŽ;\£úyk±ÚÑü–A –8 ]7IzuZ§eU»0¿ûƒîœ3®ËÐbⵋ®ÉÖ1Û¤Ó‡©AR¨»«­¯o=Aü’kNÉ7/ç×þ‚Oƒ„ÛÛjܧOe„w­jø­­JÇ~óÕn>ýAü’FöÚ·)ÓÙaëZ¾+kR±ß¼õ[¿P$ŸMñÉ£œ&ÞÛVå:{,#½kWÅmjV;÷ž«q÷êä’7¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$¯Ž@ç ·¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$íµnS§²Â;Öµ|VÖ¥c¿yê·~ þI+ã9ÁÂmíµnS§²Â;Öµ|VÖ¥c¿yê·~ þI#{m[”éì°Žõ­_µ©XïÞz­Çߨ?’Jøäpp›{m[”éì°Žõ­_µ©XïÞz­Çߨ?’HÞÛVå:{,#½kWÅmjV;÷ž«q÷êä’¾9œ&ÞÛVå:{,#½kWÅmjV;÷ž«q÷êä’7¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$¯Ž@ç ·¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$íµnS§²Â;Öµ|VÖ¥c¿yê·~ þI+ã9ÁÂmíµnS§²Â;Öµ|VÖ¥c¿yê·~ þI#{m[”éì°Žõ­_µ©XïÞz­Çߨ?’JøäqSq®¦O'g.SÎˈ"=[7ß õSìGb^Þ¥3ì—¹)XÛjܧOe„w­jø­­JÇ~óÕn>ýAü’cõ[=+š}{ù{„Ëà¸yjšYLûÀ<Š·.Â~¥…^9j[&•yTc$ó^Ãèe3“” 0¦ú£ý2iµBK©"¢‚zJ Sø¬/n ôMâêw{–~_ UˆÎ3/ôqÕ >bì(&HIˆê/ðËÃJÓî¾YÚöÝ­5tª âÁ,ø»/ŠŸÙxUŸél ŒFÅÄ;õØ6]—³N"ÏѲŸâ°•”ª¶=l‰v ²ó{6±°³pɼ7Ì2Mr+\EDF‚ªªFKéER¼p†VÃJ@A•¯!l®Hã ¨$ E++ÙEY5Ÿ¢¶_ŠÇ·6Ú¶ïÔÙa-k>)ZÞÓß´tœŸ·L¿„ŒÜœºÎsm«nýM–Rֳ╭í=ûGIÉûtËñXÛjÛ¿Se„µ¬ø¥k{O~ÑÒr~Ý2üV:ßš9ÁÂnmµmß©²Â ZÖ|Rµ½§¿hé9?n™~+›m[wêl°‚–µŸ­oiïÚ:NOÛ¦_ŠÂøäpp››m[wêl°‚–µŸ­oiïÚ:NOÛ¦_ŠÀæÛVÝú›, ¥­gÅ+[Ú{öŽ““öé—â°¾9œ&æÛVÝú›, ¥­gÅ+[Ú{öŽ““öé—â°9¶Õ·~¦Ë)kYñJÖöžý£¤äýºeø¬/Ž@oO§¤Ïrý:ã8¶½+½ípõ¸ÇäžQÎ"w;<Òó€68Èê0ê"&@‰! ¹=¹þ!Ѝjª7¶Õ¹NžËïZÕñ[Z•ŽýçªÜ}úƒù$Êœnê8¬üXÚgèþsnïVÿËçëô™¹X®ÐK¦ëlA"¢Á",**}øšom«r=–Þµ«â¶µ+ûÏU¸ûõòIá—— Ùໃ—“¬ÍÄÌk¢ë˜8ÛàâQEeIm!{*8?’M_ƒ9ç,ÎwÔo4|³¹æmÎNÏ?g•‘¤ÆÕ³Ê²X€49pÐâÎA¬ºôôÿp‘ kù\ÙÌL&Ù[e’Þì¹[“ÚxufË¢Žfl3uqˆÍY"N±+ddMÊ’Ìë\Á‡É|Ó‚Îÿ—÷˜ˆè<ÓͳÝÕÄNRÐð"*w‡GòIíý-¶ÿ®ý?­Œæ'ït»ô®×yrÌHø)nQdx_ƒ?×s71)ìµ{w¹™ÑîÓY¨ Ræåßì­å’;U,&Ή¨†û" á ”f:s&ïá^§›Ëq³ÂаîÍ6Û=PëÞÎmœl“i¬‡ÑÌsk¢Ó¦÷ˉ9Ó节¨ñ£7¨ä9`9Y½g,ž€ë]X°ÂâŒj(²n¶IÛ¹8+ä’LG ì25Ùë9g-ì,’ËÀpØ`ɇÝq·IÖ•RDÍÇ5!…"0YUT^Ç £ny³œ×âNÑ­{;4Õêyƒ]©U¾¹½Y2ûxf꾯e.B&YÑRF¤ªhZÿáò^o1a󸼿“ºa¤gbM²y-B ¿É~a;"Âõ“óï&ÞÛVå:{,#½kWÅmjV;÷ž«q÷êä’¾9œ'¹:b^“’ÂMëåÐH›™ˆ•™ŠœÕFöÚ·)ÓÙaëZ¾+kR±ß¼õ[¿P$”¶ÛZ` Á¶Â@p2„Q¨Ò©*Ü}5pÌ*ö+ ”Îqµî ž*s¶mdòΗY²{V[͹a=›ŽÛfûyY2Ú:&Ý”±ÄVÀIR(D($°9¶Õ·~¦Ë)kYñJÖöžý£¤äýºeø¬%¿þ–Üjò5{ïѶ8Ôbæôh¨D^ 9E©2kÝ;+D¿áX«ãe›BÞs@ü:7¹£g¯ËÆç-Æ­r°ØÅê<˜ÌmÍdê¡Q—œTôQ.d×í°¹sãÞÙžjÙ’0îK¡ˆö& Øê£©Ây€ñÖãDè(’ª+~Q\ýÎ6þ–ÄÇÁÇјgSÿDÚt„pèÛ­~Úxn­‹áÚ EÄð„œ_ÒdzÇÊý™Ø_õ&Üé(äþÙ4}d^Çûl-§ÒÒ¢öD_‚±±ÛçóŸ0e;Í¿£àh·xº¦°\a…ÄËq±ýÂ!GzÆydØ(:"„zÔ.Tñy'Yðí¼ÜóíÛï²ÉÔ1©ÆyÌL=‹í=úåbˆ¢¸É" ‘¡S¨©¦æaò[¼ÄÏ1æbòùî°š&YغÛ+“Ž ÕBu}B)WåQ;9ö. Ì>Ku–YÌÅåók 8¶,ƒ­²£”†é–@¢ÿPÅòSH)Ge …ñÈ3ÿ‡<ϳÚí²9¸ô¯l¶;Då¬×p5ªØÎìѾ»‚()e_QÌ'•XE™æÞl>"êÁÏ{E—´äݯ@rp±rÖd‹Ø(."¢*‘"¼—m&Yݬ¶ÜémÊü¿èØŸ¦ã&5:Aò¬'òh#øön⟱ãÑÛ³ùzÎçòu‰—ŒÓ¬‹æaÔhU\%î"«ŽªIâYYþ—Ç Ìõœ÷ÍMOõÛ­=§Òágk1³µ4$"Ò&s§@„Žîb# Tè’…Ü@³r—3ï6 þ«ú.Ïo®ÛíòÌEÅp0›1a·ˆÜq²y§¨YBm‹‹Wª–D)­™kÙÓe`i7ZÍ ¦ëŽíD¬©8áä8€«^ªÓ ¬hH†$F&‚B½´«Ëœ¿£ÃÒk²ð±05˜ÁŠÃE”…Òi¡!AU"UZ‹&Šªª¿¶Sáx_ƒ2ÉæuÆä]×5¯0fç<|Èþ‹]‰‡ŠßI’Þ|˜“‰”-© ˜³ü:’¡™˜›žwÎMG/åï7Z7ŸæãÖS¿¥½³\TÔ;˜ˆú2.ã«¢ˆ]$mU$”‹M{úXuyš·¿FL Ž¿ÍâŸK¤çP'ú€½–Ä/©ÊwTqWÁqYæ^Läž¿—´ÎcrÎ6ƒC²w8µˆÂâ;ýŸ-¢k°¸ê­WÔÉv™T_‚gá–Ó?oÊŠöÉÿ™ÉÅÙl5êú€‰<8¹¯c†‚ˆ7!hHª‚6U¨Š@¥›ˆÌL½³¬Lf&]˜hÁ¶ØÐÒˆ)"(Ó‰ Ù²üV;¹¶Õ·~¦Ë)kYñJÖöžý£¤äýºeø¬/Ž@iŽø†W¼d¾“{xtÒ&åâ"%""¡G8‰Õlð:n2{etrßmErI ­?Ì¡eÆÒ%"â• AF›ÛjܧOe„w­jø­­JÇ~óÕn>ýAü’f«p9ÆsÍ:ÌÜ¿¼£Ç0ìðo—öfXøíã«n ek”€•ƈªåÅ ±¢‚©)^›ÛjܧOe„w­jø­­JÇ~óÕn>ýAü’x&^üì|äÉÖ;– +,?pWVU@KÍMWU²ª·çÓÅ_ƒç^zËÜhùãPÆnë/O¸ø¹Þá.Ñ01Ð@qÏ1•L^sþ¨n´H!u8Ôò3·˜Ÿ1±÷;-ž&£5ÕcLÎ#x¥ƒ–IŒNY BY#ŠÞKˆ  ÏM¦’×RšÔáò^qçj±y/)×7ñ›dtò•pÔ‡¹‹òÊKä—¥3é㆓QÈ:½¢m4ºÎYÁÏw¼DÊÃa†Ý6YÚ¸¢*‚ ã ŒÄ+h‰üx_‚ðG›9Ϙ3´¹›ævmàï¹|¶Ä;× `ôã(¦cš¾¸ðùÙrˆQE$"+kü@hðù/U›¤Ååü½«¢öcøm²Û™†ªŠ&á +„ªøª*ÊË©ùw“om«r=–Þµ«â¶µ+ûÏU¸ûõòI_ÎÜ1¯IÉa&õòè$MÇÌÄJÌÅNj£{m[”éì°Žõ­_µ©XïÞz­Çߨ?’J[mέ0àÛa Œ¸F™B(ÔiT•n>š¸ æ {Jg8Ú÷Ï ¹¶Õ·~¦Ë)kYñJÖöžý£¤äýºeø¬mµmß©²Â ZÖ|Rµ½§¿hé9?n™~+|r88MͶ­»õ6XAKZÏŠV·´÷í''íÓ/Å`sm«nýM–Rֳ╭í=ûGIÉûtËñX_‚Ⱥÿì:¬_–gQóú^®¹Ès#³ Öqh5to#üû™÷Hõ;±ÁÕ±¨Pºmf.OÎë¾l1±DÉh²Ááø¬8”)QT$îE9Ž×(ëØÊc­#O P´b(â*'”D¥Åì¼.QÇ׿®éhÙÂ"S­ jCiRî¾:Eø¬x£ ”-ªéþ¨MDÓX{í–¿ g\Ëä,´(´ù+ŠàŠ'aZ£D¢ž¤(“UYÎ#1rôÜ_•ÆÉÖaã³oÚmÀl…qK²B'vÝUÿàeã»›m[wêl°‚–µŸ­oiïÚ:NOÛ¦_ŠÇ«MÆ1¥Màá76Ú¶ïÔÙa-k>)ZÞÓß´tœŸ·L¿Ͷ­»õ6XAKZÏŠV·´÷í''íÓ/ÅbïŽMá=1ßÊ÷Œ—ÒoošDܼDD¤DT"¨9¶Õ·~¦Ë)kYñJÖöžý£¤äýºeø¬+ªÙàtÜdö8Êèå¾ÚŠä ’Z™BˤJEÅ*‚’ç–à–ã æ>escñ»”^ÏÆæl6pù‘ÝnšlÑac`Û™Jê4Œ¹Õ"j°GÓe¥rÀŽÓ/iú3Yû>Íe3Òrê -\Ó¹ÀºÚ ªÂ8(ŸÉ'²eèÎÇÎLc¹`Ò²Ã÷pAÕeT¼ÔÕqÕQ;*«~};)ÿßõâ¯Úd“fÊŒ&¾@ÉÖ6Oe‚6ãæ9C‚„‚Š¢¨¬ QP¢AœMVϘµ­blöxC‰šMºÞ{ÉÞø²‚ð’ƒ*¾H‘ R}(ƒÉ}MÉ[Íè*]xã™”Æ"îK”q¶‘aWÔf€)ÛîD‰ÿßÖnÛo“ƒ­}ÌöYÈIŒþ#¯g9|³CSPi TÉ)F•ZTTIDõ¬Û9ýXN[œ§º8雇Õsª­Ð~i©+¢¢Œ'yEHóÅ/©R„¥*OðqJÄØ. »·g;'+C‡–ãJïTòCåK³'P‘HœQ|Tm%T'²'¦Å¤ÆÊ.^e¡<™o¶G”ˆòÙ³rHÀ VPEIDae´ñzz׺%Ïχ ©ßiƒ—ò.ýþwr±ý—i)%Ý;{Ùa{ÿ’ðçóyçXäüþØñEÝ„¹°«n⊵hû)AØPú¤Ge¬œ­óÀ©eààà㱡ÁÁÁÀppppÁÁÁÀp†›!¯ÑõŠæ@)>ÃhÚ“¨JétíÙnvXE_ä}‘VËç‡ø©¸ÃdòvÅw œFÑÕqOÒ¸o’ÂÜӺª¡ dŠxå©'šæèÂÒû­c°ãïº 4Ø©™™ ˆŠ$ªª¯„DúñÇ]°ÀÙ0Oë³±³¢›‹‚…±(«Þ;Ÿ î6šlFrÿT}o ¶²žê„ˆ"™tÉ;w+¶°‰+(‘ÝSˆÝ.ÛVÿêœÆ{,#®0uÚÆ|_ùfêÞŠ²kgc·dµlY-T¦•W9Ê “9[m^&sX9[,&2ÞŽ“>"áÊÂTUeeR>¼9ÅOšvÚ{7—Ùk0\Ìoÿ1u×Á²0§iT³¤ˆŸADB.Õ¶q°ÔºMW :šppppÁÁÁÀ ïO§¤Ïrý:ã8¶½+½ípõ¸ÇäžQÎÞŸOIžåúuÆqmzV{ÚáëqÉ<£œJï0$öÓæ.‘Ç럗ŒöS P½m2M …1 ûI ²¶í0±ß?/#;;%œ\Lf‰çßyÄÚI#"^Â(ˆªª½‘Œ›ãÎnÇU¶ÌÖmvxn—þaz¬æº ‹Øëˆ¬¼ …QtzÎC‚ˆPQ0‰ sþ!ywâ§"êßæ †"rkØX®lòòòK-ßÔD3'ˆO嘔 +ë;P6Î?9óîñÆv‹É¼Ý„æ§ôFÜåŽ_:fþþIJ2ÅÞŠ6/–ØÀƒÔëèuQ]çÝÆßâ¾Ã”2¹·7 l»½k8eÍ…«k C×±K2uçEÈ@q¶]•Èhz¢ ¨Ðÿsrñp™³2YÆhm‘7\@7 ÄFB(žUI;¯6‘â×ò4s~ÛcÌgÜÛî5¢Û»—ññðñ¿UyYmQi¤K–MIÖ›C©P´©1ç5|(ß7³ËÍMfõdø»ü×ÅŒ={Ï=ó®#O<Ê Ù£Ç"#S£m¿³´À{y•¤mûgâc3”ûT/CO¢ÙLBÉ0êB,¥{Ĥ»Æ'ÌYųæ?Ðy‡fö‰ÝG+>y)·%¶°žÏÈg/%·ˆÉZÄnÆøª +ªHH§Ç GCw•¨Ó`së3”ò9ÜñuÙ˜{ì•,¼1Ѻù惽W3ÙUp ›Pð(çÂ{“¦ é9,$Þ¾]‰¸ù˜‰Y˜©ÍV¿ð—/+/“Í2ò^É,M¾Ó§q\s£°Èa”#)#$m°E2U"T’U%U[äéˆzNK 7¯—A"n>f"Vf*sU™÷Xá-ÎÓO†Þ^Åþƒ.d±Š%B)u÷–†}N8>eaW‡x¦|`'™åÍV^6fn+Ìs&™±²œfâæÇ—Ð À&Ý1P)”X”EJ›M´ÀÜa¹—®®Ëy/â‘P†aãeÑ‚D_K˜Ï…‰IEEá=g4è¶[5øYÝ\—þ{¦#|ž@ãä÷TDJ:b?û¦FS¿ÿÃLíc<凋 æ²wOó—07̶öîd>?±0pñÈ1Å^OÝU1K/UP£1ßå–w¼¬ß–ç¶š,®°¸ä4‚FR€‹ TTsÜsN‹QúÏêÝÑ5£´ØþÑ—GºÐçd[Ó½é/GŽé3<~yÜeïϹ¯m¿ÉÙë9'áF·?¬Jæãs¯¨ôèBMºë@AꀒA¢-ƒ™w5ñdÑo³XæV¹“U£ÕÅÀùK‰…ón@"9°³äÙ¨tÎz)@6n3Ÿ‰Ù|ܼ¯–Ó¤Ï/‰óŸ_°Ôì‰ì’eÝ› ™8Àƒd I!û¢¶!)õV^ ŽŸ;y‘‰Ì\Àmh9ËO§ÖcälÝy¶ñò×Z¹(âš©d‘üãÈŠù9ÓJôºj“ÀgŸõvCß5Zá{s6ùZí“ï2ßug $ƒ«€@¸øbéãƒÍ8&Ž:ØÙDÝA0²ùõ®]ç&ñrvoly3—óuZµ>eìÜÕê8ï‚ÙÈùVõŽ¡ ų• l ³ˆÎdæ-`†w1ï5šlGFAüü°ÇlQUÕJ–<Â/ÛŒ3_°ÎÎå}ËXÈ˺Wöü»ˆÙi9Ã?nM›Û0o)`à$Ы-¸ª êTª)Ø?­yo3÷ø[¦æánËSË­íQFÀÁÊx3!IÄe532STDl º-(^.~>vK9X™- Ì>ˈmº’&$ˆU;*/¸¬ü0cTÏ&cžŸ{…¾ÆÊÉËÌ=†‰c¾ûù.¼ú·R$@GMı(¢ ©¢ªÙ¸=1ßÊ÷Œ—ÒoošDܼDD¤DT"¨ç éŽø†W¼d¾“{xtÒ&åâ"%""¡G8˜wP#7íf«;_ƒ–ëË—°w§ŒÆ>3¸HŠ(N¶$ Ð©‚¥ cbK$ÉñœóN añ÷”sfµËû7Dqöy 6ªÖV¹E1ê…QPÑ byßm04z<ýÞÑÿ—À×ã9•”íºm6*FP(ª°(«Š¿nãó6Ó˜ö\Ñým§Òâf«;®HÞåµ7›<„ÌN€·Œã.·L<¦Ó Äñ2ª¸(IÒ®¼Öf|hÇL~dg˜‡1¡wW08«­d±.‹‘‚Ñt\Ç?QŽS’WÊ`j€h§ÁÆÿ‡­Ç0íw˜‡³Ûá;’zBs˜0Ûæ ­ŽC{&#¯ŽãHÖ°ÅW%eT…‘‰ Ï€Ü1¯IÉa&õòè$MÇÌÄJÌÅNj®pžäéˆzNK 7¯—A"n>f"Vf*sU™÷Xàààâ€ppppÁÁÁÀpž˜ïˆe{ÆKé7·‡M"n^""R"*Ts„ôÇ|C+Þ2_I½¼:irñ‘PФ¾òæÛ?/#;;%œ\Lf‰çßyÄÚI#"^Â(ˆªª½‘ŽM¶«y«gi¤Ùálð·K+ ñy§*J+STX$TX_(©ÇhÉÓaiœÎægôìgZyÓyž£l¨8$e ¶h&®,#h7U$Ã6{ ¬Î\ÏÍþ¦åÿÑ÷ä)ºæq”´y¸£©Bª>•ÇW™c…rMÑ0%Qp˜â¼þ­ªýõßÔð¿Iùo›ùî¸ü¿B·êõ&´¯ªÓÞcƒ}´ÀÑèó÷{Gþ__ŒæVS´"é´Ø©@¢ªÀ¢¬"*ý¸Æy£š¶»P佦ט¹g—4ëú“Îçî1HõY¹XÙ,·„ø"ä4ŸºÚ=”È® "u  tm¿¶Y[Ÿü3s.ß;Vö§/;“r²_Àzz˜¦xDDÑJ ØUTVQSÂxà ÎïmªÑêÞÚnöxZÌ+ÕÊÌ|Yi» XÉQIQWÊ¢pi6Ú­æ­¦“g…³À~Ý,¬7Åæœ©(­LUQ`‘Qa|¢§ÏÄm¶×”vŸÕÛ<-/2.ïM–ß]ò{U„ÞÛ¦ë2­u»§\‹¦å×Ô Ñcqsø-“úƒ\ÕµýC móÛ´sõ]x×a\,Fú˜Ãc¨O¤IÔs÷ul3Ó4+{mËúŽAgiˆÏÏe+íã6®YuÒÛE+”¢‘{—ÿ%þ\Y8×±‹±åœF3Zg7üVú€ô:"Šy’4$_þE?‘y\TSUçCi±ê¹Ï˜[G0Ççórœw‡2v8ŒX.¹”xƪ š‡TTQUe²R:šéz…Ø.þ¨,&R‰+(¨(j‚HŠª©"‚±+ ±+RyßI¶cg¬s—9wñð™®1a1†.ã–S÷Òbµéýooðð¯ÀÜ콆·æ5ͺ<´¬"2Y $OÊ[§áþWÿ ÿ{Ǫpº£ÍgNͦLóO>1¢çM.–µÇÇ#å¾c!AV¾eâaš -ýb¶•Œ*]})rãæÿ†Û̾nÊw ì¬æ6¯ƒÉ±ÈÏq [Óu]„4*’«HÍgø•#ªZÖ§ôýV&Íeeü³Ï_)˼íEæ_â%‰Uúª¯;FZŽRS[xôóÖ”æµv*ýäæ÷­ÿÚ±Ç~8÷“˜?Þ·ÿjÇøó.¯Õü³ÒFsg÷[mþÉïø/|Fsg÷[mþÉïø/©Ü~—†öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(sƒ£Id¢8±6NbuOf,¶à;ÐL7$&‰µ5Vì•"ì£àí(ˆë{,s¥[ÍKÖ-†êy¤Lopf|ALP¡Î1E§^|6öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(÷™šÖ.F ©f>¬6¢‰HÙ¹+þPÚÿ÷3Ãõd ·²Ç:U¼Ô½bØn§šDÈö÷gÄÅ öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡Cœm%&ÞËéVóRõ‹aºži#ÛÜŸS(Ùc*Þj^±l7SÍ"d{{ƒ3â b…pp¤²ÛÙc*Þj^±l7SÍ"d{{ƒ3â b…{,s¥[ÍKÖ-†êy¤Lopf|ALP¡Î#7[¬]OSæxé…‘š½4Eô3K'uORÝ#éçºq´ªØð™ >Ó€ˆ«gÅ{ý$’ÊxgŒµÕïϸ#5¹üL\,<|Ö±Úm¶™Ä{Ò0Ú *Ïd1™ñ?Àã»{,s¥[ÍKÖ-†êy¤Lopf|ALP¡ÎÔæµ²ÕâlX²˜Á  … b{Âñ©5²ø†öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(sƒ¤²ÛÙc*Þj^±l7SÍ"d{{ƒ3â b…{,s¥[ÍKÖ-†êy¤Lopf|ALP¡Î–@›{,s¥[ÍKÖ-†êy¤Lopf|ALP oeŽt«y©zŰÝO4‰‘íî ψ)Š9ÁÂ’ÈoeŽt«y©zŰÝO4‰‘íî ψ)Š ì±Î•o5/X¶©æ‘2=½Á™ñ1B‡88RYmì±Î•o5/X¶©æ‘2=½Á™ñ1B½–9Ò­æ¥ëÃu<Ò&G·¸3> ¦(Pç K M½–9Ò­æ¥ëÃu<Ò&G·¸3> ¦(P7²Ç:U¼Ô½bØn§šDÈö÷gÄÅ àáId ·²Ç:U¼Ô½bØn§šDÈö÷gÄÅ öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡Cœ),6öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(sƒ…%&ÞËéVóRõ‹aºži#ÛÜŸS(Ùc*Þj^±l7SÍ"d{{ƒ3â b…pp¤²ÛÙc*Þj^±l7SÍ"d{{ƒ3â b…ü¿ºÄ—uùH;Ä,¸O©P–{ÝU}þ"U‘îW)Îå·Ç+—u¹@Fbö#N!ÙQAVH–Ô‰Í|ñ Jå¿6ó·6Xá{7š´´× ÕñyˆþÙDy‘‰¸ÈæË/fóV–šáº¾/1ßÛ(217sƒ‹¤²ÜÙc…ìÞjÒÓ\7WÅæ {ûeæF&ã#›,p½›ÍZZk†êø¼Äl¢<ÈÄÜeΖ@››,p½›ÍZZk†êø¼Äl¢<ÈÄÜdse޳y«KMpÝ_˜ïí”G™›Œ¹ÁÂ’Èse޳y«KMpÝ_˜ïí”G™›ŒŽl±Âöo5ii®«âó=ý²ˆó#q—88RYnl±Âöo5ii®«âó=ý²ˆó#q‘Í–8^Íæ­-5Ãu|^b¿¶Qdbn2ç K MÍ–8^Íæ­-5Ãu|^b¿¶Qdbn29²Ç Ù¼Õ¥¦¸n¯‹Ì@÷öÊ#ÌŒMÆ\àáIdÜõÇcI±p“4:XÏ*⺑QrU +ÿ¦P¨cä`’âªë{,s¥[ÍKÖ-†êy¤Lopf|ALP£Ç2>8¼»²Ê20qqH&Ȉ ²B³þ„+þiç‡ø”¥sÜ ·²Ç:U¼Ô½bØn§šDÈö÷gÄÅ öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡G Þ+ÕˆÛË—ƒ“šÑ¢'Mƒ` fl«’©R© 2|U%&ÞËéVóRõ‹aºži#ÛÜŸS(©s7-âó+Ùm?Ì|Ù¨Ú4Œì5 ã¢ãeƒm˜*ºÁ:Ș‰#N6‰TÑÃâóÁÂ’ÈoeŽt«y©zŰÝO4‰‘íî ψ)Š ì±Î•o5/X¶©æ‘2=½Á™ñ1B‡88RYmì±Î•o5/X¶©æ‘2=½Á™ñ1B½–9Ò­æ¥ëÃu<Ò&G·¸3> ¦(QÃwŠÿ5gòà6òeààãfºj‰ÓP|ßDY›"ãÊ"BŒ*ÊÄŸ K M½–9Ò­æ¥ëÃu<Ò&G·¸3> ¦(Q¼Ýb3­…€_{a>„¨®³Úªª½AJʪú’¥R'8C~øã`¶á‘Š.^3r2O€¢v!í+ß¼DÊH¬ÍJ׿>àöæË/fóV–šáº¾/1ßÛ(217Ùc…ìÞjÒÓ\7WÅæ {ûeæF&ã.qÌ»¼]¹¬ìÆÞq§s±0…DR¾NCxà«*ž”7EWë°Š½–©,ƒ»›,p½›ÍZZk†êø¼Äl¢<ÈÄÜdse޳y«KMpÝ_˜ïí”G™›Œðå­Þ.ÿ\îvo6ÓYÙxDŽ¢!_!ÌsT…_J›D©õ…ID^É¢ç]Vãq‹«ÆÇͲT¡8‚Ÿ§æ#Ó«êqÄQíÜeV«Û…%M9²Ç Ù¼Õ¥¦¸n¯‹Ì@÷öÊ#ÌŒMÆG6Xá{7š´´× ÕñyˆþÙDy‘‰¸Ì/1ó®«CýMó˜ù§ý9¤ ÞgHnÁ|Ì rI'ý•ÎË Ü{÷X³p¤²ÜÙc…ìÞjÒÓ\7WÅæ {ûeæF&ã#›,p½›ÍZZk†êø¼Äl¢<ÈÄÜeΖ@››,p½›ÍZZk†êø¼Äl¢<ÈÄÜdse޳y«KMpÝ_˜ïí”G™›Œ¹ÁÂ’Èse޳y«KMpÝ_˜ïí”G™›ŒŽl±Âöo5ii®«âó=ý²ˆó#q—88RYnl±Âöo5ii®«âó=ý²ˆó#q‘Í–8^Íæ­-5Ãu|^b¿¶Qdbn2ç K †ÒmqÞaÑDÍ5܆T—ÕIÔ;Ù*ŠIÞb¡„oeŽt«y©zŰÝO4‰‘íî ψ)ŠxÐ>98.8d‰—’ܜ̋æ*È»Jvï‚(ÿ+VàM½–9Ò­æ¥ëÃu<Ò&G·¸3> ¦(P7²Ç:U¼Ô½bØn§šDÈö÷gÄÅ â³Ïüëªä¿éÿÕ1ó^ý{w¤Åù`£ïÚ„v$€J¬ªJø„^*’È&›Ùc*Þj^±l7SÍ"d{{ƒ3â b…{,s¥[ÍKÖ-†êy¤Lopf|ALP£‡6nñyk•vÜÇœÛÎbj°^Í|DW2AETE(‰TIú§|),6öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(sƒ…%&ÞËéVóRõ‹aºži#ÛÜŸS(Þn±ÖŽBŽÀ¯Ž½°ŸBTWYí UU^ ¥eU}IR©œ!¿|q°[pÈÅ/¹ ™'ÀQ;ö•ïÞ"e $Vf¥kߟp{se޳y«KMpÝ_˜ïí”G™›ŒŽl±Âöo5ii®«âó=ý²ˆó#q—88ªK MÍ–8^Íæ­-5Ãu|^b¿¶Qdbn29²Ç Ù¼Õ¥¦¸n¯‹Ì@÷öÊ#ÌŒMÆ\àáId ¹²Ç Ù¼Õ¥¦¸n¯‹Ì@÷öÊ#ÌŒMÆG6Xá{7š´´× ÕñyˆþÙDy‘‰¸Ëœ),76Xá{7š´´× ÕñyˆþÙDy‘‰¸ÈæË/fóV–šáº¾/1ßÛ(217sƒ…%&æË/fóV–šáº¾/1ßÛ(217Ùc…ìÞjÒÓ\7WÅæ {ûeæF&ã.pp¤²ÜÙc…ìÞjÒÓ\7WÅæ {ûeæF&ã)i6¸ï0è¢fšŽnC*KŠê¤‹ê‰l•E$ï1P‚€B ¦(PçId ·²Ç:U¼Ô½bØn§šDÈö÷gÄÅ öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡Cœ),6öXçJ·š—¬[ ÔóH™ÞàÌø‚˜¡@ÞËéVóRõ‹aºži#ÛÜŸS(á»Åš³ùpy2ðpq³]5Dé¨>o€",Í‘qŽe!FebO…%&ÞËéVóRõ‹aºži#ÛÜŸS(åýÖ#ü»¯ÊAØž 9eÂ}H’„³Þê«è/ñ¬r¸©NqRÝn²ðþbí5D…—”Î8¦ú,#™Û@g$kÙ\EYS^ßâúÊŒÜÒO›y˜ÝK ›,p½›ÍZZk†êø¼Äl¢<ÈÄÜdse޳y«KMpÝ_˜ïí”G™›ŒäšŽaß0OkñÊa#7+#fY®´gžî¸Ê8ÝlN6}• Tˆ\Ô3›‚,ì2þmñ3ýê ©Ö’ˆˆ–­Qa%8í=)ë&Rè|se޳y«KMpÝ_˜ïí”G™›ŒŽl±Âöo5ii®«âó=ý²ˆó#qš_:sÞÃGñ[¡ÇÃÅs þKæ‰ËuæòK(¨°PºÊÑj”‹.ÇÎæÒ}<‰†¬g)F>·EÞaæ4DØúÁEdqÙE쨥;/…HT”T^ãy9ƒýëö¬qßñõ%ŸÿÙivy-2.4.0-rc1/doc/samples/ivy-doc.xsl000066400000000000000000000224571226750426600173460ustar00rootroot00000000000000 <xsl:value-of select="info/@module"/> by <xsl:value-of select="info/@organisation"/> :: Ivy description

http://www.jayasoft.fr/org/ivyrep/// by http://www.jayasoft.fr/org/ivyrep//

Revision:
Status
Home Page
Licenses
Ivy Authors
Description

Public Repositories

Name Url Pattern Ivys Artifacts

Public Configurations

Name Description Extends
default

Deprecated Configurations

Name Description Extends

Private Configurations

Name Description Extends

Published Artifacts

Name Type Configurations
, all
jar all

Dependencies

Organisation Name Revision Configurations
http://www.jayasoft.fr/org/ivyrep///ivy-.xml
ivy-2.4.0-rc1/doc/samples/ivy-report.css000066400000000000000000000104221226750426600200630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ body { font-family:"Trebuchet MS",Verdana,Geneva,Arial,Helvetica,sans-serif; font-size:small; } div#logo { float: right; padding-left: 10px; padding-bottom: 10px; background: white; text-align: center; } #logo img { border: 0; } div#date { font-style: italic; padding-left: 60px; padding-bottom: 40px; } h1 { margin-bottom:2px; border-color:#7A9437; border-style:solid; border-width:0 0 3px 0; } span#module { color:#7A9437; text-decoration:none; } span#organisation { color:black; text-decoration:none; } #confmenu { color: #000; border-bottom: 2px solid black; margin: 12px 0px 0px 0px; padding: 0px; z-index: 1; padding-left: 10px } #confmenu li { display: inline; overflow: hidden; list-style-type: none; } #confmenu a, a.active { color: #DEDECF; background: #898B5E; font: bold 1em "Trebuchet MS", Arial, sans-serif; border: 2px solid black; padding: 2px 5px 0px 5px; text-decoration: none; } /* background: #ABAD85 #CED4BD background: #DEE4CD */ #confmenu a.active { color: #7A9437; background: #DEE4CD; border-bottom: 3px solid #DEE4CD; } #confmenu a:hover { color: #fff; background: #ADC09F; } #confmenu a:visited { color: #DEDECF; } #confmenu a.active:visited { color: #7A9437; } #confmenu a.active:hover { background: #DEE4CD; color: #DEDECF; } #content { background: #DEE4CD; padding: 20px; border: 2px solid black; border-top: none; z-index: 2; } #content a { text-decoration: none; color: #E8E9BE; } #content a:hover { background: #898B5E; } h2 { margin-bottom:2px; font-size:medium; border-color:#7A9437; border-style:solid; border-width:0 0 2px 0; } h3 { margin-top:30px; margin-bottom:2px; padding: 5 5 5 0; font-size: 24px; border-style:solid; border-width:0 0 2px 0; } h4 { margin-bottom:2px; margin-top:2px; font-size:medium; border-color:#7A9437; border-style:dashed; border-width:0 0 1px 0; } h5 { margin-bottom:2px; margin-top:2px; margin-left:20px; font-size:medium; } span.resolved { padding-left: 15px; font-weight: 500; font-size: small; } #content table { border-collapse:collapse; width:90%; margin:auto; margin-top: 5px; } #content thead { background-color:#CED4BD; border:1px solid #7A9437; } #content tbody { border-collapse:collapse; background-color:#FFFFFF; border:1px solid #7A9437; } #content th { font-family:monospace; border:1px solid #7A9437; padding:5px; } #content td { border:1px dotted #7A9437; padding:0 3 0 3; } #content table a { color:#7A9437; text-decoration:none; } #content table a:hover { background-color:#CED4BD; color:#7A9437; } table.deps { border-collapse:collapse; width:90%; margin:auto; margin-top: 5px; } table.deps thead { background-color:#CED4BD; border:1px solid #7A9437; } table.deps tbody { border-collapse:collapse; background-color:#FFFFFF; border:1px solid #7A9437; } table.deps th { font-family:monospace; border:1px solid #7A9437; padding:2; } table.deps td { border:1px dotted #7A9437; padding:0 3 0 3; } table.header { border:0; width:90%; margin:auto; margin-top: 5px; } table.header thead { border:0; } table.header tbody { border:0; } table.header tr { padding:0px; border:0; } table.header td { padding:0 3 0 3; border:0; } td.title { width:150px; margin-right:15px; font-size:small; font-weight:700; } td.title:first-letter { color:#7A9437; background-color:transparent; } ivy-2.4.0-rc1/doc/samples/ivy-sample-xslt.xml000066400000000000000000000100231226750426600210260ustar00rootroot00000000000000 This module is great !
You can use it especially with myconf1 and myconf2, and myconf4 is not too bad too.
ivy-2.4.0-rc1/doc/samples/ivy-sample.xml000066400000000000000000000077351226750426600200560ustar00rootroot00000000000000 This module is great !
You can use it especially with myconf1 and myconf2, and myconf4 is not too bad too.
ivy-2.4.0-rc1/doc/samples/ivy-style.css000066400000000000000000000055031226750426600177140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ body { font-family:"Trebuchet MS",Verdana,Geneva,Arial,Helvetica,sans-serif; font-size:small; } div#logo { float: right; padding-left: 10px; padding-bottom: 10px; background: white; text-align: center; } #logo img { border: 0; } a#rep { color:#7A9437; text-decoration:none; } a#rep:hover { background-color:#DEE4CD; color:#7A9437; } h1 { margin-bottom:2px; border-color:#7A9437; border-style:solid; border-width:0 0 3px 0; } span#module a { color:#7A9437; text-decoration:none; } span#module a:hover { background-color:#DEE4CD; color:#7A9437; } span#organisation a { color:black; text-decoration:none; } span#organisation a:hover { background-color:black; color:white; } h2 { margin-bottom:2px; font-size:medium; border-color:#7A9437; border-style:solid; border-width:0 0 2px 0; } div#revision { margin-left:60px; font-size:medium; font-style: italic; font-weight:700; } span#revision { color:#7A9437; } td.title { width:150px; margin-right:15px; text-align: left; /* border-color:#7A9437; border-style:solid; border-width:0 0 3px 0; */ font-size:small; font-weight:700; margin:0; padding-left:0em; vertical-align: top; } td.title:first-letter { color:#7A9437; font-size:medium; background-color:transparent; } #repositories table { width:90%; margin:auto; } #repositories th { text-align: left; } .conf table, #artifacts table, #dependencies table { border-collapse:collapse; width:90%; margin:auto; margin-top: 10px; } .conf thead, #artifacts thead, #dependencies thead { background-color:#DEE4CD; border:1px solid #7A9437; } .conf tbody, #artifacts tbody, #dependencies tbody { border-collapse:collapse; background-color:#FFFFFF; border:1px solid #7A9437; } .conf th, #artifacts th, #dependencies th { font-family:monospace; border:1px solid #7A9437; padding:5px; } .conf td, #artifacts td, #dependencies td { border:1px dotted #7A9437; padding:5px; } th.conf-name { width:15%; } th.conf-desc { width:50%; } ivy-2.4.0-rc1/doc/samples/ivysettings-default.xml000066400000000000000000000016421226750426600217710ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/jayasoft-ivyrep-example-default.html000066400000000000000000000264141226750426600243360ustar00rootroot00000000000000 Ivy report :: ivyrep-example by jayasoft :: default

ivyrep-example by jayasoft

resolved on 2005-04-08 13:33:40

Dependencies Stats

Modules3
Revisions4 (0 searched searched, 0 downloaded downloaded, 1 evicted evicted, 0 errors error)
Artifacts3 (0 downloaded, 0 failed)
Artifacts size219 kB (0 kB downloaded, 219 kB in cache)

Dependencies Overview

ModuleRevisionStatusLicensesSize
commons-cli by apache1.0releaseApache32 kB
--- commons-lang by apache2.0release166 kB
--- commons-lang by apache1.00 kB evicted
--- commons-logging by apache1.0releaseApache21 kB
commons-lang by apache2.0release166 kB

Details

commons-cli by apacheresolved by ivyrep

Revision: 1.0

Home Pagehttp://jakarta.apache.org/commons/cli/
Statusrelease
Publication20021227095900
Resolverivyrep
Configurationsdefault
Artifacts size32 kB (0 kB downloaded, 32 kB in cache)
LicensesApache
Required by
OrganisationNameIn ConfigurationsAsked Revision
jayasoftivyrep-exampledefault1.0
Dependencies
ModuleRevisionStatusLicensesSize
commons-lang by apache2.0release166 kB
commons-lang by apache1.00 kB evicted
commons-logging by apache1.0releaseApache21 kB
Artifacts
NameTypeExtDownloadSize
commons-clijarjarno32 kB

commons-lang by apacheresolved by ivyrep

Revision: 2.0

Statusrelease
Publication20050407222759
Resolverivyrep
Configurationsdefault
Artifacts size166 kB (0 kB downloaded, 166 kB in cache)
Required by
OrganisationNameIn ConfigurationsAsked Revision
apachecommons-clidefault1.0
jayasoftivyrep-exampledefault2.0
Dependencies
No dependency
Artifacts
NameTypeExtDownloadSize
commons-langjarjarno166 kB

Revision: 1.0evicted

Status
Publication
Resolver
Configurations
Artifacts size0 kB (0 kB downloaded, 0 kB in cache)
Evicted by2.0 in latest-revision conflict manager
Required by
OrganisationNameIn ConfigurationsAsked Revision
apachecommons-clidefault1.0

commons-logging by apacheresolved by ivyrep

Revision: 1.0

Home Pagehttp://jakarta.apache.org/commons/logging/
Statusrelease
Publication20020220232200
Resolverivyrep
Configurationsdefault
Artifacts size21 kB (0 kB downloaded, 21 kB in cache)
LicensesApache
Required by
OrganisationNameIn ConfigurationsAsked Revision
apachecommons-clidefault1.0
Dependencies
No dependency
Artifacts
NameTypeExtDownloadSize
commons-loggingjarjarno21 kB
ivy-2.4.0-rc1/doc/samples/jayasoft-ivyrep-example-default.jpg000066400000000000000000000304241226750426600241460ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÚ9"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú(¢€ +ïÅþ°¹{kÏió¡ÃÅ5ìhÊ}ÁlŠƒþ¿ÿÐסÿàÆþ*€: +Ÿÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*€: +Ÿÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*€: +Ÿÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*€: +Ÿÿ„ïÁÿô5èø1‡ÿŠ£þ¿ÿÐסÿàÆþ*€: +Ÿÿ„ïÁÿô5èø1‡ÿŠ«ZŠi×Vww²ZÜy:|š‚G Ðv€²3|ËÇ=ý)s :Ú+ø’ÎÎââ^[m5¢XÜ4÷ –Mû~c»÷o‘íÔÔ~/Ó­5³¦<ö¢e¸ŠÙ¢k€³)R±õeù×'>¾”ù …¿sâ³Ä$.1´e?tà6rH.j…ß‹.eð­Åìvÿd¸ŸE›R³pâLlE' ¨LdƒÛ‘G:¯¬?¢¯…5;°£ívÒ][Éš9cRÊÀö Q]ø¿N´ÖΘóÚ‰–â+f‰®Ì^@¥JÇÕ—ç\œúúTþ1ÿ‘#_ÿ°mÇþ‹j$ÓMÓÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ]å–sÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅWAA‚È4ŠÊ讌Xdr¥®uô{Í škbKI¥HÛc>¦ÿ–mí÷¢äµiizÍž®’}Ùf„ížÞUÙ,-èêyÇ¡ê Ð…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@sþ;ÿ’yâ_û]覮‚¨ëZjk:¡¥ÈåöÚKvp2T:•Ïë@¶¥a©¥^ió³¬7P<È@`¬¥N3žpj´Ú<"îþþ(ÖK«›o'Ë•±À=p ¾PO<*ñÇ+x’Þ5†ïÂ÷— ÚóYÜÛœÿy|ÉQ€=pWŠÚ5Ïú5ûÿgÿÇëÑö´ßR,ÊúV˜Í+É=£Ûnà ˜ÙÜŽ¹-={š‚ûû´ý>ÊâOÞXIgm Ïû˜R`@àdäàqß7þÑ®С«ÿßû?þ?GÚ5Ïú5ûÿgÿÇèö”û…˜û=:+9æœI,³LZIH$"çjŒÀÜÞüœ“Lm*3x×Ïq™*Í,q8U•ÕB‚Üg¢¨Æpp2 h×?èPÕÿïýŸÿ£íçý ¿ýÿ³ÿãô{Z}Â̧ÿ½——*®O´ÌKŒÈë'˜®xÆà߆8 €}¿‡-mçŠq4ï$wŸlËåüƒ 8ÚsŽ}¸«?h×?èPÕÿïýŸÿ£íçý ¿ýÿ³ÿãô{J}ÂÌŠ- Ö²m’cö[Ùï“$ròù»ãîþù±ßÉç9Ö>‰|7›¨O$’3û=Ú6bV@²ò½ üÀô†+[íçý ¿ýÿ³ÿãô}£\ÿ¡CWÿ¿öü~iO¸YƒiQ›Æ¸Ž{ˆ|ÉVic‰Â¬®ªã=F3ƒj§ŒäH×ÿìqÿ¢Ú­ý£\ÿ¡CWÿ¿öü~«ßiúïˆ,fÒNu§Áx†îo'€ªDÃTG#’ÛIÀÀÆM)U…ž¡fz:KÉF•È ÷§W=à÷h4©´i 2éµ—'“¡?ŒLŸŽk¡¯<°¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬½SC·Ô¥Žé$’ÓQ„ ä£û§³¯ª¶GãƒZ”P ¶¹=ÌV -ç‘‚Cy"Þäö’v9þã÷KVõEsmå´–×0¤ÐJ¥^92°=ˆ5Ïù§†ŽmDú¦?娶ë›aþÃõª?º~aØ· @-WOÔlõ[4»±¸Ià|€èzÔÔx òZƒRÖmì<9{­!ÛÛZÉu˜Û!Õ·ð  +˜‡G×î!I¯|U}mpà3Ãcol"ŒŸá_2'bL–çÚŸýƒªÿÐå®ß›/þG¬>±Ù%Íÿ`ê¿ô9kŸ÷æËÿ‘èþÁÕèr×?ïÍ—ÿ#Ñõ˜™ÒQ\ßö«ÿC–¹ÿ~l¿ùìWþ‡-sþüÙò=Y€Y%Íÿ`ê¿ô9kŸ÷æËÿ‘èþÁÕèr×?ïÍ—ÿ#Ñõ˜™ÒQ\ßö«ÿC–¹ÿ~l¿ùìWþ‡-sþüÙò=Y€Y%Íÿ`ê¿ô9kŸ÷æËÿ‘éBÖI‹Æ:¹q÷DÖöl™÷ ’>„}húÄÌéh¬¯jsjÚ$W7(‰r²Ko8;|Ȥhœ®yÁd${Õ­ÄQEQEQEQEQEQEQEQEs×ñ,ñ½¬ý Õ­Í«žÞt[ž?Ä¡—þøZèkÅVs]è2½¢î½´d»¶Þ’2/ü ~ŒkNÊòBÂÞöÙ·ÁqËz« ƒùžŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠæüWa,ÖÍqi¨_E©ò´øa¹hãóù!™ã»Ü©Àæ_ošmO\Eõù†v·™¢}‹Ò`:Ë–GqÞ€9ÿê¾']°·Ô“Uq–Vo,7 pøÂ}!ÇlŽxâIà¯øST—v›{=‹9èÆ7g‹ù°ÿzŠúÂsM6ƒ‰å’V‚îêÙd•‹;$WF¤“É;PsÞ²¾#èZN¡àm~êïL´žæ :âX¦xTº:ÆÄØÈ @UU‡S°¸K‡‚úÚT¶b“²J¬"aÔ6ÊG¡«UÃØhZü"Qi’éQAud,£ïZü[Ê®ý:+ln9Ì:Ÿ%$Ë:ÇÕôØííõ E¶rÁfi”! pÙÇXŸe>”[êúeÕÄvöú¤ÓIœ‘Ç:³4ß•÷é\Úhš„º½­ëÚì…õÖ¾xÔ˜bM'™¶<¾{EŽƒ}nÚ16¡ ¾½w1 ¿, ±ëÎDŒG U—p7Oˆô!²kNòâTiíI„2¤œðF=jÜ×Ö–ïÍum1ÄAä¹ÿg=zŽ•Êø{Ã÷–_ð‰ý®ÍWì:–×yem· ö~Ì~Y¹yçœè|1¬'…’Áíw\Ýxr×K'ÌOôIÑ\3“žFdS•Ï1cG,{Ü6«§%òصýªÝ³X Ê$,1sœí ãЃI­¦Í©I§E¨Z=ôCt–Ë2™Pz•ÎGQÚ¹»ÍþgÖ]-ƒ=ƽ§ÝÂÛ×-_dÞzñ.n:œ‘”‹JÔGˆZ;kì­ ÷=ËI¨…Õ€– ÀºÊY²C.Ü79Wp:Yµ8 Õíô×%žÞk•~6£VÉÏ\ʸã±éÝ–Úæ‘yj÷Vº­Œöèâ6–+„dW$¤ƒ€I cÔŠÄ¿Ñu?·Ûtǰ%×:è+žÕ?â[â½+RCx­§\Ù9xXý:yh¡¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(#SðÖ›«_Ç}ro’æ8Œ*öÚ„öøBrF#uœ~CÐT÷Ú-Ž¥±],ì²J³endFÀe`cà IêNt(  ö66Úm”Vv‘ùpD0‹¸·¿$òI<’y5ã¿ù'ž%ÿ°U×þŠjè+Ÿñßü“ÏÿØ*ëÿE5mQEäQ@bfþnÚÒóKHm.ç{{iÅÎù•òÈ ¥Qˆ;‰èÖÝ`[Á®¿‰^æúËMk.–òÇxæH£#¯–bÁv gçàtèw4!šï‰gÒnnR îa±´[ÛéãË1DK€QvçÈpJýÞ¼×E\޹ k›^c°A«é‰§ß‡¸ÜdËFB~ó‰¤ìèŠë©»[@ (¢¤aEP'ƒ?äqÿa]GÿKf®†¹ïÈ ãþºþ–Í] zÑÙ…QLŠ( Š( Š( Š( Š( Š( Š( ²üE¦¾¯ ]ÙÂÁ.Y7Û¹þ †¿U?…jQ@tmI5ÏQJ ˜VB‡ª9SîA÷z¹ÏÿÄ»\Ö´SÄbQlüó˜’à}%Y°e®Ž€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ +çÅš4µ´7&öéNÞÆ6¸u>Œ¿VÀ¨¾ÝâMCþ<ô«}6#ÿ-u|Éý²Œàþ2í@x§Ç:?ƒL-­ ¸`›„¸Kv’=ßÝ%sƒìk‘ñGÅë> ×l¬5±5ÕÆqQ iƒ3˜Ê~½høçÁú¶·áÛ6Ôîõ;û‘ÃVÞÚ2XeÊ É 2ß37AÔâ² øg¤ø áw‰Z .µYt‹¡=ë®ú¦ùP þ§¿lzQ^A¡ƒ¦ßjRø¿X±½xE´6¶Ó[Eû¡ä¸RY%ˆ‰N:ƒ<“™âWR¶¹Ö$³¿’Ö=JMDÄ‘FÂä±›årÊHƒ)æëÅt±éÐŬ\êjÏçÜ[ÅnêHÚ6‘”Ž3œÊÙç°üs5 é”3êW൲ÚÝì1¶Æ¤œIòq’[îmûÌ:U¦®"ƽ{qnº}¥¤žUΡv¶É.Ðv­#ÙãG.é${OuVB *òps>´‡J}8^ßµ¸xZÜ4ª~Ê!pñ,cn0¬PIHãp ´ñÆ—yâÒ"¸³i¤¸šÔD—JÓ¬‘oݾ,eW÷m†Ï÷}ESþÝÕµ«»ìÖ[8o´›‹Û<í“Í!­ü¦|¯Ëð*Gë‘ÇCo£Ekx&†æå"I(¶W-ò]ˆ-’ÌpI9ÇLf¿…œ>f“u*]Cg%•’ÎÀÇm”<¹;|°@Ï8Á8ÁâÆ“¨G«èÖ:”JV;»xî :†ήU{ (tÝ:ÚÆÙvÁmC=•@ôb¡‰àÏù\ØWQÿÒÙ«¡®{ÁŸò¸ÿ°®£ÿ¥³WC^´vDQLŠ( Š( Š( Š( Š( Š( Š( Š( oÄ_ñ.Öt]qxHæû Éÿ¦S Ÿ¤¢/ -]%QÖtȵ÷M˜•K˜Z-ê’8aîúU êrêþ´º¹P—`®PÈJH?V  j(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¦K4vð¼ÓH‘Å–ws…P9$“ÐPÖ4gv ª2Xœ=k‹Å’Þ©›Lðæ¯¨Y–";¸ZÙ#˜âO2eb¾‡=FG5Yb›Æ’,Ó«Ãáµ!£†ÖÔ=ÇQ¢õ~§ŽVªB¨@Àµ`ÂCªЙ®ßë/þH£þSþ„ÍsþÿYòEtP>$ñN¢>Hl4xyIº›î©TSÿqGü"V—?6±w{«·t»—Ÿûbc?Š“ï]Z$²Ó£‚Ò%·µGo.P* ÂŽç N`})ooìôÛGº¿»‚ÖÙ1ºi䋞IàVˆlàÿ„¯ÂwÅ3qý ð†$©öK¦ ƒ'#“´g £Ä÷öp]h×SÝÛ¥†«þœîãl¶—fóü?4‘¼¦€:8'†êç·–9¡‘C$‘°e`{‚8"«k:jk:¡¥Èå#½¶’ݘuPêTŸÖ³|CxmdLy2ÝÝËÂ×4d{+lVýský¼) ï…o®.Py¬n-ŒRï/™*0® ñïOþÞÕèM×?ïõ—ÿ$WIEaõxìæÿ·µ_úuÏûýeÿÉoj¿ô&ëŸ÷úËÿ’+¤¢«@.Îoû{Uÿ¡7\ÿ¿Ö_ü‘Göö«ÿBn¹ÿ¬¿ù"ºJ(ú´ìæÿ·µ_úuÏûýeÿÉoj¿ô&ëŸ÷úËÿ’+¤¢«@.Îoû{Uÿ¡7\ÿ¿Ö_ü‘Göö«ÿBn¹ÿ¬¿ù"ºJ(ú´ìæÿ·µ_úuÏûýeÿÉ6»¬2‘ƒµpçî™n,Õ3îVv }úWIEW€]™^Ó&ÒtH­®ž7¹i%¸œÇžd²4®<à3=…jÑEn ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®wLLñv©§p°ßªê0ö¸Ž`>„FßY tUÏx¬}týuG:eÈiˆÿž~î\ûÁÿít4QEQEQEQEQEQEQEQEQEQEQEQEQUﯭt˯ogH-¡]ÒHçE:êê Yn®¦HmáRòI#aUGRMspÛOâùRïQ…áБƒÛXȸ{¢9LEbÜáBÚÙ]x¢êOWíôØœIe¦È0ÎGIgÞî©ü<ó}Þ¦€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ †òÖë)ìî<ÆÑH§ø•†üMEbøZæY´(íîd2]Ù;YÜ3ugŒíÜÞ_è¶«žˆÿfxâhºA«Ûùëÿ]â¿âјÿïÙ®†€ (¢€ (¢€ (¢€ (¢€ (¢€ æÏ=¹lƒéµÐ‚A}GPH=A æ“r@d áút?üÅÿÄÑÿ/„{x[Dâ Gã¶«Ëâß?HKë9Ò7¼²Š9.¢ÂO ÷ ˜…[Ÿ•‰Á)+‚3¯£êÚvROœìº¹ƒý^ÏõS<}77÷:瞸\í ¹-nN‹¨Ûh6:ü7·lš~“~ …¥bì¨ÐÃ* ê[ )Uœ`TÖ:mÞ½{¯®@ÐÁo±ÓƒåÒËŽ žƒ¹æ¨hz%½ç|I©Ý;ÍömJ1onÿêâ“ìvù”îAÐŒd×k^”â™ (¢Š  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€0|Yo9Ó!Ôm"’[½2á.ãŽ%,ò(ÊÈŠ$´làÜŠoü&Z_üúëŸø"½ÿã5ÐQ@ÿü&Z_üúëŸø"½ÿã4Âe¥ÿÏ®¹ÿ‚+ßþ3]ÏÿÂe¥ÿÏ®¹ÿ‚+ßþ3Gü&Z_üúëŸø"½ÿã5ÐQ@ÿü&Z_üúëŸø"½ÿã4Âe¥ÿÏ®¹ÿ‚+ßþ3]ÏÿÂe¥ÿÏ®¹ÿ‚+ßþ3Gü&Z_üúëŸø"½ÿã5ÐQ@ÿü&Z_üúëŸø"½ÿã4Âe¥ÿÏ®¹ÿ‚+ßþ3Z¶:–¤÷ker“›IͼûBHX®{gN ÕiüE¥Ûêé¥Ë;‹¦e^ ¢³}ÕiìV= šñûÿ×þñmÖ•ªÙK¨éƒÁ;ÛIir±· 2H«¸Ž™ÂçÍvÚ7Šôßø·DÔ4źÿe_gíÏ&[N„­ÿ$Uë?†ž‹\¸×/íµ5[‰<׸½Ã…=‚§ÝP8‚@š»|ü@Ñ@¥_€ýu´¬ë| kr]_G¹¾¿´¾±Ô>Ãuo°<‘.b¡` ÌhA9ƒšŠçÃb{éä[mno`¾ž/,ÒÄ#Ù†Ï÷1ä`ýÓÈÍnÑ^o3(À·ðÏ‘ýþ—»ìZ­Ö£þ¯üï´|xÇÚ:óx4Ï ÿgjv÷Ÿkó<Ÿí“ËÆ~Õr³õÏðíÛïœñҷ裙ËGà¨N•¦é×7m,šÚ4›cÚeY.9;x‡§?{¯Íqá‰oiî¯ÃÝË-‹ «²Ú9WnãÉ%òsü]8ÅKá«íJîã\‹TxL¶·â$HGËxdÚ å°d?1Æ}À—Ú®¤š½õÜwò%­Ž«g§1e%Y„œ±]ùàc ÉÐæ¯Þ½®•LJ®ö«Û_@z—en-Ñ€°GÆ]À°ýÞì‚§8ô9~‘á}?MŽÊY­­nµDdŽõ­ÔI³1Ø„å‘öP¹8^2krŠŽg°Å·….aÐàÒ$Õ¼Ë[Y¬ÚÑE°_.+y’ESÎYˆ@¥²…ë}Lþɲ’ÛÎówÝ\ÜîÛ·lÏ.Üdôߌ÷ÆxéZPäØžÿÏ‹?ì*ŸúEk] sÞÿÏ‹?ì*ŸúEk] ztþèC (¢¬Š( Š( Š( Š( Š+žÿ„×Db|†Ô.<Û=.æâ3GŽ2§ð4›Kp:+žÿ„ÏJÿŸmsÿW¿üføLô¯ùö×?ðE{ÿÆhæ]Àèh®{þ=+þ}µÏü^ÿñš?á3Ò¿çÛ\ÿÁïÿ£™w¡¢¹ïøLô¯ùö×?ðE{ÿÆhÿ„ÏJÿŸmsÿW¿üfŽe܆Šç¿á3Ò¿çÛ\ÿÁïÿ£þ=+þ}µÏü^ÿñš9—p:+žÿ„ÏJÿŸmsÿW¿üføLô¯ùö×?ðE{ÿÆhæ]Àèh®{þ=+þ}µÏü^ÿñš?á3Ò¿çÛ\ÿÁïÿ£™w¡¢¹ïøM4‘Öß[Ôèw ü…[67öš”w–S¤öò ¤ˆr8?ˆ9v"„ÓØ QE0 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9½ Ýt{·Ù$‚Í/–H(†líÇîÕFXeXaAä9¬BŸíGM[KÆ’ûZ±¿†d·s†!m¿t€mR<‡àNá€s]ÕW;ÿ%Fÿ°Uÿþ´®Š±uÍ*öæòÇSÒå/ìÄ‘„¸Ï—4RmÞ„ŽW”B‚½j*EÊ- F¥…öÐCÿÁÌßü‹GÚÑãúèø9›ÿ‘hö;Ñv-)-ÛU’Þâx¦ÔeóžEÚLOå$@ *G5?0<ç·RãÃ6÷:¹¿kË´æŽâ[5dòe–06;ewdmNŒÚ¹ß´xÃþ€zþfÿäZ>Ñãúèø9›ÿ‘iû½‚èÝ¢°¾Ñãúèø9›ÿ‘hûGŒ?è¡ÿàæoþE¥ì*v £vŠÂûGŒ?è¡ÿàæoþE£í0<bècßûbcÃìÔ{ ‚èȱÓuY¼Iâ›í'Wki“R ¬ñ‰-¥ÎØüÆV畇lƒŠÔ_6šÂؾ”Ý>Ø­æÙ¹ö—gÑÂþ5¡ iSé–÷2^N“ß^Ü›—v¦òªTp¨ˆ¼òqžõªÊ®¥YC+ FAßh¤@‘ȒƲFêèÃ*Êrõ\ãøM,¤{ÞI¤Lܘc]ö®Ú„ð=Ê>ôÓâ[½ ìñ&œÖÑùˆZfkb=[ÑûîG÷P-µÌ–éqk|Õé·#žµcTñ»¥oös*Åu7d'ÍýÐùøÜ·ï:r>OC‘ÙÑ\Õ߈® ¿»)?c³Ôm´ùUó¦aÔç:qƒœ7#Š‚ÇÄZœ×ö-2Ú+ÍNóMTHØH†9X±qÔç?ÃG+ܲŠä´ÏjQÍ?öìqÆV#/Ù-¬giãùÂü¡wùëórê¸9 »×çµ×µàó^),t¥·†pè¨÷3Źà©å7 …ô£•ØQ\¿ü$7þyÓB[}¿ûSû;ÎØÞWü{}§~ÍÙûŸ.7}îø¦XxRÔÎÖ8íîY/ÌŒÊÆ0–×s–ܼûŽÔr°:º+¶ñuôÖÑ_¤Pù×:v‹(V2l uq$mòî!@‚9õ,N?jbgÓ$¨ Wû8\,L±öQs¿fâ~é+Ü‘œŒâŽFWX~5_Ä *&¬ ¨è7ZÛ»~lÌ~¤ÔþÔ§Õt¦¹¹XÖeº¹·a;u;Æ1’{ ÿët¨|7ÿ!ŸØU?ôŠÖ·Ãi6„ΆŠ(®âBŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ~çÂv«t÷º<òéÎw<–¸òå?ôÒ#ò?×½¦¤þ2…|·Ót²¼yãPšß¿—äÉ·é¼ýk¢¢€9ÿ¶xÃþ€ZþfÿäZ>Ùãúhø9›ÿ‘k ¢€9ÿ¶xÃþ€ZþfÿäZ>Ùãúhø9›ÿ‘k ¬C]:î•¥‹9¤7ò´f»XŠI'ï1ò˜`tœq ßlñ‡ý´?üÍÿȵæ?u?éš^™ª´vZN©Ç•m6ªË$²©d(`@ËÀ<ž?õ½kT›MŽÒ;KXîo/.>ÏRÌbBÛÉf ĨǀzTWصØíõ©ôèRþ-¾_4 ’2HªØé¹O#À &Ó¼Iñ'Wøqââ°*çý:á¾Í)Sså€w{p ú×µM wI ȲE"”taÀŒk#ÇòOM64ó_‹g3œò#NzñדSÞhš}ÿÛþÓo¿ûBÔYÜüì<ÈFü/õ¯ÈÁùºð1¡E`Q—G°šø^Io™Ã+ç{,£ Ås‚GbFF¥6=O‹ìÛ-ñök©o"ùÛåš_3{uç>tœîÀÆ…s:U¹¶ñþ¼ óLe°²”™[;s-Ð £ Ps’I¡^Àii¾Òô›–¸³ÒB†5ß<’,HH%cVb#\ò¨è*iô‹ ›‹™æ·%ÌQÃ),~d™uà†v ŽyëÀÇãH žïÄ3Ü×wkHh§->Z?FÊÂ29è;× SwZÜ ‹Ùôóil©3yþd¾c¾ÿïn¯»ý­ÙÇKþEG¶±†â1$,ž{ÄÅ·HÅ›n×\),~RH#çÒQK™oá}* X hZS 6ïy,-œ¼9Á!É>ùÁÈâŸ{ Û\Gsä$qÍsp·2HûØùŠ‹eÚêTíER:SZÔQv~‹¥¦¥Gb’6³»9Ë;³¶a–8…Tðßü†|YÿaTÿÒ+ZÛ¬O ÿÈgÅŸöOý"µ®Œ6³bgCEWq!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYz®›5ö£¡ÜDÑ„°½k‰C’¦Þh°¼uÝ"žqÀ?C©EaëV:•ëÚ\ÚChn4ëÑql“Nʳ)…£mä!(zøÀoº§¹LJôé´½mîZ6¸y¦¸›Ê$ yeyX)8$äGjÔ¢€0ñ(’t« ÿ®M[ Á”2Aw©d&‰â‘ãpU•†A¨5ÎÅá)­"X4ÿkVv¨1º}žU{(iavÀí–5…jN¥¬4ìoQXŸðê_ô9kŸ÷æËÿ‘èÿ„oRÿ¡Ë\ÿ¿6_üX}V}ÐîmÑXŸðê_ô9kŸ÷æËÿ‘èÿ„oRÿ¡Ë\ÿ¿6_üGÕgÝͺŒA Ü=ÂÄ‚wEG(Üʤ•õ lÛ­dÂ7©Ðå®ß›/þG£þ½Kþ‡-sþüÙò=UŸt-É¡i 1.•bâÈiºÝÙÀÆ6qòã¦: ЬOøFõ/úµÏûóeÿÈôÂ7©Ðå®ß›/þG£êÓî6è¬OøFõ/úµÏûóeÿÈôÂ7©Ðå®ß›/þG£ê³î‚æÝ‰ÿÞ¥ÿC–¹ÿ~l¿ùøFõ/úµÏûóeÿÈô}V}Ð\Û¬O ó¬x¬ö:ª`ÿÛ°£þ½DõñޏG§•d?•½jiZU®b-mC•,Ò<’9w‘Øå™˜òI?ç­.ìMÜ»EWH‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ÿÙivy-2.4.0-rc1/doc/samples/projects-dependencies-graph-small.jpg000066400000000000000000000435501226750426600244250ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÏ"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú(¢€ (¢€ (¢€ (¢€ +?û{G?ó±ÿÀ”ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡Egÿohÿô±ÿÀ„ÿ?·´ú XÿàBhQYÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸã@VööÿAküOñ£û{Gÿ µþ'øÐ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ4¡EGoqÔ+5¼ÑÍgSƒƒÈ÷¤ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( «ßÜ}O¹¹Æ|˜šOÈV+?\ù´[¨»ÎžBýd;ê€,X[ýNµ¶Î|˜’?ÈV(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ *®£™dn§Ýå+¢18Üásøg5”ž3Ñ1'Ú\#LСò˜ïeÛ¸.8,×ۚߢ±ÿá&Ó²îu/1þÉnè)Cƒ»o#ÏÞxÃFŒ1šy"f€y°%—nà3Á`?úÜÐíÏÍã= y¦y¦)L,¦Ì@ÉÉñ¹©ÅšL[IJʥ^T8‚CÌy/Ñ{“@mÐõ»«SÄwKö¨¿ÞYôq½ËšÓ¬Ýg÷ñj­”žkûÇ‚$ü”–ǪŠÒ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ³õš h‡Þ’îÀ\9ýÖ…gßüÚŽ”ƒ¨¸yÐDãù°  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (ªº…ÓÙÚ‰"‰e•¤HÑö‚Y‚õÁé’zv  TV¬Ïþ¿ÿ£ÎÖ?çÆÇÿ_ÿP…Ÿçkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãT¡EgùÚÇüøØÿàkÿñª<ícþ|lð5ÿøÕhQYþv±ÿ>6?øÿüj;XÿŸü þ5@V¬Ïþ¿ÿ£ÎÖ?çÆÇÿ_ÿP…Ÿçkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãT¡EgùÚÇüøØÿàkÿñª<ícþ|lð5ÿøÕhQYþv±ÿ>6?øÿüj;XÿŸü þ5@V¬Ïþ¿ÿ£ÎÖ?çÆÇÿ_ÿP…Ÿçkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãT¡EgùÚÇüøØÿàkÿñª<ícþ|lð5ÿøÕhQYþv±ÿ>6?øÿüj;XÿŸü þ5@V¬Ïþ¿ÿ£ÎÖ?çÆÇÿ_ÿP…Ÿçkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãT¡EgùÚÇüøØÿàkÿñª<ícþ|lð5ÿøÕhQYþv±ÿ>6?øÿüj;XÿŸü þ5@'·†ê†â扱¹$PÊpr8>âªÿbé[6fYlÜ[o¸É9'§\óMóµùñ±ÿÀ×ÿãTyÚÇüøØÿàkÿñª”éZsBð› Sýä0®œò1Ï ›6¦\+¬¶ͼ–cå î'$ç®sÎzæ™çkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãT·‡t{[E¶M:Ù£Wi?y±.HbÜŽ¹þÐTÿØÚ^òÿÙ¶{ˆ`O¹ù†·pN}sLóµùñ±ÿÀ×ÿãTyÚÇüøØÿàkÿñª¾ÊJ°‚z¡£“›Y¹%ìÜÀIêTP“Ü”*O¾iöWÏ<³[\İ]łѫïVSÑ”àdÐ`‚= d¿èºÔ3gݧÃýµË!ü·ƒÿ  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Ï—æñ ¦9Ûk1>Ùh±ühV|<ø†ó¾ÛXöËKŸé@QEQEQEQEQEQEQEQEŸ}óêZdC’²¼Ä²#eþnµ¡Yÿë|B;}žÐçßÌéå~´¡EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPFÎIÄwÅRöß&&n÷‘¿Ùl úP*)$ÎŽío”œªIÁŠd9 Øô`3ØPkN²ï‘ôë“©À¥£ È”d²Ž’Ý”uîWŽHQ@¬î’öΘÁ *ºŒö>⦬½2DŽîîÑ4e¾ÕÉ!$à÷ù÷Ÿ£-jPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYúͨj¬y"áPag›δ+?Hù­î$?yîçÏüFAú(  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ϲýæ©©Ê~òIýÐÇë#V…cÚ]­¦•%ÛE$Í5ÛíXñ¹÷LU1’M½ú Ø¢³ÿ´n¿è }ÿ}ÁÿÇ(þѺÿ 5÷ý÷ÿ  +?ûFëþ€×ß÷Üürí¯ú_ßpñÊТ³ÿ´n¿è }ÿ}ÁÿÇ(þѺÿ 5÷ý÷ÿ  +?ûFëþ€×ß÷Üür¹ïøÃUÐEƒYøföùî'òšÙY Œ¸ÉeØÍÓŒäÈäwèeÕ6ÜËW7&"F‹` Ä™†Nþ.·¥'8©13BŠÏþƵÿž·ßø?ÿGö5¯üõ¾ÿÀùÿøºÐF…Ÿýkÿ=o¿ð>þ.ìk_ùë}ÿóÿñt¡EgÿcZÿÏ[ïüŸÿ‹£û×þzßà|ÿü]hQYÿØÖ¿óÖûÿçÿâèþƵÿž·ßø?ÿ@Vö5¯üõ¾ÿÀùÿøº?±­ç­÷þÏÿÅÐ…Ÿýkÿ=o¿ð>þ.ìk_ùë}ÿóÿñt¡EgÿcZÿÏ[ïüŸÿ‹£û×þzßà|ÿü]hQYÿØÖ¿óÖûÿçÿâèþƵÿž·ßø?ÿ@Vö5¯üõ¾ÿÀùÿøº?±­ç­÷þÏÿÅÐ…Ÿýkÿ=o¿ð>þ.ìk_ùë}ÿóÿñt¡EgÿcZÿÏ[ïüŸÿ‹£û×þzßà|ÿü]hQYÿØÖ¿óÖûÿçÿâèþƵÿž·ßø?ÿ@Vö5¯üõ¾ÿÀùÿøº?±­ç­÷þÏÿÅÐ…fGgvøKåI©ùn²^\)haÁoFSøúÐ+ëK*ò9mY’ÙDžY[wœE»–ŒªB’ªÀÿ R:Á|9ñψ|Gq&}ªÂHºxr¶-öˆÕUØn—N~@1†'$×y«›+é4Þi]Î×´Ñ"2w˜ààc¬{W’ü˜j¤q1HN§Œ.^VÏ ÿiŽ{TTv‹hé:§‰£Òd‘'Ô5–1»#l†Ü€Ã}θdo£üS&ñ@·¼{i5 U^5¸+j0SÛ^ýxëšík3NÕEþ¥¨Z«[ºÚ2©h¤ÜCÙVˆL’9*k…U‘v*i7ë<:¦¥R£ÇoŸ™Áág­mi—/y¥YÝH<Ð$Œ %A8üêJ« ÿÈ»¦פ_ú­ðórnä³BŠ(®¡Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@gè|è–r÷š13}_ç?«ŸP¸6šmÕÈ0Âò~@šu•¸´°¶¶"–?È@ÑEQEQEQEQEQEQEQEÕÂZZMs'ÜŠ6‘¾€f²`·xFƒ`ÿë-âó_Ðìaýdð«zßͤMk‚–äú &ñê"ýö½rýV5?Ýf%œ~B3@QEQEQE™¢YÝÙÛÎ/k$“—UŽw•Up°Ò ÐPG¥-£Ë#HÌ#hg'smgn~:œó“‚A­[/Þëœç†+`=B®üþr‘øV•gbZÏKïüŸÿ‹£ûÓþz_à|ÿü]hÑSËÀgÌŒ½#ÐßMÿÅÕøãH£XãUD@UF ê)¤–ÀQE0 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3õÏ›F¹‹¼ê-ÇÖB~­ZŸ«üÐ[B>ô—pãþáÏ膴(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(?Rùî4ØO*÷Yaì¨Î?ñåZ4ŸÞ%ÝÉë5Ô„ÿÀ–?HÁüjû”·ÕË‚ÑÚXÍ,€vÉL~ˆõsM¶{=.ÖÚB ‘Dªäw`9?žhÕQ@Q@Q@Q@Q@Q@Q@Q@Q@eJ£JÔÒŒZ]º¬ãû’ðªÿCŸ}§ûƵi“EÄ2C2+Å"•taÀðA ÑYÚl²A#é—.Ï4 )¬±t=Øto|7 Ñ Š( Š( Š( Š( Š+:æîk›–°°m²/ü|\c"Fp;# è'°` gÕ´Ûišõ H¥_¼’LªÃ¿ šû{Gÿ µþ'øÕ»{x­`Xa]¨¾ù$žI'¹'’OSRÐööÿAküOñ£û{Gÿ µþ'øÖ…Ÿý½£ÿÐZÇÿühþÞÑÿè-cÿ þ5¡EeG4zÕÈhœI§Û°;ÔågsÁî«ú·û§.íÇÄRîK…±X8fhÊ;’¿t¸c Ôs¸ö :¡­ÜIk¢^Ë Äâ&Xë¡Aÿ}@è?>’—?óôïrª»_üt¨ü+N¢¶·ŽÒÖh†#‰4€ –€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3ïþmGJA÷–wÿº"u'óeüëB³åù¼Cká´›>Ùx±ühPEPEPEPEPEPEPEPEP?ûûËä%{k&_ï —ürCùWA\ý§úF­ \ÜÜzÇ‹p?søWA@Q@Q@Q@Q@mfš„×—SMwµ®#T»•„°yXþ5cû×þzßà|ÿü]hQYÿØÖ¿óÖûÿçÿâèþƵÿž·ßø?ÿ@Vö5¯üõ¾ÿÀùÿøºÍhh‰µ;„É${Q˜¡`Ùùøiçéê(¢¢°cþÚXâ‹SžI$}Š©©LĶ ÇÁÀ?äÓ<íOä6«2Ìã(u9² çv~~0oZèh®{ÎðîõOí–ùÚ§U—'·JjÜxy˜«M…, N`]¤Ž_¶áŸNsÒ€::+"ÖËK¾ˆÉi{s<`í-¥3p8Bâ*ac{n1k¨³(è—q‰†ÖüIj϶»}zÆ[Û6µk›9Ùmä†]É! 7)8ÎÒI^G`àt­«K¨ïmRx²² °Ã+‚¤v ‚õTßÞÛÿÇÞšåG&KGóTpB¾}‚šÏk­+í3Mºt÷˜†–ÑÆwcŠJ¥”íÐPCEsÿm±ÿ¡¿ÿ"Ûñ÷–FÞ@çó4­á!žG6Ÿ4,Ž|×å¥I߸QÅkQ@ô> Ò`¾YÑ%¢H‘À%mˆd\Žz1í“퉣𖉠ŠÑÑA€³È0dûý½mÑ@¬´û]:¤^Z¹‰û¨¨:ŸîªÂ¬ÑH̨¥™‚ªŒ’N½Mgý²òãç±´‚[á’iÚ=þê6WÐñŸ¦ P§SÃ8+eÙÁ›Üÿ³íß¿ôŸçkóãcÿ¯ÿƪ™õQnêö–hJ‚—¯»¡û¿ºëZÕ›©é¨\Y:Ë GÂIàÞÎ+pÛʃß$ ñ@8[x›OÓ,F¯áÍ;N³¶¹2`œÊcu ð  ’Xd†Ïû5ÑÜÞ4ºíÊAv-bV27ÙîC–Ã6y{Jó“È$…þè§¢±7v4Ì"÷Wú¼Øn!‚T‘î¬ä–hÈ„ýÓÈÏëW|cþ¬ð ÿøíhQZB åB3ücþ¬ð ÿøí!‹Y"öÁˆþhã>Ùó>¸?JÑ¢¨ ê@H°^Äm'c… ÙIûÐýÚ¯Ó%Š9¢h¥dÆdèEP6wv<éò‰"òëpÇýÇä¯Ðî†ÚÒ¢³—Y„ Mkƒ†Ci#àÿ¼€©ü ¥þÙµÿžWßø?ÿ@Vöͯüò¾ÿÀ ÿøŠ?¶mç•÷þOÿÄP…Ÿý³kÿ<¯¿ðþ"í›_ùå}ÿ€ÿñ¡YÚwï¯õ;ž Ì!FÏUEƒ™*Õ­ä–þ|,Jne;¡!€#‘Þ«hy:5´§!®¸`{ r?Ø  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3ôšÚyÞ{¹÷\HÊ?E¡Yú:”å‰eo«üÇõ&´(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬oÝ](8a*È£þ¹7ê##ñ­šç|Gþ‘©èÖþZÎe×a]ÃñC%mXÛ ->ÚЈ"XÁõÚþ•bŠ(¢Š(¢Š(¢Š(¬ýkæÓÄ}¥žˆõV‘C~„Ö…gê=þ™çý!‡°ùÿ¾Šþ”¡EPEPYã^ÑÈÈÕ¬ÿ¯”ÿnªæå¢Òãbè+)å!xû£¿Í‘Ò´UU*¨UQ€À€(ohÿô±ÿÀ„ÿ?·´ú XÿàBhQ@ÿÛÚ?ý¬ð!?Æííþ‚Ö?øŸãZPööÿA[üOñ§*> âI‘’ÕNc‰† ú3ŽÃÑÏõQEQEQEQEQEQEQEQEQEÏêdÚ¾§l¬WûF%0‘ÔJÛacžÀnˆþ&·ÕB¨U0íX(eô©Ê^,ÒûD îcì§k}TWA@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@UÔî×J¼¸O½ãêšµYúßͤMü÷+oôó'þÍ@­-ÖÖÎ tû±F¨>€b¦¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®oZñN•Õ4í(íõh­]Òo-Û(J²g¾«œê*–±¦›q6þ†æ"¼±ÚoÚ7`çIã'ŒŸ§Ê¥NKh4ŽÆŠà ÞÙ1ÿ"0Ø•€u8Àå=[Óò9¨öh þŽf`΢;l<ÆP¬6ppÏ9È隬yF®vLÜøþ(ÏÍ­‰”~ä…ŠóõV?•A¥ZZ^Ý^Awá›[QnÁVC•—–©*2>PàCñ—ÚdvZÿˆ¦†1/<1GŒ( ±Àì3!üsUN·<¹l %Q[(¢Š(¢Š(¢Š+9¿yâ8°?ÔZ>ïûhëýÕ£YöŸ¼Ö5» Šßî©|ÿä_Ò€4(¢Š)’˼²¸HÑK31ÀP9$Óë2øýºþ-5Õ Yî½×?"À˜}ƒ÷¨ú\NÂ[ùÔ¬÷D6ÖÇû‰øIÞf­ N¬ÿííÿÌZÇÿSühBŠÏþÞÑÿè-cÿ þ4ohÿô±ÿÀ„ÿТ³ÿ·´ú XÿàBÛÚ?ý¬ð!?Æ€4(¬ÿííþ‚Ö?øŸãGööÿAküOñ  +?û{Gÿ µþ'øÑý½£ÿÐZÇÿühBŠÏþÞÑÿè-cÿ þ4ohÿô±ÿÀ„ÿТ³ÿ·´ú XÿàBÛÚ?ý¬ð!?Æ€4(¬ÿííþ‚Ö?øŸãGööÿAküOñ  +?û{Gÿ µþ'øÑý½£ÿÐZÇÿühBŠÏþÞÑÿè-cÿ þ4ohÿô±ÿÀ„ÿТ³ÿ·´ú XÿàBÛÚ?ý¬ð!?Æ€4(¬ÿííþ‚Ö?øŸãGööÿAküOñ  +?û{Gÿ µþ'øÑý½£ÿÐZÇÿüh’Åîµ,2 hâ³ØÊGÞ±È?„Có§è’Èú\qNÅî-‰·•›«2»ûÀú0¦é­Ñ½½ÖHg¸>S)È*Н¦åcøÒD>ÉâãéìBaÿ]ßš˜ñþé  :(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¬O_ƒLº[Smsq1A#,!~E$€If’Lô¦¢äì„ÚJìÖ¢¹ÏøL!?ó Ô?8øåÆœcKÔ9éÌ?ür¯ØÔþVGµ‡s£¢¹ÏøL!ÿ ]ÿnðÿñÊhñ³3¨Ó/Ë!à ÃÁÀ?óÓÐÎcSùX{Xw:Z+/ˆçV qטøå]Ó5è5;–·×ò„.`¿2‚ «Á#®:Òt§v†ªA»&jÑE…Q@Q@gêß:Z@:Ëw?àÌ?¢ЬûïŸSÒãVW”ýl¿ÍÅhU)¤{¹šÖ*‹Äò©Áì©õ=ÏaîFâi%”Ú[6Ù1™%ùCú±ì;u=± 1Û±D»Qz çñ'¹÷  Ø:8ò ±ÿÀtÿ ?°túØÿà:…hQ@ÿØ:?ýlð?Âìþ6?øŸáZP'â øqák­Ñáxe˜íаٷ€1Ï *¢uß G$qM B²˜ÖF mUÈRF{ãpéèsŒf»ª(ŒºÔ]ÄGžÞ„tùNAÀ⪮§%k\C¢Ý¯Ë ýs÷Øœ0Iàn#VŠÏþÞÑÿè-cÿ þ4ohÿô±ÿÀ„ÿТ³ÿ·´ú XÿàBÛÚ?ý¬ð!?Æ€4(¬ÿííþ‚Ö?øŸãGööÿAküOñ  ÏÒ~t¼¸<4×rä¸|¡úF(þÞÑÿè-cÿ þ5ÍÍã­ Ã^±Ô/o#’'n>Ï"»ÆÒrX®rFãÎ2yé×¥ËEâvÕìfÔ´K«YlHáŒ!•˜'?yJ€\ `ž öªÐø¶K”€Áo#ÌcF›(Ày{²d²? ÍÕŠv޲îê;+IneÎÈ×$(É>€äžîMS¶Ù¥éò]ê$sLÞmÃg#yÀ =p6¨Ç'¹¬«›ë‘¬Åe}åܘUn"ŠÙ ´îKKÚX±8ÉN˜çZÚÂY.óQe–åyŽ4ÉŽ÷sÕºäg“€Å\d¤®„D-§ÕÎûèÚ/à´o½'¼¸íþÇO\ôÔQLŠ( Š( Š( Š*­æ¥a§ìûmíµ¶üìó¥TÝŽ¸Éæ€-QYð’è_ôÓð)?ÆøIt/ú é¿øŸãNÌWF¥—ÿ .…ÿA½7ÿ“ühÿ„—Bÿ Þ›ÿIþ4Y…Ñ©EeÿÂK¡ÐoMÿÀ¤ÿ?á%пè7¦ÿàRatjQYð’è_ôÓð)?Æ¥¶Öô›ÉÖ ]RÊy›¤q\#1ü¢Ì.‹ôQE!…Q@Q@Q@fë_º´Žø›)DçýÌ“ëò3þ8©µ4»{R2O¹H+·$n7ŒÿJ­jkSyñ¿Ø&X¡^‘à`sœù¹íÈëÆ5h¬ý™l«’d´cnź¿tŸr»[ñ­ (¢Š(¢Š(¢©M#ÝÊÖÖîV58še<öTúúžß^€ %åÌ’²XÛÃ2Æv»Ë1wz.²GNs†ùÚÇüøØÿàkÿñª½i KhaT )ÔŸçkóãcÿ¯ÿƨóµùñ±ÿÀ×ÿãU¡EgùÚÇüøØÿàkÿñª<ícþ|lð5ÿøÕhU=NÖ[ˆZ9 +++Ñê9Ç;Њ5?iú ×:V—i=ò²yP¤¯7˜KT®ÅãçpÇ_cÏÍ&«ª]Ì5í6-:êk‘à†äM€ZQÛ@¯ýMv–öW‰®Ëy+§ñJÄ‚DxÆ0 ¹Ïûg޵KYÑ/nõA{fÐ6èV'Iœ¦6³A sçÓ¥m‡”cQ9le^.Pj''…ìf”<­#ýÿ—d`|Ë´ô_Oךºs,ã÷€Í#HXmÊîel8 ô&ºìgþyØàKÿñº?°uŸùçaÿ/ÿÆë¿ÛÐîq{ÝŽ1ô-#Ü5ë&“tŠÈ>cËÂñ;|Ùã5nãÂÖ7Wëw$·%–e›apT•ÁÈ$ŒZØŸÁZœðÉ6È®ìÿ-Ñಕ8ý×£ÐþÁÖç‡þ¿ÿ¤«Ñêÿ1º5z#›Ñ´5Ñ圤ÛãtHÐ…RÇ’:Ÿœþ_€é4ùãÿ¯Iô8¨þÁÖç‡þ¿ÿ«ú6{i©»³í…¢T…ËçqRI%F1´zõ¬ëV¦é¸Å—J•EQJHè(¢ŠóÎàª:܃¨É²H–²²²œ!N«ÕG[åÐuãFyÖUUQ’Ä©À“Ø ßØš2 2Ä`g˜ ïÒì]8þ̰Îq!:þU™~ÞÔîæMbÕXÂ~é$}àHäœúô5–š„ãDTÖ£]©°•¹„™¹ÀÿlLÇæëܳ¥JÐågXôý=™Ö88ÓÑüEU{¬¼Eiý™i Ëi:3"Eâù˜ g‡¿a’3,4Ï iú¸Ô¢×#iüÆ“k]D,¥OÊ ŒjüÚÕ«x§Jû-ÔÂñM­†Y£ØI¬ãý¯jÒý¢Øè­íÒÚ!dó–fä±îO½KEÞHQEQEQEQEQEQEQETsÁͼ°L»¢• :ú‚0EIEQÒ§’[CíºæÙŒ3üL1†ÿ)VÿUêΔ}XŽàqÚˆdô¹(¹Iîv Ñ Š( Š( Š(  :Ó²hwå yw@ýqT- S¿¹·¾²Y­ldCj.-¸Ü7&î´çqàWuž xGß–ê£×k‡oüu­Ý,k*Å?‘!B]¡¶}ì=è/O’ ›ýeU’Qò«¡XC ÇÔqQZ[i“^Ílº=´fȦÆò€w3(û¤¿Fõ<X^ðmÎ…¤\0×/Ù5 · â3 2"çyd9lŽHÇÒº(<<¶²Í-½ýÄ2LÛ¥xá·S!ç–".O'¯­rN„œ›E\fnÓÄ—mimm)6if1‘óËÀÂ6jç¬Ïþ¿ÿ¨×J’ÚW»†êY¯ Zrt!P$ƒŒ‚{ŒƒzÚå.c,¡•”íxÛï#zó‚0FA®ŠqqŠL–Uóµùñ±ÿÀ×ÿãTyÚÇüøØÿàkÿñªÐ¢¬ ÿ;XÿŸü þ5G¬Ïþ¿ÿ­ (?ÎÖ?çÆÇÿ_ÿQçkóãcÿ¯ÿÆ«BŠÏóµùñ±ÿÀ×ÿãT}¯Qýn–þ½®¿ô0•¡Yºâß6— Ó|ßµ`ù~YAÎ3¸Ž3þ¸È ¾"ñT¾ÐnµIt{­¶êl’FòÐU˜î9Àã“\Ëë‹âk‰oì­ol¤{ÕúÙ¢tbÒààŒÓ‘‘]ê%ÛjÆG-öCÄm· &Nzsœ\Vˆ-î\7"Þy"’Ú8ÃEIó+9 …0ëý+|3J¢lƺn›HäÞË^yËåŠ?ŸøÃ»òË?ïr}½iÇ^ 1MM7yä‚7.Ýß']»óîEnboùò¾ÿÀ9øš17üù_à¿üMz<ôÿ›ñ89*/à`›/n,º„@ol+@_—hÎÀIûÙú޽*ÅÕ¶²òH`ºŒ÷pÁ@ùxà£9Ï·Ó[Ï•÷þËÿÄÖX°Ô Ú†mo’+ˆöǶ)ò­ós÷2 ôSé‘ÏqïPÞh—w>w—©ÉòÄ2ïÊå³ýð8×B„jC™œµ«Ê²;oøK"ÿ ]ÿþBÿã”ÂYýïÿòÿ®$èN.¼Ó¨Üùªóó7g;¿»ò}?* ºc sâ'q*‰ÕŸ÷½NŒ}áí[}Rz2ú̼¾ãÑ‹a“¦_€:“äÿñÊ‹a##L¿#®G”ö¥qSèwéâÕµ)÷ogSƒ»¾‡ qÉ#ž«RÒ¶³‚ÈÑF¨\õb3øÓX8y‰â§äv"ôjH‹a'îäEwœº¬gøˆ û“ØÐÃ,Q(TQ€+;ÃQ¤^Ò–5 ¿dˆàåA'ñ5©^ièQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@bøžÓíbJcA*¾ü}À~RÿðÛþ¨+j£¸‚;›imå]ÑÊ…z‚0h+ £yc Ã.ÇeùÓ9Øã†_À‚? ³X^šE[NÙ‘‡™ž€¸%%þ¥¿í ­Ú(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š¯}j/läƒvÆa”qÕ«p@?…%…×Û,£™—cVDÎv88eü#ð«5›û·$Gˆ¯GšžÒ¨‡â»Hì¹  *(¢€ (¢€ (¢€3ïy«i±¨Ò\¢¡Oç(¤ÖòÚT–ê~k¦[p…b>ŠIü)Gï|BÙÿ—{A1ÎôPüè¸~µgU·W¸8ìÄl\ûÒß4 `QEU[›g2 ›b«r£ýÙû­ýP}A Ú¢€!¶¹K˜Ë(ee;^6ûÈÞ‡üàŒjj«slæAslUnTcæû²/÷[ú ú‚A‡ûFëþ€×ß÷Üür€4(¬ÿí¯ú_ßpñÊ?´n¿è }ÿ}ÁÿÇ(BŠÏþѺÿ 5÷ý÷ÿ£ûFëþ€×ß÷Üür€4(¬ÿí¯ú_ßpñÊ?´n¿è }ÿ}ÁÿÇ(BŠÏþѺÿ 5÷ý÷ÿ£ûFëþ€×ß÷Üür€4(¬ÿí¯ú_ßpñÊ?´n¿è }ÿ}ÁÿÇ(BŠÏþѺÿ 5÷ý÷ÿ£ûFëþ€×ß÷Üür€4(¬ÿí¯ú_ßpñÊ?´n¿è }ÿ}ÁÿÇ(BŠÏþѺÿ 5÷ý÷ÿ¤mF÷iè·{ÿ‡Ì–\ûäôûµuw ”>lí…ΖcØ9'ØU%³›Ru›RM 4vD‚êB8föåAõ 5¥ƒ,ßk¼OvA„ˆáAÛÜõ=øÀ¨¢Š(¢Š(¢Š(È#$gÒ°F“¨¬:tbuo³0ÞÍpä°ó³œ|Çjºóýî½k~³/f’öèé¶®Èêu81©èоÃþùðJäŠmCÄþ)ñÖœ,m,ôÝ-Dñ¹¿Ú]‹F (IÀpMlakóÇOÿÀ§ÿãuÐ9–ÎòÆÞÚ[ŒŽ©;0ÜÀ{~X¦h—W·v’=ôMÀ¢1õE$`õ‹ ûwëZ´à­e:0›¼‘ƒýƒ­Ÿùc§àSÿñº¡ÿ^­‹qþŠ •knFålÜôÊŠô *Þ&«êJÃÓ]?û [ÿž:þ?ÿ¤þÁ×?ç–ž?íéÿøÝv4Qõª½ÃêÔûvZ5Ö‹co›r$Ĩö÷ùn@•<˜ÉÇA•öç5~ÓS†êSnêö÷j75¼ÀÇ¨Ç =Ô‘øÕÚ¯wem}Žæ áNå9!‘½U‡*}Á¹ÍËVbG«Zoô_Âפ_bUHo®ß=iþv±ÿ>6?øÿüj€4(¬ÿ;XÿŸü þ5G¬Ïþ¿ÿ  +?ÎÖ?çÆÇÿ_ÿSZçUPKYéàŒ›æëÿ~¨ÝíÜv’†1ÛÄÒ¸Q’B‚N=ø®wþ«à2tËeã87§ÿÖ¡?ŽÞ_-Õžž¾ÓÚiœ?vwyeWæ\çÀ>øæ¢½Ò`¾¸HÝ$¼§Ôýk¯ F5¹Íˆ«(5c¢ÿ„ªôÌ6×ÿOÿ£þ«ßúÚÿàiÿãuÈGáM68à@ù2,›ˆ\¾Öf¾^GÎxö éâD`d ìÂm%}Þ‡ã®k£ê°íøœÿY—Àë_Å·q®çÓ­@Ü&õº’êû’?:wü%wŸô µìãôÿñºàÆ—£Ûé3EçÞyÄmÔcË6Œ)=9ÆG'’óÁÞ|²®Â#$ŠB„æL=ãäy¥õht_ˆþ±>¯ð;µñeã¨eÓmHnŸéÿÆéßð”_ÿÐ.ßÿÿ×¾¶·{Ck3(…“y‘U‹…“̺çŒúcÓžŽ©ai½Ðž&}ÚÙÝ%õ½ÜA„sƲ¨n 0ÈÏçSÖo‡¿äZÒ¿ëÎýV•yg¢QEQEQEs÷?è:¼ÓŽ7K‚z~íÇ— ú)U×AYz´IçÙÍ"­fc”c÷qüê}*W’Åc™‹O0ÊOVeãqÿxa¾Œ(íQ@Q@Q@Q@Q@Q@Q@Q@V½²[Ø‘L²Bñ¸’9cÆäaéG xèMY¢€3ÿ³®¿è3}ÿ|AÿÆèþκÿ Í÷ýñÿ­ (?û:ëþƒ7ß÷Äünìë¯ú ßßñºÐ¢€3ÿ³®¿è3}ÿ|AÿÆèþκÿ Í÷ýñÿ­ (ËO¹“RÔ¤:Åîä‘ d<¨Eqÿ,ýdjK ‰ï¯®¶/Ai<ˆØ,?2GÁãËìí üªÝ…Â[i7wÒç`šâgaÔª»`ÿß Vm/ôÛ‹S{ ¸­äId $›Y›!‡ñ®€5ÿ³®¿è3}ÿ|AÿÆé?³îröÕöO8Ùÿ¬cá;õ’3ˆ."Š8Ö5‰U°6…ýÿöIç?xãbëÃW3ÚØA­5ºÚA$ ÄKî@ªÄ‡ê¤ÿ Òþκÿ Í÷ýñÿ¤:}Ê‚Nµ|ä’ñºç¯ü)«­¹~µ/y 3¢'È>Cg ßRHô3KàûÙ$‰Ž¿pV;v‹k+6]£ æg~s’äö¿0 Ïìë¯ú ßßñº?³®¿è3}ÿ|AÿÆê†Ÿáë»=En¥ÕçU”ùD¸R:¶Ar>fecÇUéÍoÐöu×ýo¿ïˆ?øÝÙ×_ô¾ÿ¾ ÿãu¡Egÿg]ÐfûþøƒÿÑýuÿA›ïûâþ7ZPöu×ýo¿ïˆ?øÝÙ×_ô¾ÿ¾ ÿãu¡Egÿg]ÐfûþøƒÿÑýuÿA›ïûâþ7ZPöu×ýo¿ïˆ?øÝÙ×_ô¾ÿ¾ ÿãu¡Egÿg]ÐfûþøƒÿÑýuÿA›ïûâþ7ZPöu×ýo¿ïˆ?øÝÙ×_ô¾ÿ¾ ÿãu¡Egÿg]ÐfûþøƒÿÒ:ïkW öÌpÿ¢ëFŠÌûN©gÿV©wüõ´ùX}ccÐ{3éVm5+;âËo:´ˆ2ñ0+"¼‡ ¿ˆ«UZïO´¾ .`I £ôd>ªÃ•>àŠ³Eg.™: ±ê÷èƒî©òŸÓs!cø’i³®¿è3}ÿ|AÿÆèBŠÏþκÿ Í÷ýñÿ£û:ëþƒ7ß÷Äün€4(¬ÿìë¯ú ßßñº?³®¿è3}ÿ|AÿÆèu É#t²³ ׳WpÊĽäoaØw8rE‹;Hì­„1î<–gc–v<–'ÔšŽÊÂ;#,žd“O3$Òãsc àu=I&ÝQEQEQEQEQEQEƒuá±=Œö±ÏI$òL3à «+q‘Ÿ¿œúÖõõ¤wö6r–ÜDÑ9S‚=ù®tx[PÚ¶ÇÜÙ7ÿ®¦Š¸T”>D©Æ9oøEõú ÚÿàñÚ?áÔ?è+kÿ€MÿÇk©¢¯ë{‘ì)ö8¹¼ ,ñ¼rjå]‹°ÒH ô—¸$U¿øEõú ÚÿàñÚêh£ë;ØSìrßð‹êôµÿÀ&ÿã´Â-¨ÐVÛð²oþ9]M}b¯pöûYÚ¥½¤eŒpF±)n¤(ÀÏåSÑEbjQEQEQEUÔ­Mî›qlŒGB#r3±ú«~ðª6K%ä*¥"Ô­Ö]¤ýÙT ƒþÑRý³5±\ë«Á¡ jÍ5…ÏÛ`QË:>]€ú“2 訦Ç"KIG•‡BCN Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™4©2M!ÂF¥˜ú2iõŸ®|Ú%ÜCïNžBÿ½'È?VHDëáý&ÂA‰fò#p{íܪ£Æ·k<þÿ_ømm³õiÄÏý÷ZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ¸™ÅãÆ%YDQoÉ%ºü§ÐzPê*£]Ic|`²D$›æÆÑÏO^†•¯BJ±”äÈPó÷G?øòþtjŠ úœhªÍå¨+¿ & \œ1Éã¥J÷žYœ²*ÇÜ_$.;p>n´j²îÙuû)ú%Ò5«ã»dB}€YGÕ…YKÑ,`Æä/倯•'ûØôö¬ý`ÜO᛹ãȹ·/<@Ñ9e_Çh_¡4oûGó ±ÿÀdÿ ?°túØÿà:…KúʨáAGÁƒdm|í?˜©ÎaŠ]Ÿ+°zpãÇç@¿°túØÿà:…Ø:?ýlð?ÂpóÜ€%š$hÕFÉa’vœpJg´„çì9Ç#ËÝéë@`èÿô ±ÿÀtÿ ?°túØÿà:…>E&ݰ+Ÿ,È«îbb;G-¥É¹BÛPÝpút¯ýƒ£ÿÐ&ÇÿÓü(þÁÑÿècÿ€éþ¡Egÿ`èÿô ±ÿÀtÿ ?°túØÿà:…hQ@ÿØ:?ýlð?Âìþ6?øŸáZPöÿ@›üOð£ûGÿ Mþ§øV…Ÿýƒ£ÿÐ&ÇÿÓü(þÁÑÿècÿ€éþ¡Egÿ`èÿô ±ÿÀtÿ ?°túØÿà:…hQ@ÿØ:?ýlð?Âìþ6?øŸáZPöÿ@›üOð£ûGÿ Mþ§øV…Ÿýƒ£ÿÐ&ÇÿÓü)É¢éQH²G¦Y#¡ ¬°(*G ƒŽµzªjwMg¦\\F•Pùj‰Ï ? ~4“ûÔº»ïqräzm_Ý®=ˆ@àU¡PYÛ-•½ªVÖ0ORÅO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@0FÍ.NæP§Ó?âiôP3[,ÌIfPÃkŒ0ô?™üé²ÙE+JÌX)ÁéŽãß§ä*Å[)ÆÇxð¡NÂ@è?SÒœmЉy?¼`çØ€Çýò*Z(³f0¦Y Ü$$dž˜éí@µAhöûœ£†“ÏÌI?Χ¢€1¤ðÆ‘öi#L²,à(f>QíÚŸ?‡4™-Z(ô«JíÀ£ý+ZŠÌ_èÉ!a¥Ùr¡qötÀÆ}½é¿ðhÞfÿìË<ïß!1»qÓ§­jÑ@+áwìëR¥vä Ú=°?^´°øoG‰™Ži#6/oAôQZ´Pöÿ@›üOð£ûGÿ Mþ§øV…Ÿýƒ£ÿÐ&ÇÿÓü(þÁÑÿècÿ€éþ¡Egÿ`èÿô ±ÿÀtÿ ?°túØÿà:…hQ@ÿØ:?ýlð?Âìþ6?øŸáZPöÿ@›üOð£ûGÿ Mþ§øV…Ÿýƒ£ÿÐ&ÇÿÓü(þÁÑÿècÿ€éþ¡Egÿ`èÿô ±ÿÀtÿ ?°túØÿà:…hQ@ÿØ:?ýlð?Âìþ6?øŸáZPöÿ@›üOð§&‹¥G"É™dŽŒY`PTŽAjõQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÿÙivy-2.4.0-rc1/doc/samples/projects-dependencies-graph.jpg000066400000000000000000001504261226750426600233200ustar00rootroot00000000000000ÿØÿàJFIFÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ!"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?÷ú(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ +xVÖâ[{èÐÏ”’9/âVF[ ƒÆ*?øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(®þ¿ÿÐסÿàÆþ*øNüÿC^‡ÿƒøªè(¬½;ÄÚ±rm´ÍoM¾œ)sµÜr°Q€N“ŽG>õ©@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@U=Zïì5õæqö{y%ÏûªOô  ¿üÞ±Ÿþ~¼Ë¯¯›#Iÿ³WAY~´û…´‹íCõ&€7袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ÆäŸêñ†¸¶k`G¬Ÿ»úo×?âÿÞi¶6¿óñ©Ù¯Ô,èì?ï”"€7À p¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢±üK}q§éPMk'—#jP“´¤—QFãŸUfÙãšØ¢¹KÝÁâ8´sacæÝ<±Z£jCÍgHÞ@ÒF¨JFÁÌ ‘•ÉÅaÚ|J†´iõ¹tĽ—JƒP»ßžHÜ6(<Ç; (0 x$Ñè®ZÉŒÿá6ã˜Â´×‚)¦ 2^(ÊâD^só†ù[ p3VÓİøy¯ë:œqÇwdÚ—öIƒ°É*¨ Ñ€Ù´­¡ˆÉ*;:+•¹ñeݾ¯yöJ6Ÿg©[iòÝ}«Zu„«,{y§PrÃŽFz ‹o]ØiQlèð_Ï{~ý§Rò!1Apc*$hÆ\d(ù‚î$@ô+ŽÔütÐhòêzV™öø ÒSV˜Iqä²Âêæ0ÖÉ>[ç¦îpƒx†ù®õÈàÒâ’.U€H÷‚?1Ú(¤Épª§'$ü¼'¡¢¸HÄеWM¿‡TÓ-u bL1,Éž¸a‘Ÿ~jÕQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÏøƒ÷ºï†mû}½æaþÊ[Ëÿ³2WA\ýçï¼}¤GÚ >îSõ/¯é¾€: (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ §©é°ê¶©o;H¨—\„º)VUƒÆäûg§Z¹Esx2Æß\‡TK»ÌÃw-ävû“ËH²+“òîlù¬FXã€02 m¼ogciikªêp%½ºZ³Äñ«ÍeŒq³È €)µ°y$ó]-‡¨xf-KSŠî}GPò#ž+Ÿ± ÂdŒ‚Ê–\€$rNXþ·}'SÒýïØuv$‡1üŸh;œ©Ùž r¹'ïœäÛ¿EcÍá»9þÛºIÇÛ5 }BL0âH| q÷O™ynG­ÿ”1«ý—SÔ-e3ÜL“Eå‰gq$±©d#iq»XŒt4Pâ¿ßë=:c6_a»¸{Öó.pLld#sïBKIçjïÃW–Ú¬I8•ÔwrW)",J»r1ä¡Ã Îr+jŠæí<ifÑÈš…ûΚŠê^s´{šA€®cÈÀ;Jàa?áÓÆiaÝìvÐØÅ§ÌŠÉþ—o!RRW§ÌÜ®ÓóƺZ(o ÙÏöÝÒN>Ù¨[êa‡Cäíº|„ÈëËr8ÆÅP?áüéú–«¢7 ßk¶ÿ®3Øü$Œvk ®{Äû7VÒu±ÄqËö+£ùe1IúH#úÕÐÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ý·ï¾ j-Ô[é–È¡y&,?$Jè+ŸÐ¿{âO\vîaô[xßùÈh ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šç¼\^[]7NŽyá7úŒ0³[ÌÑ>ÅÌ®© 2±°8#‚h¡¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üz€: +Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿǨ ¢¹{­mWRÐçÔçž™lîuîæ?â@%v ýÔŒr0N ­ý>þÛT°†úÎA%¼Ë¹üìGB ŒPuM:[J»Ó®3äÜÄÑ1@#㨪~ÔeÔôy.ˆûl;­îÀí4d£þ‚G±¯\Ý©þÊñÅÝž6Ûêðý²#ÛÏŒ,rÅ<£ø1 ’Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¹ÿ âKmVèËÆ«uÏýsÃÿ´ë ®Á#wƒì'ÿŸ ÷__5ÚLÿãôÐQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW=©ÿ¤xÛ@¶ê †êðû!úLß‘®†¹û_ôŸêRõ[M>ÞögyÿEŽ€: (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ æ®Ûþ}U¯ÁÛ£_H>Ö;ZÌxû#ô8nìk¥¨ç‚+˜$‚xÒXeRŽŽ2¬¤`‚;‚(Jç¼c‘iQjð!k"u½P£–Œ%QõœëŠn4º%úøvöV’2¥´Û‰L±Ž±1îè;õeÁêº&PÊU€*F=è#‘&‰%ƒÆêX‚CN®{Â,mlnt9 ó4™²g©ƒ¡>ÿ»e\ú«WC@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@µ{¯°è·÷yÇ‘o$¹ÿuIþ•‡->Áá}"Ïò,¡‹›PéTünIðV¯87íl>²~ïÿf­ð€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Ã_¾¾ñ ïü÷Ô™ÿ³i?ï¤søšè+ŸðGÏá +¯ùý2^ç×Α¥ÿÙè ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(?YÒcÖtólÒ<2« `¸ïÃ*ò®¾àöèA ðMWÐ5y5(&¶½aÕ,œEw ôÝü.¾¨ã~ ò lV½§\‰¡Öô¤Ý©Z.ÖˆÜ9ËDO¯u=›Ø¶@#¿Ùž1ÓõÄŒfÂàöÞ¹’ò*ý]k¡¬+ï'Å~ytÉi£ZHÃ\Èw&áÔuF­ #RWÑí5Ô¢ÜD¡ê‡ºŸpr¸  ´QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsþ/ýæŸakÿ?¥šãÔ,Ë!’è+Ÿ×ÿ{¯xbßþŸ¤¾‰o(ÿЙk  Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  Ÿ^6ŸáM^î?õ‘YÊÑWÚvÄàU½.ÈiºE•Šãm´ Ç¢¨Ò²ü^|Í"ÞϽÝý¬õ_9YÿñÅjß Š( Š( Š( Š( Š( Š( Š( Š( ŠÎÖµuÑìã“È’æâyV {xÈ ,‡8<€I' Öwö‡‹#AÑ@ômb\þ–Õ2œc» Îý¿ÅßôÐÿðs/ÿ"ÑöÿÐ CÿÁÌ¿ü‹Sí¡ÜvgEEs©xµ³xHu•‡X¹ú·QŸ©ZÖÒu852ûuuIAÊH¸t`J²°ìC¸ªŒã-˜‹´QEPQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@¯á¹¸²’+K¿²NØ,9A‘œÆqœg CáÉož èï.žò8.Ú+k©UæŒ*ä°P!Ì‹;A«ú¥‹jzdöK{udf]¿hµeYŸá,;Ó4:M.ÄZ¾¡szü:D…$EÀǦyëÓƒþZMMIEë¶§kiOqè§€þ‡ ýãRh‡û7Ä:¶ŒxŠFþѵìÊO˜ÒPÍÿmoKsÄñJ‹$n¥]d0<Gq\EÕ†•§Èš_‰4'Ö,` ÚeÓio~cŒã16Ôr¥p'—’¦€+?ÅÝHñ-χ¼OºMä…œƒ$!û® ŒŽy3ÅuW^(Òá±¶ºµ›ûGío²Ö;%iÎ2vàãrI æ¾N׆¦üA™µ6Iô²CÇki±+åT«D„1“»®ê÷o·…î2›Ly?´ßbÛ!ósö;ž]Ùø(ükÐ/l,õ+Vµ¿´‚êÝþôSÆêÈv¨Š[÷PHìz×¾øbÀØx‹@Qâ‹ÆúMöÛ©]x–Ó‘þó7JηÀÆ·;[½2ÊúæÊææÝdšÊS5»þíÊ•'߆=}P*Ðtèõ_í%…þÒ ÌÎcFo¼Ë;ŽNXNNO&´¨¯6죞Õ4OZh–‘j,l4èDMöé-ŒQà.Ï4:¶UÎsV Ñ4;›2ÖÐBö·Û+C!ØaŒ±ˆ!S´»W‘Ï â[HÑ,b¿Ö$¶DŽ`-Úr«ûÒY¸S‚Ã9É4Ï Çi‡ 67v×pI$³y¶²ˆ³ÈÎáãhfe€bž¶¸[èmªZ¬p96³µÌO$Îïæ²4eÙ˜’çk°ù‰ê=-ÙÙ[éð46±ùq´²LFârò;;ž}Y˜ûgŽ*Å7`bxoþC>,ÿ°ªé­t5ÏxoþC>,ÿ°ªé­t5êSø¡ (¢Š° (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9ý ÷¾#ñ<ÿÝ»†Ü}Þ6þrè+ŸðŸï-µ[¯ùïªÝã’¿ötQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÏè_¿ñ‰.û ˜­ú¬p£üzW…&¥þ•ãmתÚÁqzÞÍ…‰?1,Ÿ•/ƒy¡ÉxzÞ^ÜÜgÕZgÙÿޤÒÿÒ¼g¯Ýõ[d·°_bªfoÏÏ_ûäzPCEPEPEPEPEPEPEP?âkíoLµŸPÓŃZÚÁæ´3#´·, ýÚ@BF?6Kc;±Ã;¼¨Ñ71fÚ dž¤ûÖ.³¥ëWÚ…´ö­½´+Ÿ³]X4á¤Ï••:€äÏ\cv€9ßñ¬xPžƒU|Ÿ­ÈþdVåAªéVºÍ‰´»·rÈ”xÝNU•‡ ƒY_ðj#ãtÃʲ?Îß5ÍZŒ§+¡§boêÚF‰cþ±%²$snÓ•_Þ@ÚÍœÈÀÎH¦xV;Hü=±»¶»‚I%›Íµç“ZѤàÛbnâØßÚjvqÞXÜÅsm ÊKSøŠ±XÞï$Ôt›‰4IÎ^kp Lé¬gå¯ è¡OÝé-åxžÑ-S8]Fß/jÃÕÉæþ÷ËþÑ®-ØäIcY#uxÜVSAèA§PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP¦—­Câ¯î5[‹I‚CöYbøQdóvõÁ'f[°1»EcxƒWšÂ(,ôøÖmZùŒv‘·Ý\}éý„'×ÔŠ£¬Îþ ÕÃVŒëlŠU¸FÆÄ<¬ ¼ã¯¢{²ÕYôM']ñ«Ú_i–Wv:N›pÁ< $q¼®IÂ@!aOÁ«¡Ñtˆ4M5m!g‘‹&žN^y–v>¤ÿ€àVw…‡Ú'×u3ÏÚõ)û…ƒMÑ1üMy\ |1¯øæêMZî+2gK}/K´k{p#à ›`WpÜ}8ô”ø£iqÛIá»{}öÛ!.a€9‘HÁIsÌŠzòrRNßVñlÒÚjQgM!¤Ó§Xä—c)7fÀ¡Ô|ß1oeÏOI¤Õ˜ïØ<_ÿAÝÿÒÿòU`ñwýt?üKÿÉUÑQQìaØwg;öÐwCÿÁ4¿ü•GØ<]ÿAÝÿÒÿòUtTQìaØ.Îwì.ÿ î‡ÿ‚iù*ìÿ½¢í£KŸý)®ŠŠ=Œ;Ù›¢é £Ùɸ’æâyZ{‹‰ ,‡œè Ò¢ŠÐAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEKY»û‡¨^gg¶’\ÿº¤ÿJÌðGÍàí>ùùWºÿ¿®ÒìÕÐVg‡m>Áá&Ïû=œ1cýÔúVQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEOW¾f‹~q‹[y&9ÿeIþ•r¹ÿþóÂ×ïe†Ë¢YR3ú1ü(ï†ìN›á*ųºÞÎ(›=I'ß5KÁ¿¾ÑeÔ;ê—@ú£HÂ?ü†®x’ý´¿ j—ÉŸ2 Y0:— võ8cH°]/F±ÓÓmmã€cÑT/ô  ”QEQEQEQEQEQEQEQEQEQEQE„R¬`ƒÞ–ŠçÃ2iÓ5φîÿ³Ù›sÙ:—´“×äÏîÉõB=Hj}·Š#Šê;rÙ´›Ùd~kî‚vôŽ^?ì­þÍt Õ¥½õ¬–·pEqo ÚñJ•‡¡ƒ@Q\òx+G‰E.±kÂǵxˆ£Ð(”=‡¿ð†éóõ®àö÷ÿPAEsÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõtW?ÿn—ÿ?Zçþoøõð†éóõ®àö÷ÿPAEsÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõtW?ÿn—ÿ?Zçþoøõð†éóõ®àö÷ÿPAEsÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõtV‡qqa{7‡ïå’Y!S-•Ä®Y®-ó˜žK¡!XžH*Ç–5¿@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PH$àP=WS¶Ñ´ÉïîØˆa\£,Ç UØ’É i·Iµ­UÕoT;…¬C•…O¶rÇ»zKÿ„§VY”gH³sýœ‡¤òt7zB{e»®:НyŸ§\ÞÌq¼O+ŸöT•gxJÒK ipÎ1qöt’n1ûÆŸÿ&«xÝ·øb[÷µ¡°ÇªË"£þHXþÑPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX7$ø+V„n 6ÃþÚþÍ[õÏø»÷–}·ü÷Õ,Çà“,‡ôŒÐ@`QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW?â/ßê¾²í& fqþÌqHÙÿ¾ö~uÐW??úGÄ $ê¶zlÒþÔ²"©ü£qøÐx·3Ûézhë}©Aª‡Îqÿ|ÄÃñ®†¹Ûßô¿éPg)eg=Ó ôw+~žmtTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE•¯irê6qËfë£hþ}¤­Ð8ê­þË «{õ¦ÑõHµ2;ÈÑâbJK ýèdS‡F÷úŽ*ýsz–<;¬ÿm'˧^QQÒ7áR§Dom§¢šé(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ªZ–±¥èФڦ¥gc¶Õ{©Ö%c×±5™ÿ ߃ÿèkÐÿðcÿ@ÏÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ@ÏÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ@ÏÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ@ÏÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ@ÏÿÂwàÿúô?üÃÿÅQÿ ߃ÿèkÐÿðcÿ@sZ»¿ˆu'ðõ³²ÙÄÕfC”Œ‹p¼Ã½ú°!·^0ÓµņuM;RÕgùb[{„™aå)᯹ŽMléT>œ–|òK!ËË#³±îÄäÐî㺋N1iil“¨TˆL@輜 à gduô ëûÈï¡ÔD =Ñ·óíФsˆÛ•K1,TÇ”<ÕÍR Û2xtëÔ²»uÄwš#9äìÈÏïùô¨tK+Í?N×·“º±ØÖ¶Ï í÷ #’ÙÉ-žsëÉÍÖÿÒü[ừϨ8ÇhãòÆàSƒøWG\åúgµkŽ ÙYÁhžÎÅ¥ÐÅùWG@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@sú÷ï|Aá‹~ÂöIØ{%¼£ÿBu®‚¹û¿ßxÿKNÖúuÔ‡êÒB«ú ‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¹ý'ý#Åþ"ºëäýšÈÀc2ÿízè+Ÿð—ïlµ+Óÿ/ZÓçÔ$†%?ŠÆ 6.¼Oâþ¾\Ø£z¬qù‡ð)˜}EtÏø,ùÞ‚øòu %¾ÏªË#:þJÊ? è(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦M W0IѬ‘H¥d2‘‚ôÅ>Šç|?4ºeäž½‘­Ó̰™ÎLöÙÆ îèHSÜ‚­üUÑVV½¥I©ZG-£¤Z•£ùös0á\6·û, Vö> TÚ6«³¦Gv‘´O’“@ÿzáѽÁ{õ¿EPEPEPEPEPEPEPEPEPEPYÚÖµk¡Ø‹‹€ò;°Ž x†é'ôDÉü€œM;XÖ-tKus½‰aPÄ»¤šC÷Q»þ¹ÀÖv£Ý=ñ×5½©º•†;£²ŒÿË4=Øÿ÷è0íG¸ûQÖµ«Ì›Uå-#<ùQþ››«èÔQ@Q@Q@Q@Q@Q@Q@U oPNƒ¨êG‘im$øÆsµIþ”›áßÙê:‘Îoõ‰A=ÑÉCô)ŸÆºÍðöœtŸiº{}ûkhãsêÁFOârkJ€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ çí}ñS~Öúm´cêòL[ôT®‚¹ý ÷¾#ñ<ÿÝ»†Ü}Þ6þrè(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠŠætµµšâC„‰Øû“\zÉ>‘ðyx½m-väã÷ò¯øûÖ¿]—Áš¬hq%ÄÙ£Kû±ú°¨|Lªí i(0·:”D¨ì†ŸòÌJ?@¶V‘ØX[ÙÂ1,IôPþU=PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP95m6-J=6MBÑ/ä]ÉjÓ(•‡¨LäŽ=+Q_øGµ£­'˧]•‹Q^Ñ¿ÝIÿ’·û;OD5OZÔ¼9qât¿ÓmuymwpTŽWteh”Awm¨¼gåÈã*[41\A$F²E"”taÊF#Ò€Esúòé·²xvñ™Œ æXLç&{q‚{º÷ £ucŽ‚€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ¥ªê¶º5‹]ݳmÈDsÊç…D_âbz 5]VÓE°{ËÇ`€…TEÜò9áQrÌO ÍÒ´Ë»»å×5¥ {´‹[@Û’ÍQž†B>ó~Œ’iMÔ÷ßÛšØS¨2•·¶rXÆzªžî‰ûôw袀 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ çü_ûí*×Ooï­íÈõMáä÷íº çõô¯è–½VÖ‹æöl,Iù‰dÿ¾MtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÏøO÷–Ú­×ü÷Õn¿ñÉ _ûNº çüóx;OŸþ~Uî¿ïë´Ÿû5tQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsþ*ý÷ö-üýj°qÿ\³?þѦL~×ñÖ.«§é²LÃý¹¤ §òŠOΟ¨ÿ¤xßD·ê-íî®Ï±ýÜkù‰ò5‡Ò¼CâmGøMÜvqŸTŠ%Ïþ>òPIEPEPEPEPEPEPEPEPEP6»«ÞiÓéÖšu”wwÓ4j³Ü˜cg,X#Ÿáþ*ƒíž0ÿ ‡ÿƒ™¿ù’çý#âðÚé×°ÿiä‰TþK'ç] sÿlñ‡ý´?üÍÿÈ´}³ÆôÐÿðs7ÿ"×AEsÿlñ‡ý´?üÍÿÈ´}³ÆôÐÿðs7ÿ"×AEsÿlñ‡ý´?üÍÿÈ´}³ÆôÐÿðs7ÿ"×AEsÿlñ‡ý´?üÍÿÈ´}³ÆôÐÿðs7ÿ"×AEsÿlñ‡ý´?üÍÿÈ´}³ÆôÐÿðs7ÿ"Õ‹Ÿ[Yjº…­Øò ²´·¹iòX±šIP P2NbÆI.´ŸÆúaºÒ ¶Žîs|Ö-þ‰2µ»¬M'ï¦Tð¼6>V-÷Uˆ—íž0ÿ ‡ÿƒ™¿ù¶xÃþ€ZþfÿäZ·‰t™–é…ÑHíb3I$ÑÙãúhø9›ÿ‘kB-oO›Sm9%´ €L.#b>ò¬„lfåA$`äqT?á4ðþë o˜}šÚkÉ ·&"ȧnA`2¹Ï8Îíž0ÿ ‡ÿƒ™¿ù¶xÃþ€ZþfÿäZ}׌tK(ã’âætGO0“i1òÓq]ï„ýÚ§ Ø ‚G5 §‹íï5Ë-`’'ƒRþÏÝ U4ñ¬QKø/[WÀÜ{"ö?h¤ÿ„ÂÚÛ_NÔ´ŸW¹ƒ|CþÚFYâE;þ¿‘ÿ#^‡ÿƒ¿øª?á!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"øNüÿC^‡ÿƒøª?á;ðý zþ aÿâ¨ÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Añ¦AÁšï?ôÚËÿ’(ÿ„ïÁÿô5èø1‡ÿФox@©Åš’8?ÚñÿPŠÉñÅñî‡qk.«gûb¶»d7q©Á æDΆqÎãô¾rÿß"º çüûí]@õÔ.çºÕFÿä0”ÐQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEGZ»û…¨Þgg¶’\úmR¥GáëO°xkJ³Æ>Ïg XôÚ€J£ã›ÁZ¬óóÙ¿ïéÿìÕÐPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP=jË/Žu{† Gico'³•ßô1ÑàxÛþ +—R$¾ß|ù9Ú^~›ñøVìòÂ/ã+ØN'¿½’Òôm©j¿øúŸÎ»‹h#µµŠÞ%ÛH €%¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ŸÓÒà›![y 9¬-¤¹¾¹»·%¢v ‹”Lç ` V¾× ѯ-TÚD‚êÊæÎÄßÍÅb ýk¡ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Åß¼²Ó­çãT´õ *ÈHÍtÏëß½ñ†-ý/%¸op¶ò¯ó‘Oá]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE„…RÄà’M-cxºé¬¼¬ÜGþµlåòÇ«•!GæEsr›¯ø:ØŽußí9AôýåÖïáó¯@®bÎÕÆ6¶qó£ˆÇÖg~8·?Ÿ½tôQEQEQEQEQEQEQEQERK€I4µâ»¶±ð†³r™ó#²˜ Kl;@üq@x%Iðn›9k¨ÍÙó1”ÿèu¿Uì-ÃNµ³Lm‚$ˆcÑ@Ò¬PEPEPEPEPEPEPEPEPEPEPEP\Åî¡wâÉtv‚Ö&Ù}©ÇüuŠÞOVèžíÀK›Û¯ÝI§éS<Tlc¼Ôc8i81@}z†~ÝÍ’½ ¶Ÿgœ ¼*8ã =¨º~Ÿk¥ØÅee Åo¨çÜ’O$“’Iä““Vh¢€ (¢€ æ›O–ZIi¨ßÍ#<’ßG5Ë4KV¢?º‡~ͤHGÉ<×KY¾Ólµiu8 òÜK+M"Bs; b/³§O—Œ c€5袊(¢Š(¢Š(¢Š(¢Š(¢Š*–§¤Xk,WöÉ0Cº6å^6þò0Ã+{‚ ]¢€9‚ž!ðñÌEõí4Ë7e[ȇ³,£Øíov5¯¥kz~³µ”û¤ˆíšR’ÂÞŽ†Sõ¡Y:¿‡4ýeÒyD¶÷Ñ E{jæ9ã‡QþÉÊžàеÌÇuâ}Äv_·ÇÉudÑC8ö’9Pÿ¼­ÿ7ü$:§ý šçýþ²ÿäŠè(®þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’( ¢¹ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH ‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"€: +Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè(®þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’( ¢°­ê%Yß(ÕÑW3â“þÅ+b+su¨H{Ž#Oýÿ  ¼9þ“©øƒQê%¿ò#?ìB‹÷ðIù×AX^ …âðŽšò©Y®c7rƒÔ<ÄÊÙ÷Üæ·h¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Æ?¼Ñ ³nïí`#ÕLÈ_ÿ ]súïïüEá«^Âî[¦ª:ÿèR!ütQEQEQEQEQEVÞ5ð­´òA?‰´h¦ŠIßĬŒ ·Õü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtMr²ÜMã)ÚÆi Е¸¼Š½é8ˆäGÙœuè½Í0¼¾7%"g‡Ã@á¥Sµµe=D>§«öùynª(£‚$Š$XãE ˆƒ@èì(¶ÖðÙÛEmmCJ8Ñpª£€ì*Z( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( wÆhñhCU… O¤Ì—êrU2%ÜÄÒ/ã[ë,o Ì®­.ààðG\ÓÑ‘Ô2°Ád\Û'Ó¾kXsöÝ0I¥DXòKamÏâ’D~¦€7< ¥ü'mzÀ‡Ô[󑃉¤iòVQøWEPÙÚÅce¤#lPF± ôUʦ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( BýïˆüO?÷ná·E·¿œ†º çü'ûËmVëþ{ê·_øä†/ý§]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEç¾/v¹×5h#bi0ièGg½¸1þxE5èUç‘ÿÄÇÇsʾ³’=b¶µ_å4¢€=cED*€…:Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬høƒqe¥¹>ÆiWú þµ¿\þŽ<ÿøŽï9òÚÚËþøÍÿÚæ€: (¢€ (¢€ (¢€ (¢€ ÃñN¥qg§Gg§°¦£'Ùm8ÎÆ –DPÌ~€w­Êæt/øžë—^#šÖ0Özh=<°ß¼”¾ë€ºŠ{ÐÖ•¦[hÚU®h¤AoEÉÉ8êIîIÉ'¹5rŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Ä–òEñD´Ñu©£–~xZn•N?Úùý³ß×ã14Þ"…¸f—Ö+¨^­æKóêLPJ¸ÿoÞ€;ú)‘J“D’ÄÁãu ¬:yŸ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@U rïìÔ¯3"ÖYï”'úPw‚>oéÓÿÏÒ5Ö}|×i3ÿWAYÚ§Ø<9¥ÙãE¤Qß(ô­(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Ï<>ß­\_žBÁ,êÝyº¹’L~ÅàEvzõÿö_‡u=C8û-¤³gýÔ'úW=ðâÃìz íŒfqn¾Ëo[ãþú‰âh±¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(®Â#ͲÔoO[½Néþª’”ÿß1­nO2[[Ë<‡Æ…Øú2kÁ°5¿ƒ4ubW´ŽY?ßq½¿V4¹EPEPEPEŒÊŠYˆ I'€(Å˾‡c)Ž÷Sc˜§˜`ódú…!GûNµµkm •¤6¶Ñ¬PB‹q¨ÀU°|4§T¸¹ñ,Àÿ¦’·Tµ_º~®rçØ¨?vº:(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+žÐou/^:nIo~Ê›¹8£T#é¿ÍüëziRdšV jY˜ödšÅðdl¾Óf‘JËu¼•OPó1•‡ýôæ€!ð[4<º<™t{‡±äòc\4Gþý4Žk£®mÿâWãøß¤ͧ–}<ørGâѳ~WI@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@sþ7ù¼ªAÿ?1 _¯šÂ<ãÕÐW?âßÞYé–¿óßU´÷Ä«)ý# ‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠÀñgŠað†˜š¥íÄúzÈâ[p €ÅN2¹ààädpjoø·AñM¿¢ê–÷` ²#aÓýä?0üEcé+­x—K¶Ö[Ä7št7±‰ííl ·*‘0ÊnicrÍ´‚O'¥@eVµÔ&µø‡¨]>7{ˆà“M-ÐI L !àýâîEiøþI÷†¿ìkÿ¢–¹ðδº>»¦[iSCjú5Õ¥¬73[ÉåÊã ¼‹‡ò7„÷®i&Þ¥X݆kkLéüMº“PVd6©&œe ¹Ü63‘ƒ‘Ž0jkXôi%§ÄMBáS ´GOpÒI@D°œuÀ5[TµÕµË½bÒmöÜËk=…é–!£#Í IænfÀû™Œ±5WDÖšËSÔ:ŒÚ’5´–‰¨ÍjV™¶ª(`Ì›˜’Açhi/æ 5›£]jãÍ^h-Òf+ Ø3;D¬Î‹ûŒŒñƒœ`Õˆ!k¨nf·ø‡¨K«¸x̓,$rC‘ÊG|×0ÞÖ-ôÝkNŽ!=¿ö<ëf|Åmäð,ru<|ѳdà~üúq¿¬ørúâÿV}=ZÖ)-4Ñ–þXbÖ÷È衾PvpÛór¡Ô—ó‰E°Šý¾#ß )‰\Óü· B·‘ƒÂ±ã²ŸJ™,æ—P“OÇú›ÞÄ¡ä¶Q`dE= _³äG5COÐu6•ssã°ÖÞú·KnÒ"}ŽH•ˆ…Uͳ…ÜrwÉÂ麫o∞æ]J[H/n¯ÚKe¶S&ÕPÌÄ !ˆ\Œ‚p/i/æ v㆖LtEüØà¼M®ëCH¶a€Ýj,c³´S†™ñž½”Y»Àh:!ÒÒk«¹…Ö«xCÝÝcˆèŠ?…¢Ää’H8<f!_µêzíÍÁ–o틨·±êB$Tg²€Iÿn—ÿ?ZçþoøõtP?ÿn—ÿ?Zçþoøõð†éóõ®àö÷ÿWAEsÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõtP?ÿn—ÿ?Zçþoøõð†éóõ®àö÷ÿWAEsÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõtÁÏ{%÷ˆÒÛ›Y®5Ø¡O²@’Í)û ±7åáIË0§Œ@çü!º_üýkŸø=½ÿãÔÂ¥ÿÏÖ¹ÿƒÛßþ=\=¶¹ªÌÖ"kÛ™ç´Ñµ²¶Å!Ûpmî#Dݰ™€Bv62ƒn`ÛCVñöN¹Í5µÔ)nÖÒê“Y ·Hä2b(2\rÍÎà({þÝ/þ~µÏüÞÿñê?á Òÿçë\ÿÁíïÿ®^«íRûÃ^~­¨¥Å¦¿-½Ä3Ãn²)rɲBŠQøà2meé¸#Ôoí5ÝR=>â;iŒZ4I7ŒÊ&¾–'É#,6ž8$`’hcþÝ/þ~µÏüÞÿñê?á Òÿçë\ÿÁíïÿ®jFÔçñ6•gs­]È4ï5ºÉå­29§L&27²|¡~V?Äé~,×Ηu©\Y]åôYu4‚í­@ª©T…bo0Æw0&A‘…ÉÅtÿð†éóõ®àö÷ÿQÿn—ÿ?ZçþoøõswZ¶µgw©XCâ#xcþÇò® æ3svÑɪÊcèïóu­zÿL×-á·Õï®D:…•Œñ›hÞ´a„Œ@v¬›Ç—€2>\hþÝ/þ~µÏüÞÿñê?á Òÿçë\ÿÁíïÿ®/L¾¾Ðmçn$Ôf‚ÛÄW)öˆ£Þ^+ȨdE 1Ë8%½Bìjž³§Å}§Á­=Ì«.–b¿’‰_´ÝyN›UBr8ίC@¼oà ­WB:^ƒq¨$×m²{‹ÝjîH¢‹ø¾F‘ƒ“Ó×8â¨xOàG‡|=$Ww×7züd2ʲµº#êƒù±®ÛÃw¯6µc{x÷‡O¿G<ˆŠì2Á\ƒ)p~kz€9¯ÿÉ>ð×ý‚­ôRÖýsžž6ðV‘hMŤVw1çæŠXÔ#«Ä5Ñו/‰–QEHÌ3­jë–ÖwšRÃgw<–öó‹îYQŸ,pªÊŒAÜO@@&·+Þ uüJ÷7ÖZkX©t·–;Ç2E|³ ±'§C»~›QE†sž7y"ðìrC šUÔ´öHƒ.Eä8\žzdÖΗ¬ÚjË ž;ˆHÛL»%„ú2öö=PH®wâ«m§hp y…õ­ÂÁÝ#¤3¤Ò½p69ö­ÝGF³ÖV´‘¡»E͵õ³"ÏÊ{©Êžâ»ðß Õ¢¹Èõë­U¶ñ*Ee‚ũ·žÁÏ”ßRTölœWGÔdW@‚Š( Š( Š( Š( Š( Š( Š( Š( Wýÿ‹ü;k×ÊûMî?ÜŒEŸü˜®‚¹øÿÒ> Ü¢ÏKAô3JäÊý+  Š( Š( Š*®¥¨A¤é—7÷Dˆmã26Ñ’qØäô¹4‹­ÿÄïZ¶ðú|ÖÑ…¼ÔHéå†ýÜGýöRHþê0=Et•‹á­:âÎÆ[»õS¿ÜÝàçcÆ¢(U÷Á=ëRêêÞÊÖ[«©£‚”´’HÁU@îI  «˜—S»ñ4òYhr½¾œ¤­Æ¬˜;ˆ8)x'ÖN@í“ѾMç‹Î륚Ë@?r”šøzÉÝ#?ÜûÍüXSÓEpÄ‘D‹h¡U`(…`Gà/¤a[ÃZLÌ:É=¢K#žåf'¹$“Nÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚Šçÿáðý šþ ¡ÿâhÿ„Áÿô*hø.‡ÿ‰®‚ŠËÓ|5 è÷-q¥èšmŒì… ¶¶‰$e@8È{ Ô¢Š+›—þ%ž?†Nk†ôóáË/âcgÿ¿bºJÀñ”2µü^çL•/â«yg.£Ý“zÿÀ¨~ŠŽ £¹·Žx\¯$Å¿EJè+ŸÐ¿{â?ÏýÛ¸mÇÑmãoç! ‚¨k½¶‰`n®w¹,#†Æé&ýÔAÝø“€ ©¯ïí´Ëo.äÁË62}rI8I ÈÒ4ë›ûõ×õxŒw[JÙÚ1ÏØã=sØÈßÄ{”p hšMÄw2ë¶ÇÕ®WiU;’Ú<äD‡Ó»7ñzåPEPEPEPEPTît6öáºÓ­'ŠáÄ“$°«,®PÌ䀪2{éW(  QédFÜǧZ!¶gx À£ÊgÎò¼|¥²s޹9¦ÛèšM¥”ÖVÚ]”6“’f‚;tTž»” ûÕú(> H·³‚Î*Æ;X%à [¢¤rê `0<äsR&“¦Æˆ‰§Ú*"DŠ¢V&ÝpŽT äb®Q@%ÒôùØ´¶6Ò1nIxTŸ9@ 'O¼¨ Ô=)‘i¯w-•¥½ÅÞLÓÛŠîÜüÌqóžù«ÔP?¢x;KÑ#œ" –£gi …îØºa#DAµØ°!s“œç¥>‹¥]_-õÆ™g-ÚíÛ<+H6°eÞ=¯Q@!Òôûk—¹‚ÂÖ)ägg•!Uf/·y$ ’Û>»W=2ÛEÒ¬íM­®™e¹”LbŠT2 cpe¹ö«ÔPqÁ /3Åhó>ùYTí´.[ÔíU=€ªJ(  ­CÂþÕ®~Ó©hZeäøÇ›si«j§ü žÿ¡SCÿÁt?üMtP?ÿ'ƒÿèTÐÿð]ÿGü žÿ¡SCÿÁt?üMtP?ÿ'ƒÿèTÐÿð]ÿGü žÿ¡SCÿÁt?üMtP?ÿ'ƒÿèTÐÿð]ÿGü žÿ¡SCÿÁt?üMtPfŸáÍI27FӬ̫¶Cmj‘ï‡h›ák½ðÜÄ—Òœ-¹'%í_&øÑýc5Ò×3â04[Mñ $Mö+â;Á#ÿ¹&Óì ÐI$i4mˆ¯‚¬¬2=AÎ6•¨øw÷šúNž9m&WÆÁÿLýß÷åì WKEgi厷 i# !m“ÛÊ¥%¿ºèyô=FEhÖF¯áëmRhï#’[-Nˆo­ˆ(þéÏ¿ì°#ñæ©/ˆæÑO‘âŸ"Ñ ©©Ûk/ûÄŸÝ7³ÌzPIEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅPAEsÿðø?þ†½ÿ0ÿñTÂwàÿúô?üÃÿÅP þÿ_ñ-ßo¶Gl‡Õc†2ñ÷qøWA\…Y4}1g˜Ï ¬ÆR3#¬jJ–L€X 9#•aJ¼+n4‰ÿá;ðý zþ aÿâ¨ÿ„ïÁÿô5èø1‡ÿЬø|^cŽÞ±¼Ô¯¦{ÐÊÝ#[Oå?)’0K|ÞÄ…¨õßÃgá«OJµžõÿ²Ž¥ÁH‘‘ŒM(,­µŠ‘…É$à ÖXÊ6­<_á›û”¶³ñ‘q<‡ 7±»1ö²j•ñþßñdZüÖIK»ÃÙç<Ãüýa÷òýk_QÓ­5[ ¬¯`I­æR®Ž3øû~ÕÉxSSM#Á"@’êZæ­j—ÏÿžY$PÍ$ü2ãØ8¥*¾ÒúV:ýWW´Ñ­D÷nÙv Q®é&sÑG,Oÿ\àk*×H»ÖnbÔ¼@Š«µÓŽÙä=$“ÿ^Ù?1³¥hMãjº¤Ëy«:•óBá Cÿ,âS÷WÔõn§°U°‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š+&ÿÅ>Ò®M¶£¯ivs“Åäq°üƒ@ÔW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿGü'~ÿ¡¯CÿÁŒ?üUtW?ÿ ߃ÿèkÐÿðcÿZZnµ¥k1¼š^§g|ˆpík:Êû•'zŠ( Š( Š( Š( Š( Š( Š( Š( ±µý}t/°ƒgqr×wpÛæ5!"J‘ïvÆ ƒ©íÆHÙ¬½M›UÓ¢·£WKÛK‚\6Åq¬8¨@÷ÇN´&µ©#K{µ‡Ï“ÌŽ¢ß°<’:Æ€¶fàâ¢Ñu9µH¯"¼´ŽÚîÎàÛ\EÞjgb¸!Š© «©ä´Ïi÷º®Ÿ5µºÛ«Fö÷6Ï$†–)„›\ár‰È$üÇ“@Óïm£u¨­º]êi’;yÒ§.ç!cd-|W©Ë·• ¶–çz¦Õy<Ë‚ü÷o˜ß‘ëY:ñ–fÕ<›[Ù­¤ÇmlRÙÎÙ3/ßã÷ëTüØè{Šô_øWúýE¿ðuyÿÇhÿ… Ô[ÿWŸüv¡âãkXµ†•ïs*ŠÕÿ… Ô[ÿWŸüvøWúýE¿ðuyÿÇjþ»Ä}N]̪+WþþÿQoü^ñÚ?á_èõÿÁÕçÿ£ë±ìS—s*µ>sáÜr²^Þȇ³+]JÊG±ƃðûÃÍÃǨȧªK«]º°ô*e c]$Eko½¼I1(HãE ª `@+ž½uU$‘½ ›m²J(¢¹Ž€¢Š(ªZΤš6‡¨j’!xì­¤¸eX"–#ô«µÏøïþIç‰ìuÿ¢š€ ƒG×î!I¯|U}mpà3Ãcol"ŒŸá_2'bL–çÚŸýƒªÿÐå®ß›/þG­Ò@“€:“TF¹¤6˜Ú˜Õ,Žž¤†º å9|ã¯kÍöµRìŠØ:¯ýZçýù²ÿäz?°u_úµÏûóeÿÈõzë^ÑìmâžïV±·†d2E$·Šè1–RNù—‘ýáëNºÖ´«íà»Ôìíå¹ÿQ³ª4¿î‚~n£§­Ö§p²3ÿ°u_úµÏûóeÿÈô`ê¿ô9kŸ÷æËÿ‘ëQõ;µôù/­’öU/³J¢GQÔ…ÎHàÕHüG¥<ß\ÝÅen.¦´w"Æ ‘Êñ 8å‘܎ݨöµ;…‘U´-aT˜¼c«—tMofÉŸp°)#èGÖ ð]̱øwPÔõg‚^þéîN#S˜˜‚z/î^ÕÓuÂxgMº×Râ+øü½ËW¿t‡9ûl¿l•ƒ7ý3BxSÕ†Og£RRm6&½> ¼Iµ}G§Bwé¶’. ?óÞ@ˆº§îƒ“ó/MEÔHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETÖpj6WQ‰-î#h¥CüJÃ~F§¢€0¼'y<ºSØ_HdÔ4ÉMÞ²¤Ÿð4(ßV#µn×7¨Ä›ÅÖZ˜â×SU°ºôŒ˜ýIt÷.ž•ÒPEPEPEPEPEPEPEPUu+ÅÓô»»×ÆÛx^SŸER¥Z®ÆÄ·ƒõ qÖíVÌ}fu‹ÿg  ú^£cá_ hvš„²‰E”clVòLìU{E$O'ëU5ßh¾9Õ,µ}bê[ý>(³´ŽMá°K’¼±TÉ.ÜduÙŒöÎyéYž;¾µµÒôÛiæTšïXÓãY]D䢩?…tuÅŠÒH¤`ižþÎÔíï>׿y?Ú'—ŒýªågëŸáÛ·ß9ã¥dÜxàømt‹Ma`ó4hô{©š×y•#FUeÆÓ—|Žr uµÕÕ²Çk¨½ß™&Ž4wÙƒÂïAÎ9!¸Žr+ørâòëB‚kçó&- Yv…ócÂ9Ȉõ=«g¸ÍZæ>i6zw€ôIíã>}ÞŸm,ò»w>RàdÿЕÓ×འQ›À¾•ú± <qÅzyG„£_øEô뢠Ü^[¥ÕÄŸÅ$’(fb{œ“Xß ¾0øƒXX¬õŸjŠêZu«>9ÆdP1õ#JÜð—ü‰šýƒíÿôZ×n âg&3áDþ"ž]êriÞ\3y&σç‰X,{¸Ê²ç‚n§'ˆ®ÓÉ·]:7¿kãe$"ç÷hÞI˜0}™+´/ðƒÉàã̶‚Â[/µ]¼g’¯ "Ü!Ü‚1Œ §“ÀÉ ’ žÞWžâiáº7m4…wK!‰¢Ëa@ÆÆÆt~=¶™Çxì¼Esssd³iË 7WÚy‹q¼¬ñ‰ mOÝ8 œä—œÕ{jz„M‹ ËgöËdkÞ ›·Ÿ/úÅÆÎyÛÎ5¢Ñ-¢û.×”ýšòkÔɼ¾nàxéûæÇ~'œ–:%µ‡öo”òŸìû3eâ>d>_-Ç_Ý/LO…§ßúþ®c5üWºÆ;ëk-öËa£rd—cE †#hîl#ñ‘Ó¯5$þ"¹‡Q¹‹û9ZÎÚö )'ûFt¢=¤&Þ@2¨<Ž9èÿ­˜²¶´K‹¤‚+Hì¥PWý&“+îßwoÞ5n]Ú_µnyGÚo!½|ÃÅåmŽŸ¹\÷äò8Ái…àg[x¨K­^XϽ¼V­'˜Ò]…•|ÖŒˆÏf zŒÎ-\ëáÍ¢èñCª”’U1\¨CeUÊ· ¶]@ ç$b¤gW‹P’öò_%ÞH`‘Ô¤là© íÝÐbx K©i1êRC)¹¹¶– È$·p¬Q±¹3ƒ€v¯#``Š-;»r­ÆºðêD-U¬à¹ŠÒyüÜ:Ë&Í &ÞGï'#¯CŠÍƒÄ7MçÞÌZÖ(µY¥%`¹TNÝ‘ïß&¶&Ðà›P7FyÕTžKu+åÉ"ck·²6¯BÊ2)‹á»Nÿ6Dd»‘ÈÃ-Ì‚IÀõÝsÖ†§pN% oAsixÑ ;›‹v…lïѹ™öF íNî£yªúν¬ØÈí#·‰t›Û©‘.pñÁBc ýáŒõIPWiÙ:ËiqΡ}rÓ20–GPÑ; U  ã'9¨nü3o}jÏ{zÄ[\Z¼…Ô¼‰0÷§…#cRjmn4áqn5ׇP’!j­gÌV“ÏæáÖY6m6ò?x™9zT6~"¹¸¾‚9tåŠÖâòâÊ)…Ææ/“’»Fˆ›¾Aãæ®M¡Á6 nŒóª<©<–êWË’DÆ×n7dm^„”dS¢Ñ-¢û.×”ýšòkÔɼ¾nàxéûæÇ~'œÕ§q^6(ø{Ä®O4mi P%‘nCËÎÊ„Œy¢ªøÛÁ¶>5ÐÚÆä˜ncËÚ] ùà“Ô{ã¸÷Á%ð°êñ‡ˆ´«ÛºÖÅp‰6«/ÌÞasœ&Ð¼àŸ˜ SI·d&ÒWgÒ4Wÿ o‰?è^Òðo'ÿ#Qÿ o‰?è^Òðo'ÿ#V¾Â§c?oO¹ÛQ\Oü%¾$ÿ¡{IÿÁ¼ŸüGü%¾$ÿ¡{IÿÁ¼ŸüG°©Ø=½>çmEq?ð–ø“þ…í'ÿòò5ð–ø“þ…í'ÿòò5§`öôûµÄÿÂ[âOú´ŸüÉÿÈÔÂ[âOú´ŸüÉÿÈÔ{ ƒÛÓîvÔWÿ o‰?è^Òðo'ÿ#Qÿ w‰_i_†¯&ôžaS°{z}Îکꚥ®`÷—nU…UQ—‘DQÕ˜ž—iâû ¼?6«t²Z}žCöî7H²Œa/ß-•ÛŽ»‡­&•¦Ý_ߦ¹­ÄåAvd†hz“ØÊGÞaÐ|£Œ–Å«î.“¥]Ý_®¹­¨¸"ÖÐÉd‡¨£HGÞoÀq× ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+Ÿñßü“ÏÿØ*ëÿE5tâûI¯ü¯YÛ!’{:â(ÐufhØùšv¿a6©á½SO·G=Õ¤°Fäãk2ó5‡-­ôÖ¶ñøwìi¨}¦M>)a2\/ÑH!7ÊF[¤kÈ<MÔ­5m>ëÒky”2²œþÐŽãµZ¯)6´,ã´]ëi7–‰åEo©³«o!®."‘#÷Âo\Ž>R:œ)ü3­[èvºTÇS‹F¶±œ‰­ÞdÅsŸz0Iù£%¹lvϧQO…Ž>ûHÔdÖnáŽÍÞ+ÍNÒýo· XèÈ-¿'Ê|`ûÓ’9¬ùü?®Ah#Çsª‚Å­KÈ·~dl|ðSnÑÏñ ÃÜW QKKG³m?CÓ윱k{hâ;äó* rØp3è+3À×0Ï£_džx5F9@þ7r¶àÊÝšh­áy§‘"‰æw`ª£Ô“Ò¼÷áõôê÷æÓ[¹½I~ùn׃Ýà–6Ñ×NvÄÏK¢Š+°¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(†µ¥Ç­h×Z|Žcó“ *ýèÜr®=Õ€aî*ê’jú$#¼BÐÝD:G2®¶àqê0kV¹´ÿ‰7š>–šÚo_EºpGÕãÿÛ#ë@%Q@Q@Q@Q@Q@Q@Q@sþ(ýôú —üüj‘=¢W›ùÄ+ ®PýÿŽtH:ˆ-n®³f8×ó?äh ¨/om´Ûïo&Xm BòHÝEOH@#=èåoø»[ñÅMôÚÍegô)¥Çw"). »ñüDqØcœWЫ®ë* KàíXÈ>ñ†âÑ“>ŦRGÔ¥RÑôm?ÄÚ^¥}Ï¡©5Ì,z „ˆ¡u=¸ˆ0ÿxúšì«9ÒŒ÷Î+[¸Õµ«iÿç‰ì—xf{Y´ì¸ÂÁæ`T÷çémYjÚÕ¥œpMáŸÞH¹Ìó˧‡~Iä$ʼtàž¼×WEGÕákÎbmc_¸…â²ð¥ý½ËŒG-õŰ…«yr»`uÀSš«¢Åa j—&çLÚ–öƒ(]ŒqÀÿa»ýÓÈ»‚òÎÛP³–ÒîžÞe)$n2Æ´…8Ã`lžŠæ,o.|7{‘«\<Ö38N¿”ä“ÚO÷ÿºßÅÐüß{§«QEQEQEQEQEQEQEVf±}¨ÙD§éÐÝpÏ+Ü]‹xãUå¶±ÉíÆ89#ŒéÖ7ˆìo5+!iŸ¥ê’‚·º‹2«r °![¡à¯'2ã cÖâ—ÃvúÔv·RG<ͼq”ïjíÌÏ’Hš©gm¥xËDÑuGK‚o6Ú;¸a¸U„Ⱥ‚FqœgéWô{;7N´Óæ\%­¤1}©œ™&uX²ãŽŠs¸ä±àc&? i³hÞÒ4»†§²²†ÞFŒ’¥‘’2ÆG   5EDŠ@À`^Yá/ù4/ûÛÿ赯T¯3´ÑõÿÙÅ¥.…s¨Áh¢.m'€xMÂI†Æ29k« R0“æg6&”W*4(ªßñ?ÿ¡GVÿ¿öü~øŸÿУ«ßû?þ?]þÞŸs‹ØTìY¢«Äÿþ…[þÿÙÿñú?âÿBŽ­ÿìÿøýÞŸpö;hªßñ?ÿ¡GVÿ¿öü~øŸÿУ«ßû?þ?G·§Ü=…NÆ'‹Òkm.mJ oİFvyìŽ d™]AÔw_›ÀêjÇŒö? êsXÝ›Ya¶–S"®[ Œp§?)ÈóÆqÎ’÷FÔ5 …žçÁzÃ8P‡må²PI ánuÉ<0#“ëRÜXj÷v·vÓø;X’µd™ò×Jí ¤|£øqÎORMfêÓw÷·-RžštUoøŸÿУ«ßû?þ?GüOÿèQÕ¿ïýŸÿ­=½>ä{ ‹4UoøŸÿУ«ßû?þ?GüOÿèQÕ¿ïýŸÿ£ÛÓî§bÍ[þ'ÿô(êß÷þÏÿÑÿÿúuoûÿgÿÇèöôû‡°©Ø³U¿ækð·ý„%ÿÒ;Š?âÿBŽ­ÿìÿøý\Ñô}Zû_Óï¯ôÙ4Û]=ÞeYåä–F£Ù”(YäœçVUëÓtÚLÖ©¦ÑÜÑE垈QE#2¢–f  d’p ¢¹ÁªêÚì„øxÚÛØ'üÄ/mÚU¸>‘"º¿í“ƒØÍ?ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€: +ŸûŒ?è;¡ÿàšoþJ£ì~0ÿ î‡ÿ‚i¿ù*€5¬u;N7{¸n7(þ[‚QÁVˆ=5ÅøªÊÚ/ˆMâB‹s>™v’È.Km ý77ç^I©xgÆÞ"ø¨jžýÎ$É«ZÆöVò¸3 Îå†FÒsŒãšôi,|Ea¯h0ø“W¶Ôîÿ³¯q$6ÞVßÞZäœ7nv¯ã[Pþ"2¯ü6C®]ÜǨZZè¦A=ÃÜ:+.c1€§wNòN8^ëUîõ+äÔîeK–X­¯í¬ÖÓbí•dnrq»#Ìl`û³y­ë›;[Áº¶†q‰Km¬:ž‡Þ‘ì,ä½K×´®ã]©9ŒQè¨긷Ôó‘ËÁw«Í5«ZEKÍRîÈ"Ã"Ž39VnK9ò –—š¾£sab5Y %5–xጼ† „‰H“ŽOŒuKil»6ÛÄ<¹T•Ûvæ„îlž§qõ4Gim‹$vñ#®ü2 omÏÏûL>¤dÒä}Çλ„î«o¨Éqö“w¡M¨‹c…ŽDXˆU dƒærO c*{ËýNÎ;»8µFžE’ÀÇxñFJù÷[® (Èï‡ëÐÖý‹éw ëb¶íölÿt€xBcp1³ qÀ¸¦'ðþŸt4„·‚iQü¸íˆJHdËØ “ž©r»n;«ìeÜÞkIk{io¨4×ÚšÛ¬‡ÉŽy£0¤¥SpïËž£î©ïÍjhš´÷¶¶€ÛÝܤėŒ‘F¨ÊÌ¥Cçp+‚UJ“ÈÀé¥>cuÑ\YÛÍìT’%a#,äá@çÐzT°A ¬ ¼I1©jTz:U(´ïr\“[p»¹¾ðÕ¥ÕÖ¢—ÜÜé·ßb«[¹Œ•ã’¼`dg*Üžƒ ðô­6›30@Eõâüˆ`\Èuã“ÔžNI«i¦ØD$Ù[ ’Q3…‰Fù9ã–ž¹§Š B‘F‘©fr@˜’ÇêI$ú“DbÓ» I5d'‚´x.|C¯êwòµ¾¢«o «‰Í¤¤ûä¹=8ÆN}¹­ñ/ý…WÿI-«¯¯"¯ñ%êÏV—À½Š(¬Ë (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€1®ü!á›û—¹¼ðî‘q;œ¼³YFìÇܕɨ?áðý šþ ¡ÿâk ¢€9ÿøA<ÿB¦‡ÿ‚èøš?áðý šþ ¡ÿâk ¢€9ÿøA<ÿB¦‡ÿ‚èøš?áðý šþ ¡ÿâk ¢€0£ðG„á‘d‹Âú*:œ«-„@ƒìv×7âKy4ýsPžÙ J±Å­Û"õy ÄW =ÚàUè5Ïx  Y4_Wˆ’Ÿúc7î›>Àº1ÿr€7`ž+«x®!pñJчFR2 I\ç„ ³µ½Ð\üÚMÁ‚/{váü‘‚}P×G@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@dx—M›SÑd[BþÝ–æÍA2ËŸc§ÙkÑ@´JcHµÔmÁÜF+}ä'ªŸBA ÕÚç4‘ýâ}CG<[^nÔlý$ Ð}«ÿÛSé]QEQEQEQEQEQEÏÚ¤x÷T—ªÚØ[@¾ÌÏ+·éå×A\ÿ†ÿ}¨xŠó¨›R(§ý˜âŽ<ßJÿ™ ‚²k èki—k£wÿ ŽA  TW1¦êz£…¬ÊóE)Û§j/ÿ-ÿ锇´ ñž¹ÓÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE™«ëpé~\)—wóçìöpã|˜êNxUØà©€Z¿Ô-4»7º½a…p7¤ž€É$ðäž•ˆ–~&+>± Úéy šÇæ›Ñ®1Ûþ™ôþöz ~‰,—©«kR%΢ ù1¦|›@zˆÁêØà¹äó£å­Ê@€´Q@Q@Q@Q@Q@Q@Q@÷…ïõ[Éõصv·ó­5ioÊF†Þ† ÁüÄ ú€3oõ]Q5‹ë¸µ #´°Õ¬ôãd"Œ¤«0ƒs–+¿p7`>N‡5ÑŤ¥»j²[ÜÏÚ”¾sÈ»I‰ü¤ˆHàF§æ Î{qTî|/ms¬A¯o7š+‰lѓɖXÀí•Ý‘µ:0bäPÓ2EweDQ’IÀW˜ê^)Ò|GãË´›ŸµGeey—ŒÄÎÏlv«tbÉÇŠÅø¿ ø‹]k›[ÏqÏy6— 8£…A »†Ë3©8$` Öøià+&øY¤%ßäìu¸¶IH0$Ah ‚¥]9rMI‘R<Ñq6(«¿ð‚IÿC^¹ÿ|ZñŠ?á“þ†½sþø´ÿãè}vŸfpýR}ÑJŠ»ÿ$Ÿô5ëŸ÷ŧÿ£þI?èk×?ï‹Oþ1G×iöaõI÷G+£Û&•.¼VÕ µ[µx’(N hGȪ2Ü« yu¬ûØçþÓ½±×L÷z¥¥ÜR¬,b ƒ~_AýËpNyµÝ 'ý zçýñiÿÆ(ÿ„OúõÏûâÓÿŒT̪Oº)QWá“þ†½sþø´ÿãÂýüU®é¶ÓÿŒQõÚ}˜}R}Ñ•ávÖ­¯¼Gw§Ç å¯ö’‰,Û÷r-mòÑÈNÒ{ml>ðç=ž—®XêÆHàvŽæ,yÖ³©Žh¿ÞCÎ=CØš~‘¤ZhšzÙÙ«„ ]žF,ò99,Ìz’Ã¥GªèVÇ–÷1²ÜC“ Ô.cšþËŽGÓ¡î yÓ—4œ»ñ\±HÒ¢¹¿¶ëz Æ¥jÚxÿ—ËX¿Ò#ôÒ%ûÿïGÏûënÃQ³Õ-îÂæ+˜¤‘0ažã؎㨩(³EPEPEPEPEPEPEGZÔ—Fе QкY[IpÈ7RØý(õç 7‰®Msâk«yœe¡³¶·!ô_2'bL“Nÿ‰ÿý Ú·ýø³ÿãÓõJ‡?Ö©ž‹Ey×üOÿènÕ¿ïÅŸÿ£þ'ÿô7jß÷âÏÿŒQõJõªg¢Ñ^uÿÿúµoûñgÿÆ(ÿ‰ÿý Ú·ýø³ÿã}R }j™è´WÄÿþ†í[þüYÿñŠ?âÿCv­ÿ~,ÿøÅT¨Z¦z-æ‹w¬=ì¶kãXÏi+§Ù­8W,çìøä£~_J›þ'ÿô7jß÷âÏÿŒQõJõªg¢Ñ^uÿÿúµoûñgÿÆ)‚]tÌÑë•Cmmà’ìø'ƒGê2}R }j™éWÄÿþ†í[þüYÿñŠ?âÛÅÚ®}íìñÿ¢(ú¥@úÕ3Ñh®Â:½Þ«awùï,.¬²Æ»V_‘$VÇbVEÈõÎ+ ®všvf馮‚Š(¤0¢Š(¢Š(¢Š(¢Š(ªz¶Ÿ­£ÞéÒœGuÂÄuã9«”P ¥ê2KÃÚÜÃcj–ÇL¿–æ=̹ú:ΟVZîk‡ºÓeœø£@·!.wÇ«iÄÿ ŒwøOìþõÕèú”ZÎg©BŽæ”)깩÷ƒô  ´QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE`ø² SN‹V´žïJ“íh‹ÖD‰Pz–Œ°ím=«fÞâ»h®mäY!™‘ºœ†R2ü*Zæ|.ßÙwº†Ÿ…²a=—½¬„•ýÆŸE_Z騢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ŸðWÏá[k¯ùü’kÌú‰eyè¯ø‚÷û3Ãz¥ø86Ö’ÌõT'úSôK/ìÍN°eµŠÛTé@«œÓ¿Óüs«ÞuŽÂ¬ÙØyÒ~ýó]ºÆŒîÁUFI=¬£7†¢¿‘vË©I%û0@•‹ ?D(¿ðè(¢Š(¢Š(¢Š(¢Š«©i¶š¾Ÿ-ô"[yFO ‚9G ŒŠÄÒõ Í#QBÖ¥i¼Ìÿgê ÇÚ@ÿ–oØJàÀdr-TÔôËM_O–Êö?21Ðà©!”ŽC‚ä@è®r7ÅÖñ,)â-.dAµd¹Ò¥aع[…½HP §ýÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT}ÆôÐÿðM7ÿ%PAEsÿcñ‡ýt?üMÿÉT×ÒüOt<›¿X%»q!±Ó^Šú+´î>»IôÁäK¨kW]É¥èQÇq~˜Ï'0Zg»‘÷›ˆÇ=2TÕDƒIJÒÉu}> Åäø2J{8U”`NµkOÓ­4«(ìì`H LáW¹<’ORIä“É=jÕQEQEQEQEQEQEQEQE“®êï¦[Ç ¤"ãSºo.ÒÜœnìDz(å§HΫª[hÚt—·e¶.QsÈäáQGv$€©¬ýJ¹IæÖup‡Vº]¥åmbÎV>ÝXÿsÐ-hÚ:i62$³›™ÜËws ÁšB0I€:íRè÷ºv¡¥Ã6“,RØ©hbh¾çîØ¡ ì ‘‘ÇqV§‚«ymî"Ia• I®UÔŒGpEax^3¥èÇ=´ÐíKБ¬ HW½—a BÊsÐ)Î@æ€.Câ=*ãXm*;‡7j̘0H™FYVB»€ê$w­Zá4访¶tí4ÙÞ¬–:ÕýôÓ=»¬&EÉM²µ‰óÓ€IN@ÅwtQEQEQEQEQEV£áˆg¼}KK¹“KÕ–¸€³{Kùdç ;0­ê(›Ä—:\‹oâ{T³É ºŒ$µ¤‡¶Iæ#ìüv k£V ¡”‚¤dÞ†Uu*ÊX`‚2¬øBôU'ȬdäCgª][Ä¿îÇWè ‚Šçÿá Òÿçë\ÿÁíïÿ£þÝ/þ~µÏüÞÿñêè(®þÝ/þ~µÏüÞÿñê?á Òÿçë\ÿÁíïÿ ‚Šçÿá Òÿçë\ÿÁíïÿ£þÝ/þ~µÏüÞÿñêè(®þÝ/þ~µÏüÞÿñê?á Òÿçë\ÿÁíïÿ ‚Šçÿá Òÿçë\ÿÁíïÿ£þÝ/þ~µÏüÞÿñêÅ>6Ó<5›kIq ÓÖõ#ßn9Úàr29ÐôÅVñ>¯§k_ ÕÌ|Aøm}â;kMDšò+w“Í»»Ô5{™Ñ@è«ÈÁ›<çóY¯ðsDðg±áȳ}ö‰vÞK’»÷ ‘Û%OSU¼7§]Y_ÜÁ§Û˜ÀOÛ/4ù•¼ÁòK‡ pÄn"E<`òw`õZÂßk7úzÛM´HÛÍmó74ŠvƒÎŒóß·&¾¯¯M¦Ïp°Ù$ñZ[ «·iöŒ–hÚw‘Î :óSË®W4›±©ÙßI{¨³FÓ³ÓÖfŠ& 2¬ò™•FOT'åÉ?0걯Ø3ýŸ/ööŸ™ö/²¶~ÏäíÇ“Øó¾m¸éÎ+³ª÷–6š„Eí¬0ç>\ч\úàÕ:d©œ>Ÿ¹Ñì%¹±¸›KIµ܈̌’‚bcŒã nè #­Eg¦Ïu ÙFÖ³¸5,QGIQ¬q  ¨ƒ@ìj¥ Jâs¼lhxýo‰ì*¿úIm]}rÿ[â_û ¯þ’[W_^E_âKÕž¥/zQY–QEQEQEQEQEsºÙû‰´-PqŽútçý™@d'þÚFª?ß4ßÿÄ·ZÖ´3Äi7Û­Gý2˜’À}%ý-\ñVŸ.§á‹ûkoøúù¶ÇÒhÈxÏýö«YÚŒRÿÂ3âûn-åÙçÒ ¸Ïû²ˆ¾ƒuuôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÏxŠÊö=CL×4»Gº»³vŠkxݧ·“Ô*¹ ÆHû¤w®†Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( ÅÚî£sáé,ßÂzÌBòhm²òÙCʪW圜Hôõ dÏøHuOú5ÏûýeÿÉx‹÷Ú·‡,ú‡Ô ®?ÙŽ?÷ÖÊè(…ñ_ˆµI<=qd¾Ö­å¿Å”nÓYõíãläç‘Æ2p2k^-sP‚†/kk(UQ5–ÿýH ïhö]RÎ9uÿ{T`ý|ÉÕ+  þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉâkè†û k±D>ôƒìÒíîÇ39üšèh  ý/]Òõ•s§ÞÅ3Gþ²0vÉôt8e>Ä Ð¬ÍSÃÚV²É%íš<ñÿ«¸Bcš?÷dRYßÙÞ#ÒFtíJ=RÜt¶ÔþY1è³ ÿБ«PIEsÑøºÎXu«{vm£í ˜ÿ³2“Ï`H>ÕÐ++¨e`ÊFA ŠZ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ dÓEo“Í"Çj]ÝΨ$žÂŸ\´¤x¿R{e9Ðl¥Ûp{^̧ýXõù¿¼Ão@À€?J†OêQø‚ñlâÏö]³©0gp‰Âƒ÷Tú±¦¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠåüCjßð—xNóíW~ß$"ßpŒÚ\’ØÆK(äœÆ2s/‹ ‚òmÊö(æ°¸Ô¶\Å($QÌ¡à1càõ8­ù †g…åŠ7x_|LÊ FÚW+èv³ ŽÄŽõ^çHÓo`¸‚ïO´ž—O°«,¬˜óFOe”—ఫ᥎Ûk{°;O“ðܤb+b¹Ëø•øÓP±|¿6ãÞW%ä?÷Û5-ׇ4»Ï<Ënáç¹o$SɉDb êÊÀ¡Ø¡~R8ϩȋõwšË[šh~Åo¤êó\ÙÇo"žÖtpÜÙBp¤RT;²ºñx—^›GÕÞÖÁîï-'‚GÒî-@ìC(ŠRÙK­óe@ÚMmÛøSD´KT‚ËbZ‹y®WlíºUaœ2±çkdÀÂÇám!,îí¼²¥ÙS3Ms,²6ӕóO+‚6žF(˜‹\ÖuKŸ ¼Z•š+k[]¢ÙM H¢ÖY6_•ˆÁ-ón‹´šg®nt»½V[)ä²]*MM?â[=°ˆ*«Œ’|’³á“å'Á®ª]Lšäܵ» âßïYOž±ˆƒpzlP¥zœƒ“˜áðÞ›j×RÚÀÓÂÐ>Gš4Cü ŒØTÎ2«´j箼Gâ=:âþÊçû*[˜³<™#ŠECö«¦…÷äü¡xÁ÷ï´?UñF¥¤ë6¶¯w¦Î>Õik4ÚÌd&VD.\1Hp_!vF>l°«:íôát÷ó-ä·lÇ`•~ÎæH±¾GrCòØÀ Vß…tkíGí÷®ÓùÑ\O"¡–2¥ `¥†Å#8éÅqúgˆõM*Þk­Zt¿6ðk·DÄ$+ou„Úde?Å‚A*»T¼_ZûÄZî™휣NŸSŠM<Ç"Dé K«Ÿ'i]äåv¿9ç 㨭è<5¤ÛÜÉ:ZeäûFàò»®'di@RH™3“üG-ƒÃM½³[­¼Ž4S±šâI¼N?™˜¶”¹Çl`šg‡õëÇÕm5l÷:}çÙŒ¶ñ´i 1G(;Y˜©Ä ¸ò¹ïµUíìmí'»šöIw(šs¸îcžŸ*(ãÓ×5b€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€$i4m¨¯ 2°È#ЊçÛÂöæè7—4™Ï—lC[·ÖÊøSï]ÎGĺyòïtDÕ´ú\É?ïG3¨_ÁÚÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( þSþ„ÍsþÿYòEðêŸô&kŸ÷úËÿ’+ ¢€9ÿøHuOú5ÏûýeÿÉÂCªЙ®ßë/þH®‚Šçÿá!Õ?èL×?ïõ—ÿ$Qÿ ©ÿBf¹ÿ¬¿ù"º (Ÿÿ„‡Tÿ¡3\ÿ¿Ö_ü‘Gü$:§ý šçýþ²ÿäŠè( ^îë]×BiÐèú†§7·[–Xû¬b)\ïn›ˆFOPtVv–öpÚZBÛÂ#¨èMEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEã(ÜxzKø”´úd‰$ùGs¨ÿy7¯ü ·éUУÊÄP9â·XtË/@w .e»f_â· ¬¿‡–ÌßUÑ‚AèEsÞEo6r<ç<štŠüîDá3똊Æàùd]´Ë‡/s¥LÖ23ueLØû´f6ú“@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@R3RÌ@P2Ií@ý÷öÕïüýj³óëåmƒÿhÑâÏô›K $ruØ¡aëŸ6@}ŠFËÿ¥ðJŸøC4¹˜×0ý­ë™Içß/HÓ¼xXô»ÞÞdíÌ,'ð’€: (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9øIÓüus âRÑgOúë ÿ‰G‹þø5§û+ÇËÒßY·òXö‚Ëø´eÿïØ©8'KeBûA>\*ljë×ÐQ@ïˆÿÓu}I Ä—l•}c€nùÃ]szú޵{ÃÊiðEaôvlŸ¡‡ò®’€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (ªòO(ãŽ$`ˆ‹I·©>ÇÒ€,QP ¸¼¸Ù‰_1C´œ뎟8ÜÄA~YʃÔP´T&êÜpOP¤Î9ôæ—í1tÜsÞùO?ÄP´T_i‹Êó2ØÎ1´ç>˜ÆsQ‹°le¹ Èë´‘úâ€,ÑQ-ÄL@ Ôí‘ÇZQ4eT†á›h8êyÿ ’Š«ö™$™’Þ8Ü*†,îW©#Ðÿvžn˜G€s/—Áéònôÿ?¥O\÷ˆ?ÐuW*\Ïý3ŸäU‡ó5¸.b;Îü‰ Qž£ÜVn¹jº÷‡µ w+4Ÿ)™J”“¬mƒèÀ€5èª&¤ºÆ‡c©*ìûL !NèHåO¸9…_ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ‘ÝQÝ‚ªŒ’zKX4–Aá{›HX¬úƒ%ŒDuf’>‹ÀhžC'†£Ô]JɪK& Ùë‰X²Á6º*dQG) J8Ô*¨èà }QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEY­#–í¥–8ÜlU]Ë’,OófŠ«qm$ M»eŒFÙ8Ú9äzýãQÏe#Ë,ˆÊGžÏÇ_o”~f¯Q@$ÓÉ «ó-clÈÊ03ÎÞëÞ¥’Õ¤K€OúÉ׎{öå{Uª(šZȈ¬ù‹'™ƒ#0?.ÞXóÓÚ—ìÒ:h O2A'#§ÌIέÑ@g†_&iN ÛT @O*IÛ“ø ’xŒz—%Ð.Ì å†1úÕª(¤v1¬êîˆá#DBÃ$O?¨¥û3ý§ÌÊãÏó?/oó«TP{&„B±˜Ô³³ç§PxÀ©,à’ áðãj,¯'ùUª(Ÿÿ„/G#Dú¬ $!ŽßX»‰3l"ÊrI8hÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üzøCt¿ùú×?ð{{ÿÇ« ¢€9ÿøCt¿ùú×?ð{{ÿǨÿ„7KÿŸ­sÿ·¿üzº (Ÿÿ„7KÿŸ­sÿ·¿üz¤·ðŽ•m{ow»Rš[wó"Z¥Ìè­´®í’HËœ1çf·( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ÿÙivy-2.4.0-rc1/doc/samples/standard-osgi/000077500000000000000000000000001226750426600177715ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/samples/standard-osgi/build.xml000066400000000000000000000071071226750426600216170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/standard-osgi/ivy.xml000066400000000000000000000020241226750426600213200ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/standard-osgi/ivysettings.xml000066400000000000000000000026061226750426600231070ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/standard-osgi/org.apache.ivy.sample.standard-osgi.bnd000066400000000000000000000017771226750426600273250ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** ivy-2.4.0-rc1/doc/samples/target-platform/000077500000000000000000000000001226750426600203425ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/samples/target-platform/build.xml000066400000000000000000000047021226750426600221660ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/target-platform/ivy.xml000066400000000000000000000020241226750426600216710ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/samples/target-platform/ivysettings.xml000066400000000000000000000025611226750426600234600ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings.html000066400000000000000000000210531226750426600163150ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/000077500000000000000000000000001226750426600154265ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/settings/caches.html000066400000000000000000000140711226750426600175450ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/caches/000077500000000000000000000000001226750426600166545ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/settings/caches/cache.html000066400000000000000000000127451226750426600206160ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/caches/ttl.html000066400000000000000000000074241226750426600203540ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/classpath.html000066400000000000000000000053261226750426600203040ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/conflict-managers.html000066400000000000000000000115541226750426600217160ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/credentials.html000066400000000000000000000035421226750426600206150ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/include.html000066400000000000000000000066161226750426600177500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/latest-strategies.html000066400000000000000000000077231226750426600217710ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/lock-strategies.html000066400000000000000000000055611226750426600214230ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/macrodef.html000066400000000000000000000135131226750426600200770ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/macrodef/000077500000000000000000000000001226750426600172065ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/settings/macrodef/attribute.html000066400000000000000000000033731226750426600221050ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/module.html000066400000000000000000000120721226750426600176030ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/modules.html000066400000000000000000000043511226750426600177670ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespace.html000066400000000000000000000077511226750426600202620ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespace/000077500000000000000000000000001226750426600173625ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/settings/namespace/dest.html000066400000000000000000000057371226750426600212230ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespace/fromtosystem.html000066400000000000000000000036031226750426600230250ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespace/rule.html000066400000000000000000000037721226750426600212300ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespace/src.html000066400000000000000000000036501226750426600210430ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/namespaces.html000066400000000000000000000054041226750426600204360ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/outputters.html000066400000000000000000000062351226750426600205600ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/parsers.html000066400000000000000000000046201226750426600177750ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/properties.html000066400000000000000000000046061226750426600205160ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/property.html000066400000000000000000000060031226750426600201770ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/resolvers.html000066400000000000000000000272721226750426600203520ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/settings.html000066400000000000000000000122601226750426600201550ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/signers.html000066400000000000000000000071531226750426600177740ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/status.html000066400000000000000000000034311226750426600176400ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/statuses.html000066400000000000000000000062771226750426600202030ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/triggers.html000066400000000000000000000473301226750426600201510ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/typedef.html000066400000000000000000000036301226750426600177560ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/settings/version-matchers.html000066400000000000000000000126671226750426600216210ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/standalone.html000066400000000000000000000130031226750426600166010ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/template.html000066400000000000000000000076001226750426600162720ustar00rootroot00000000000000 ${title} | Apache Ivy™ @version@ Documentation

${title}

${body}
ivy-2.4.0-rc1/doc/terminology.html000066400000000000000000000273601226750426600170340ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/textual.html000066400000000000000000000103461226750426600161460ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/toc.json000066400000000000000000001004021226750426600152430ustar00rootroot00000000000000{ "children": [ { "id":"index", "title":"Documentation", "children": [ { "id":"tutorial", "title":"Tutorials", "children": [ { "id":"release-notes", "title":"Release Notes", "children": [ ] }, { "id":"tutorial/start", "title":"Quick Start", "children": [ ] }, { "id":"tutorial/defaultconf", "title":"Adjusting default settings", "children": [ ] }, { "id":"tutorial/multiple", "title":"Multiple Resolvers", "children": [ ] }, { "id":"tutorial/dual", "title":"Dual Resolver", "children": [ ] }, { "id":"tutorial/dependence", "title":"Project dependencies", "children": [ ] }, { "id":"tutorial/multiproject", "title":"Using Ivy in multiple projects environment", "children": [ ] }, { "id":"tutorial/conf", "title":"Using Ivy Module Configurations", "children": [ ] }, { "id":"tutorial/build-repository", "title":"Building a repository", "children": [ { "id":"tutorial/build-repository/basic", "title":"Basic repository copy", "children": [ ] }, { "id":"tutorial/build-repository/advanced", "title":"Using namespaces", "children": [ ] } ] }, { "id":"moreexamples", "title":"More examples", "children": [ ] } ] }, { "id":"reference", "title":"Reference", "children": [ { "id":"intro", "title":"Introduction", "isAbstract":true, "children": [ { "id":"terminology", "title":"Terminology", "children": [ ] }, { "id":"concept", "title":"Main Concepts", "children": [ ] }, { "id":"textual", "title":"Text Conventions", "children": [ ] }, { "id":"principle", "title":"How does it work ?", "children": [ ] }, { "id":"bestpractices", "title":"Best practices", "children": [ ] }, { "id":"compatibility", "title":"Compatibility", "children": [ ] }, { "id":"install", "title":"Installation", "children": [ ] } ] }, { "id":"settings", "title":"Settings Files", "children": [ { "id":"settings/property", "title":"property", "children": [ ] }, { "id":"settings/properties", "title":"properties", "children": [ ] }, { "id":"settings/settings", "title":"settings", "children": [ ] }, { "id":"settings/include", "title":"include", "children": [ ] }, { "id":"settings/classpath", "title":"classpath", "children": [ ] }, { "id":"settings/typedef", "title":"typedef", "children": [ ] }, { "id":"settings/credentials", "title":"credentials", "children": [ ] }, { "id":"settings/signers", "title":"signers", "children": [ ] }, { "id":"settings/lock-strategies", "title":"lock-strategies", "children": [ ] }, { "id":"settings/caches", "title":"caches", "children": [ { "id":"settings/caches/cache", "title":"cache", "children": [ { "id":"settings/caches/ttl", "title":"ttl", "children": [ ] } ] } ] }, { "id":"settings/latest-strategies", "title":"latest-strategies", "children": [ ] }, { "id":"settings/parsers", "title":"parsers", "children": [ ] }, { "id":"settings/namespaces", "title":"namespaces", "children": [ { "id":"settings/namespace", "title":"namespace", "children": [ { "id":"settings/namespace/rule", "title":"rule", "children": [ { "id":"settings/namespace/fromtosystem", "title":"fromsystem / tosystem", "children": [ { "id":"settings/namespace/src", "title":"src", "children": [ ] }, { "id":"settings/namespace/dest", "title":"dest", "children": [ ] } ] } ] } ] } ] }, { "id":"settings/macrodef", "title":"macrodef", "children": [ { "id":"settings/macrodef/attribute", "title":"attribute", "children": [ ] } ] }, { "id":"settings/resolvers", "title":"resolvers", "children": [ { "id":"resolver/ivyrep", "title":"IvyRep Resolver", "children": [ ] }, { "id":"resolver/ibiblio", "title":"IBiblio Resolver", "children": [ ] }, { "id":"resolver/packager", "title":"Packager resolver", "children": [ ] }, { "id":"resolver/filesystem", "title":"File System resolver", "children": [ ] }, { "id":"resolver/url", "title":"Url Resolver", "children": [ ] }, { "id":"resolver/chain", "title":"Chain Resolver", "children": [ ] }, { "id":"resolver/dual", "title":"Dual resolver", "children": [ ] }, { "id":"resolver/sftp", "title":"sftp resolver", "children": [ ] }, { "id":"resolver/ssh", "title":"ssh resolver", "children": [ ] }, { "id":"resolver/vfs", "title":"vfs resolver", "children": [ ] }, { "id":"resolver/jar", "title":"Jar resolver", "children": [ ] }, { "id":"resolver/obr", "title":"OSGi Bundle Repository", "children": [ ] }, { "id":"resolver/osgiagg", "title":"Aggregated OSGi Repository", "children": [ ] }, { "id":"resolver/updatesite", "title":"Eclipse updatesite", "children": [ ] }, { "id":"resolver/mirrored", "title":"Mirrored Resolver", "children": [ ] } ] }, { "id":"settings/conflict-managers", "title":"conflict-managers", "children": [ ] }, { "id":"settings/modules", "title":"modules", "children": [ { "id":"settings/module", "title":"module", "children": [ ] } ] }, { "id":"settings/outputters", "title":"outputters", "children": [ ] }, { "id":"settings/signers", "title":"signers", "children": [ ] }, { "id":"settings/statuses", "title":"statuses", "children": [ { "id":"settings/status", "title":"status", "children": [ ] } ] }, { "id":"settings/triggers", "title":"triggers", "children": [ ] }, { "id":"settings/version-matchers", "title":"version-matchers", "children": [ ] } ] }, { "id":"ivyfile", "title":"Ivy Files", "children": [ { "id":"ivyfile/info", "title":"info", "children": [ { "id":"ivyfile/extends", "title":"extends", "children": [ ] }, { "id":"ivyfile/license", "title":"license", "children": [ ] }, { "id":"ivyfile/ivyauthor", "title":"ivyauthor", "children": [ ] }, { "id":"ivyfile/repository", "title":"repository", "children": [ ] }, { "id":"ivyfile/description", "title":"description", "children": [ ] } ] }, { "id":"ivyfile/configurations", "title":"configurations", "children": [ { "id":"ivyfile/conf", "title":"conf", "children": [ ] }, { "id":"ivyfile/include", "title":"include", "children": [ ] } ] }, { "id":"ivyfile/publications", "title":"publications", "children": [ { "id":"ivyfile/artifact", "title":"artifact", "children": [ { "id":"ivyfile/artifact-conf", "title":"conf", "children": [ ] } ] } ] }, { "id":"ivyfile/dependencies", "title":"dependencies", "children": [ { "id":"ivyfile/dependency", "title":"dependency", "children": [ { "id":"ivyfile/dependency-conf", "title":"conf", "children": [ { "id":"ivyfile/mapped", "title":"mapped", "children": [ ] } ] }, { "id":"ivyfile/dependency-artifact", "title":"artifact", "children": [ { "id":"ivyfile/dependency-artifact-conf", "title":"conf", "children": [ ] } ] }, { "id":"ivyfile/artifact-exclude", "title":"exclude", "children": [ { "id":"ivyfile/artifact-exclude-conf", "title":"conf", "children": [ ] } ] }, { "id":"ivyfile/dependency-include", "title":"include", "children": [ { "id":"ivyfile/dependency-include-conf", "title":"conf", "children": [ ] } ] } ] }, { "id":"ivyfile/exclude", "title":"exclude", "children": [ ] }, { "id":"ivyfile/override", "title":"override", "children": [ ] }, { "id":"ivyfile/conflict", "title":"conflict", "children": [ ] } ] }, { "id":"ivyfile/conflicts", "title":"conflicts", "children": [ { "id":"ivyfile/manager", "title":"manager", "children": [ ] } ] } ] }, { "id":"ant", "title":"Ant Tasks", "children": [ { "id":"use/artifactproperty", "title":"artifactproperty", "children": [ ] }, { "id":"use/artifactreport", "title":"artifactreport", "children": [ ] }, { "id":"use/buildlist", "title":"buildlist", "children": [ ] }, { "id":"use/buildobr", "title":"buildobr", "children": [ ] }, { "id":"use/buildnumber", "title":"buildnumber", "children": [ ] }, { "id":"use/cachefileset", "title":"cachefileset", "children": [ ] }, { "id":"use/cachepath", "title":"cachepath", "children": [ ] }, { "id":"use/checkdepsupdate", "title":"checkdepsupdate", "children": [ ] }, { "id":"use/cleancache", "title":"cleancache", "children": [ ] }, { "id":"use/configure", "title":"configure", "children": [ ] }, { "id":"use/convertmanifest", "title":"convertmanifest", "children": [ ] }, { "id":"use/convertpom", "title":"convertpom", "children": [ ] }, { "id":"use/deliver", "title":"deliver", "children": [ ] }, { "id":"use/dependencytree", "title":"dependencytree", "children": [ ] }, { "id":"use/findrevision", "title":"findrevision", "children": [ ] }, { "id":"use/fixdeps", "title":"fixdeps", "children": [ ] }, { "id":"use/info", "title":"info", "children": [ ] }, { "id":"use/install", "title":"install", "children": [ ] }, { "id":"use/listmodules", "title":"listmodules", "children": [ ] }, { "id":"use/makepom", "title":"makepom", "children": [ ] }, { "id":"use/postresolvetask", "title":"post resolve tasks", "children": [ ] }, { "id":"use/publish", "title":"publish", "children": [ ] }, { "id":"use/repreport", "title":"repreport", "children": [ ] }, { "id":"use/resolve", "title":"resolve", "children": [ ] }, { "id":"use/resources", "title":"resources", "children": [ ] }, { "id":"use/retrieve", "title":"retrieve", "children": [ ] }, { "id":"use/report", "title":"report", "children": [ { "id":"yed", "title":"Using yEd to layout report graphs", "children": [ ] } ] }, { "id":"use/settings", "title":"settings", "children": [ ] }, { "id":"use/var", "title":"var", "children": [ ] } ] }, { "id":"standalone", "title":"Using standalone", "children": [ ] }, { "id":"osgi", "title":"OSGi", "children": [ { "id":"osgi/osgi-mapping", "title":"OSGi mapping", "children": [ ] }, { "id":"osgi/eclipse-plugin", "title":"Building an Eclipse plugin", "children": [ ] }, { "id":"osgi/standard-osgi", "title":"Building a standard OSGi bundle", "children": [ ] }, { "id":"osgi/target-platform", "title":"Managing a target platform", "children": [ ] }, { "id":"osgi/sigil", "title":"Apache Felix Sigil", "children": [ ] } ] } ] }, { "id":"dev", "title":"Developer doc", "children": [ { "id":"extend", "title":"Extending Ivy", "children": [ ] }, { "id":"dev/makerelease", "title":"Making a release", "children": [ ] } ] } ] } ] } ivy-2.4.0-rc1/doc/tutorial.html000066400000000000000000000065651226750426600163330ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/000077500000000000000000000000001226750426600154315ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/tutorial/build-repository.html000066400000000000000000000063621226750426600216420ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/build-repository/000077500000000000000000000000001226750426600207455ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/tutorial/build-repository/advanced.html000066400000000000000000000154471226750426600234130ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/build-repository/basic.html000066400000000000000000000162631226750426600227240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/conf.html000066400000000000000000000233041226750426600172460ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/defaultconf.html000066400000000000000000000326311226750426600206160ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/dependence.html000066400000000000000000000243411226750426600204150ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/dual.html000066400000000000000000000140621226750426600172470ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/multiple.html000066400000000000000000000155241226750426600201610ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/multiproject.html000066400000000000000000000347621226750426600210540ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/tutorial/start.html000066400000000000000000000202671226750426600174630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use.html000066400000000000000000000017111226750426600152500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/000077500000000000000000000000001226750426600143625ustar00rootroot00000000000000ivy-2.4.0-rc1/doc/use/artifactproperty.html000066400000000000000000000077531226750426600206660ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/artifactreport.html000066400000000000000000000122341226750426600203030ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/buildlist.html000066400000000000000000000233071226750426600172500ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/buildnumber.html000066400000000000000000000150661226750426600175700ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/buildobr.html000066400000000000000000000113241226750426600170530ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/cachefileset.html000066400000000000000000000053661226750426600177010ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/cachepath.html000066400000000000000000000070171226750426600171750ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/checkdepsupdate.html000066400000000000000000000066641226750426600204200ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/cleancache.html000066400000000000000000000046011226750426600173170ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/configure.html000066400000000000000000000115211226750426600172310ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/convertmanifest.html000066400000000000000000000035331226750426600204630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/convertpom.html000066400000000000000000000034631226750426600174520ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/deliver.html000066400000000000000000000200071226750426600167010ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/dependencytree.html000066400000000000000000000064641226750426600202600ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/findrevision.html000066400000000000000000000055271226750426600177600ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/fixdeps.html000066400000000000000000000076161226750426600167240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/info.html000066400000000000000000000223751226750426600162140ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/install.html000066400000000000000000000115671226750426600167300ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/listmodules.html000066400000000000000000000074171226750426600176250ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/makepom.html000066400000000000000000000174451226750426600167140ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/postresolvetask.html000066400000000000000000000222611226750426600205230ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/publish.html000066400000000000000000000173411226750426600167240ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/report.html000066400000000000000000000132471226750426600165720ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/repreport.html000066400000000000000000000145351226750426600173020ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/resolve.html000066400000000000000000000356141226750426600167400ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/resources.html000066400000000000000000000064101226750426600172630ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/retrieve.html000066400000000000000000000232411226750426600170770ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/settings.html000066400000000000000000000136401226750426600171140ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/use/var.html000066400000000000000000000053511226750426600160440ustar00rootroot00000000000000 ivy-2.4.0-rc1/doc/yed.html000066400000000000000000000054311226750426600152400ustar00rootroot00000000000000 ivy-2.4.0-rc1/ivy.xml000066400000000000000000000105161226750426600143550ustar00rootroot00000000000000 Apache Ivy is a tool for managing (recording, tracking, resolving and reporting) project dependencies. ivy-2.4.0-rc1/ivysettings-release.xml000066400000000000000000000034371226750426600175600ustar00rootroot00000000000000 ivy-2.4.0-rc1/optional.patterns000066400000000000000000000034431226750426600164340ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** #This file defines the sources to compile for ivy-optional.jar org/apache/ivy/Main.java org/apache/ivy/plugins/matcher/GlobPatternMatcher.java org/apache/ivy/plugins/repository/sftp/**/*.java org/apache/ivy/plugins/repository/ssh/**/*.java org/apache/ivy/plugins/repository/vfs/**/*.java org/apache/ivy/plugins/repository/vsftp/**/*.java org/apache/ivy/plugins/resolver/AbstractSshBasedResolver.java org/apache/ivy/plugins/resolver/SFTPResolver.java org/apache/ivy/plugins/resolver/SshResolver.java org/apache/ivy/plugins/resolver/VfsResolver.java org/apache/ivy/plugins/resolver/VsftpResolver.java org/apache/ivy/plugins/resolver/packager/*.java org/apache/ivy/plugins/signer/bouncycastle/**/*.java org/apache/ivy/util/url/HttpClientHandler.java #This section defines the resources to copy for ivy-optional.jar org/apache/ivy/plugins/repository/vfs/*.xml ivy-2.4.0-rc1/src/000077500000000000000000000000001226750426600136105ustar00rootroot00000000000000ivy-2.4.0-rc1/src/etc/000077500000000000000000000000001226750426600143635ustar00rootroot00000000000000ivy-2.4.0-rc1/src/etc/checkstyle/000077500000000000000000000000001226750426600165215ustar00rootroot00000000000000ivy-2.4.0-rc1/src/etc/checkstyle/RequiredHeader.txt000066400000000000000000000014611226750426600221550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ivy-2.4.0-rc1/src/etc/checkstyle/checkstyle-config000066400000000000000000000122561226750426600220530ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/etc/checkstyle/checkstyle-frames.xsl000066400000000000000000000251061226750426600226660ustar00rootroot00000000000000 CheckStyle Audit <h2>Frame Alert</h2> <p> This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. </p>

CheckStyle Audit

Designed for use with CheckStyle and Ant.


.bannercell { border: 0px; padding: 0px; } body { margin-left: 10; margin-right: 10; font:normal 80% arial,helvetica,sanserif; background-color:#FFFFFF; color:#000000; } .oddrow td { background: #efefef; } .evenrow td { background: #fff; } th, td { text-align: left; vertical-align: top; } th { font-weight:bold; background: #ccc; color: black; } table, th, td { font-size:100%; border: none } table.log tr td, tr th { } h2 { font-weight:bold; font-size:140%; margin-bottom: 5; } h3 { font-size:100%; font-weight:bold; background: #525D76; color: white; text-decoration: none; padding: 5px; margin-right: 2px; margin-left: 2px; margin-bottom: 0; }

Files

Files

Name Errors
files/.html files/.html ../ ../ stylesheet.css

File

Error Description Line:Column
:

Summary

Total Files Files With Errors Errors
oddrow evenrow
ivy-2.4.0-rc1/src/etc/checkstyle/checkstyle-suppress.xml000066400000000000000000000020751226750426600232670ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/etc/checkstyle/checkstyle-text.xsl000066400000000000000000000025021226750426600223700ustar00rootroot00000000000000 : : ivy-2.4.0-rc1/src/etc/checkstyle/checkstyle-xdoc.xsl000066400000000000000000000112251226750426600223430ustar00rootroot00000000000000 Checkstyle Audit
Name Errors
files.html Checkstyle Audit
Error Description Line
Files Files With Errors Errors
oddrow evenrow
ivy-2.4.0-rc1/src/etc/license/000077500000000000000000000000001226750426600160055ustar00rootroot00000000000000ivy-2.4.0-rc1/src/etc/license/license-header.xml000066400000000000000000000014521226750426600214010ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/etc/makepom/000077500000000000000000000000001226750426600160145ustar00rootroot00000000000000ivy-2.4.0-rc1/src/etc/makepom/pom.template000066400000000000000000000047541226750426600203560ustar00rootroot00000000000000 4.0.0 org.apache apache 7 ${ivy.pom.groupId} ${ivy.pom.artifactId} ${ivy.pom.version} Apache Ivy ${ivy.pom.url} scm:svn:http://svn.apache.org/repos/asf/ant/ivy/core/trunk/ scm:svn:https://svn.apache.org/repos/asf/ant/ivy/core/trunk http://svn.apache.org/repos/asf/ant/ivy/core/trunk Ant/Ivy Developers List dev-subscribe@ant.apache.org dev-unsubscribe@ant.apache.org dev@ant.apache.org http://mail-archives.apache.org/mod_mbox/ant-dev Ivy Users List ivy-user-subscribe@ant.apache.org ivy-user-unsubscribe@ant.apache.org ivy-user@ant.apache.org http://mail-archives.apache.org/mod_mbox/ant-ivy-user jira http://issues.apache.org/jira/browse/IVY ivy-2.4.0-rc1/src/example/000077500000000000000000000000001226750426600152435ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/build-a-ivy-repository/000077500000000000000000000000001226750426600216025ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/build-a-ivy-repository/build.xml000066400000000000000000000126471226750426600234350ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/build-a-ivy-repository/settings/000077500000000000000000000000001226750426600234425ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/build-a-ivy-repository/settings/ivysettings-advanced.xml000066400000000000000000000140031226750426600303150ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/build-a-ivy-repository/settings/ivysettings-basic.xml000066400000000000000000000025571226750426600276440ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/chained-resolvers/000077500000000000000000000000001226750426600206605ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/build.xml000066400000000000000000000032231226750426600225010ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/000077500000000000000000000000001226750426600256645ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/build.xml000066400000000000000000000061371226750426600275140ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/ivy.xml000066400000000000000000000020751226750426600272210ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/src/000077500000000000000000000000001226750426600264535ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/src/example/000077500000000000000000000000001226750426600301065ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/chainedresolvers-project/src/example/Hello.java000066400000000000000000000026571226750426600320260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package example; import org.apache.commons.lang.WordUtils; /** * Simple example world to show how easy it is to retreive libs with ivy !!! */ public final class Hello { public static void main(String[] args) { String message = "example world !"; System.out.println("standard message :" + message); System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); System.out.println("upperCased by " + test.StringUtils.class.getName() + " : " + test.StringUtils.upperCase(message)); } private Hello() { } } ivy-2.4.0-rc1/src/example/chained-resolvers/settings/000077500000000000000000000000001226750426600225205ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/settings/ivysettings.xml000066400000000000000000000022071226750426600256330ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/chained-resolvers/settings/repository/000077500000000000000000000000001226750426600247375ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/chained-resolvers/settings/repository/test-1.0.jar000066400000000000000000000021531226750426600267110ustar00rootroot00000000000000PK F›&2 META-INF/PK E›&2‚aq½^jMETA-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àårÌCq,HLÎHUŠ%ÍôŒx¹œ‹RKRSt*AêMôŒâ Ìt“ Œ4‚Kó|3“‹ò‹+‹KRs‹<ó’õ4y¹x¹PK F›&2test/PK F›&2dB©¿"test/StringUtils.classmOÍ ‚`œÕÌR+ s—PõE¯A‡°»•ˆ*úÕsÙ¥ C× ‡Š¾4¨…ý›™eØÇóz0BWA ŠšŒ–Œ6¡> £Í¢i­5'Þú„æ!IüÔñ2>ÍùÎ;zã½ã%KÃ(˜X¿ u : ‚ÎüŒ}8—…ûŒCÕÍb½ó7ì *¥•ÅneÞ3ÿXa‘?òôöåUæ›Á;ñ.ÙЩ4ÑàYÒý­ÚwH”Ûgy! PK ôš&2U³\"/test/StringUtils.javaUO]KÄ0|/ô?,ÜË]‘öJ9P‘Sl|í¶­II¶"þw7I¯í-!“™Ù,‰#H Nf›‘ÍL^ÿPK F›&2 íAMETA-INF/PK E›&2‚aq½^j¤'META-INF/MANIFEST.MFPK F›&2íA·test/PK F›&2dB©¿"¤Útest/StringUtils.classPK ôš&2U³\"/¤Ítest/StringUtils.javaPK3"ivy-2.4.0-rc1/src/example/configurations/000077500000000000000000000000001226750426600202755ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/jdbc-example/000077500000000000000000000000001226750426600226305ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/jdbc-example/build.xml000066400000000000000000000077511226750426600244630ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/configurations/jdbc-example/ivy.xml000066400000000000000000000050511226750426600241620ustar00rootroot00000000000000 This is an example project that aims to demonstrate the usage of the configuration in ivy. This project provide 4 configurations. Each configurations describe the requirement to build or run the project ivy-2.4.0-rc1/src/example/configurations/jdbc-example/src/000077500000000000000000000000001226750426600234175ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/jdbc-example/src/dev.properties000066400000000000000000000017531226750426600263210ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** driver.class=com.mckoi.JDBCDriver ivy-2.4.0-rc1/src/example/configurations/jdbc-example/src/example/000077500000000000000000000000001226750426600250525ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/jdbc-example/src/example/ConfigurationsExample.java000066400000000000000000000050001226750426600322160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package example; import java.io.IOException; import java.util.Properties; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; public final class ConfigurationsExample { public static void main(String[] args) { String jdbcPropToLoad = "prod.properties"; CommandLineParser parser = new PosixParser(); Options options = new Options(); options.addOption("d", "dev", false, "Dev tag to launch app in dev mode. Means that app will launch embedded mckoi db."); try { CommandLine line = parser.parse(options, args); if (line.hasOption("d")) { System.err.println("App is in DEV mode"); jdbcPropToLoad = "dev.properties"; } } catch (ParseException exp) { System.err.println("Parsing failed. Reason: " + exp.getMessage()); } Properties p = new Properties(); try { p.load(ConfigurationsExample.class.getResourceAsStream("/" + jdbcPropToLoad)); } catch (IOException e) { System.err.println("Properties loading failed. Reason: " + e.getMessage()); } try { String clazz = p.getProperty("driver.class"); Class.forName(clazz); System.out.println(" Jdbc driver loaded :" + clazz); } catch (ClassNotFoundException e) { System.err.println("Jdbc Driver class loading failed. Reason: " + e.getMessage()); e.printStackTrace(); } } private ConfigurationsExample() { } } ivy-2.4.0-rc1/src/example/configurations/jdbc-example/src/prod.properties000066400000000000000000000017561226750426600265120ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** driver.class=org.gjt.mm.mysql.Driver ivy-2.4.0-rc1/src/example/configurations/multi-projects/000077500000000000000000000000001226750426600232565ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/000077500000000000000000000000001226750426600265365ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/build.xml000066400000000000000000000130111226750426600303530ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/ivy.xml000066400000000000000000000035071226750426600300740ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/000077500000000000000000000000001226750426600273255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/000077500000000000000000000000001226750426600306125ustar00rootroot00000000000000FilterProvider.java000066400000000000000000000026431226750426600343430ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter; public final class FilterProvider { public static IFilter getFilter() { try { Class clazz = Class.forName("filter.ccimpl.CCFilter"); return (IFilter) clazz.newInstance(); } catch (Exception e) { try { Class clazz = Class.forName("filter.hmimpl.HMFilter"); return (IFilter) clazz.newInstance(); } catch (Exception e1) { System.err.println("No filter implementation found in classpath !"); } return null; } } private FilterProvider() { } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/IFilter.java000066400000000000000000000016241226750426600330160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter; public interface IFilter { String[] filter(String[] values, String prefix); } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/ccimpl/000077500000000000000000000000001226750426600320615ustar00rootroot00000000000000CCFilter.java000066400000000000000000000031361226750426600343030ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/ccimpl/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter.ccimpl; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import filter.IFilter; public class CCFilter implements IFilter { public String[] filter(String[] values, final String prefix) { if (values == null) { return null; } if (prefix == null) { return values; } List result = new ArrayList(Arrays.asList(values)); CollectionUtils.filter(result, new Predicate() { public boolean evaluate(Object o) { return o != null && o.toString().startsWith(prefix); } }); return (String[]) result.toArray(new String[result.size()]); } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/hmimpl/000077500000000000000000000000001226750426600321005ustar00rootroot00000000000000HMFilter.java000066400000000000000000000027151226750426600343430ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/src/filter/hmimpl/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter.hmimpl; import java.util.ArrayList; import java.util.List; import filter.IFilter; public class HMFilter implements IFilter { public String[] filter(String[] values, String prefix) { if (values == null) { return null; } if (prefix == null) { return values; } List result = new ArrayList(); for (int i = 0; i < values.length; i++) { String string = values[i]; if (string != null && string.startsWith(prefix)) { result.add(string); } } return (String[]) result.toArray(new String[result.size()]); } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/000077500000000000000000000000001226750426600275155ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/000077500000000000000000000000001226750426600310025ustar00rootroot00000000000000AbstractTestFilter.java000066400000000000000000000042401226750426600353370ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter; import junit.framework.TestCase; public abstract class AbstractTestFilter extends TestCase { public void testFilterNull() { Exception err = null; try { getIFilter().filter(null, null); } catch (NullPointerException npe) { err = npe; } assertNull(err); } /** * @return */ public abstract IFilter getIFilter(); public void testFilterNullValues() { Exception err = null; try { getIFilter().filter(null, "test"); } catch (NullPointerException npe) { err = npe; } assertNull(err); } public void testFilterNullPrefix() { Exception err = null; try { getIFilter().filter(new String[]{"test"}, null); } catch (NullPointerException npe) { err = npe; } assertNull(err); } public void testFilter() { String[] result = getIFilter().filter( new String[]{"test", "nogood", "mustbe filtered"}, "t"); assertNotNull(result); assertEquals(result.length, 1); } public void testFilterWithNullValues() { String[] result = getIFilter().filter(new String[]{"test", null, "mustbe filtered"}, "t"); assertNotNull(result); assertEquals(result.length, 1); } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/ccimpl/000077500000000000000000000000001226750426600322515ustar00rootroot00000000000000CCFilterTest.java000066400000000000000000000020031226750426600353230ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/ccimpl/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter.ccimpl; import filter.AbstractTestFilter; import filter.IFilter; public class CCFilterTest extends AbstractTestFilter { public IFilter getIFilter() { return new CCFilter(); } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/hmimpl/000077500000000000000000000000001226750426600322705ustar00rootroot00000000000000HMFilterTest.java000066400000000000000000000020031226750426600353610ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/filter-framework/test/filter/hmimpl/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package filter.hmimpl; import filter.AbstractTestFilter; import filter.IFilter; public class HMFilterTest extends AbstractTestFilter { public IFilter getIFilter() { return new HMFilter(); } } ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/000077500000000000000000000000001226750426600244045ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/build.xml000066400000000000000000000073421226750426600262330ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/ivy.xml000066400000000000000000000026071226750426600257420ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/src/000077500000000000000000000000001226750426600251735ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/src/myapp/000077500000000000000000000000001226750426600263215ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/configurations/multi-projects/myapp/src/myapp/Main.java000066400000000000000000000025011226750426600300460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package myapp; import java.util.Arrays; import filter.FilterProvider; import filter.IFilter; public final class Main { public static void main(String[] args) { String[] toFilter = new String[] {"one", "two", "tree", "four"}; IFilter filter = FilterProvider.getFilter(); System.out.println("Filtering with:" + filter.getClass()); String[] filtered = filter.filter(toFilter, "t"); System.out.println("Result :" + Arrays.asList(filtered)); } private Main() { } } ivy-2.4.0-rc1/src/example/dependence/000077500000000000000000000000001226750426600173355ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/build.xml000066400000000000000000000037451226750426600211670ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dependence/dependee/000077500000000000000000000000001226750426600211065ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/dependee/build.xml000066400000000000000000000105621226750426600227330ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dependence/dependee/ivy.xml000066400000000000000000000017711226750426600224450ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dependence/dependee/src/000077500000000000000000000000001226750426600216755ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/dependee/src/standalone/000077500000000000000000000000001226750426600240255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/dependee/src/standalone/Main.java000066400000000000000000000044411226750426600255570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package standalone; import java.util.Properties; import org.apache.commons.lang.WordUtils; /** * TODO write javadoc */ public final class Main { /** * Returns the version of the project * @return a string representation of the version, null if the version could not be retreived */ public static String getVersion() { Properties p = new Properties(); try { p.load(Main.class.getResourceAsStream("/version.properties")); String version = p.getProperty("version"); if (version != null) { return String.valueOf(Integer.parseInt(version)); } } catch (Exception e) { e.printStackTrace(); } return null; } /** * Return the same string with all words capitalized. * @param str the string conatining the words to capitalize * @return null if the string was null, the string with all words capitalized otherwise */ public static String capitalizeWords(String str) { System.out.println(" [" + Main.class.getName() + "] capitalizing string \"" + str + "\" using " + WordUtils.class.getName()); return WordUtils.capitalizeFully(str); } public static void main(String[] args) { String message = "sentence to capitalize"; System.out.println("standard message : " + message); System.out.println("capitalized message : " + capitalizeWords(message)); } private Main() { } } ivy-2.4.0-rc1/src/example/dependence/depender/000077500000000000000000000000001226750426600211235ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/depender/build.xml000066400000000000000000000074641226750426600227570ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dependence/depender/ivy.xml000066400000000000000000000017621226750426600224620ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dependence/depender/src/000077500000000000000000000000001226750426600217125ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/depender/src/depending/000077500000000000000000000000001226750426600236475ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/depender/src/depending/Main.java000066400000000000000000000031621226750426600254000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package depending; /** * TODO write javadoc */ public final class Main { public static void main(String[] args) { String standaloneVersion = standalone.Main.getVersion(); if (standaloneVersion != null) { System.out.println("you are using version " + standaloneVersion + " of class " + standalone.Main.class.getName()); } else { System.err.println("failed to get version of " + standalone.Main.class.getName()); } String message = "i am " + Main.class.getName() + " and " + standalone.Main.class.getName() + " will do the job for me"; System.out.println("standard message : " + message); System.out.println("capitalized message : " + standalone.Main.capitalizeWords(message)); } private Main() { } } ivy-2.4.0-rc1/src/example/dependence/settings/000077500000000000000000000000001226750426600211755ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dependence/settings/ivysettings.properties000066400000000000000000000017671226750426600257160ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** repository.dir=${ivy.settings.dir}/repository ivy-2.4.0-rc1/src/example/dependence/settings/ivysettings.xml000066400000000000000000000025431226750426600243130ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dual/000077500000000000000000000000001226750426600161705ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/build.xml000066400000000000000000000032021226750426600200060ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dual/project/000077500000000000000000000000001226750426600176365ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/project/build.xml000066400000000000000000000061511226750426600214620ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dual/project/ivy.xml000066400000000000000000000021171226750426600211700ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dual/project/src/000077500000000000000000000000001226750426600204255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/project/src/example/000077500000000000000000000000001226750426600220605ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/project/src/example/Hello.java000066400000000000000000000040211226750426600237630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package example; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.lang.WordUtils; /** * Simple hello world example to show how easy it is to retrieve libs with ivy, * including transitive dependencies */ public final class Hello { public static void main(String[] args) throws Exception { String message = "hello ivy !"; System.out.println("standard message : " + message); System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); HttpClient client = new HttpClient(); HeadMethod head = new HeadMethod("http://www.ibiblio.org/"); client.executeMethod(head); int status = head.getStatusCode(); System.out.println("head status code with httpclient: " + status); head.releaseConnection(); System.out.println( "now check if httpclient dependency on commons-logging has been realized"); Class clss = Class.forName("org.apache.commons.logging.Log"); System.out.println("found logging class in classpath: " + clss); } private Hello() { } } ivy-2.4.0-rc1/src/example/dual/repository/000077500000000000000000000000001226750426600204075ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/repository/commons-httpclient-ivy-2.0.2.xml000066400000000000000000000022121226750426600262170ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/dual/settings/000077500000000000000000000000001226750426600200305ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/dual/settings/ivysettings.xml000066400000000000000000000022141226750426600231410ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/go-ivy/000077500000000000000000000000001226750426600164555ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/go-ivy/build.xml000066400000000000000000000146611226750426600203060ustar00rootroot00000000000000 We are now ready to execute our simple program with its dependency on commons-lang. Let's go! package example; import org.apache.commons.lang.WordUtils; public class Hello { public static void main(String[] args) { String message = "hello ivy !"; System.out.println("standard message : " + message); System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); } } ivy-2.4.0-rc1/src/example/hello-ivy/000077500000000000000000000000001226750426600171535ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/hello-ivy/build.xml000066400000000000000000000060321226750426600207750ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/hello-ivy/ivy.xml000066400000000000000000000020771226750426600205120ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/hello-ivy/src/000077500000000000000000000000001226750426600177425ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/hello-ivy/src/example/000077500000000000000000000000001226750426600213755ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/hello-ivy/src/example/Hello.java000066400000000000000000000037021226750426600233050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package example; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.lang.WordUtils; /** * Simple example to show how easy it is to retrieve transitive libs with ivy !!! */ public final class Hello { public static void main(String[] args) throws Exception { Option msg = OptionBuilder.withArgName("msg") .hasArg() .withDescription("the message to capitalize") .create("message"); Options options = new Options(); options.addOption(msg); CommandLineParser parser = new GnuParser(); CommandLine line = parser.parse(options, args); String message = line.getOptionValue("message", "hello ivy !"); System.out.println("standard message : " + message); System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); } private Hello() { } } ivy-2.4.0-rc1/src/example/multi-project/000077500000000000000000000000001226750426600200415ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/build.xml000066400000000000000000000053751226750426600216740ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/common/000077500000000000000000000000001226750426600213315ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/common/build.properties000066400000000000000000000023761226750426600245560ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** lib.dir = ${basedir}/lib build.dir = ${basedir}/build classes.dir = ${build.dir}/classes src.dir = ${basedir}/src repository.dir=${common.dir}/../repository ivy.file = ${basedir}/ivy.xml jar.file = ${build.dir}/${ant.project.name}.jar main.class.name = ${ant.project.name}.Main module.version.target = 1.0 ivy-2.4.0-rc1/src/example/multi-project/common/common.xml000066400000000000000000000211151226750426600233430ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/000077500000000000000000000000001226750426600216725ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/console/000077500000000000000000000000001226750426600233345ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/console/build.properties000066400000000000000000000020521226750426600265500ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/console/build.xml000066400000000000000000000016621226750426600251620ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/console/ivy.xml000066400000000000000000000024731226750426600246730ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/console/src/000077500000000000000000000000001226750426600241235ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/console/src/console/000077500000000000000000000000001226750426600255655ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/console/src/console/Main.java000066400000000000000000000056431226750426600273240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package console; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Collection; import java.util.Arrays; import java.lang.reflect.Method; public final class Main { private static final Collection QUIT_COMMANDS = Arrays.asList(new String[] {"quit", "q", "exit"}); private static final Collection HELP_COMMANDS = Arrays.asList(new String[] {"help", "h", "?"}); public static void main(String[] a) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.print("> "); String command = in.readLine().trim(); if (QUIT_COMMANDS.contains(command)) { return; } if (HELP_COMMANDS.contains(command)) { help(); continue; } String[] split = command.split(" "); if (split.length == 0) { error(command); continue; } try { String[] args = new String[split.length - 1]; System.arraycopy(split, 1, args, 0, args.length); Class cl = Class.forName(split[0] + ".Main"); Method m = cl.getMethod("main", new Class[] {String[].class}); m.invoke(null, new Object[] {args}); } catch (Exception ex) { error(command); continue; } } } private static void help() { System.out.println("available commands:"); System.out.println("\tquit: quit the console"); System.out.println("\thelp: displays this message"); System.out.println("\tlist -dir : list files in given directory"); System.out.println("\tfind -dir -name : list files with given name in given dir"); System.out.println("\tsizewhere -dir -name : " + "compute total size of files with given name in given dir"); System.out.println("\thelp: displays this message"); } private static void error(String command) { System.out.println("unknown command " + command); System.out.println("type ? for help"); } private Main() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/find/000077500000000000000000000000001226750426600226125ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/find/build.properties000066400000000000000000000020521226750426600260260ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/find/build.xml000066400000000000000000000016571226750426600244440ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/find/ivy.xml000066400000000000000000000030311226750426600241400ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/find/src/000077500000000000000000000000001226750426600234015ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/find/src/find/000077500000000000000000000000001226750426600243215ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/find/src/find/FindFile.java000066400000000000000000000027441226750426600266530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package find; import version.Version; import list.ListFile; import java.util.Collection; import java.io.File; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; public final class FindFile { static { Version.register("find"); } public static Collection find(File dir, String name) { return find(ListFile.list(dir), name); } private static Collection find(Collection files, final String name) { return CollectionUtils.select(files, new Predicate() { public boolean evaluate(Object o) { return ((File) o).getName().indexOf(name) != -1; } }); } private FindFile() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/find/src/find/Main.java000066400000000000000000000053601226750426600260540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package find; import java.io.File; import java.util.Collection; import java.util.Iterator; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; public final class Main { private static Options getOptions() { Option dir = OptionBuilder.withArgName("dir") .hasArg() .withDescription("list files in given dir") .create("dir"); Option name = OptionBuilder.withArgName("name") .hasArg() .withDescription("list files with given name") .create("name"); Options options = new Options(); options.addOption(dir); options.addOption(name); return options; } public static void main(String[] args) throws Exception { Options options = getOptions(); try { CommandLineParser parser = new GnuParser(); CommandLine line = parser.parse(options, args); File dir = new File(line.getOptionValue("dir", ".")); String name = line.getOptionValue("name", "jar"); Collection files = FindFile.find(dir, name); System.out.println("listing files in " + dir + " containing " + name); for (Iterator it = files.iterator(); it.hasNext();) { System.out.println("\t" + it.next() + "\n"); } } catch (ParseException exp) { // oops, something went wrong System.err.println("Parsing failed. Reason: " + exp.getMessage()); HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("find", options); } } private Main() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/list/000077500000000000000000000000001226750426600226455ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/list/build.properties000066400000000000000000000020521226750426600260610ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/list/build.xml000066400000000000000000000016571226750426600244770ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/list/ivy.xml000066400000000000000000000025521226750426600242020ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/list/src/000077500000000000000000000000001226750426600234345ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/list/src/list/000077500000000000000000000000001226750426600244075ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/list/src/list/ListFile.java000066400000000000000000000026411226750426600267700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package list; import version.Version; import java.util.Collection; import java.util.ArrayList; import java.io.File; public final class ListFile { static { Version.register("list"); } public static Collection list(File dir) { Collection files = new ArrayList(); return list(dir, files); } private static Collection list(File file, Collection files) { if (file.isDirectory()) { File[] f = file.listFiles(); for (int i = 0; i < f.length; i++) { list(f[i], files); } } else { files.add(file); } return files; } private ListFile() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/list/src/list/Main.java000066400000000000000000000046341226750426600261450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package list; import java.io.File; import java.util.Collection; import java.util.Iterator; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; public final class Main { private static Options getOptions() { Option dir = OptionBuilder.withArgName("dir") .hasArg() .withDescription("list files in given dir") .create("dir"); Options options = new Options(); options.addOption(dir); return options; } public static void main(String[] args) throws Exception { Options options = getOptions(); try { CommandLineParser parser = new GnuParser(); CommandLine line = parser.parse(options, args); File dir = new File(line.getOptionValue("dir", ".")); Collection files = ListFile.list(dir); System.out.println("listing files in " + dir); for (Iterator it = files.iterator(); it.hasNext();) { System.out.println("\t" + it.next() + "\n"); } } catch (ParseException exp) { // oops, something went wrong System.err.println("Parsing failed. Reason: " + exp.getMessage()); HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("list", options); } } private Main() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/size/000077500000000000000000000000001226750426600226445ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/size/build.properties000066400000000000000000000020521226750426600260600ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/size/build.xml000066400000000000000000000016571226750426600244760ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/size/ivy.xml000066400000000000000000000022031226750426600241720ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/size/src/000077500000000000000000000000001226750426600234335ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/size/src/size/000077500000000000000000000000001226750426600244055ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/size/src/size/FileSize.java000066400000000000000000000025161226750426600267660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package size; import version.Version; import java.util.Collection; import java.util.Iterator; import java.io.File; public final class FileSize { static { Version.register("size"); } public static long totalSize(File dir) { return totalSize(list.ListFile.list(dir)); } public static long totalSize(Collection files) { long total = 0; for (Iterator it = files.iterator(); it.hasNext();) { File f = (File) it.next(); total += f.length(); } return total; } private FileSize() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/000077500000000000000000000000001226750426600236775ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/build.properties000066400000000000000000000020521226750426600271130ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/build.xml000066400000000000000000000016641226750426600255270ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/ivy.xml000066400000000000000000000030111226750426600252230ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/src/000077500000000000000000000000001226750426600244665ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/src/sizewhere/000077500000000000000000000000001226750426600264735ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/src/sizewhere/Main.java000066400000000000000000000050531226750426600302250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package sizewhere; import java.io.File; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; public final class Main { private static Options getOptions() { Option dir = OptionBuilder.withArgName("dir") .hasArg() .withDescription("give total size of files in given dir") .create("dir"); Option name = OptionBuilder.withArgName("name") .hasArg() .withDescription("give total size of files with given name") .create("name"); Options options = new Options(); options.addOption(dir); options.addOption(name); return options; } public static void main(String[] args) throws Exception { Options options = getOptions(); try { CommandLineParser parser = new GnuParser(); CommandLine line = parser.parse(options, args); File dir = new File(line.getOptionValue("dir", ".")); String name = line.getOptionValue("name", "jar"); System.out.println("total size of files in " + dir + " containing " + name + ": " + SizeWhere.totalSize(dir, name)); } catch (ParseException exp) { // oops, something went wrong System.err.println("Parsing failed. Reason: " + exp.getMessage()); HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("sizewhere", options); } } private Main() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/sizewhere/src/sizewhere/SizeWhere.java000066400000000000000000000022121226750426600312400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package sizewhere; import version.Version; import size.FileSize; import find.FindFile; import java.io.File; public final class SizeWhere { static { Version.register("sizewhere"); } public static long totalSize(File dir, String name) { return FileSize.totalSize(FindFile.find(dir, name)); } private SizeWhere() { } } ivy-2.4.0-rc1/src/example/multi-project/projects/version/000077500000000000000000000000001226750426600233575ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/version/build.properties000066400000000000000000000020521226750426600265730ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** projects.dir = ${basedir}/.. wkspace.dir = ${projects.dir}/.. common.dir = ${wkspace.dir}/common ivy-2.4.0-rc1/src/example/multi-project/projects/version/build.xml000066400000000000000000000016621226750426600252050ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/version/ivy.xml000066400000000000000000000017041226750426600247120ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/example/multi-project/projects/version/src/000077500000000000000000000000001226750426600241465ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/version/src/version/000077500000000000000000000000001226750426600256335ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/multi-project/projects/version/src/version/Version.java000066400000000000000000000033741226750426600301320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package version; import java.io.InputStream; import java.util.Properties; import java.util.Map; import java.util.HashMap; public final class Version { static { versions = new HashMap(); register("version"); } private static Map versions; public static void register(String module) { try { InputStream moduleVersion = Version.class.getResourceAsStream("/" + module + ".properties"); Properties props = new Properties(); props.load(moduleVersion); String version = (String) props.get("version"); versions.put(module, version); System.out.println("--- using " + module + " v" + version); } catch (Exception ex) { System.err.println("an error occurred while registering " + module + ": " + ex.getMessage()); ex.printStackTrace(); } } private Version() { } } ivy-2.4.0-rc1/src/example/packager-resolver/000077500000000000000000000000001226750426600206575ustar00rootroot00000000000000ivy-2.4.0-rc1/src/example/packager-resolver/ivysettings.xml000066400000000000000000000030431226750426600237710ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/000077500000000000000000000000001226750426600145315ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/000077500000000000000000000000001226750426600153205ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/000077500000000000000000000000001226750426600165415ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/000077500000000000000000000000001226750426600173505ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/Ivy.java000066400000000000000000000753371226750426600210010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.check.CheckEngine; import org.apache.ivy.core.deliver.DeliverEngine; import org.apache.ivy.core.deliver.DeliverOptions; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.install.InstallEngine; import org.apache.ivy.core.install.InstallOptions; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.publish.PublishEngine; import org.apache.ivy.core.publish.PublishOptions; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.repository.RepositoryManagementEngine; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.retrieve.RetrieveEngine; import org.apache.ivy.core.retrieve.RetrieveOptions; import org.apache.ivy.core.retrieve.RetrieveReport; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.core.search.SearchEngine; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.sort.SortEngine; import org.apache.ivy.core.sort.SortOptions; import org.apache.ivy.plugins.circular.CircularDependencyException; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.plugins.repository.TransferListener; import org.apache.ivy.plugins.resolver.BasicResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.trigger.Trigger; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.HostUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.MessageLoggerEngine; /** * Ivy is a free java based dependency manager. *

* This class is the main class of Ivy, which acts as a Facade to all services offered by Ivy: *

    *
  • resolve dependencies
  • *
  • retrieve artifacts to a local location
  • *
  • deliver and publish modules
  • *
  • repository search and listing
  • *
* Here is one typical usage: * *
 * Ivy ivy = Ivy.newInstance();
 * ivy.configure(new URL("ivysettings.xml"));
 * ivy.resolve(new URL("ivy.xml"));
 * 
* *

*

Using Ivy engines directly

*

* If the methods offered by the {@link Ivy} class are not flexible enough and you want to use Ivy * engines directly, you need to call the methods within a single {@link IvyContext} associated to * the {@link Ivy} instance you use.
* To do so, it is recommended to use the {@link #execute(org.apache.ivy.Ivy.IvyCallback)} method * like this: * *

 * Ivy ivy = Ivy.newInstance();
 * ivy.execute(new IvyCallback() {
 *     public Object doInIvyContext(Ivy ivy, IvyContext context) {
 *         // obviously we can use regular Ivy methods in the callback
 *         ivy.configure(new URL("ivysettings.xml"));
 *         // and we can safely use Ivy engines too
 *         ivy.getResolveEngine().resolve(new URL("ivy.xml"));
 *         return null;
 *     }
 * });
 * 
* *

*/ public class Ivy { /** * Callback used to execute a set of Ivy related methods within an {@link IvyContext}. * * @see Ivy#execute(org.apache.ivy.Ivy.IvyCallback) */ public static interface IvyCallback { /** * Executes Ivy related job within an {@link IvyContext} * * @param ivy * the {@link Ivy} instance to which this callback is related * @param context * the {@link IvyContext} in which this callback is executed * @return the result of this job, null if there is no result */ public Object doInIvyContext(Ivy ivy, IvyContext context); } private static final int KILO = 1024; /** * @deprecated Use the {@link DateUtil} utility class instead. */ @Deprecated public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat( DateUtil.DATE_FORMAT_PATTERN); /** * the current version of Ivy, as displayed on the console when Ivy is initialized */ private static final String IVY_VERSION; /** * the date at which this version of Ivy has been built. May be empty if unknown. */ private static final String IVY_DATE; static { // initialize IVY_VERSION and IVY_DATE Properties props = new Properties(); URL moduleURL = Message.class.getResource("/module.properties"); if (moduleURL != null) { try { InputStream module = moduleURL.openStream(); props.load(module); module.close(); } catch (IOException e) { // ignore this exception, we will initialize with default values } } IVY_VERSION = props.getProperty("version", "non official version"); IVY_DATE = props.getProperty("date", ""); } /** * Returns the current version of Ivy, as displayed on the console when Ivy is initialized. * * @return the current version of Ivy */ public static String getIvyVersion() { return IVY_VERSION; } /** * Returns the date at which this version of Ivy has been built. *

* May be empty if unknown. * * @return the date at which this version of Ivy has been built */ public static String getIvyDate() { return IVY_DATE; } /** * Returns the URL at which Ivy web site can be found. * * @return the URL at which Ivy web site can be found */ public static String getIvyHomeURL() { return "http://ant.apache.org/ivy/"; } public static Ivy newInstance() { Ivy ivy = new Ivy(); ivy.bind(); return ivy; } public static Ivy newInstance(IvySettings settings) { Ivy ivy = new Ivy(); ivy.setSettings(settings); ivy.bind(); return ivy; } /** * True if the current processing has been requested to be interrupted, false otherwise */ private boolean interrupted; /** * True if this instance of Ivy has already been bound to its dependencies, false otherwise. * * @see bind() */ private boolean bound; /* * Following are dependencies of the Ivy instance on instances of engines and manager which * actually do the work The attributes can be set either manually using the corresponding * setters, or all at once with the default implementations using the bind method */ private IvySettings settings; private EventManager eventManager; private SortEngine sortEngine; private SearchEngine searchEngine; private CheckEngine checkEngine; private ResolveEngine resolveEngine; private RetrieveEngine retrieveEngine; private DeliverEngine deliverEngine; private PublishEngine publishEngine; private InstallEngine installEngine; private RepositoryManagementEngine repositoryEngine; /** * The logger engine to use to log messages when using this Ivy instance. */ private MessageLoggerEngine loggerEngine = new MessageLoggerEngine(); /** * The default constructor of Ivy allows to create an instance of Ivy with none of its * dependencies (engines, settings, ...) created. If you use this constructor, it's your * responsibility to set the dependencies of Ivy using the appropriate setters * (setResolveEngine, ...). You can also call the bind method to set all the dependencies except * those that you have provided using the setters. If you want to get an instance ready to use, * prefer the use of Ivy.newInstance(). */ public Ivy() { } /** * This method is used to bind this Ivy instance to required dependencies, i.e. instance of * settings, engines, and so on. *

* After this call Ivy is still not configured, which means that the settings object is still * empty. *

*/ public void bind() { pushContext(); try { if (settings == null) { settings = new IvySettings(); } if (eventManager == null) { eventManager = new EventManager(); } if (sortEngine == null) { sortEngine = new SortEngine(settings); } if (searchEngine == null) { searchEngine = new SearchEngine(settings); } if (resolveEngine == null) { resolveEngine = new ResolveEngine(settings, eventManager, sortEngine); } if (retrieveEngine == null) { retrieveEngine = new RetrieveEngine(settings, eventManager); } if (deliverEngine == null) { deliverEngine = new DeliverEngine(settings); } if (publishEngine == null) { publishEngine = new PublishEngine(settings, eventManager); } if (installEngine == null) { installEngine = new InstallEngine(settings, searchEngine, resolveEngine); } if (repositoryEngine == null) { repositoryEngine = new RepositoryManagementEngine(settings, searchEngine, resolveEngine); } eventManager.addTransferListener(new TransferListener() { public void transferProgress(TransferEvent evt) { ResolveData resolve; switch (evt.getEventType()) { case TransferEvent.TRANSFER_PROGRESS: resolve = IvyContext.getContext().getResolveData(); if (resolve == null || !LogOptions.LOG_QUIET.equals(resolve.getOptions().getLog())) { Message.progress(); } break; case TransferEvent.TRANSFER_COMPLETED: resolve = IvyContext.getContext().getResolveData(); if (resolve == null || !LogOptions.LOG_QUIET.equals(resolve.getOptions().getLog())) { Message.endProgress(" (" + (evt.getTotalLength() / KILO) + "kB)"); } break; default: break; } } }); bound = true; } finally { popContext(); } } /** * Executes the given callback in the context of this Ivy instance. *

* Alternatively you can use the {@link #pushContext()} and {@link #popContext()} methods, but * this is not recommended: * *

     * Object result = null;
     * pushContext();
     * try {
     *     result = callback.doInIvyContext(this, IvyContext.getContext());
     * } finally {
     *     popContext();
     * }
     * doSomethingWithResult(result);
     * 
* *

* * @param callback * @return */ public Object execute(IvyCallback callback) { pushContext(); try { return callback.doInIvyContext(this, IvyContext.getContext()); } finally { popContext(); } } /** * Pushes a new IvyContext bound to this Ivy instance if the current context is not already * bound to this Ivy instance. If the current context is already bound to this Ivy instance, it * pushes the current context on the context stack, so that you can (and must) always call * {@link #popContext()} when you're done. *

* Alternatively, you can use the {@link #execute(org.apache.ivy.Ivy.IvyCallback)} method which * takes care of everything for you. *

*/ public void pushContext() { if (IvyContext.getContext().peekIvy() != this) { // the current Ivy context is associated with another Ivy instance, we push a new // instance IvyContext.pushNewContext(); IvyContext.getContext().setIvy(this); } else { // the current Ivy context is already associated with this Ivy instance, we only push it // for popping consistency IvyContext.pushContext(IvyContext.getContext()); } } /** * Pops the current Ivy context. *

* You must call this method once and only once for each call to {@link #pushContext()}, when * you're done with the your Ivy related work. *

*

* Alternatively, you can use the {@link #execute(org.apache.ivy.Ivy.IvyCallback)} method which * takes care of everything for you. *

*/ public void popContext() { IvyContext.popContext(); } // /////////////////////////////////////////////////////////////////////// // LOAD SETTINGS // /////////////////////////////////////////////////////////////////////// public void configure(File settingsFile) throws ParseException, IOException { pushContext(); try { assertBound(); settings.load(settingsFile); postConfigure(); } finally { popContext(); } } public void configure(URL settingsURL) throws ParseException, IOException { pushContext(); try { assertBound(); settings.load(settingsURL); postConfigure(); } finally { popContext(); } } public void configureDefault() throws ParseException, IOException { pushContext(); try { assertBound(); settings.loadDefault(); postConfigure(); } finally { popContext(); } } /** * Configures Ivy with 1.4 compatible default settings */ public void configureDefault14() throws ParseException, IOException { pushContext(); try { assertBound(); settings.loadDefault14(); postConfigure(); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // CHECK // /////////////////////////////////////////////////////////////////////// public boolean check(URL ivyFile, String resolvername) { pushContext(); try { return checkEngine.check(ivyFile, resolvername); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // RESOLVE // /////////////////////////////////////////////////////////////////////// public ResolveReport resolve(File ivySource) throws ParseException, IOException { pushContext(); try { return resolveEngine.resolve(ivySource); } finally { popContext(); } } public ResolveReport resolve(URL ivySource) throws ParseException, IOException { pushContext(); try { return resolveEngine.resolve(ivySource); } finally { popContext(); } } public ResolveReport resolve(ModuleRevisionId mrid, ResolveOptions options, boolean changing) throws ParseException, IOException { pushContext(); try { return resolveEngine.resolve(mrid, options, changing); } finally { popContext(); } } public ResolveReport resolve(URL ivySource, ResolveOptions options) throws ParseException, IOException { pushContext(); try { return resolveEngine.resolve(ivySource, options); } finally { popContext(); } } public ResolveReport resolve(File ivySource, ResolveOptions options) throws ParseException, IOException { return resolve(ivySource.toURI().toURL(), options); } public ResolveReport resolve(ModuleDescriptor md, ResolveOptions options) throws ParseException, IOException { pushContext(); try { return resolveEngine.resolve(md, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // INSTALL // /////////////////////////////////////////////////////////////////////// public ResolveReport install(ModuleRevisionId mrid, String from, String to, InstallOptions options) throws IOException { pushContext(); try { return installEngine.install(mrid, from, to, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // RETRIEVE // /////////////////////////////////////////////////////////////////////// public int retrieve(ModuleRevisionId mrid, String destFilePattern, RetrieveOptions options) throws IOException { pushContext(); try { return retrieveEngine.retrieve(mrid, destFilePattern, options); } finally { popContext(); } } public RetrieveReport retrieve(ModuleRevisionId mrid, RetrieveOptions options) throws IOException { pushContext(); try { return retrieveEngine.retrieve(mrid, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // DELIVER // /////////////////////////////////////////////////////////////////////// public void deliver(ModuleRevisionId mrid, String revision, String destIvyPattern) throws IOException, ParseException { pushContext(); try { deliverEngine.deliver(mrid, revision, destIvyPattern, DeliverOptions.newInstance(settings)); } finally { popContext(); } } public void deliver(String revision, String destIvyPattern, DeliverOptions options) throws IOException, ParseException { pushContext(); try { deliverEngine.deliver(revision, destIvyPattern, options); } finally { popContext(); } } /** * Example of use: deliver(mrid, "1.5", "target/ivy/ivy-[revision].xml", * DeliverOptions.newInstance(settings).setStatus("release").setValidate(false)); * * @param mrid * @param revision * @param destIvyPattern * @param options * @throws IOException * @throws ParseException */ public void deliver(ModuleRevisionId mrid, String revision, String destIvyPattern, DeliverOptions options) throws IOException, ParseException { pushContext(); try { deliverEngine.deliver(mrid, revision, destIvyPattern, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // PUBLISH // /////////////////////////////////////////////////////////////////////// public Collection publish(ModuleRevisionId mrid, Collection srcArtifactPattern, String resolverName, PublishOptions options) throws IOException { pushContext(); try { return publishEngine.publish(mrid, srcArtifactPattern, resolverName, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // SORT // /////////////////////////////////////////////////////////////////////// /** * Sorts the collection of IvyNode from the less dependent to the more dependent */ public List sortNodes(Collection nodes, SortOptions options) { pushContext(); try { return getSortEngine().sortNodes(nodes, options); } finally { popContext(); } } /** * Sorts the given ModuleDescriptors from the less dependent to the more dependent. This sort * ensures that a ModuleDescriptor is always found in the list before all ModuleDescriptors * depending directly on it. * * @param moduleDescriptors * a Collection of ModuleDescriptor to sort * @param options * Options to use to sort the descriptors. * @return a List of sorted ModuleDescriptors * @throws CircularDependencyException * if a circular dependency exists and circular dependency strategy decide to throw * an exception */ public List sortModuleDescriptors(Collection moduleDescriptors, SortOptions options) { pushContext(); try { return getSortEngine().sortModuleDescriptors(moduleDescriptors, options); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // SEARCH // /////////////////////////////////////////////////////////////////////// public ResolvedModuleRevision findModule(ModuleRevisionId mrid) { pushContext(); try { ResolveOptions options = new ResolveOptions(); options.setValidate(false); return resolveEngine.findModule(mrid, options); } finally { popContext(); } } public ModuleEntry[] listModuleEntries(OrganisationEntry org) { pushContext(); try { return searchEngine.listModuleEntries(org); } finally { popContext(); } } public ModuleId[] listModules(ModuleId criteria, PatternMatcher matcher) { pushContext(); try { return searchEngine.listModules(criteria, matcher); } finally { popContext(); } } public ModuleRevisionId[] listModules(ModuleRevisionId criteria, PatternMatcher matcher) { pushContext(); try { return searchEngine.listModules(criteria, matcher); } finally { popContext(); } } public String[] listModules(String org) { pushContext(); try { return searchEngine.listModules(org); } finally { popContext(); } } public OrganisationEntry[] listOrganisationEntries() { pushContext(); try { return searchEngine.listOrganisationEntries(); } finally { popContext(); } } public String[] listOrganisations() { pushContext(); try { return searchEngine.listOrganisations(); } finally { popContext(); } } public RevisionEntry[] listRevisionEntries(ModuleEntry module) { pushContext(); try { return searchEngine.listRevisionEntries(module); } finally { popContext(); } } public String[] listRevisions(String org, String module) { pushContext(); try { return searchEngine.listRevisions(org, module); } finally { popContext(); } } public String[] listTokenValues(String token, Map otherTokenValues) { pushContext(); try { return searchEngine.listTokenValues(token, otherTokenValues); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////////// // INTERRUPTIONS // /////////////////////////////////////////////////////////////////////// /** * Interrupts the current running operation, no later than interruptTimeout milliseconds after * the call */ public void interrupt() { Thread operatingThread = IvyContext.getContext().getOperatingThread(); interrupt(operatingThread); } /** * Interrupts the current running operation in the given operating thread, no later than * interruptTimeout milliseconds after the call */ public void interrupt(Thread operatingThread) { if (operatingThread != null && operatingThread.isAlive()) { if (operatingThread == Thread.currentThread()) { throw new IllegalStateException("cannot call interrupt from ivy operating thread"); } Message.verbose("interrupting operating thread..."); operatingThread.interrupt(); synchronized (this) { interrupted = true; } try { Message.verbose("waiting clean interruption of operating thread"); operatingThread.join(settings.getInterruptTimeout()); } catch (InterruptedException e) { // reset thread interrupt status Thread.currentThread().interrupt(); } if (operatingThread.isAlive()) { Message.warn("waited clean interruption for too long: stopping operating thread"); operatingThread.stop(); } synchronized (this) { interrupted = false; } } } public synchronized boolean isInterrupted() { return interrupted; } /** * Check if the current operation has been interrupted, and if it is the case, throw a runtime * exception */ public void checkInterrupted() { if (isInterrupted()) { Message.info("operation interrupted"); throw new RuntimeException("operation interrupted"); } } public static String getWorkingRevision() { return "working@" + HostUtil.getLocalHostName(); } public ResolutionCacheManager getResolutionCacheManager() { return settings.getResolutionCacheManager(); } private void assertBound() { if (!bound) { bind(); } } private void postConfigure() { Collection triggers = settings.getTriggers(); for (Iterator iter = triggers.iterator(); iter.hasNext();) { Trigger trigger = (Trigger) iter.next(); eventManager.addIvyListener(trigger, trigger.getEventFilter()); } for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); if (resolver instanceof BasicResolver) { ((BasicResolver) resolver).setEventManager(eventManager); } } } public String getVariable(String name) { pushContext(); try { assertBound(); return settings.getVariable(name); } finally { popContext(); } } public String substitute(String str) { pushContext(); try { assertBound(); return settings.substitute(str); } finally { popContext(); } } public void setVariable(String varName, String value) { pushContext(); try { assertBound(); settings.setVariable(varName, value); } finally { popContext(); } } // /////////////////////////////////////////////////////////////////// // GETTERS / SETTERS // /////////////////////////////////////////////////////////////////// public IvySettings getSettings() { return settings; } public EventManager getEventManager() { return eventManager; } public CheckEngine getCheckEngine() { return checkEngine; } public void setCheckEngine(CheckEngine checkEngine) { this.checkEngine = checkEngine; } public DeliverEngine getDeliverEngine() { return deliverEngine; } public void setDeliverEngine(DeliverEngine deliverEngine) { this.deliverEngine = deliverEngine; } public InstallEngine getInstallEngine() { return installEngine; } public void setInstallEngine(InstallEngine installEngine) { this.installEngine = installEngine; } public PublishEngine getPublishEngine() { return publishEngine; } public void setPublishEngine(PublishEngine publishEngine) { this.publishEngine = publishEngine; } public ResolveEngine getResolveEngine() { return resolveEngine; } public void setResolveEngine(ResolveEngine resolveEngine) { this.resolveEngine = resolveEngine; } public RetrieveEngine getRetrieveEngine() { return retrieveEngine; } public void setRetrieveEngine(RetrieveEngine retrieveEngine) { this.retrieveEngine = retrieveEngine; } public SearchEngine getSearchEngine() { return searchEngine; } public void setSearchEngine(SearchEngine searchEngine) { this.searchEngine = searchEngine; } public SortEngine getSortEngine() { return sortEngine; } public void setSortEngine(SortEngine sortEngine) { this.sortEngine = sortEngine; } public RepositoryManagementEngine getRepositoryEngine() { return repositoryEngine; } public void setRepositoryEngine(RepositoryManagementEngine repositoryEngine) { this.repositoryEngine = repositoryEngine; } public void setEventManager(EventManager eventManager) { this.eventManager = eventManager; } public void setSettings(IvySettings settings) { this.settings = settings; } public MessageLoggerEngine getLoggerEngine() { return loggerEngine; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/Ivy14.java000066400000000000000000000526631226750426600211430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy; import java.io.File; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.ivy.core.deliver.DeliverOptions; import org.apache.ivy.core.deliver.PublishingDependencyRevisionResolver; import org.apache.ivy.core.install.InstallOptions; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.publish.PublishOptions; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.retrieve.RetrieveOptions; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.core.sort.SilentNonMatchingVersionReporter; import org.apache.ivy.core.sort.SortOptions; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; /** * This class can be used for easy migration from Ivy 1.4 API. *

* Indeed, Ivy 2.0 API has changed substantially, so it can take time to migrate existing code using * Ivy 1.4 API to the new API. Using this class it's really easy: replace your instance of Ivy by an * instance of this class. *

* For instance, where you were doing: * *

 * Ivy ivy = new Ivy();
 * 
* * do instead: * *
 * Ivy14 ivy = new Ivy14();
 * 
* * And that should be enough in most cases! */ public class Ivy14 { // CheckStyle:ParameterNumberCheck OFF // don't check parameter numbers, since this class is here for backward compatibility private Ivy ivy; public Ivy14() { this(Ivy.newInstance()); } public Ivy14(Ivy ivy) { this.ivy = ivy; } public boolean check(URL ivyFile, String resolvername) { return ivy.check(ivyFile, resolvername); } public void configure(File settingsFile) throws ParseException, IOException { ivy.configure(settingsFile); } public void configure(URL settingsURL) throws ParseException, IOException { ivy.configure(settingsURL); } public void configureDefault() throws ParseException, IOException { ivy.configureDefault(); } public void deliver(ModuleRevisionId mrid, String revision, File cache, String destIvyPattern, String status, Date pubdate, PublishingDependencyRevisionResolver pdrResolver, boolean validate, boolean resolveDynamicRevisions) throws IOException, ParseException { ivy.deliver(mrid, revision, destIvyPattern, new DeliverOptions(status, pubdate, pdrResolver, validate, resolveDynamicRevisions, null)); } public void deliver(ModuleRevisionId mrid, String revision, File cache, String destIvyPattern, String status, Date pubdate, PublishingDependencyRevisionResolver pdrResolver, boolean validate) throws IOException, ParseException { deliver(mrid, revision, cache, destIvyPattern, status, pubdate, pdrResolver, validate, true); } public Map determineArtifactsToCopy(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter) throws ParseException, IOException { return ivy.getRetrieveEngine().determineArtifactsToCopy( new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern) .setArtifactFilter(artifactFilter)); } public Map determineArtifactsToCopy(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern) throws ParseException, IOException { return ivy.getRetrieveEngine().determineArtifactsToCopy( new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern)); } public ArtifactDownloadReport download(Artifact artifact, File cache, boolean useOrigin) { Message.deprecated("using cache and useOrigin when calling download is not supported anymore"); return ivy.getResolveEngine().download(artifact, new DownloadOptions()); } public ResolvedModuleRevision findModule(ModuleRevisionId id) { ResolveOptions options = new ResolveOptions(); options.setValidate(false); return ivy.getResolveEngine().findModule(id, options); } public IvyNode[] getDependencies(ModuleDescriptor md, String[] confs, File cache, Date date, ResolveReport report, boolean validate, boolean transitive) { return ivy.getResolveEngine().getDependencies( md, newResolveOptions(confs, null, cache, date, validate, false, transitive, false, true, true, FilterHelper.NO_FILTER), report); } public IvyNode[] getDependencies(ModuleDescriptor md, String[] confs, File cache, Date date, ResolveReport report, boolean validate) { return ivy.getResolveEngine().getDependencies( md, newResolveOptions(confs, null, cache, date, validate, false, true, false, true, true, FilterHelper.NO_FILTER), report); } public IvyNode[] getDependencies(URL ivySource, String[] confs, File cache, Date date, boolean validate) throws ParseException, IOException { return ivy.getResolveEngine().getDependencies( ivySource, newResolveOptions(confs, null, cache, date, validate, false, true, false, true, true, FilterHelper.NO_FILTER)); } public String getVariable(String name) { return ivy.getVariable(name); } public ResolveReport install(ModuleRevisionId mrid, String from, String to, boolean transitive, boolean validate, boolean overwrite, Filter artifactFilter, File cache, String matcherName) throws IOException { return ivy.install(mrid, from, to, new InstallOptions().setTransitive(transitive) .setValidate(validate).setOverwrite(overwrite).setArtifactFilter(artifactFilter) .setMatcherName(matcherName)); } public void interrupt() { ivy.interrupt(); } public void interrupt(Thread operatingThread) { ivy.interrupt(operatingThread); } public boolean isInterrupted() { return ivy.isInterrupted(); } public ModuleEntry[] listModuleEntries(OrganisationEntry org) { return ivy.listModuleEntries(org); } public ModuleId[] listModules(ModuleId criteria, PatternMatcher matcher) { return ivy.listModules(criteria, matcher); } public ModuleRevisionId[] listModules(ModuleRevisionId criteria, PatternMatcher matcher) { return ivy.listModules(criteria, matcher); } public String[] listModules(String org) { return ivy.listModules(org); } public OrganisationEntry[] listOrganisationEntries() { return ivy.listOrganisationEntries(); } public String[] listOrganisations() { return ivy.listOrganisations(); } public RevisionEntry[] listRevisionEntries(ModuleEntry module) { return ivy.listRevisionEntries(module); } public String[] listRevisions(String org, String module) { return ivy.listRevisions(org, module); } public String[] listTokenValues(String token, Map otherTokenValues) { return ivy.listTokenValues(token, otherTokenValues); } public Collection publish(ModuleDescriptor md, DependencyResolver resolver, Collection srcArtifactPattern, String srcIvyPattern, Artifact[] extraArtifacts, boolean overwrite, String conf) throws IOException { return ivy.getPublishEngine().publish( md, srcArtifactPattern, resolver, new PublishOptions().setSrcIvyPattern(srcIvyPattern).setExtraArtifacts(extraArtifacts) .setOverwrite(overwrite).setConfs(splitConfs(conf))); } public Collection publish(ModuleRevisionId mrid, String pubrevision, File cache, Collection srcArtifactPattern, String resolverName, String srcIvyPattern, String status, Date pubdate, Artifact[] extraArtifacts, boolean validate, boolean overwrite, boolean update, String conf) throws IOException { return ivy.publish( mrid, srcArtifactPattern, resolverName, new PublishOptions().setStatus(status).setPubdate(pubdate).setPubrevision(pubrevision) .setSrcIvyPattern(srcIvyPattern).setExtraArtifacts(extraArtifacts) .setUpdate(update).setValidate(validate).setOverwrite(overwrite) .setConfs(splitConfs(conf))); } public Collection publish(ModuleRevisionId mrid, String pubrevision, File cache, String srcArtifactPattern, String resolverName, String srcIvyPattern, boolean validate, boolean overwrite) throws IOException { return ivy.publish(mrid, Collections.singleton(srcArtifactPattern), resolverName, new PublishOptions().setPubrevision(pubrevision).setSrcIvyPattern(srcIvyPattern) .setValidate(validate).setOverwrite(overwrite)); } public Collection publish(ModuleRevisionId mrid, String pubrevision, File cache, String srcArtifactPattern, String resolverName, String srcIvyPattern, boolean validate) throws IOException { return ivy.publish(mrid, Collections.singleton(srcArtifactPattern), resolverName, new PublishOptions().setPubrevision(pubrevision).setSrcIvyPattern(srcIvyPattern) .setValidate(validate)); } public Collection publish(ModuleRevisionId mrid, String pubrevision, File cache, String srcArtifactPattern, String resolverName, String srcIvyPattern, String status, Date pubdate, Artifact[] extraArtifacts, boolean validate, boolean overwrite, boolean update, String conf) throws IOException { return ivy.publish( mrid, Collections.singleton(srcArtifactPattern), resolverName, new PublishOptions().setStatus(status).setPubdate(pubdate).setPubrevision(pubrevision) .setSrcIvyPattern(srcIvyPattern).setExtraArtifacts(extraArtifacts) .setUpdate(update).setValidate(validate).setOverwrite(overwrite) .setConfs(splitConfs(conf))); } public ResolveReport resolve(File ivySource) throws ParseException, IOException { return ivy.resolve(ivySource); } public ResolveReport resolve(ModuleDescriptor md, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, boolean useOrigin, boolean download, boolean outputReport, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( md, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, transitive, useOrigin, download, outputReport, artifactFilter)); } private ResolveOptions newResolveOptions(String[] confs, String revision, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, boolean useOrigin, boolean download, boolean outputReport, Filter artifactFilter) { if (useOrigin) { ivy.getSettings().useDeprecatedUseOrigin(); } return new ResolveOptions().setConfs(confs).setRevision(revision).setValidate(validate) .setUseCacheOnly(useCacheOnly).setTransitive(transitive).setDownload(download) .setOutputReport(outputReport).setArtifactFilter(artifactFilter); } public ResolveReport resolve(ModuleDescriptor md, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, boolean download, boolean outputReport, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( md, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, transitive, false, download, outputReport, artifactFilter)); } public ResolveReport resolve(ModuleDescriptor md, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( md, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, transitive, false, true, true, artifactFilter)); } public ResolveReport resolve(ModuleDescriptor md, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( md, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, true, false, true, true, artifactFilter)); } public ResolveReport resolve(ModuleRevisionId mrid, String[] confs, boolean transitive, boolean changing, File cache, Date date, boolean validate, boolean useCacheOnly, boolean useOrigin, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( mrid, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, transitive, useOrigin, true, true, artifactFilter), changing); } public ResolveReport resolve(ModuleRevisionId mrid, String[] confs, boolean transitive, boolean changing, File cache, Date date, boolean validate, boolean useCacheOnly, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( mrid, newResolveOptions(confs, null, cache, date, validate, useCacheOnly, transitive, false, true, true, artifactFilter), changing); } public ResolveReport resolve(ModuleRevisionId mrid, String[] confs) throws ParseException, IOException { return ivy.resolve( mrid, newResolveOptions(confs, null, ivy.getSettings().getDefaultCache(), null, true, false, true, false, true, true, FilterHelper.NO_FILTER), false); } public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, boolean useOrigin, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( ivySource, newResolveOptions(confs, revision, cache, date, validate, useCacheOnly, transitive, useOrigin, true, true, artifactFilter)); } public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, boolean transitive, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( ivySource, newResolveOptions(confs, revision, cache, date, validate, useCacheOnly, transitive, false, true, true, artifactFilter)); } public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly, Filter artifactFilter) throws ParseException, IOException { return ivy.resolve( ivySource, newResolveOptions(confs, revision, cache, date, validate, useCacheOnly, true, false, true, true, artifactFilter)); } public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate, boolean useCacheOnly) throws ParseException, IOException { return ivy.resolve( ivySource, newResolveOptions(confs, revision, cache, date, validate, useCacheOnly, true, false, true, true, FilterHelper.NO_FILTER)); } public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate) throws ParseException, IOException { return ivy.resolve( ivySource, newResolveOptions(confs, revision, cache, date, validate, false, true, false, true, true, FilterHelper.NO_FILTER)); } public ResolveReport resolve(URL ivySource) throws ParseException, IOException { return ivy.resolve(ivySource); } public int retrieve(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter, boolean sync, boolean useOrigin, boolean makeSymlinks) { try { return ivy.retrieve(new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern) .setArtifactFilter(artifactFilter).setSync(sync).setUseOrigin(useOrigin) .setMakeSymlinks(makeSymlinks)); } catch (IOException e) { throw new RuntimeException(e); } } public int retrieve(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter, boolean sync, boolean useOrigin) { try { return ivy.retrieve(new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern) .setArtifactFilter(artifactFilter).setSync(sync).setUseOrigin(useOrigin)); } catch (IOException e) { throw new RuntimeException(e); } } public int retrieve(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter) { try { return ivy.retrieve(new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern) .setArtifactFilter(artifactFilter)); } catch (IOException e) { throw new RuntimeException(e); } } public int retrieve(ModuleId moduleId, String[] confs, File cache, String destFilePattern, String destIvyPattern) { try { return ivy.retrieve(new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs).setDestIvyPattern(destIvyPattern)); } catch (IOException e) { throw new RuntimeException(e); } } public int retrieve(ModuleId moduleId, String[] confs, File cache, String destFilePattern) { try { return ivy.retrieve(new ModuleRevisionId(moduleId, Ivy.getWorkingRevision()), destFilePattern, new RetrieveOptions().setConfs(confs)); } catch (IOException e) { throw new RuntimeException(e); } } public void setVariable(String varName, String value) { ivy.setVariable(varName, value); } public List sortModuleDescriptors(Collection moduleDescriptors) { return ivy .sortModuleDescriptors(moduleDescriptors, new SortOptions() .setNonMatchingVersionReporter(new SilentNonMatchingVersionReporter())); } public List sortNodes(Collection nodes) { return ivy .sortNodes(nodes, new SortOptions() .setNonMatchingVersionReporter(new SilentNonMatchingVersionReporter())); } public String substitute(String str) { return ivy.substitute(str); } private String[] splitConfs(String conf) { if (conf == null || "".equals(conf)) { return null; } String[] confs = conf.split(","); for (int i = 0; i < confs.length; i++) { confs[i] = confs[i].trim(); } return confs; } // CheckStyle:ParameterNumberCheck ON } ivy-2.4.0-rc1/src/java/org/apache/ivy/Main.java000066400000000000000000000645361226750426600211150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.StringTokenizer; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.deliver.DeliverOptions; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.publish.PublishOptions; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.retrieve.RetrieveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.util.DefaultMessageLogger; import org.apache.ivy.util.Message; import org.apache.ivy.util.cli.CommandLine; import org.apache.ivy.util.cli.CommandLineParser; import org.apache.ivy.util.cli.OptionBuilder; import org.apache.ivy.util.cli.ParseException; import org.apache.ivy.util.filter.FilterHelper; import org.apache.ivy.util.url.CredentialsStore; import org.apache.ivy.util.url.URLHandler; import org.apache.ivy.util.url.URLHandlerDispatcher; import org.apache.ivy.util.url.URLHandlerRegistry; /** * Class used to launch ivy as a standalone tool. *

* Valid arguments can be obtained with the -? argument. */ public final class Main { private static final int HELP_WIDTH = 80; static CommandLineParser getParser() { return new CommandLineParser() .addCategory("settings options") .addOption( new OptionBuilder("settings").arg("settingsfile") .description("use given file for settings").create()) .addOption( new OptionBuilder("cache").arg("cachedir") .description("use given directory for cache").create()) .addOption( new OptionBuilder("novalidate").description( "do not validate ivy files against xsd").create()) .addOption( new OptionBuilder("m2compatible").description("use maven2 compatibility") .create()) .addOption( new OptionBuilder("conf").arg("settingsfile").deprecated() .description("use given file for settings").create()) .addOption( new OptionBuilder("useOrigin") .deprecated() .description( "use original artifact location " + "with local resolvers instead of copying to the cache") .create()) .addCategory("resolve options") .addOption( new OptionBuilder("ivy").arg("ivyfile") .description("use given file as ivy file").create()) .addOption( new OptionBuilder("refresh").description("refresh dynamic resolved revisions") .create()) .addOption( new OptionBuilder("dependency") .arg("organisation") .arg("module") .arg("revision") .description( "use this instead of ivy file to do the rest " + "of the work with this as a dependency.").create()) .addOption( new OptionBuilder("confs").arg("configurations").countArgs(false) .description("resolve given configurations").create()) .addOption( new OptionBuilder("types").arg("types").countArgs(false) .description("comma separated list of accepted artifact types") .create()) .addOption( new OptionBuilder("mode").arg("resolvemode") .description("the resolve mode to use").create()) .addOption( new OptionBuilder("notransitive").description( "do not resolve dependencies transitively").create()) .addCategory("retrieve options") .addOption( new OptionBuilder("retrieve").arg("retrievepattern") .description("use given pattern as retrieve pattern").create()) .addOption( new OptionBuilder("ivypattern").arg("pattern") .description("use given pattern to copy the ivy files").create()) .addOption( new OptionBuilder("sync").description("use sync mode for retrieve").create()) .addOption( new OptionBuilder("symlink").description("create symbolic links").create()) .addCategory("cache path options") .addOption( new OptionBuilder("cachepath") .arg("cachepathfile") .description( "outputs a classpath consisting of all dependencies in cache " + "(including transitive ones) " + "of the given ivy file to the given cachepathfile") .create()) .addCategory("deliver options") .addOption( new OptionBuilder("deliverto").arg("ivypattern") .description("use given pattern as resolved ivy file pattern").create()) .addCategory("publish options") .addOption( new OptionBuilder("publish").arg("resolvername") .description("use given resolver to publish to").create()) .addOption( new OptionBuilder("publishpattern").arg("artpattern") .description("use given pattern to find artifacts to publish").create()) .addOption( new OptionBuilder("revision").arg("revision") .description("use given revision to publish the module").create()) .addOption( new OptionBuilder("status").arg("status") .description("use given status to publish the module").create()) .addOption( new OptionBuilder("overwrite").description( "overwrite files in the repository if they exist").create()) .addCategory("http auth options") .addOption( new OptionBuilder("realm").arg("realm") .description("use given realm for HTTP AUTH").create()) .addOption( new OptionBuilder("host").arg("host") .description("use given host for HTTP AUTH").create()) .addOption( new OptionBuilder("username").arg("username") .description("use given username for HTTP AUTH").create()) .addOption( new OptionBuilder("passwd").arg("passwd") .description("use given password for HTTP AUTH").create()) .addCategory("launcher options") .addOption( new OptionBuilder("main").arg("main") .description("the FQCN of the main class to launch").create()) .addOption( new OptionBuilder("args").arg("args").countArgs(false) .description("the arguments to give to the launched process").create()) .addOption( new OptionBuilder("cp").arg("cp") .description("extra classpath to use when launching process").create()) .addCategory("message options") .addOption( new OptionBuilder("debug").description("set message level to debug").create()) .addOption( new OptionBuilder("verbose").description("set message level to verbose") .create()) .addOption( new OptionBuilder("warn").description("set message level to warn").create()) .addOption( new OptionBuilder("error").description("set message level to error").create()) .addCategory("help options") .addOption(new OptionBuilder("?").description("display this help").create()) .addOption( new OptionBuilder("deprecated").description("show deprecated options").create()) .addOption( new OptionBuilder("version").description("displays version information") .create()); } public static void main(String[] args) throws Exception { CommandLineParser parser = getParser(); try { run(parser, args); System.exit(0); } catch (ParseException ex) { System.err.println(ex.getMessage()); usage(parser, false); System.exit(1); } } static void run(CommandLineParser parser, String[] args) throws Exception { // parse the command line arguments CommandLine line = parser.parse(args); if (line.hasOption("?")) { usage(parser, line.hasOption("deprecated")); return; } if (line.hasOption("version")) { System.out.println("Apache Ivy " + Ivy.getIvyVersion() + " - " + Ivy.getIvyDate() + " :: " + Ivy.getIvyHomeURL()); return; } boolean validate = line.hasOption("novalidate") ? false : true; Ivy ivy = Ivy.newInstance(); initMessage(line, ivy); IvySettings settings = initSettings(line, ivy); ivy.pushContext(); File cache = new File(settings.substitute(line.getOptionValue("cache", settings .getDefaultCache().getAbsolutePath()))); if (line.hasOption("cache")) { // override default cache path with user supplied cache path settings.setDefaultCache(cache); } if (!cache.exists()) { cache.mkdirs(); } else if (!cache.isDirectory()) { error(cache + " is not a directory"); } String[] confs; if (line.hasOption("confs")) { confs = line.getOptionValues("confs"); } else { confs = new String[] {"*"}; } File ivyfile; if (line.hasOption("dependency")) { String[] dep = line.getOptionValues("dependency"); ivyfile = File.createTempFile("ivy", ".xml"); ivyfile.deleteOnExit(); DefaultModuleDescriptor md = DefaultModuleDescriptor .newDefaultInstance(ModuleRevisionId.newInstance(dep[0], dep[1] + "-caller", "working")); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, ModuleRevisionId.newInstance(dep[0], dep[1], dep[2]), false, false, true); for (int i = 0; i < confs.length; i++) { dd.addDependencyConfiguration("default", confs[i]); } md.addDependency(dd); XmlModuleDescriptorWriter.write(md, ivyfile); confs = new String[] {"default"}; } else { ivyfile = new File(settings.substitute(line.getOptionValue("ivy", "ivy.xml"))); if (!ivyfile.exists()) { error("ivy file not found: " + ivyfile); } else if (ivyfile.isDirectory()) { error("ivy file is not a file: " + ivyfile); } } if (line.hasOption("useOrigin")) { ivy.getSettings().useDeprecatedUseOrigin(); } ResolveOptions resolveOptions = new ResolveOptions() .setConfs(confs) .setValidate(validate) .setResolveMode(line.getOptionValue("mode")) .setArtifactFilter( FilterHelper.getArtifactTypeFilter(line.getOptionValues("types"))); if (line.hasOption("notransitive")) { resolveOptions.setTransitive(false); } if (line.hasOption("refresh")) { resolveOptions.setRefresh(true); } ResolveReport report = ivy.resolve(ivyfile.toURI().toURL(), resolveOptions); if (report.hasError()) { System.exit(1); } ModuleDescriptor md = report.getModuleDescriptor(); if (confs.length == 1 && "*".equals(confs[0])) { confs = md.getConfigurationsNames(); } if (line.hasOption("retrieve")) { String retrievePattern = settings.substitute(line.getOptionValue("retrieve")); if (retrievePattern.indexOf("[") == -1) { retrievePattern = retrievePattern + "/lib/[conf]/[artifact].[ext]"; } String ivyPattern = settings.substitute(line.getOptionValue("ivypattern")); ivy.retrieve( md.getModuleRevisionId(), retrievePattern, new RetrieveOptions() .setConfs(confs) .setSync(line.hasOption("sync")) .setUseOrigin(line.hasOption("useOrigin")) .setDestIvyPattern(ivyPattern) .setArtifactFilter( FilterHelper.getArtifactTypeFilter(line.getOptionValues("types"))) .setMakeSymlinks(line.hasOption("symlink")) .setMakeSymlinksInMass(line.hasOption("symlinkmass"))); } if (line.hasOption("cachepath")) { outputCachePath(ivy, cache, md, confs, line.getOptionValue("cachepath", "ivycachepath.txt")); } if (line.hasOption("revision")) { ivy.deliver( md.getResolvedModuleRevisionId(), settings.substitute(line.getOptionValue("revision")), settings.substitute(line.getOptionValue("deliverto", "ivy-[revision].xml")), DeliverOptions.newInstance(settings) .setStatus(settings.substitute(line.getOptionValue("status", "release"))) .setValidate(validate)); if (line.hasOption("publish")) { ivy.publish( md.getResolvedModuleRevisionId(), Collections.singleton(settings.substitute(line.getOptionValue("publishpattern", "distrib/[type]s/[artifact]-[revision].[ext]"))), line.getOptionValue("publish"), new PublishOptions() .setPubrevision(settings.substitute(line.getOptionValue("revision"))) .setValidate(validate) .setSrcIvyPattern( settings.substitute(line.getOptionValue("deliverto", "ivy-[revision].xml"))) .setOverwrite(line.hasOption("overwrite"))); } } if (line.hasOption("main")) { // check if the option cp has been set List fileList = getExtraClasspathFileList(line); // merge -args and left over args String[] fargs = line.getOptionValues("args"); if (fargs == null) { fargs = new String[0]; } String[] extra = line.getLeftOverArgs(); if (extra == null) { extra = new String[0]; } String[] params = new String[fargs.length + extra.length]; System.arraycopy(fargs, 0, params, 0, fargs.length); System.arraycopy(extra, 0, params, fargs.length, extra.length); // invoke with given main class and merged params invoke(ivy, cache, md, confs, fileList, line.getOptionValue("main"), params); } ivy.getLoggerEngine().popLogger(); ivy.popContext(); } /** * Parses the cp option from the command line, and returns a list of {@link File}. *

* All the files contained in the returned List exist, non existing files are simply skipped * with a warning. *

* * @param line * the command line in which the cp option shold be parsed * @return a List of files to include as extra classpath entries, or null if no cp * option was provided. */ private static List/* */getExtraClasspathFileList(CommandLine line) { List fileList = null; if (line.hasOption("cp")) { fileList = new ArrayList/* */(); String[] cpArray = line.getOptionValues("cp"); for (int index = 0; index < cpArray.length; index++) { StringTokenizer tokenizer = new StringTokenizer(cpArray[index], System.getProperty("path.separator")); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); File file = new File(token); if (file.exists()) { fileList.add(file); } else { Message.warn("Skipping extra classpath '" + file + "' as it does not exist."); } } } } return fileList; } private static IvySettings initSettings(CommandLine line, Ivy ivy) throws java.text.ParseException, IOException, ParseException { IvySettings settings = ivy.getSettings(); settings.addAllVariables(System.getProperties()); if (line.hasOption("m2compatible")) { settings.setVariable("ivy.default.configuration.m2compatible", "true"); } configureURLHandler(line.getOptionValue("realm", null), line.getOptionValue("host", null), line.getOptionValue("username", null), line.getOptionValue("passwd", null)); String settingsPath = line.getOptionValue("settings", ""); if ("".equals(settingsPath)) { settingsPath = line.getOptionValue("conf", ""); if (!"".equals(settingsPath)) { Message.deprecated("-conf is deprecated, use -settings instead"); } } if ("".equals(settingsPath)) { ivy.configureDefault(); } else { File conffile = new File(settingsPath); if (!conffile.exists()) { error("ivy configuration file not found: " + conffile); } else if (conffile.isDirectory()) { error("ivy configuration file is not a file: " + conffile); } ivy.configure(conffile); } return settings; } private static void initMessage(CommandLine line, Ivy ivy) { if (line.hasOption("debug")) { ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_DEBUG)); } else if (line.hasOption("verbose")) { ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_VERBOSE)); } else if (line.hasOption("warn")) { ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_WARN)); } else if (line.hasOption("error")) { ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_ERR)); } else { ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_INFO)); } } private static void outputCachePath(Ivy ivy, File cache, ModuleDescriptor md, String[] confs, String outFile) { try { String pathSeparator = System.getProperty("path.separator"); StringBuffer buf = new StringBuffer(); Collection all = new LinkedHashSet(); ResolutionCacheManager cacheMgr = ivy.getResolutionCacheManager(); XmlReportParser parser = new XmlReportParser(); for (int i = 0; i < confs.length; i++) { String resolveId = ResolveOptions.getDefaultResolveId(md); File report = cacheMgr.getConfigurationResolveReportInCache(resolveId, confs[i]); parser.parse(report); all.addAll(Arrays.asList(parser.getArtifactReports())); } for (Iterator iter = all.iterator(); iter.hasNext();) { ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter.next(); if (artifact.getLocalFile() != null) { buf.append(artifact.getLocalFile().getCanonicalPath()); buf.append(pathSeparator); } } PrintWriter writer = new PrintWriter(new FileOutputStream(outFile)); if (buf.length() > 0) { writer.println(buf.substring(0, buf.length() - pathSeparator.length())); } writer.close(); System.out.println("cachepath output to " + outFile); } catch (Exception ex) { throw new RuntimeException("impossible to build ivy cache path: " + ex.getMessage(), ex); } } private static void invoke(Ivy ivy, File cache, ModuleDescriptor md, String[] confs, List fileList, String mainclass, String[] args) { List urls = new ArrayList(); // Add option cp (extra classpath) urls if (fileList != null && fileList.size() > 0) { for (Iterator iter = fileList.iterator(); iter.hasNext();) { File file = (File) iter.next(); try { urls.add(file.toURI().toURL()); } catch (MalformedURLException e) { // Should not happen, just ignore. } } } try { Collection all = new LinkedHashSet(); ResolutionCacheManager cacheMgr = ivy.getResolutionCacheManager(); XmlReportParser parser = new XmlReportParser(); for (int i = 0; i < confs.length; i++) { String resolveId = ResolveOptions.getDefaultResolveId(md); File report = cacheMgr.getConfigurationResolveReportInCache(resolveId, confs[i]); parser.parse(report); all.addAll(Arrays.asList(parser.getArtifactReports())); } for (Iterator iter = all.iterator(); iter.hasNext();) { ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter.next(); if (artifact.getLocalFile() != null) { urls.add(artifact.getLocalFile().toURI().toURL()); } } } catch (Exception ex) { throw new RuntimeException("impossible to build ivy cache path: " + ex.getMessage(), ex); } URLClassLoader classLoader = new URLClassLoader((URL[]) urls.toArray(new URL[urls.size()]), Main.class.getClassLoader()); try { Class c = classLoader.loadClass(mainclass); Method mainMethod = c.getMethod("main", new Class[] {String[].class}); Thread.currentThread().setContextClassLoader(classLoader); mainMethod.invoke(null, new Object[] {(args == null ? new String[0] : args)}); } catch (ClassNotFoundException cnfe) { throw new RuntimeException("Could not find class: " + mainclass, cnfe); } catch (SecurityException e) { throw new RuntimeException("Could not find main method: " + mainclass, e); } catch (NoSuchMethodException e) { throw new RuntimeException("Could not find main method: " + mainclass, e); } catch (IllegalAccessException e) { throw new RuntimeException("No permissions to invoke main method: " + mainclass, e); } catch (InvocationTargetException e) { throw new RuntimeException("Unexpected exception invoking main method: " + mainclass, e); } } private static void configureURLHandler(String realm, String host, String username, String passwd) { CredentialsStore.INSTANCE.addCredentials(realm, host, username, passwd); URLHandlerDispatcher dispatcher = new URLHandlerDispatcher(); URLHandler httpHandler = URLHandlerRegistry.getHttp(); dispatcher.setDownloader("http", httpHandler); dispatcher.setDownloader("https", httpHandler); URLHandlerRegistry.setDefault(dispatcher); } private static void error(String msg) throws ParseException { throw new ParseException(msg); } private static void usage(CommandLineParser parser, boolean showDeprecated) { // automatically generate the help statement PrintWriter pw = new PrintWriter(System.out); parser.printHelp(pw, HELP_WIDTH, "ivy", showDeprecated); pw.flush(); } private Main() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/000077500000000000000000000000001226750426600201325ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/AddPathTask.java000066400000000000000000000062321226750426600231300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.DirSet; import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Path.PathElement; /** * This task is not directly related to ivy, but is useful in some modular build systems. The idea * is to be able to contribute new sub path elements to an existing path. */ public class AddPathTask extends Task { private String toPath; private boolean first = false; private Path toAdd; public String getTopath() { return toPath; } public void setTopath(String toPath) { this.toPath = toPath; } public void setProject(Project project) { super.setProject(project); toAdd = new Path(project); } public void execute() throws BuildException { Object element = getProject().getReference(toPath); if (element == null) { throw new BuildException("destination path not found: " + toPath); } if (!(element instanceof Path)) { throw new BuildException("destination path is not a path: " + element.getClass()); } Path dest = (Path) element; if (first) { // now way to add path elements at te beginning of the existing path: we do the opposite // and replace the reference toAdd.append(dest); getProject().addReference(toPath, toAdd); } else { dest.append(toAdd); } } public void add(Path path) throws BuildException { toAdd.add(path); } public void addDirset(DirSet dset) throws BuildException { toAdd.addDirset(dset); } public void addFilelist(FileList fl) throws BuildException { toAdd.addFilelist(fl); } public void addFileset(FileSet fs) throws BuildException { toAdd.addFileset(fs); } public Path createPath() throws BuildException { return toAdd.createPath(); } public PathElement createPathElement() throws BuildException { return toAdd.createPathElement(); } public boolean isFirst() { return first; } public void setFirst(boolean first) { this.first = first; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/AntBuildTrigger.java000066400000000000000000000126061226750426600240300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.plugins.trigger.AbstractTrigger; import org.apache.ivy.plugins.trigger.Trigger; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Ant; import org.apache.tools.ant.taskdefs.Property; /** * Triggers an ant build on an event occurence. *

* Example of use: * *

 * <ant-build-trigger event="pre-resolve-dependency" 
 *                    filter="revision=latest.integration"
 *                    antfile="/path/to/[module]/build.xml" 
 *                    target="compile"/>
 * 
* * Triggers an ant build for any dependency in asked in latest.integration, just before resolving * the dependency. *

*

* The onlyonce property is used to tell if the ant build should be triggered only once, or several * times in the same build. *

* * @see AntCallTrigger * @since 1.4 */ public class AntBuildTrigger extends AbstractTrigger implements Trigger { private boolean onlyOnce = true; private String target = null; private Collection builds = new ArrayList(); private String buildFilePattern; private String prefix; public void progress(IvyEvent event) { File f = getBuildFile(event); if (f.exists()) { if (onlyOnce && isBuilt(f)) { Message.verbose("target build file already built, skipping: " + f); } else { Ant ant = new Ant(); Project project = (Project) IvyContext .peekInContextStack(IvyTask.ANT_PROJECT_CONTEXT_KEY); if (project == null) { project = new Project(); project.init(); } ant.setProject(project); ant.setTaskName("ant"); ant.setAntfile(f.getAbsolutePath()); ant.setInheritAll(false); String target = getTarget(); if (target != null) { ant.setTarget(target); } Map atts = event.getAttributes(); for (Iterator iter = atts.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); String value = (String) atts.get(key); if (value != null) { Property p = ant.createProperty(); p.setName(prefix == null ? key : prefix + key); p.setValue(value); } } Message.verbose("triggering build: " + f + " target=" + target + " for " + event); try { ant.execute(); } catch (BuildException e) { Message.verbose("Exception occurred while executing target " + target); throw e; } markBuilt(f); Message.debug("triggered build finished: " + f + " target=" + target + " for " + event); } } else { Message.verbose("no build file found for dependency, skipping: " + f); } } private void markBuilt(File f) { builds.add(f.getAbsolutePath()); } private boolean isBuilt(File f) { return builds.contains(f.getAbsolutePath()); } private File getBuildFile(IvyEvent event) { return IvyContext .getContext() .getSettings() .resolveFile( IvyPatternHelper.substituteTokens(getBuildFilePattern(), event.getAttributes())); } public String getBuildFilePattern() { return buildFilePattern; } public void setAntfile(String pattern) { buildFilePattern = pattern; } public String getTarget() { return target; } public void setTarget(String target) { this.target = target; } public boolean isOnlyonce() { return onlyOnce; } public void setOnlyonce(boolean onlyonce) { onlyOnce = onlyonce; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; if (!prefix.endsWith(".")) { this.prefix += "."; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/AntCallTrigger.java000066400000000000000000000101271226750426600236400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.plugins.trigger.AbstractTrigger; import org.apache.ivy.plugins.trigger.Trigger; import org.apache.ivy.util.Message; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.CallTarget; import org.apache.tools.ant.taskdefs.Property; /** * Triggers an call to an ant target on an event occurence. *

* This trigger only works when ivy is called from an ant build file, otherwise the trigger only log * a failure. *

* Example of use in an ivysettings file: * *

 * <ant-call-trigger event="post-download-artifact" filter="type=zip"
 * target="unzip"/>
 * 
* * Triggers a call to the target "unzip" for any downloaded artifact of type zip * * @see AntBuildTrigger * @since 1.4 */ public class AntCallTrigger extends AbstractTrigger implements Trigger { private boolean onlyonce = true; private String target = null; private Collection calls = new ArrayList(); private String prefix; public void progress(IvyEvent event) { Project project = (Project) IvyContext.peekInContextStack(IvyTask.ANT_PROJECT_CONTEXT_KEY); if (project == null) { Message.info("ant call trigger can only be used from an ant build. Ignoring."); return; } if (onlyonce && isTriggered(event)) { Message.verbose("call already triggered for this event, skipping: " + event); } else { CallTarget call = new CallTarget(); call.setProject(project); call.setTaskName("antcall"); Map attributes = event.getAttributes(); String target = IvyPatternHelper.substituteTokens(getTarget(), attributes); call.setTarget(target); for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); String value = (String) attributes.get(key); Property p = call.createParam(); p.setName(prefix == null ? key : prefix + key); p.setValue(value == null ? "" : value); } Message.verbose("triggering ant call: target=" + target + " for " + event); call.execute(); markTriggered(event); Message.debug("triggered ant call finished: target=" + target + " for " + event); } } private void markTriggered(IvyEvent event) { calls.add(event); } private boolean isTriggered(IvyEvent event) { return calls.contains(event); } public String getTarget() { return target; } public void setTarget(String target) { this.target = target; } public boolean isOnlyonce() { return onlyonce; } public void setOnlyonce(boolean onlyonce) { this.onlyonce = onlyonce; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; if (!prefix.endsWith(".")) { this.prefix += "."; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/AntMessageLogger.java000066400000000000000000000123021226750426600241620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.Ivy; import org.apache.ivy.util.AbstractMessageLogger; import org.apache.ivy.util.Checks; import org.apache.ivy.util.MessageLogger; import org.apache.tools.ant.BuildEvent; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; /** * Implementation of the simple message facility for ant. */ public class AntMessageLogger extends AbstractMessageLogger { private static final int PROGRESS_LOG_PERIOD = 1500; /** * Creates and register an {@link AntMessageLogger} for the given {@link Task}, with the given * {@link Ivy} instance. *

* The created instance will automatically be unregistered from the Ivy instance when the task * finishes. *

* * @param task * the task the logger should use for logging * @param ivy * the ivy instance on which the logger should be registered */ public static void register(ProjectComponent task, final Ivy ivy) { MessageLogger current = ivy.getLoggerEngine().peekLogger(); if (current instanceof AntMessageLogger && task instanceof Task && ((AntMessageLogger) current).task instanceof Task) { Task currentTask = (Task) ((AntMessageLogger) current).task; if ((currentTask.getTaskName() != null) && currentTask.getTaskName().equals(((Task) task).getTaskName())) { // The current AntMessageLogger already logs with the same // prefix as the given task. So we shouldn't do anything... return; } } AntMessageLogger logger = new AntMessageLogger(task); ivy.getLoggerEngine().pushLogger(logger); task.getProject().addBuildListener(new BuildListener() { private int stackDepth = 0; public void buildFinished(BuildEvent event) { } public void buildStarted(BuildEvent event) { } public void targetStarted(BuildEvent event) { } public void targetFinished(BuildEvent event) { } public void taskStarted(BuildEvent event) { stackDepth++; } public void taskFinished(BuildEvent event) { // NB: There is somtimes task created by an other task // in that case, we should not uninit Message. The log should stay associated // with the initial task, except if it was an antcall, ant or subant target // NB2 : Testing the identity of the task is not enought, event.getTask() return // an instance of UnknownElement is wrapping the concrete instance stackDepth--; if (stackDepth == -1) { ivy.getLoggerEngine().popLogger(); event.getProject().removeBuildListener(this); } } public void messageLogged(BuildEvent event) { } }); } private ProjectComponent task; private long lastProgressFlush = 0; private StringBuffer buf = new StringBuffer(); /** * Constructs a new AntMEssageImpl instance. * * @param antProjectComponent * the ant project component this message implementation should use for logging. Must * not be null. */ protected AntMessageLogger(ProjectComponent task) { Checks.checkNotNull(task, "task"); this.task = task; } public void log(String msg, int level) { task.log(msg, level); } public void rawlog(String msg, int level) { task.getProject().log(msg, level); } public void doProgress() { buf.append("."); if (lastProgressFlush == 0) { lastProgressFlush = System.currentTimeMillis(); } // log with ant causes a new line -> we do it only once in a while if (System.currentTimeMillis() - lastProgressFlush > PROGRESS_LOG_PERIOD) { task.log(buf.toString()); buf.setLength(0); lastProgressFlush = System.currentTimeMillis(); } } public void doEndProgress(String msg) { task.log(buf + msg); buf.setLength(0); lastProgressFlush = 0; } public String toString() { return "AntMessageLogger:" + task; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/BuildOBRTask.java000066400000000000000000000162501226750426600232260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.ParseException; import java.util.Arrays; import java.util.List; import javax.xml.transform.TransformerConfigurationException; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.cache.DefaultRepositoryCacheManager; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.osgi.obr.xml.OBRXMLWriter; import org.apache.ivy.osgi.repo.ArtifactReportManifestIterable; import org.apache.ivy.osgi.repo.FSManifestIterable; import org.apache.ivy.osgi.repo.ManifestAndLocation; import org.apache.ivy.osgi.repo.ResolverManifestIterable; import org.apache.ivy.plugins.resolver.BasicResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; public class BuildOBRTask extends IvyCacheTask { private String resolverName = null; private File file = null; private String cacheName = null; private String encoding = "UTF-8"; private boolean indent = true; private File baseDir; private boolean quiet; private List sourceTypes = Arrays.asList("source", "sources", "src"); public void setResolver(String resolverName) { this.resolverName = resolverName; } public void setCache(String cacheName) { this.cacheName = cacheName; } public void setOut(File file) { this.file = file; } public void setEncoding(String encoding) { this.encoding = encoding; } public void setIndent(boolean indent) { this.indent = indent; } public void setBaseDir(File dir) { this.baseDir = dir; } public void setQuiet(boolean quiet) { this.quiet = quiet; } public void setSourceType(String sourceType) { this.sourceTypes = Arrays.asList(sourceType.split(",")); } protected void prepareTask() { // if browsing a folder, not need for an Ivy instance if (baseDir == null) { super.prepareTask(); } // ensure the configured source type get also resolved if (getType() != null && !getType().equals("*") && sourceTypes != null && !sourceTypes.isEmpty()) { StringBuilder buffer = new StringBuilder(getType()); for (String sourceType : sourceTypes) { buffer.append(","); buffer.append(sourceType); } setType(buffer.toString()); } } public void doExecute() throws BuildException { if (file == null) { throw new BuildException("No output file specified: use the attribute 'out'"); } Iterable it; if (resolverName != null) { if (baseDir != null) { throw new BuildException("specify only one of 'resolver' or 'baseDir'"); } if (cacheName != null) { throw new BuildException("specify only one of 'resolver' or 'cache'"); } Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); DependencyResolver resolver = settings.getResolver(resolverName); if (resolver == null) { throw new BuildException("the resolver '" + resolverName + "' was not found"); } if (!(resolver instanceof BasicResolver)) { throw new BuildException("the type of resolver '" + resolver.getClass().getName() + "' is not supported."); } it = new ResolverManifestIterable((BasicResolver) resolver); } else if (baseDir != null) { if (cacheName != null) { throw new BuildException("specify only one of 'baseDir' or 'cache'"); } if (!baseDir.isDirectory()) { throw new BuildException(baseDir + " is not a directory"); } it = new FSManifestIterable(baseDir); } else if (cacheName != null) { Ivy ivy = getIvyInstance(); RepositoryCacheManager cacheManager = ivy.getSettings().getRepositoryCacheManager( cacheName); if (!(cacheManager instanceof DefaultRepositoryCacheManager)) { throw new BuildException("the type of cache '" + cacheManager.getClass().getName() + "' is not supported."); } File basedir = ((DefaultRepositoryCacheManager) cacheManager).getBasedir(); it = new FSManifestIterable(basedir); } else { prepareAndCheck(); try { it = new ArtifactReportManifestIterable(getArtifactReports(), sourceTypes); } catch (ParseException e) { throw new BuildException("Impossible to parse the artifact reports: " + e.getMessage(), e); } catch (IOException e) { throw new BuildException("Impossible to read the artifact reports: " + e.getMessage(), e); } } OutputStream out; try { out = new FileOutputStream(file); } catch (FileNotFoundException e) { throw new BuildException(file + " was not found", e); } ContentHandler hd; try { hd = OBRXMLWriter.newHandler(out, encoding, indent); } catch (TransformerConfigurationException e) { throw new BuildException("Sax configuration error: " + e.getMessage(), e); } class AntMessageLogger2 extends AntMessageLogger { AntMessageLogger2() { super(BuildOBRTask.this); } } IvyContext.getContext().getMessageLogger(); Message.setDefaultLogger(new AntMessageLogger2()); try { OBRXMLWriter.writeManifests(it, hd, quiet); } catch (SAXException e) { throw new BuildException("Sax serialisation error: " + e.getMessage(), e); } try { out.flush(); out.close(); } catch (IOException e) { // don't care } Message.sumupProblems(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/ConvertManifestTask.java000066400000000000000000000067761226750426600247470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.ParseException; import java.util.jar.Manifest; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleInfoAdapter; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.core.ManifestParser; import org.apache.ivy.osgi.core.OSGiManifestParser; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.tools.ant.BuildException; public class ConvertManifestTask extends IvyTask { private File manifest = null; private File ivyFile = null; private ExecutionEnvironmentProfileProvider profileProvider; public void setProfileProvider(ExecutionEnvironmentProfileProvider profileProvider) { this.profileProvider = profileProvider; } public void setManifest(File manifest) { this.manifest = manifest; } public void setIvyFile(File ivyFile) { this.ivyFile = ivyFile; } public void doExecute() throws BuildException { if (ivyFile == null) { throw new BuildException("destination ivy file is required for convertmanifest task"); } if (manifest == null) { throw new BuildException("source manifest file is required for convertmanifest task"); } if (profileProvider == null) { try { profileProvider = new ExecutionEnvironmentProfileProvider(); } catch (IOException e) { throw new BuildException("Enable to load the default environment profiles", e); } } Manifest m; try { m = new Manifest(new FileInputStream(manifest)); } catch (FileNotFoundException e) { throw new BuildException("the manifest file '" + manifest + "' was not found", e); } catch (IOException e) { throw new BuildException("the manifest file '" + manifest + "' could not be read", e); } BundleInfo bundleInfo; try { bundleInfo = ManifestParser.parseManifest(m); } catch (ParseException e) { throw new BuildException("Incorrect manifest file '" + manifest + "'", e); } ModuleDescriptor md = BundleInfoAdapter.toModuleDescriptor( OSGiManifestParser.getInstance(), null, bundleInfo, profileProvider); try { XmlModuleDescriptorWriter.write(md, ivyFile); } catch (IOException e) { throw new BuildException("The ivyFile '" + ivyFile + "' could not be written", e); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/FixDepsTask.java000066400000000000000000000054501226750426600231660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.tools.ant.BuildException; public class FixDepsTask extends IvyPostResolveTask { private File dest; private List/* */keeps = new ArrayList(); public void setToFile(File dest) { this.dest = dest; } public static class Keep { private String org; private String module; public void setOrg(String org) { this.org = org; } public void setModule(String module) { this.module = module; } } public Keep createKeep() { Keep k = new Keep(); keeps.add(k); return k; } public void doExecute() throws BuildException { prepareAndCheck(); if (dest == null) { throw new BuildException("Missing required parameter 'tofile'"); } if (dest.exists() && dest.isDirectory()) { throw new BuildException("The destination file '" + dest.getAbsolutePath() + "' already exist and is a folder"); } ResolveReport report = getResolvedReport(); List/* */midToKeep = new ArrayList(); for (int i = 0; i < keeps.size(); i++) { midToKeep.add(ModuleId.newInstance(((Keep) keeps.get(i)).org, ((Keep) keeps.get(i)).module)); } ModuleDescriptor md = report.toFixedModuleDescriptor(getSettings(), midToKeep); try { XmlModuleDescriptorWriter.write(md, dest); } catch (IOException e) { throw new BuildException("Failed to write into the file " + dest.getAbsolutePath() + " (" + e.getMessage() + ")", e); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyAntSettings.java000066400000000000000000000313751226750426600237410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.util.Properties; import org.apache.ivy.Ivy; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.settings.IvyVariableContainer; import org.apache.ivy.util.Message; import org.apache.ivy.util.url.CredentialsStore; import org.apache.ivy.util.url.URLHandler; import org.apache.ivy.util.url.URLHandlerDispatcher; import org.apache.ivy.util.url.URLHandlerRegistry; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Property; import org.apache.tools.ant.types.DataType; public class IvyAntSettings extends DataType { public static class Credentials { private String realm; private String host; private String username; private String passwd; public String getPasswd() { return this.passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public String getRealm() { return this.realm; } public void setRealm(String realm) { this.realm = format(realm); } public String getHost() { return this.host; } public void setHost(String host) { this.host = format(host); } public String getUsername() { return this.username; } public void setUsername(String userName) { this.username = format(userName); } } private Ivy ivyEngine = null; private File file = null; private URL url = null; private String realm = null; private String host = null; private String userName = null; private String passwd = null; private String id = "ivy.instance"; private boolean autoRegistered = false; /** * Returns the default ivy settings of this classloader. If it doesn't exist yet, a new one is * created using the given project to back the VariableContainer. * * @param project * TODO add text. * @return An IvySetting instance. */ public static IvyAntSettings getDefaultInstance(ProjectComponent task) { Project project = task.getProject(); Object defaultInstanceObj = project.getReference("ivy.instance"); if (defaultInstanceObj != null && defaultInstanceObj.getClass().getClassLoader() != IvyAntSettings.class .getClassLoader()) { task.log("ivy.instance reference an ivy:settings defined in an other classloader. " + "An new default one will be used in this project.", Project.MSG_WARN); defaultInstanceObj = null; } if (defaultInstanceObj != null && !(defaultInstanceObj instanceof IvyAntSettings)) { throw new BuildException("ivy.instance reference a " + defaultInstanceObj.getClass().getName() + " an not an IvyAntSettings. Please don't use this reference id ()"); } if (defaultInstanceObj == null) { task.log("No ivy:settings found for the default reference 'ivy.instance'. " + "A default instance will be used", Project.MSG_VERBOSE); IvyAntSettings settings = new IvyAntSettings(); settings.setProject(project); project.addReference("ivy.instance", settings); settings.createIvyEngine(task); return settings; } else { return (IvyAntSettings) defaultInstanceObj; } } /* * Keep this for backwards compatibility! */ public static IvyAntSettings getDefaultInstance(Task task) { return getDefaultInstance((ProjectComponent) task); } public File getFile() { return file; } public URL getUrl() { return url; } public String getPasswd() { return passwd; } public void setPasswd(String aPasswd) { passwd = aPasswd; } public String getRealm() { return realm; } public void setRealm(String aRealm) { realm = format(aRealm); } public String getHost() { return host; } public void setHost(String aHost) { host = format(aHost); } public String getUsername() { return userName; } public void setUsername(String aUserName) { userName = format(aUserName); } public void setProject(Project p) { super.setProject(p); if ("ivy.instance".equals(id) && !getProject().getReferences().containsKey(id)) { // register ourselfs as default settings, just in case the id attribute is not set getProject().addReference("ivy.instance", this); autoRegistered = true; } } private static String format(String str) { return str == null ? str : (str.trim().length() == 0 ? null : str.trim()); } public void addConfiguredCredentials(Credentials c) { CredentialsStore.INSTANCE.addCredentials(c.getRealm(), c.getHost(), c.getUsername(), c.getPasswd()); } public void setFile(File file) { this.file = file; } public void setUrl(String confUrl) throws MalformedURLException { this.url = new URL(confUrl); } public void setUrl(URL url) { this.url = url; } /* * This is usually not necessary to define a reference in Ant, but it's the only way to know the * id of the settings, which we use to set ant properties. */ public void setId(String id) { if (autoRegistered && getProject().getReference(this.id) == this) { getProject().getReferences().remove(this.id); autoRegistered = false; } this.id = id; if (getProject() != null) { getProject().addReference(this.id, this); } } public String getId() { return id; } /** * Return the configured Ivy instance. * * @return Returns the configured Ivy instance. */ public Ivy getConfiguredIvyInstance(ProjectComponent task) { if (ivyEngine == null) { createIvyEngine(task); } return ivyEngine; } /* * Keep this for backwards compatibility! */ public Ivy getConfiguredIvyInstance(Task task) { return getConfiguredIvyInstance((ProjectComponent) task); } void createIvyEngine(final ProjectComponent task) { Project project = task.getProject(); Property prop = new Property() { public void execute() throws BuildException { addProperties(getDefaultProperties(task)); } }; prop.setProject(project); prop.init(); prop.execute(); IvyAntVariableContainer ivyAntVariableContainer = new IvyAntVariableContainer(project); IvySettings settings = new IvySettings(ivyAntVariableContainer); settings.setBaseDir(project.getBaseDir()); if (file == null && url == null) { defineDefaultSettingFile(ivyAntVariableContainer, task); } Ivy ivy = Ivy.newInstance(settings); try { ivy.pushContext(); AntMessageLogger.register(task, ivy); Message.showInfo(); configureURLHandler(); if (file != null) { if (!file.exists()) { throw new BuildException("settings file does not exist: " + file); } ivy.configure(file); } else { if (url == null) { throw new AssertionError( "ivy setting should have either a file, either an url," + " and if not defineDefaultSettingFile must set it."); } ivy.configure(url); } ivyAntVariableContainer.updateProject(id); ivyEngine = ivy; } catch (ParseException e) { throw new BuildException("impossible to configure ivy:settings with given " + (file != null ? "file: " + file : "url: " + url) + " : " + e, e); } catch (IOException e) { throw new BuildException("impossible to configure ivy:settings with given " + (file != null ? "file: " + file : "url: " + url) + " : " + e, e); } finally { ivy.popContext(); } } protected Properties getDefaultProperties(ProjectComponent task) { URL url = IvySettings.getDefaultPropertiesURL(); // this is copy of loadURL code from ant Property task (not available in 1.5.1) Properties props = new Properties(); task.log("Loading " + url, Project.MSG_VERBOSE); try { InputStream is = url.openStream(); try { props.load(is); } finally { if (is != null) { is.close(); } } } catch (IOException ex) { throw new BuildException(ex); } return props; } /** * Set file or url to its default value * * @param variableContainer */ private void defineDefaultSettingFile(IvyVariableContainer variableContainer, ProjectComponent task) { String settingsFileName = variableContainer.getVariable("ivy.conf.file"); if (settingsFileName != null && !settingsFileName.equals(variableContainer.getVariable("ivy.settings.file"))) { task.log("DEPRECATED: 'ivy.conf.file' is deprecated, use 'ivy.settings.file' instead", Project.MSG_INFO); } else { settingsFileName = variableContainer.getVariable("ivy.settings.file"); } File[] settingsLocations = new File[] { new File(getProject().getBaseDir(), settingsFileName), new File(getProject().getBaseDir(), "ivyconf.xml"), new File(settingsFileName), new File("ivyconf.xml")}; for (int i = 0; i < settingsLocations.length; i++) { file = settingsLocations[i]; task.log("searching settings file: trying " + file, Project.MSG_VERBOSE); if (file.exists()) { break; } } if (!file.exists()) { file = null; if (Boolean.valueOf(getProject().getProperty("ivy.14.compatible")).booleanValue()) { task.log("no settings file found, using Ivy 1.4 default...", Project.MSG_VERBOSE); url = IvySettings.getDefault14SettingsURL(); } else { String settingsFileUrl = variableContainer.getVariable("ivy.settings.url"); if (settingsFileUrl != null) { try { url = new URL(settingsFileUrl); } catch (MalformedURLException e) { throw new BuildException( "Impossible to configure ivy:settings with given url: " + settingsFileUrl + ": " + e.getMessage(), e); } } else { task.log("no settings file found, using default...", Project.MSG_VERBOSE); url = IvySettings.getDefaultSettingsURL(); } } } } private void configureURLHandler() { // TODO : the credentialStore should also be scoped CredentialsStore.INSTANCE.addCredentials(getRealm(), getHost(), getUsername(), getPasswd()); URLHandlerDispatcher dispatcher = new URLHandlerDispatcher(); URLHandler httpHandler = URLHandlerRegistry.getHttp(); dispatcher.setDownloader("http", httpHandler); dispatcher.setDownloader("https", httpHandler); URLHandlerRegistry.setDefault(dispatcher); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyAntVariableContainer.java000066400000000000000000000073541226750426600255310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.settings.IvyVariableContainer; import org.apache.ivy.core.settings.IvyVariableContainerImpl; import org.apache.ivy.util.Message; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Property; class IvyAntVariableContainer extends IvyVariableContainerImpl implements IvyVariableContainer { private Map overwrittenProperties = new HashMap(); private Project project; public IvyAntVariableContainer(Project project) { this.project = project; } public String getVariable(String name) { String r = (String) overwrittenProperties.get(name); if (r == null) { r = project.getProperty(name); } if (r == null) { r = super.getVariable(name); } return r; } public void setVariable(String varName, String value, boolean overwrite) { if (overwrite) { Message.debug("setting '" + varName + "' to '" + value + "'"); overwrittenProperties.put(varName, substitute(value)); } else { super.setVariable(varName, value, overwrite); } } /** * Updates the Ant Project used in this container with variables set in Ivy. * * All variables defined in Ivy will be set in the Ant project under two names: *
    *
  • the name of the variable
  • *
  • the name of the variable suffxied with a dot + the given id, if the given id is not null
  • *
* * @param id * The identifier of the settings in which the variables have been set, which should * be used as property names suffix */ public void updateProject(String id) { Map r = new HashMap(super.getVariables()); r.putAll(overwrittenProperties); for (Iterator it = r.entrySet().iterator(); it.hasNext();) { Entry entry = (Entry) it.next(); setPropertyIfNotSet((String) entry.getKey(), (String) entry.getValue()); if (id != null) { setPropertyIfNotSet((String) entry.getKey() + "." + id, (String) entry.getValue()); } } if (getEnvironmentPrefix() != null) { Property propTask = new Property(); propTask.setProject(project); propTask.setEnvironment(getEnvironmentPrefix()); propTask.init(); propTask.execute(); } } private void setPropertyIfNotSet(String property, String value) { if (project.getProperty(property) == null) { project.setProperty(property, value); } } public Object clone() { IvyAntVariableContainer result = (IvyAntVariableContainer) super.clone(); result.overwrittenProperties = (HashMap) ((HashMap) this.overwrittenProperties).clone(); return result; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyArtifactProperty.java000066400000000000000000000064411226750426600247740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.tools.ant.BuildException; /** * Set a set of ant properties according to the last artifact resolved */ public class IvyArtifactProperty extends IvyPostResolveTask { private String name; private String value; private boolean overwrite = false; public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getValue() { return this.value; } public void setValue(String value) { this.value = value; } public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } public void doExecute() throws BuildException { prepareAndCheck(); try { ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); String[] confs = splitConfs(getConf()); String resolveId = getResolveId(); if (resolveId == null) { resolveId = ResolveOptions.getDefaultResolveId(getResolvedModuleId()); } XmlReportParser parser = new XmlReportParser(); for (int i = 0; i < confs.length; i++) { File report = cacheMgr.getConfigurationResolveReportInCache(resolveId, confs[i]); parser.parse(report); Artifact[] artifacts = parser.getArtifacts(); for (int j = 0; j < artifacts.length; j++) { Artifact artifact = artifacts[j]; String name = IvyPatternHelper.substitute(getSettings().substitute(getName()), artifact, confs[i]); String value = IvyPatternHelper.substitute( getSettings().substitute(getValue()), artifact, confs[i]); setProperty(name, value); } } } catch (Exception ex) { throw new BuildException("impossible to add artifact properties: " + ex, ex); } } private void setProperty(String name, String value) { if (overwrite) { getProject().setProperty(name, value); } else { getProject().setNewProperty(name, value); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyArtifactReport.java000066400000000000000000000312371226750426600244240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.ParseException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.retrieve.RetrieveOptions; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * Generates a report of all artifacts involved during the last resolve. */ public class IvyArtifactReport extends IvyPostResolveTask { private File tofile; private String pattern; public File getTofile() { return tofile; } public void setTofile(File aFile) { tofile = aFile; } public String getPattern() { return pattern; } public void setPattern(String aPattern) { pattern = aPattern; } public void doExecute() throws BuildException { prepareAndCheck(); if (tofile == null) { throw new BuildException( "no destination file name: please provide it through parameter 'tofile'"); } pattern = getProperty(pattern, getSettings(), "ivy.retrieve.pattern"); try { String[] confs = splitConfs(getConf()); ModuleDescriptor md = null; if (getResolveId() != null) { md = (ModuleDescriptor) getResolvedDescriptor(getResolveId()); } else { md = (ModuleDescriptor) getResolvedDescriptor(getOrganisation(), getModule(), false); } IvyNode[] dependencies = getIvyInstance().getResolveEngine().getDependencies( md, ((ResolveOptions) new ResolveOptions().setLog(getLog())).setConfs(confs) .setResolveId(getResolveId()).setValidate(doValidate(getSettings())), null); Map artifactsToCopy = getIvyInstance().getRetrieveEngine().determineArtifactsToCopy( ModuleRevisionId.newInstance(getOrganisation(), getModule(), getRevision()), pattern, ((RetrieveOptions) new RetrieveOptions().setLog(getLog())).setConfs(confs) .setResolveId(getResolveId())); Map moduleRevToArtifactsMap = new HashMap(); for (Iterator iter = artifactsToCopy.keySet().iterator(); iter.hasNext();) { ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter.next(); Set moduleRevArtifacts = (Set) moduleRevToArtifactsMap.get(artifact.getArtifact() .getModuleRevisionId()); if (moduleRevArtifacts == null) { moduleRevArtifacts = new HashSet(); moduleRevToArtifactsMap.put(artifact.getArtifact().getModuleRevisionId(), moduleRevArtifacts); } moduleRevArtifacts.add(artifact); } generateXml(dependencies, moduleRevToArtifactsMap, artifactsToCopy); } catch (ParseException e) { log(e.getMessage(), Project.MSG_ERR); throw new BuildException("syntax errors in ivy file: " + e, e); } catch (IOException e) { throw new BuildException("impossible to generate report: " + e, e); } } private void generateXml(IvyNode[] dependencies, Map moduleRevToArtifactsMap, Map artifactsToCopy) { try { FileOutputStream fileOuputStream = new FileOutputStream(tofile); try { TransformerHandler saxHandler = createTransformerHandler(fileOuputStream); saxHandler.startDocument(); saxHandler.startElement(null, "modules", "modules", new AttributesImpl()); for (int i = 0; i < dependencies.length; i++) { IvyNode dependency = dependencies[i]; if (dependency.getModuleRevision() == null || dependency.isCompletelyEvicted()) { continue; } startModule(saxHandler, dependency); Set artifactsOfModuleRev = (Set) moduleRevToArtifactsMap.get(dependency .getModuleRevision().getId()); if (artifactsOfModuleRev != null) { for (Iterator iter = artifactsOfModuleRev.iterator(); iter.hasNext();) { ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter.next(); RepositoryCacheManager cache = dependency.getModuleRevision() .getArtifactResolver().getRepositoryCacheManager(); startArtifact(saxHandler, artifact.getArtifact()); writeOriginLocationIfPresent(cache, saxHandler, artifact); writeCacheLocationIfPresent(cache, saxHandler, artifact); Set artifactDestPaths = (Set) artifactsToCopy.get(artifact); for (Iterator iterator = artifactDestPaths.iterator(); iterator .hasNext();) { String artifactDestPath = (String) iterator.next(); writeRetrieveLocation(saxHandler, artifactDestPath); } saxHandler.endElement(null, "artifact", "artifact"); } } saxHandler.endElement(null, "module", "module"); } saxHandler.endElement(null, "modules", "modules"); saxHandler.endDocument(); } finally { fileOuputStream.close(); } } catch (SAXException e) { throw new BuildException("impossible to generate report", e); } catch (TransformerConfigurationException e) { throw new BuildException("impossible to generate report", e); } catch (IOException e) { throw new BuildException("impossible to generate report", e); } } private TransformerHandler createTransformerHandler(FileOutputStream fileOuputStream) throws TransformerFactoryConfigurationError, TransformerConfigurationException, SAXException { SAXTransformerFactory transformerFact = (SAXTransformerFactory) SAXTransformerFactory .newInstance(); TransformerHandler saxHandler = transformerFact.newTransformerHandler(); saxHandler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8"); saxHandler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); saxHandler.setResult(new StreamResult(fileOuputStream)); return saxHandler; } private void startModule(TransformerHandler saxHandler, IvyNode dependency) throws SAXException { AttributesImpl moduleAttrs = new AttributesImpl(); moduleAttrs.addAttribute(null, "organisation", "organisation", "CDATA", dependency .getModuleId().getOrganisation()); moduleAttrs.addAttribute(null, "name", "name", "CDATA", dependency.getModuleId().getName()); ResolvedModuleRevision moduleRevision = dependency.getModuleRevision(); moduleAttrs.addAttribute(null, "rev", "rev", "CDATA", moduleRevision.getId().getRevision()); moduleAttrs.addAttribute(null, "status", "status", "CDATA", moduleRevision.getDescriptor() .getStatus()); saxHandler.startElement(null, "module", "module", moduleAttrs); } private void startArtifact(TransformerHandler saxHandler, Artifact artifact) throws SAXException { AttributesImpl artifactAttrs = new AttributesImpl(); artifactAttrs.addAttribute(null, "name", "name", "CDATA", artifact.getName()); artifactAttrs.addAttribute(null, "ext", "ext", "CDATA", artifact.getExt()); artifactAttrs.addAttribute(null, "type", "type", "CDATA", artifact.getType()); saxHandler.startElement(null, "artifact", "artifact", artifactAttrs); } private void writeOriginLocationIfPresent(RepositoryCacheManager cache, TransformerHandler saxHandler, ArtifactDownloadReport artifact) throws IOException, SAXException { ArtifactOrigin origin = artifact.getArtifactOrigin(); if (!ArtifactOrigin.isUnknown(origin)) { String originName = origin.getLocation(); boolean isOriginLocal = origin.isLocal(); String originLocation; AttributesImpl originLocationAttrs = new AttributesImpl(); if (isOriginLocal) { originLocationAttrs.addAttribute(null, "is-local", "is-local", "CDATA", "true"); originLocation = originName.replace('\\', '/'); } else { originLocationAttrs.addAttribute(null, "is-local", "is-local", "CDATA", "false"); originLocation = originName; } saxHandler .startElement(null, "origin-location", "origin-location", originLocationAttrs); char[] originLocationAsChars = originLocation.toCharArray(); saxHandler.characters(originLocationAsChars, 0, originLocationAsChars.length); saxHandler.endElement(null, "origin-location", "origin-location"); } } private void writeCacheLocationIfPresent(RepositoryCacheManager cache, TransformerHandler saxHandler, ArtifactDownloadReport artifact) throws SAXException { File archiveInCache = artifact.getLocalFile(); if (archiveInCache != null) { saxHandler.startElement(null, "cache-location", "cache-location", new AttributesImpl()); char[] archiveInCacheAsChars = archiveInCache.getPath().replace('\\', '/') .toCharArray(); saxHandler.characters(archiveInCacheAsChars, 0, archiveInCacheAsChars.length); saxHandler.endElement(null, "cache-location", "cache-location"); } } private void writeRetrieveLocation(TransformerHandler saxHandler, String artifactDestPath) throws SAXException { artifactDestPath = removeLeadingPath(getProject().getBaseDir(), new File(artifactDestPath)); saxHandler.startElement(null, "retrieve-location", "retrieve-location", new AttributesImpl()); char[] artifactDestPathAsChars = artifactDestPath.replace('\\', '/').toCharArray(); saxHandler.characters(artifactDestPathAsChars, 0, artifactDestPathAsChars.length); saxHandler.endElement(null, "retrieve-location", "retrieve-location"); } // method largely inspired by ant 1.6.5 FileUtils method public String removeLeadingPath(File leading, File path) { String l = leading.getAbsolutePath(); String p = path.getAbsolutePath(); if (l.equals(p)) { return ""; } // ensure that l ends with a / // so we never think /foo was a parent directory of /foobar if (!l.endsWith(File.separator)) { l += File.separator; } return (p.startsWith(l)) ? p.substring(l.length()) : p; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyBuildList.java000066400000000000000000000506401226750426600233650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.sort.SortOptions; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; /** * Creates an ant filelist of files (usually build.xml) ordered according to the dependencies * declared in ivy files. */ public class IvyBuildList extends IvyTask { public static final class OnMissingDescriptor { public static final String HEAD = "head"; public static final String TAIL = "tail"; public static final String SKIP = "skip"; public static final String FAIL = "fail"; public static final String WARN = "warn"; private OnMissingDescriptor() { } } public static final String DESCRIPTOR_REQUIRED = "required"; private List buildFileSets = new ArrayList(); // List (FileSet) private String reference; private boolean haltOnError = true; private String onMissingDescriptor = OnMissingDescriptor.HEAD; private boolean reverse = false; private String ivyFilePath; private String root = "*"; private boolean excludeRoot = false; private String leaf = "*"; private String delimiter = ","; private boolean excludeLeaf = false; private boolean onlydirectdep = false; private String restartFrom = "*"; public void addFileset(FileSet buildFiles) { buildFileSets.add(buildFiles); } public String getReference() { return reference; } public void setReference(String reference) { this.reference = reference; } public String getRoot() { return root; } public void setRoot(String root) { this.root = root; } public boolean isExcludeRoot() { return excludeRoot; } public void setExcludeRoot(boolean root) { excludeRoot = root; } public String getLeaf() { return leaf; } public void setLeaf(String leaf) { this.leaf = leaf; } public boolean isExcludeLeaf() { return excludeLeaf; } public void setExcludeLeaf(boolean excludeLeaf) { this.excludeLeaf = excludeLeaf; } public String getDelimiter() { return delimiter; } public void setDelimiter(String delimiter) { this.delimiter = delimiter; } public boolean getOnlydirectdep() { return onlydirectdep; } public void setOnlydirectdep(boolean onlydirectdep) { this.onlydirectdep = onlydirectdep; } public void doExecute() throws BuildException { if (reference == null) { throw new BuildException("reference should be provided in ivy build list"); } if (buildFileSets.isEmpty()) { throw new BuildException( "at least one nested fileset should be provided in ivy build list"); } Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); ivyFilePath = getProperty(ivyFilePath, settings, "ivy.buildlist.ivyfilepath"); Path path = new Path(getProject()); Map buildFiles = new HashMap(); // Map (ModuleDescriptor -> File buildFile) List independent = new ArrayList(); List noDescriptor = new ArrayList(); Collection mds = new ArrayList(); Set rootModuleNames = new LinkedHashSet(); if (!"*".equals(root)) { StringTokenizer st = new StringTokenizer(root, delimiter); while (st.hasMoreTokens()) { rootModuleNames.add(st.nextToken()); } } Set leafModuleNames = new LinkedHashSet(); if (!"*".equals(leaf)) { StringTokenizer st = new StringTokenizer(leaf, delimiter); while (st.hasMoreTokens()) { leafModuleNames.add(st.nextToken()); } } Set restartFromModuleNames = new LinkedHashSet(); if (!"*".equals(restartFrom)) { StringTokenizer st = new StringTokenizer(restartFrom, delimiter); // Only accept one (first) module restartFromModuleNames.add(st.nextToken()); } for (ListIterator iter = buildFileSets.listIterator(); iter.hasNext();) { FileSet fs = (FileSet) iter.next(); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); String[] builds = ds.getIncludedFiles(); for (int i = 0; i < builds.length; i++) { File buildFile = new File(ds.getBasedir(), builds[i]); File ivyFile = getIvyFileFor(buildFile); if (!ivyFile.exists()) { onMissingDescriptor(buildFile, ivyFile, noDescriptor); } else { try { ModuleDescriptor md = ModuleDescriptorParserRegistry.getInstance() .parseDescriptor(settings, ivyFile.toURI().toURL(), doValidate(settings)); buildFiles.put(md, buildFile); mds.add(md); Message.debug("Add " + md.getModuleRevisionId().getModuleId()); } catch (Exception ex) { if (haltOnError) { throw new BuildException("impossible to parse ivy file for " + buildFile + ": ivyfile=" + ivyFile + " exception=" + ex, ex); } else { Message.warn("impossible to parse ivy file for " + buildFile + ": ivyfile=" + ivyFile + " exception=" + ex.getMessage()); Message.info("\t=> adding it at the beginning of the path"); independent.add(buildFile); } } } } } List leafModuleDescriptors = convertModuleNamesToModuleDescriptors(mds, leafModuleNames, "leaf"); List rootModuleDescriptors = convertModuleNamesToModuleDescriptors(mds, rootModuleNames, "root"); List restartFromModuleDescriptors = convertModuleNamesToModuleDescriptors(mds, restartFromModuleNames, "restartFrom"); if (!rootModuleDescriptors.isEmpty()) { Message.info("Filtering modules based on roots " + rootModuleNames); mds = filterModulesFromRoot(mds, rootModuleDescriptors); } if (!leafModuleDescriptors.isEmpty()) { Message.info("Filtering modules based on leafs " + leafModuleNames); mds = filterModulesFromLeaf(mds, leafModuleDescriptors); } List sortedModules = ivy.sortModuleDescriptors(mds, SortOptions.DEFAULT); if (!OnMissingDescriptor.TAIL.equals(onMissingDescriptor)) { for (ListIterator iter = noDescriptor.listIterator(); iter.hasNext();) { File buildFile = (File) iter.next(); addBuildFile(path, buildFile); } } for (ListIterator iter = independent.listIterator(); iter.hasNext();) { File buildFile = (File) iter.next(); addBuildFile(path, buildFile); } if (isReverse()) { Collections.reverse(sortedModules); } // Remove modules that are before the restartFrom point // Independent modules (without valid ivy file) can not be addressed // so they are not removed from build path. if (!restartFromModuleDescriptors.isEmpty()) { boolean foundRestartFrom = false; List keptModules = new ArrayList(); ModuleDescriptor restartFromModuleDescriptor = (ModuleDescriptor) restartFromModuleDescriptors .get(0); for (ListIterator iter = sortedModules.listIterator(); iter.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) iter.next(); if (md.equals(restartFromModuleDescriptor)) { foundRestartFrom = true; } if (foundRestartFrom) { keptModules.add(md); } } sortedModules = keptModules; } StringBuffer order = new StringBuffer(); for (ListIterator iter = sortedModules.listIterator(); iter.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) iter.next(); order.append(md.getModuleRevisionId().getModuleId()); if (iter.hasNext()) { order.append(", "); } File buildFile = (File) buildFiles.get(md); addBuildFile(path, buildFile); } if (OnMissingDescriptor.TAIL.equals(onMissingDescriptor)) { for (ListIterator iter = noDescriptor.listIterator(); iter.hasNext();) { File buildFile = (File) iter.next(); addBuildFile(path, buildFile); } } getProject().addReference(getReference(), path); getProject().setProperty("ivy.sorted.modules", order.toString()); } private void onMissingDescriptor(File buildFile, File ivyFile, List noDescriptor) { if (OnMissingDescriptor.SKIP.equals(onMissingDescriptor)) { Message.debug("skipping " + buildFile + ": descriptor " + ivyFile + " doesn't exist"); } else if (OnMissingDescriptor.FAIL.equals(onMissingDescriptor)) { throw new BuildException( "a module has no module descriptor and onMissingDescriptor=fail. " + "Build file: " + buildFile + ". Expected descriptor: " + ivyFile); } else { if (OnMissingDescriptor.WARN.equals(onMissingDescriptor)) { Message.warn("a module has no module descriptor. " + "Build file: " + buildFile + ". Expected descriptor: " + ivyFile); } Message.verbose("no descriptor for " + buildFile + ": descriptor=" + ivyFile + ": adding it at the " + (OnMissingDescriptor.TAIL.equals(onMissingDescriptor) ? "tail" : "head" + " of the path")); Message.verbose("\t(change onMissingDescriptor if you want to take another action"); noDescriptor.add(buildFile); } } private List convertModuleNamesToModuleDescriptors(Collection mds, Set moduleNames, String kind) { List result = new ArrayList(); Set foundModuleNames = new HashSet(); for (Iterator it = mds.iterator(); it.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) it.next(); String name = md.getModuleRevisionId().getModuleId().getName(); if (moduleNames.contains(name)) { foundModuleNames.add(name); result.add(md); } } if (foundModuleNames.size() < moduleNames.size()) { Set missingModules = new HashSet(moduleNames); missingModules.removeAll(foundModuleNames); StringBuffer missingNames = new StringBuffer(); String sep = ""; for (Iterator it = missingModules.iterator(); it.hasNext();) { missingNames.append(sep); missingNames.append(it.next()); sep = ", "; } throw new BuildException("unable to find " + kind + " module(s) " + missingNames.toString() + " in build fileset"); } return result; } /** * Returns a collection of ModuleDescriptors that are conatined in the input collection of * ModuleDescriptors and upon which the root module depends * * @param mds * input collection of ModuleDescriptors * @param rootmd * root module * @return filtered list of modules */ private Collection filterModulesFromRoot(Collection mds, List rootmds) { // Make a map of ModuleId objects -> ModuleDescriptors Map moduleIdMap = new HashMap(); for (Iterator iter = mds.iterator(); iter.hasNext();) { ModuleDescriptor md = ((ModuleDescriptor) iter.next()); moduleIdMap.put(md.getModuleRevisionId().getModuleId(), md); } // recursively process the nodes Set toKeep = new LinkedHashSet(); Iterator it = rootmds.iterator(); while (it.hasNext()) { ModuleDescriptor rootmd = (ModuleDescriptor) it.next(); processFilterNodeFromRoot(rootmd, toKeep, moduleIdMap); // With the excluderoot attribute set to true, take the rootmd out of the toKeep set. if (excludeRoot) { // Only for logging purposes Message.verbose("Excluded module " + rootmd.getModuleRevisionId().getModuleId().getName()); } else { toKeep.add(rootmd); } } // just for logging for (Iterator iter = toKeep.iterator(); iter.hasNext();) { ModuleDescriptor md = ((ModuleDescriptor) iter.next()); Message.verbose("Kept module " + md.getModuleRevisionId().getModuleId().getName()); } return toKeep; } /** * Adds the current node to the toKeep collection and then processes the each of the direct * dependencies of this node that appear in the moduleIdMap (indicating that the dependency is * part of this BuildList) * * @param node * the node to be processed * @param toKeep * the set of ModuleDescriptors that should be kept * @param moduleIdMap * reference mapping of moduleId to ModuleDescriptor that are part of the BuildList */ private void processFilterNodeFromRoot(ModuleDescriptor node, Set toKeep, Map moduleIdMap) { // toKeep.add(node); DependencyDescriptor[] deps = node.getDependencies(); for (int i = 0; i < deps.length; i++) { ModuleId id = deps[i].getDependencyId(); ModuleDescriptor md = (ModuleDescriptor) moduleIdMap.get(id); // we test if this module id has a module descriptor, and if it isn't already in the // toKeep Set, in which there's probably a circular dependency if (md != null && !toKeep.contains(md)) { toKeep.add(md); if (!getOnlydirectdep()) { processFilterNodeFromRoot(md, toKeep, moduleIdMap); } } } } /** * Returns a collection of ModuleDescriptors that are conatined in the input collection of * ModuleDescriptors which depends on the leaf module * * @param mds * input collection of ModuleDescriptors * @param leafmd * leaf module * @return filtered list of modules */ private Collection filterModulesFromLeaf(Collection mds, List leafmds) { // Make a map of ModuleId objects -> ModuleDescriptors Map moduleIdMap = new HashMap(); for (Iterator iter = mds.iterator(); iter.hasNext();) { ModuleDescriptor md = ((ModuleDescriptor) iter.next()); moduleIdMap.put(md.getModuleRevisionId().getModuleId(), md); } // recursively process the nodes Set toKeep = new LinkedHashSet(); Iterator it = leafmds.iterator(); while (it.hasNext()) { ModuleDescriptor leafmd = (ModuleDescriptor) it.next(); // With the excludeleaf attribute set to true, take the rootmd out of the toKeep set. if (excludeLeaf) { Message.verbose("Excluded module " + leafmd.getModuleRevisionId().getModuleId().getName()); } else { toKeep.add(leafmd); } processFilterNodeFromLeaf(leafmd, toKeep, moduleIdMap); } // just for logging for (Iterator iter = toKeep.iterator(); iter.hasNext();) { ModuleDescriptor md = ((ModuleDescriptor) iter.next()); Message.verbose("Kept module " + md.getModuleRevisionId().getModuleId().getName()); } return toKeep; } /** * Search in the moduleIdMap modules depending on node, add them to the toKeep set and process * them recursively. * * @param node * the node to be processed * @param toKeep * the set of ModuleDescriptors that should be kept * @param moduleIdMap * reference mapping of moduleId to ModuleDescriptor that are part of the BuildList */ private void processFilterNodeFromLeaf(ModuleDescriptor node, Set toKeep, Map moduleIdMap) { for (Iterator iter = moduleIdMap.values().iterator(); iter.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) iter.next(); DependencyDescriptor[] deps = md.getDependencies(); for (int i = 0; i < deps.length; i++) { ModuleId id = deps[i].getDependencyId(); if (node.getModuleRevisionId().getModuleId().equals(id) && !toKeep.contains(md)) { toKeep.add(md); if (!getOnlydirectdep()) { processFilterNodeFromLeaf(md, toKeep, moduleIdMap); } } } } } private void addBuildFile(Path path, File buildFile) { FileSet fs = new FileSet(); fs.setFile(buildFile); path.addFileset(fs); } private File getIvyFileFor(File buildFile) { return new File(buildFile.getParentFile(), ivyFilePath); } public boolean isHaltonerror() { return haltOnError; } public void setHaltonerror(boolean haltOnError) { this.haltOnError = haltOnError; } public String getIvyfilepath() { return ivyFilePath; } public void setIvyfilepath(String ivyFilePath) { this.ivyFilePath = ivyFilePath; } public String getOnMissingDescriptor() { return onMissingDescriptor; } public void setOnMissingDescriptor(String onMissingDescriptor) { this.onMissingDescriptor = onMissingDescriptor; } /** * @deprecated use {@link #getOnMissingDescriptor()} instead. */ @Deprecated public boolean isSkipbuildwithoutivy() { return onMissingDescriptor == OnMissingDescriptor.SKIP; } /** * @deprecated use {@link #setOnMissingDescriptor(String)} instead. */ @Deprecated public void setSkipbuildwithoutivy(boolean skipBuildFilesWithoutIvy) { Message.deprecated("skipbuildwithoutivy is deprecated, use onMissingDescriptor instead."); this.onMissingDescriptor = skipBuildFilesWithoutIvy ? OnMissingDescriptor.SKIP : OnMissingDescriptor.FAIL; } public boolean isReverse() { return reverse; } public void setReverse(boolean reverse) { this.reverse = reverse; } public String getRestartFrom() { return restartFrom; } public void setRestartFrom(String restartFrom) { this.restartFrom = restartFrom; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyBuildNumber.java000066400000000000000000000310071226750426600236760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.List; import java.util.ListIterator; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.SearchEngine; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.matcher.ExactOrRegexpPatternMatcher; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.tools.ant.BuildException; /** * Look for the latest module in the repository matching the given criteria, and sets a set of * properties according to what was found. */ public class IvyBuildNumber extends IvyTask { public static class ResolvedModuleRevisionArtifactInfo implements ArtifactInfo { private ModuleRevisionId rmr; public ResolvedModuleRevisionArtifactInfo(ModuleRevisionId rmr) { this.rmr = rmr; } public String getRevision() { return rmr.getRevision(); } public long getLastModified() { return -1; } } private String organisation; private String module; private String branch; private String revision; private String revSep = "."; private String prefix = "ivy."; private String defaultValue = "0"; private String defaultBuildNumber = "0"; private String resolver = null; public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public String getDefault() { return defaultValue; } public void setDefault(String default1) { defaultValue = default1; } public String getResolver() { return resolver; } public void setResolver(String resolver) { this.resolver = resolver; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public void doExecute() throws BuildException { if (organisation == null) { throw new BuildException("no organisation provided for ivy buildnumber task"); } if (module == null) { throw new BuildException("no module name provided for ivy buildnumber task"); } if (prefix == null) { throw new BuildException("null prefix not allowed"); } Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); if (branch == null) { branch = settings.getDefaultBranch(new ModuleId(organisation, module)); } if (revision == null || revision.length() == 0) { revision = "latest.integration"; } else if (!revision.endsWith("+")) { revision = revision + "+"; } if (!prefix.endsWith(".") && prefix.length() > 0) { prefix = prefix + "."; } SearchEngine searcher = new SearchEngine(settings); PatternMatcher patternMatcher = new PatternMatcher() { private PatternMatcher exact = new ExactPatternMatcher(); private PatternMatcher regexp = new ExactOrRegexpPatternMatcher(); public Matcher getMatcher(String expression) { if (expression.equals(organisation) || expression.equals(module) || expression.equals(branch)) { return exact.getMatcher(expression); } return regexp.getMatcher(expression); } public String getName() { return "buildnumber-matcher"; } }; ModuleRevisionId[] revisions; if (resolver == null) { revisions = searcher.listModules( ModuleRevisionId.newInstance(organisation, module, branch, ".*"), patternMatcher); } else { DependencyResolver depResolver = settings.getResolver(resolver); if (depResolver == null) { throw new BuildException("Unknown resolver: " + resolver); } revisions = searcher.listModules(depResolver, ModuleRevisionId.newInstance(organisation, module, branch, ".*"), patternMatcher); } ArtifactInfo[] infos = new ArtifactInfo[revisions.length]; for (int i = 0; i < revisions.length; i++) { infos[i] = new ResolvedModuleRevisionArtifactInfo(revisions[i]); } VersionMatcher matcher = settings.getVersionMatcher(); LatestStrategy latestStrategy = settings.getLatestStrategy("latest-revision"); List sorted = latestStrategy.sort(infos); ModuleRevisionId askedMrid = ModuleRevisionId.newInstance(organisation, module, branch, revision); String foundRevision = null; for (ListIterator iter = sorted.listIterator(sorted.size()); iter.hasPrevious();) { ResolvedModuleRevisionArtifactInfo info = (ResolvedModuleRevisionArtifactInfo) iter .previous(); if (!matcher.accept(askedMrid, info.rmr)) { continue; } if (matcher.needModuleDescriptor(askedMrid, info.rmr)) { ResolvedModuleRevision rmr = ivy.findModule(info.rmr); if (matcher.accept(askedMrid, rmr.getDescriptor())) { foundRevision = info.rmr.getRevision(); } } else { foundRevision = info.rmr.getRevision(); } if (foundRevision != null) { break; } } NewRevision newRevision = computeNewRevision(foundRevision); setProperty("revision", newRevision.getRevision()); setProperty("new.revision", newRevision.getNewRevision()); setProperty("build.number", newRevision.getBuildNumber()); setProperty("new.build.number", newRevision.getNewBuildNumber()); } private void setProperty(String propertyName, String value) { if (value != null) { getProject().setProperty(prefix + propertyName, value); } } private NewRevision computeNewRevision(String revision) { String revPrefix = "latest.integration".equals(this.revision) ? "" : this.revision .substring(0, this.revision.length() - 1); if (revision != null && !revision.startsWith(revPrefix)) { throw new BuildException("invalid exception found in repository: '" + revision + "' for '" + revPrefix + "'"); } if (revision == null) { if (revPrefix.length() > 0) { return new NewRevision(revision, revPrefix + (revPrefix.endsWith(revSep) ? defaultBuildNumber : revSep + defaultBuildNumber), null, defaultBuildNumber); } else { Range r = findLastNumber(defaultValue); if (r == null) { // no number found return new NewRevision(revision, defaultValue, null, null); } else { long n = Long.parseLong(defaultValue.substring(r.getStartIndex(), r.getEndIndex())); return new NewRevision(revision, defaultValue, null, String.valueOf(n)); } } } Range r; if (revPrefix.length() == 0) { r = findLastNumber(revision); if (r == null) { return new NewRevision(revision, revision + (revision.endsWith(revSep) ? "1" : revSep + "1"), null, "1"); } } else { r = findFirstNumber(revision, revPrefix.length()); if (r == null) { return new NewRevision(revision, revPrefix + (revPrefix.endsWith(revSep) ? "1" : revSep + "1"), null, "1"); } } long n = Long.parseLong(revision.substring(r.getStartIndex(), r.getEndIndex())) + 1; return new NewRevision(revision, revision.substring(0, r.getStartIndex()) + n, String.valueOf(n - 1), String.valueOf(n)); } private Range findFirstNumber(String str, int startIndex) { // let's find the first digit in the string int startNumberIndex = startIndex; while (startNumberIndex < str.length() && !Character.isDigit(str.charAt(startNumberIndex))) { startNumberIndex++; } if (startNumberIndex == str.length()) { return null; } // let's find the end of the number int endNumberIndex = startNumberIndex + 1; while (endNumberIndex < str.length() && Character.isDigit(str.charAt(endNumberIndex))) { endNumberIndex++; } return new Range(startNumberIndex, endNumberIndex); } private Range findLastNumber(String str) { int endNumberIndex = str.length() - 1; while (endNumberIndex >= 0 && !Character.isDigit(str.charAt(endNumberIndex))) { endNumberIndex--; } int startNumberIndex = endNumberIndex == -1 ? -1 : endNumberIndex - 1; while (startNumberIndex >= 0 && Character.isDigit(str.charAt(startNumberIndex))) { startNumberIndex--; } endNumberIndex++; startNumberIndex++; if (startNumberIndex == endNumberIndex) { // no number found return null; } else { return new Range(startNumberIndex, endNumberIndex); } } private static class Range { private int startIndex; private int endIndex; public Range(int startIndex, int endIndex) { this.startIndex = startIndex; this.endIndex = endIndex; } public int getStartIndex() { return startIndex; } public int getEndIndex() { return endIndex; } } private static class NewRevision { private String revision; private String newRevision; private String buildNumber; private String newBuildNumber; public NewRevision(String revision, String newRevision, String buildNumber, String newBuildNumber) { this.revision = revision; this.newRevision = newRevision; this.buildNumber = buildNumber; this.newBuildNumber = newBuildNumber; } public String getRevision() { return revision; } public String getNewRevision() { return newRevision; } public String getBuildNumber() { return buildNumber; } public String getNewBuildNumber() { return newBuildNumber; } } public String getRevSep() { return revSep; } public void setRevSep(String revSep) { this.revSep = revSep; } public String getDefaultBuildNumber() { return defaultBuildNumber; } public void setDefaultBuildNumber(String defaultBuildNumber) { this.defaultBuildNumber = defaultBuildNumber; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyCacheFileset.java000066400000000000000000000152251226750426600240110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.PatternSet.NameEntry; /** * Creates an ant fileset consisting in all artifacts found during a resolve. Note that this task is * not compatible with the useOrigin mode. */ public class IvyCacheFileset extends IvyCacheTask { private String setid; public String getSetid() { return setid; } public void setSetid(String id) { setid = id; } public void setUseOrigin(boolean useOrigin) { if (useOrigin) { throw new UnsupportedOperationException( "the cachefileset task does not support the useOrigin mode, since filesets " + "require to have only one root directory. Please use the the cachepath " + "task instead"); } } public void doExecute() throws BuildException { prepareAndCheck(); if (setid == null) { throw new BuildException("setid is required in ivy cachefileset"); } try { List paths = getArtifactReports(); File base = null; for (Iterator iter = paths.iterator(); iter.hasNext();) { ArtifactDownloadReport a = (ArtifactDownloadReport) iter.next(); if (a.getLocalFile() != null) { base = getBaseDir(base, a.getLocalFile()); } } FileSet fileset; if (base == null) { fileset = new EmptyFileSet(); } else { fileset = new FileSet(); fileset.setDir(base); for (Iterator iter = paths.iterator(); iter.hasNext();) { ArtifactDownloadReport a = (ArtifactDownloadReport) iter.next(); if (a.getLocalFile() != null) { NameEntry ne = fileset.createInclude(); ne.setName(getPath(base, a.getLocalFile())); } } } fileset.setProject(getProject()); getProject().addReference(setid, fileset); } catch (Exception ex) { throw new BuildException("impossible to build ivy cache fileset: " + ex, ex); } } /** * Returns the path of the file relative to the given base directory. * * @param base * the parent directory to which the file must be evaluated. * @param file * the file for which the path should be returned * @return the path of the file relative to the given base directory. */ private String getPath(File base, File file) { String absoluteBasePath = base.getAbsolutePath(); int beginIndex = absoluteBasePath.length(); // checks if the basePath ends with the file separator (which can for instance // happen if the basePath is the root on unix) if (!absoluteBasePath.endsWith(File.separator)) { beginIndex++; // skip the seperator char as well } return file.getAbsolutePath().substring(beginIndex); } /** * Returns the common base directory between a current base directory and a given file. *

* The returned base directory must be a parent of both the current base and the given file. *

* * @param base * the current base directory, may be null. * @param file * the file for which the new base directory should be returned. * @return the common base directory between a current base directory and a given file. */ File getBaseDir(File base, File file) { if (base == null) { return file.getParentFile().getAbsoluteFile(); } else { Iterator bases = getParents(base).iterator(); Iterator fileParents = getParents(file.getAbsoluteFile()).iterator(); File result = null; while (bases.hasNext() && fileParents.hasNext()) { File next = (File) bases.next(); if (next.equals(fileParents.next())) { result = next; } else { break; } } return result; } } /** * @return a list of files, starting with the root and ending with the file itself */ private LinkedList/* */getParents(File file) { LinkedList r = new LinkedList(); while (file != null) { r.addFirst(file); file = file.getParentFile(); } return r; } private static class EmptyFileSet extends FileSet { private DirectoryScanner ds = new EmptyDirectoryScanner(); public Iterator iterator() { return new EmptyIterator(); } public Object clone() { return new EmptyFileSet(); } public int size() { return 0; } public DirectoryScanner getDirectoryScanner(Project project) { return ds; } } private static class EmptyIterator implements Iterator { public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException("EmptyFileSet Iterator"); } public void remove() { throw new IllegalStateException("EmptyFileSet Iterator"); } } private static class EmptyDirectoryScanner extends DirectoryScanner { public String[] getIncludedFiles() { return new String[0]; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyCachePath.java000066400000000000000000000071471226750426600233160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ManifestParser; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Path; /** * Creates an ant path consisting in all artifacts found during a resolve. */ public class IvyCachePath extends IvyCacheTask { private String pathid; private String id; private boolean osgi = false; public String getPathid() { return pathid; } public void setPathid(String id) { pathid = id; } public void setOsgi(boolean osgi) { this.osgi = osgi; } /** * @deprecated use setPathid instead * @param id */ @Deprecated public void setId(String id) { this.id = id; } public void doExecute() throws BuildException { prepareAndCheck(); if (pathid == null) { if (id != null) { pathid = id; log("ID IS DEPRECATED, PLEASE USE PATHID INSTEAD", Project.MSG_WARN); } else { throw new BuildException("pathid is required in ivy classpath"); } } try { Path path = new Path(getProject()); getProject().addReference(pathid, path); for (Iterator iter = getArtifactReports().iterator(); iter.hasNext();) { ArtifactDownloadReport a = (ArtifactDownloadReport) iter.next(); File f = a.getLocalFile(); if (a.getUnpackedLocalFile() != null) { f = a.getUnpackedLocalFile(); } addToPath(path, f); } } catch (Exception ex) { throw new BuildException("impossible to build ivy path: " + ex, ex); } } protected void addToPath(Path path, File f) throws Exception { if (!osgi || !f.isDirectory()) { path.createPathElement().setLocation(f); return; } File manifest = new File(f, "META-INF/MANIFEST.MF"); if (!manifest.exists()) { path.createPathElement().setLocation(f); return; } BundleInfo bundleInfo = ManifestParser.parseManifest(manifest); List/* */cp = bundleInfo.getClasspath(); if (cp == null) { path.createPathElement().setLocation(f); return; } for (int i = 0; i < cp.size(); i++) { String p = (String) cp.get(i); if (p.equals(".")) { path.createPathElement().setLocation(f); } else { path.createPathElement().setLocation(new File(f, p)); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyCacheTask.java000066400000000000000000000104421226750426600233140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; /** * Base class for the cache path related classes: cachepath and cachefileset. Most of the behviour * is common to the two, since only the produced element differs. */ public abstract class IvyCacheTask extends IvyPostResolveTask { protected List getArtifactReports() throws BuildException, ParseException, IOException { Collection artifacts = getAllArtifactReports(); List ret = new ArrayList(); for (ArtifactDownloadReport artifactReport : artifacts) { if (getArtifactFilter().accept(artifactReport.getArtifact())) { ret.add(artifactReport); } } return ret; } private Collection getAllArtifactReports() throws ParseException, IOException { String[] confs = splitConfs(getConf()); Collection all = new LinkedHashSet(); ResolveReport report = getResolvedReport(); if (report != null) { Message.debug("using internal report instance to get artifacts list"); for (int i = 0; i < confs.length; i++) { ConfigurationResolveReport configurationReport = report .getConfigurationReport(confs[i]); if (configurationReport == null) { throw new BuildException("bad confs provided: " + confs[i] + " not found among " + Arrays.asList(report.getConfigurations())); } Set revisions = configurationReport.getModuleRevisionIds(); for (ModuleRevisionId revId : revisions) { ArtifactDownloadReport[] aReports = configurationReport .getDownloadReports(revId); all.addAll(Arrays.asList(aReports)); } } } else { Message.debug("using stored report to get artifacts list"); XmlReportParser parser = new XmlReportParser(); ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); String resolvedId = getResolveId(); if (resolvedId == null) { resolvedId = ResolveOptions.getDefaultResolveId(getResolvedModuleId()); } for (int i = 0; i < confs.length; i++) { File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolvedId, confs[i]); parser.parse(reportFile); ArtifactDownloadReport[] aReports = parser.getArtifactReports(); all.addAll(Arrays.asList(aReports)); } } return all; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyCheck.java000066400000000000000000000063451226750426600225120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; import org.apache.ivy.Ivy; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.types.FileSet; /** * Checks the given ivy file using current configuration to see if all dependencies are available, * with good confs. If a resolver name is given, it also checks that the declared publications are * available in the corresponding resolver. Note that the check is not performed recursively, i.e. * if a dependency has itself dependencies badly described or not available, this check will not * discover it. */ public class IvyCheck extends IvyTask { private File file = null; private List filesets = new ArrayList(); private String resolvername; public File getFile() { return file; } public void setFile(File file) { this.file = file; } /** * Adds a set of files to check. * * @param set * a set of files to check */ public void addFileset(FileSet set) { filesets.add(set); } public String getResolvername() { return resolvername; } public void setResolvername(String resolverName) { resolvername = resolverName; } public void doExecute() throws BuildException { try { Ivy ivy = getIvyInstance(); if (file != null) { if (ivy.check(file.toURI().toURL(), resolvername)) { Message.verbose("checked " + file + ": OK"); } } for (int i = 0; i < filesets.size(); i++) { FileSet fs = (FileSet) filesets.get(i); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); File fromDir = fs.getDir(getProject()); String[] srcFiles = ds.getIncludedFiles(); for (int j = 0; j < srcFiles.length; j++) { File file = new File(fromDir, srcFiles[j]); if (ivy.check(file.toURI().toURL(), resolvername)) { Message.verbose("checked " + file + ": OK"); } } } } catch (MalformedURLException e) { throw new BuildException("impossible to convert a file to an url! " + e, e); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyCleanCache.java000066400000000000000000000054131226750426600234360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.settings.IvySettings; import org.apache.tools.ant.BuildException; /** * Cleans the content of Ivy cache(s). */ public class IvyCleanCache extends IvyTask { public static final String ALL = "*"; public static final String NONE = "NONE"; private boolean resolution = true; private String cache = ALL; public String getCache() { return cache; } /** * Sets the name of the repository cache to clean, '*' for all caches, 'NONE' for no repository * cache cleaning at all. * * @param cache * the name of the cache to clean. Must not be null. */ public void setCache(String cache) { this.cache = cache; } public boolean isResolution() { return resolution; } /** * Sets weither the resolution cache should be cleaned or not. * * @param resolution * true if the resolution cache should be cleaned, false * otherwise. */ public void setResolution(boolean resolution) { this.resolution = resolution; } public void doExecute() throws BuildException { IvySettings settings = getIvyInstance().getSettings(); if (isResolution()) { settings.getResolutionCacheManager().clean(); } if (ALL.equals(getCache())) { RepositoryCacheManager[] caches = settings.getRepositoryCacheManagers(); for (int i = 0; i < caches.length; i++) { caches[i].clean(); } } else if (!NONE.equals(getCache())) { RepositoryCacheManager cache = settings.getRepositoryCacheManager(getCache()); if (cache == null) { throw new BuildException("unknown cache '" + getCache() + "'"); } else { cache.clean(); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyConfigure.java000066400000000000000000000107451226750426600234150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Collection; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; /** * Configure Ivy with an ivysettings.xml file */ public class IvyConfigure extends Task { /** * Use to override a previous definition of settings with the same id */ public static final String OVERRIDE_TRUE = "true"; /** * Use to avoid overriding a previous definition of settings with the same id */ public static final String OVERRIDE_FALSE = "false"; /** * Use to raise an error if attempting to override a previous definition of settings with the * same id */ public static final String OVERRIDE_NOT_ALLOWED = "notallowed"; private static final Collection OVERRIDE_VALUES = Arrays.asList(new String[] {OVERRIDE_TRUE, OVERRIDE_FALSE, OVERRIDE_NOT_ALLOWED}); private String override = OVERRIDE_NOT_ALLOWED; private IvyAntSettings settings = new IvyAntSettings(); public void setSettingsId(String settingsId) { settings.setId(settingsId); } public String getSettingsId() { return settings.getId(); } public void setOverride(String override) { if (!OVERRIDE_VALUES.contains(override)) { throw new IllegalArgumentException("invalid override value '" + override + "'. " + "Valid values are " + OVERRIDE_VALUES); } this.override = override; } public String getOverride() { return override; } public File getFile() { return settings.getFile(); } public void setFile(File file) { settings.setFile(file); } public URL getUrl() { return settings.getUrl(); } public void setUrl(String url) throws MalformedURLException { settings.setUrl(url); } public void setUrl(URL url) { if (url == null) { throw new NullPointerException("Cannot set a null URL"); } settings.setUrl(url); } public String getRealm() { return settings.getRealm(); } public void setRealm(String realm) { settings.setRealm(realm); } public String getHost() { return settings.getHost(); } public void setHost(String host) { settings.setHost(host); } public String getUserName() { return settings.getUsername(); } public void setUserName(String userName) { settings.setUsername(userName); } public String getPasswd() { return settings.getPasswd(); } public void setPasswd(String passwd) { settings.setPasswd(passwd); } public void execute() throws BuildException { String settingsId = settings.getId(); Object otherRef = getProject().getReference(settingsId); if ((otherRef != null) && OVERRIDE_NOT_ALLOWED.equals(override)) { throw new BuildException( "Overriding a previous definition of ivy:settings with the id '" + settingsId + "' is not allowed when using override='" + OVERRIDE_NOT_ALLOWED + "'."); } if ((otherRef != null) && OVERRIDE_FALSE.equals(override)) { verbose("A settings definition is already available for " + settingsId + ": skipping"); return; } settings.setProject(getProject()); getProject().addReference(settingsId, settings); settings.createIvyEngine(this); } private void verbose(String msg) { log(msg, Project.MSG_VERBOSE); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyConflict.java000066400000000000000000000047641226750426600232410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.conflict.FixedConflictManager; import org.apache.ivy.plugins.matcher.PatternMatcher; public class IvyConflict { private String org; private String module; private String manager; private String rev; private String matcher; public void setOrg(String org) { this.org = org; } public void setModule(String module) { this.module = module; } public void setManager(String manager) { this.manager = manager; } public void setRev(String rev) { this.rev = rev; } public void setMatcher(String matcher) { this.matcher = matcher; } void addConflict(DefaultModuleDescriptor md, IvySettings settings) { String matcherName = matcher == null ? PatternMatcher.EXACT : matcher; String orgPattern = org == null ? PatternMatcher.ANY_EXPRESSION : org; String modulePattern = module == null ? PatternMatcher.ANY_EXPRESSION : module; ConflictManager cm = null; if (rev != null) { String[] revs = rev.split(","); for (int i = 0; i < revs.length; i++) { revs[i] = revs[i].trim(); } cm = new FixedConflictManager(revs); } else if (manager != null) { cm = settings.getConflictManager(manager); } md.addConflictManager(new ModuleId(orgPattern, modulePattern), settings.getMatcher(matcherName), cm); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyConvertPom.java000066400000000000000000000055031226750426600235640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.MalformedURLException; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorParser; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Convert a pom to an ivy file */ public class IvyConvertPom extends IvyTask { private File pomFile = null; private File ivyFile = null; public File getPomFile() { return pomFile; } public void setPomFile(File file) { pomFile = file; } public File getIvyFile() { return ivyFile; } public void setIvyFile(File ivyFile) { this.ivyFile = ivyFile; } public void doExecute() throws BuildException { try { if (pomFile == null) { throw new BuildException("source pom file is required for convertpom task"); } if (ivyFile == null) { throw new BuildException("destination ivy file is required for convertpom task"); } ModuleDescriptor md = PomModuleDescriptorParser.getInstance().parseDescriptor( getSettings(), pomFile.toURI().toURL(), false); PomModuleDescriptorParser.getInstance().toIvyFile(pomFile.toURI().toURL().openStream(), new URLResource(pomFile.toURI().toURL()), getIvyFile(), md); } catch (MalformedURLException e) { throw new BuildException("unable to convert given pom file to url: " + pomFile + ": " + e, e); } catch (ParseException e) { log(e.getMessage(), Project.MSG_ERR); throw new BuildException("syntax errors in pom file " + pomFile + ": " + e, e); } catch (Exception e) { throw new BuildException("impossible convert given pom file to ivy file: " + e + " from=" + pomFile + " to=" + ivyFile, e); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDeliver.java000066400000000000000000000402741226750426600230660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.Date; import org.apache.ivy.Ivy; import org.apache.ivy.core.deliver.DefaultPublishingDRResolver; import org.apache.ivy.core.deliver.DeliverOptions; import org.apache.ivy.core.deliver.PublishingDependencyRevisionResolver; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.CallTarget; import org.apache.tools.ant.taskdefs.Echo; import org.apache.tools.ant.taskdefs.Input; import org.apache.tools.ant.taskdefs.Property; /** * Trigger the delivery of a module, which may consist in a recursive delivery of dependencies and * on the replacement in the ivy file of dynamic revisions (like latest.integration) by static ones. */ public class IvyDeliver extends IvyTask { private final class DeliverDRResolver extends DefaultPublishingDRResolver { public String resolve(ModuleDescriptor published, String publishedStatus, ModuleRevisionId depMrid, String depStatus) { if (StatusManager.getCurrent().isIntegration(publishedStatus)) { // published status is integration one, nothing to ask return super.resolve(published, publishedStatus, depMrid, depStatus); } // we are publishing a delivery (a non integration module) if (!StatusManager.getCurrent().isIntegration(depStatus)) { // dependency is already a delivery, nothing to ask return super.resolve(published, publishedStatus, depMrid, depStatus); } // the dependency is not a delivery String statusProperty = depMrid.getName() + "." + depMrid.getRevision() + ".status"; String versionProperty = depMrid.getName() + "." + depMrid.getRevision() + ".version"; String deliveredProperty = depMrid.getName() + "." + depMrid.getRevision() + ".delivered"; String version = getProject().getProperty(versionProperty); String status = getProject().getProperty(statusProperty); String delivered = getProject().getProperty(deliveredProperty); Message.debug("found version = " + version + " status=" + status + " delivered=" + delivered); if (version != null && status != null) { if ("true".equals(delivered)) { // delivery has already been done : just return the value return version; } else { deliverDependency(depMrid, version, status, depStatus); loadDeliveryList(); return version; } } /** * By setting these properties: recursive.delivery.status and * recursive.delivery.version, then if the specific status/version is not found, then we * will use the status/version set in these global properties. This will apply to all * artifacts in the system. This patch is meant to be used for recursive deliveries so * that all deliveries will use the global status/version unless a more specific one is * set. */ String globalStatusProperty = "recursive.delivery.status"; String globalVersionProperty = "recursive.delivery.version"; version = getProject().getProperty(globalVersionProperty); status = getProject().getProperty(globalStatusProperty); if (version != null && status != null) { // found global delivery properties delivered = getProject().getProperty( "recursive." + depMrid.getName() + ".delivered"); Message.debug("found global version = " + version + " and global status=" + status + " - delivered = " + delivered); if ("true".equals(delivered)) { // delivery has already been done : just return the value return version; } else { getProject().setProperty(statusProperty, status); deliverDependency(depMrid, version, status, depStatus); loadDeliveryList(); return version; } } // we must ask the user what version and status he want to have // for the dependency Input input = (Input) getProject().createTask("input"); input.setOwningTarget(getOwningTarget()); input.init(); // ask status input.setMessage(depMrid.getName() + " " + depMrid.getRevision() + ": please enter a status: "); input.setValidargs(StatusManager.getCurrent().getDeliveryStatusListString()); input.setAddproperty(statusProperty); input.perform(); status = getProject().getProperty(statusProperty); appendDeliveryList(statusProperty + " = " + status); // ask version input.setMessage(depMrid.getName() + " " + depMrid.getRevision() + ": please enter a version: "); input.setValidargs(null); input.setAddproperty(versionProperty); input.perform(); version = getProject().getProperty(versionProperty); appendDeliveryList(versionProperty + " = " + version); deliverDependency(depMrid, version, status, depStatus); loadDeliveryList(); return version; } public void deliverDependency(ModuleRevisionId depMrid, String version, String status, String depStatus) { // call deliver target if any if (deliverTarget != null && deliverTarget.trim().length() > 0) { CallTarget ct = (CallTarget) getProject().createTask("antcall"); ct.setOwningTarget(getOwningTarget()); ct.init(); ct.setTarget(deliverTarget); ct.setInheritAll(true); ct.setInheritRefs(true); Property param = ct.createParam(); param.setName("dependency.name"); param.setValue(depMrid.getName()); param = ct.createParam(); param.setName("dependency.published.status"); param.setValue(status); param = ct.createParam(); param.setName("dependency.published.version"); param.setValue(version); param = ct.createParam(); param.setName("dependency.version"); param.setValue(depMrid.getRevision()); param = ct.createParam(); param.setName("dependency.status"); param.setValue(depStatus == null ? "null" : depStatus); ct.perform(); String deliveredProperty = depMrid.getName() + "." + depMrid.getRevision() + ".delivered"; getProject().setProperty(deliveredProperty, "true"); appendDeliveryList(deliveredProperty + " = true"); getProject().setProperty("recursive." + depMrid.getName() + ".delivered", "true"); appendDeliveryList("recursive." + depMrid.getName() + ".delivered" + " = true"); } } } private String organisation; private String module; private String revision; private String pubRevision; private String deliverpattern; private String status; private String pubdate; private String deliverTarget; private File deliveryList; private boolean replacedynamicrev = true; private boolean replaceForcedRev = false; private String resolveId; private String conf; private String pubBranch; private boolean generateRevConstraint = true; private boolean merge = true; public void setCache(File cache) { cacheAttributeNotSupported(); } public String getDeliverpattern() { return deliverpattern; } public void setDeliverpattern(String destivypattern) { this.deliverpattern = destivypattern; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getPubdate() { return pubdate; } public void setPubdate(String pubdate) { this.pubdate = pubdate; } public String getPubrevision() { return pubRevision; } public void setPubrevision(String pubRevision) { this.pubRevision = pubRevision; } public String getPubbranch() { return pubBranch; } public void setPubbranch(String pubBranch) { this.pubBranch = pubBranch; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public void setDelivertarget(String deliverTarget) { this.deliverTarget = deliverTarget; } public void setDeliveryList(File deliveryList) { this.deliveryList = deliveryList; } public boolean isReplacedynamicrev() { return replacedynamicrev; } public void setReplacedynamicrev(boolean replacedynamicrev) { this.replacedynamicrev = replacedynamicrev; } public boolean isReplaceForcedRev() { return replaceForcedRev; } public void setReplaceForcedRev(boolean replaceForcedRev) { this.replaceForcedRev = replaceForcedRev; } public String getResolveId() { return resolveId; } public void setResolveId(String resolveId) { this.resolveId = resolveId; } public String getConf() { return conf; } public void setConf(String confs) { conf = confs; } public boolean isGenerateRevConstraint() { return generateRevConstraint; } public void setGenerateRevConstraint(boolean generateRevConstraint) { this.generateRevConstraint = generateRevConstraint; } public boolean isMerge() { return merge; } public void setMerge(boolean merge) { this.merge = merge; } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); organisation = getProperty(organisation, settings, "ivy.organisation", resolveId); module = getProperty(module, settings, "ivy.module", resolveId); revision = getProperty(revision, settings, "ivy.revision", resolveId); pubBranch = getProperty(pubBranch, settings, "ivy.deliver.branch"); pubRevision = getProperty(pubRevision, settings, "ivy.deliver.revision"); deliverpattern = getProperty(deliverpattern, settings, "ivy.deliver.ivy.pattern"); status = getProperty(status, settings, "ivy.status"); if (deliveryList == null) { String deliveryListPath = getProperty(settings, "ivy.delivery.list.file"); if (deliveryListPath == null) { deliveryList = new File(System.getProperty("java.io.tmpdir") + "/delivery.properties"); } else { deliveryList = getProject().resolveFile(settings.substitute(deliveryListPath)); } } if (resolveId == null) { if (organisation == null) { throw new BuildException("no organisation provided for ivy deliver task: " + "It can either be set explicitely via the attribute 'organisation' " + "or via 'ivy.organisation' property or a prior call to "); } if (module == null) { throw new BuildException("no module name provided for ivy deliver task: " + "It can either be set explicitely via the attribute 'module' " + "or via 'ivy.module' property or a prior call to "); } } if (revision == null) { revision = Ivy.getWorkingRevision(); } Date pubdate = getPubDate(this.pubdate, new Date()); if (pubRevision == null) { if (revision.startsWith("working@")) { pubRevision = DateUtil.format(pubdate); } else { pubRevision = revision; } } if (deliverpattern == null) { throw new BuildException( "deliver ivy pattern is missing: either provide it as parameters " + "or through ivy.deliver.ivy.pattern properties"); } if (status == null) { throw new BuildException( "no status provided: either provide it as parameter or through " + "the ivy.status.default property"); } ModuleRevisionId mrid = null; if (resolveId == null) { mrid = ModuleRevisionId.newInstance(organisation, module, revision); } boolean isLeading = false; try { if (!deliveryList.exists()) { isLeading = true; } loadDeliveryList(); PublishingDependencyRevisionResolver drResolver; if (deliverTarget != null && deliverTarget.trim().length() > 0) { drResolver = new DeliverDRResolver(); } else { drResolver = new DefaultPublishingDRResolver(); } DeliverOptions options = new DeliverOptions(status, pubdate, drResolver, doValidate(settings), replacedynamicrev, splitConfs(conf)) .setResolveId(resolveId).setReplaceForcedRevisions(isReplaceForcedRev()) .setGenerateRevConstraint(generateRevConstraint).setMerge(merge) .setPubBranch(pubBranch); if (mrid == null) { ivy.deliver(pubRevision, deliverpattern, options); } else { ivy.deliver(mrid, pubRevision, deliverpattern, options); } } catch (Exception e) { throw new BuildException("impossible to deliver " + mrid == null ? resolveId : mrid + ": " + e, e); } finally { if (isLeading) { if (deliveryList.exists()) { deliveryList.delete(); } } } } private void loadDeliveryList() { Property property = (Property) getProject().createTask("property"); property.setOwningTarget(getOwningTarget()); property.init(); property.setFile(deliveryList); property.perform(); } private void appendDeliveryList(String msg) { Echo echo = (Echo) getProject().createTask("echo"); echo.setOwningTarget(getOwningTarget()); echo.init(); echo.setFile(deliveryList); echo.setMessage(msg + "\n"); echo.setAppend(true); echo.perform(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependency.java000066400000000000000000000126731226750426600235540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.descriptor.DefaultIncludeRule; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvySettings; import org.apache.tools.ant.BuildException; public class IvyDependency { private List/* */confs = new ArrayList(); private List/* */artifacts = new ArrayList(); private List/* */excludes = new ArrayList(); private List/* */includes = new ArrayList(); private String org; private String name; private String rev; private String branch; private String conf; private boolean changing; private boolean force; private boolean transitive = true; public IvyDependencyConf createConf() { IvyDependencyConf c = new IvyDependencyConf(); confs.add(c); return c; } public IvyDependencyArtifact createArtifact() { IvyDependencyArtifact artifact = new IvyDependencyArtifact(); artifacts.add(artifact); return artifact; } public IvyDependencyExclude createExclude() { IvyDependencyExclude exclude = new IvyDependencyExclude(); excludes.add(exclude); return exclude; } public IvyDependencyInclude createInclude() { IvyDependencyInclude include = new IvyDependencyInclude(); includes.add(include); return include; } public String getOrg() { return org; } public void setOrg(String org) { this.org = org; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRev() { return rev; } public void setRev(String rev) { this.rev = rev; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public boolean isChanging() { return changing; } public void setChanging(boolean changing) { this.changing = changing; } public boolean isForce() { return force; } public void setForce(boolean force) { this.force = force; } public boolean isTransitive() { return transitive; } public void setTransitive(boolean transitive) { this.transitive = transitive; } DependencyDescriptor asDependencyDescriptor(ModuleDescriptor md, String masterConf, IvySettings settings) { if (org == null) { throw new BuildException("'org' is required on "); } if (name == null) { throw new BuildException("'name' is required when using inline mode"); } ModuleRevisionId mrid = ModuleRevisionId.newInstance(org, name, branch, rev); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, mrid, force, changing, transitive); if (conf != null) { dd.addDependencyConfiguration(masterConf, conf); } else { dd.addDependencyConfiguration(masterConf, "*"); } Iterator itConfs = confs.iterator(); while (itConfs.hasNext()) { IvyDependencyConf c = (IvyDependencyConf) itConfs.next(); c.addConf(dd, masterConf); } Iterator itArtifacts = artifacts.iterator(); while (itArtifacts.hasNext()) { IvyDependencyArtifact artifact = (IvyDependencyArtifact) itArtifacts.next(); artifact.addArtifact(dd, masterConf); } Iterator itExcludes = excludes.iterator(); while (itExcludes.hasNext()) { IvyDependencyExclude exclude = (IvyDependencyExclude) itExcludes.next(); DefaultExcludeRule rule = exclude.asRule(settings); dd.addExcludeRule(masterConf, rule); } Iterator itIncludes = includes.iterator(); while (itIncludes.hasNext()) { IvyDependencyInclude include = (IvyDependencyInclude) itIncludes.next(); DefaultIncludeRule rule = include.asRule(settings); dd.addIncludeRule(masterConf, rule); } return dd; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyArtifact.java000066400000000000000000000042741226750426600252300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.net.MalformedURLException; import java.net.URL; import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.tools.ant.BuildException; public class IvyDependencyArtifact { private String name; private String type; private String ext; private String url; public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } public void setExt(String ext) { this.ext = ext; } public void setUrl(String url) { this.url = url; } void addArtifact(DefaultDependencyDescriptor dd, String masterConf) { String typePattern = type == null ? PatternMatcher.ANY_EXPRESSION : type; String extPattern = ext == null ? typePattern : ext; URL u; try { u = url == null ? null : new URL(url); } catch (MalformedURLException e) { throw new BuildException("Malformed url in the artifact: " + e.getMessage(), e); } DefaultDependencyArtifactDescriptor dad = new DefaultDependencyArtifactDescriptor(dd, name, typePattern, extPattern, u, null); dd.addDependencyArtifact(masterConf, dad); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyConf.java000066400000000000000000000041031226750426600243470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; public class IvyDependencyConf { private List/* */mappeds = new ArrayList(); public static class IvyDependencyConfMapped { private String name; public void setName(String name) { this.name = name; } } private String mapped; public void setMapped(String mapped) { this.mapped = mapped; } public IvyDependencyConfMapped createMapped() { IvyDependencyConfMapped m = new IvyDependencyConfMapped(); mappeds.add(m); return m; } void addConf(DefaultDependencyDescriptor dd, String masterConf) { if (mapped != null) { String[] mappeds = mapped.split(","); for (int i = 0; i < mappeds.length; i++) { dd.addDependencyConfiguration(masterConf, mappeds[i].trim()); } } Iterator itMappeds = mappeds.iterator(); while (itMappeds.hasNext()) { IvyDependencyConfMapped m = (IvyDependencyConfMapped) itMappeds.next(); dd.addDependencyConfiguration(masterConf, m.name); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyExclude.java000066400000000000000000000047101226750426600250570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; public class IvyDependencyExclude { private String org; private String module; private String name; private String type; private String ext; private String matcher; public void setOrg(String org) { this.org = org; } public void setModule(String module) { this.module = module; } public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } public void setExt(String ext) { this.ext = ext; } public void setMatcher(String matcher) { this.matcher = matcher; } DefaultExcludeRule asRule(IvySettings settings) { String matcherName = matcher == null ? PatternMatcher.EXACT : matcher; String orgPattern = org == null ? PatternMatcher.ANY_EXPRESSION : org; String modulePattern = module == null ? PatternMatcher.ANY_EXPRESSION : module; String namePattern = name == null ? PatternMatcher.ANY_EXPRESSION : name; String typePattern = type == null ? PatternMatcher.ANY_EXPRESSION : type; String extPattern = ext == null ? typePattern : ext; ArtifactId aid = new ArtifactId(new ModuleId(orgPattern, modulePattern), namePattern, typePattern, extPattern); return new DefaultExcludeRule(aid, settings.getMatcher(matcherName), null); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyInclude.java000066400000000000000000000041741226750426600250550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.descriptor.DefaultIncludeRule; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; public class IvyDependencyInclude { private String name; private String type; private String ext; private String matcher; public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } public void setExt(String ext) { this.ext = ext; } public void setMatcher(String matcher) { this.matcher = matcher; } DefaultIncludeRule asRule(IvySettings settings) { String matcherName = matcher == null ? PatternMatcher.EXACT : matcher; String namePattern = name == null ? PatternMatcher.ANY_EXPRESSION : name; String typePattern = type == null ? PatternMatcher.ANY_EXPRESSION : type; String extPattern = ext == null ? typePattern : ext; ArtifactId aid = new ArtifactId(new ModuleId(PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION), namePattern, typePattern, extPattern); return new DefaultIncludeRule(aid, settings.getMatcher(matcherName), null); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyTree.java000066400000000000000000000123471226750426600243720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.IvyNodeCallers.Caller; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.tools.ant.BuildException; public class IvyDependencyTree extends IvyPostResolveTask { private Map/* > */dependencies = new HashMap/* * > */(); private boolean showEvicted = false; public void doExecute() throws BuildException { prepareAndCheck(); ResolveReport report = getResolvedReport(); log("Dependency tree for " + report.getResolveId()); ModuleRevisionId mrid = report.getModuleDescriptor().getModuleRevisionId(); // make dependency tree easier to fetch informations for (Iterator iterator = report.getDependencies().iterator(); iterator.hasNext();) { IvyNode dependency = (IvyNode) iterator.next(); populateDependencyTree(dependency, mrid, report); } printDependencies((List) dependencies.get(mrid), 0); } private void printDependencies(List/* */dependencyList, int indent) { for (Iterator iterator = dependencyList.iterator(); iterator.hasNext();) { IvyNode dependency = (IvyNode) iterator.next(); boolean evicted = dependency.isEvicted(getConf()); if (evicted && !showEvicted) { continue; } StringBuffer sb = new StringBuffer(); if (indent > 0) { for (int i = 0; i < indent; i++) { if (i == indent - 1 && !iterator.hasNext() && !hasDependencies(dependency)) { sb.append(" "); } else { sb.append("| "); } } } if (iterator.hasNext()) { sb.append("+- "); } else { sb.append("\\- "); } sb.append(dependency.getId().toString()); if (evicted && showEvicted) { EvictionData evictedData = dependency.getEvictedData(getConf()); if (evictedData.isTransitivelyEvicted()) { sb.append(" transitively"); } else { sb.append(" evicted by "); sb.append(evictedData.getSelected()); sb.append(" in ").append(evictedData.getParent()); if (evictedData.getDetail() != null) { sb.append(" ").append(evictedData.getDetail()); } } } log(sb.toString()); printDependencies((List) dependencies.get(dependency.getId()), indent + 1); } } private boolean hasDependencies(IvyNode dependency) { List dependencyList = (List) dependencies.get(dependency.getId()); return dependencyList.size() > 0; } private void populateDependencyTree(IvyNode dependency, ModuleRevisionId currentMrid, ResolveReport report) { registerNodeIfNecessary(dependency.getId()); for (int i = 0; i < dependency.getAllCallers().length; i++) { Caller caller = dependency.getAllCallers()[i]; addDependency(caller.getModuleRevisionId(), dependency); } } private void registerNodeIfNecessary(ModuleRevisionId moduleRevisionId) { if (!dependencies.containsKey(moduleRevisionId)) { dependencies.put(moduleRevisionId, new ArrayList/* */()); } } private void addDependency(ModuleRevisionId moduleRevisionId, IvyNode dependency) { registerNodeIfNecessary(moduleRevisionId); List/* */list = (List) dependencies.get(moduleRevisionId); list.add(dependency); } public boolean isShowEvicted() { return showEvicted; } public void setShowEvicted(boolean showEvicted) { this.showEvicted = showEvicted; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyDependencyUpdateChecker.java000066400000000000000000000231101226750426600261700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.tools.ant.BuildException; public class IvyDependencyUpdateChecker extends IvyPostResolveTask { private String revisionToCheck = "latest.integration"; private boolean download = false; private boolean checkIfChanged = false; private boolean showTransitive = false; public void doExecute() throws BuildException { prepareAndCheck(); ModuleDescriptor originalModuleDescriptor = getResolvedReport().getModuleDescriptor(); // clone module descriptor DefaultModuleDescriptor latestModuleDescriptor = new DefaultModuleDescriptor( originalModuleDescriptor.getModuleRevisionId(), originalModuleDescriptor.getStatus(), originalModuleDescriptor.getPublicationDate()); // copy configurations for (int i = 0; i < originalModuleDescriptor.getConfigurations().length; i++) { Configuration configuration = originalModuleDescriptor.getConfigurations()[i]; latestModuleDescriptor.addConfiguration(configuration); } // clone dependency and add new one with the requested revisionToCheck for (int i = 0; i < originalModuleDescriptor.getDependencies().length; i++) { DependencyDescriptor dependencyDescriptor = originalModuleDescriptor.getDependencies()[i]; ModuleRevisionId upToDateMrid = ModuleRevisionId.newInstance( dependencyDescriptor.getDependencyRevisionId(), revisionToCheck); latestModuleDescriptor.addDependency(dependencyDescriptor.clone(upToDateMrid)); } // resolve ResolveOptions resolveOptions = new ResolveOptions(); resolveOptions.setDownload(isDownload()); resolveOptions.setLog(getLog()); resolveOptions.setConfs(splitConfs(getConf())); resolveOptions.setCheckIfChanged(checkIfChanged); ResolveReport latestReport; try { latestReport = getIvyInstance().getResolveEngine().resolve(latestModuleDescriptor, resolveOptions); displayDependencyUpdates(getResolvedReport(), latestReport); if (showTransitive) { displayNewDependencyOnLatest(getResolvedReport(), latestReport); displayMissingDependencyOnLatest(getResolvedReport(), latestReport); } } catch (ParseException e) { throw new BuildException("impossible to resolve dependencies:\n\t" + e, e); } catch (IOException e) { throw new BuildException("impossible to resolve dependencies:\n\t" + e, e); } } private void displayDependencyUpdates(ResolveReport originalReport, ResolveReport latestReport) { log("Dependencies updates available :"); boolean dependencyUpdateDetected = false; for (Iterator iterator = latestReport.getDependencies().iterator(); iterator.hasNext();) { IvyNode latest = (IvyNode) iterator.next(); for (Iterator iterator2 = originalReport.getDependencies().iterator(); iterator2 .hasNext();) { IvyNode originalDependency = (IvyNode) iterator2.next(); if (originalDependency.getModuleId().equals(latest.getModuleId())) { if (!originalDependency.getResolvedId().getRevision() .equals(latest.getResolvedId().getRevision())) { // is this dependency a transitive dependency ? or direct dependency // (unfortunatly // .isTranstive() methods doesn't have the same meaning) boolean isTransitiveDependency = latest.getDependencyDescriptor(latest .getRoot()) == null; if ((!isTransitiveDependency) || (isTransitiveDependency && showTransitive)) { StringBuffer sb = new StringBuffer(); sb.append("\t")// .append(originalDependency.getResolvedId().getOrganisation()) // .append('#')// .append(originalDependency.getResolvedId().getName())// .append(isTransitiveDependency ? " (transitive)" : "") // .append("\t")// .append(originalDependency.getResolvedId().getRevision())// .append(" -> ")// .append(latest.getResolvedId().getRevision()); log(sb.toString()); dependencyUpdateDetected = true; } } } } } if (!dependencyUpdateDetected) { log("\tAll dependencies are up to date"); } } private void displayMissingDependencyOnLatest(ResolveReport originalReport, ResolveReport latestReport) { List/* */listOfMissingDependencyOnLatest = new ArrayList/* * */(); for (Iterator iterator = originalReport.getDependencies().iterator(); iterator.hasNext();) { IvyNode originalDependency = (IvyNode) iterator.next(); boolean dependencyFound = false; for (Iterator iterator2 = latestReport.getDependencies().iterator(); iterator2 .hasNext();) { IvyNode latest = (IvyNode) iterator2.next(); if (originalDependency.getModuleId().equals(latest.getModuleId())) { dependencyFound = true; } } if (!dependencyFound) { listOfMissingDependencyOnLatest.add(originalDependency.getId()); } } if (listOfMissingDependencyOnLatest.size() > 0) { log("List of missing dependency on latest resolve :"); for (Iterator iterator = listOfMissingDependencyOnLatest.iterator(); iterator.hasNext();) { ModuleRevisionId moduleRevisionId = (ModuleRevisionId) iterator.next(); log("\t" + moduleRevisionId.toString()); } } } private void displayNewDependencyOnLatest(ResolveReport originalReport, ResolveReport latestReport) { List/* */listOfNewDependencyOnLatest = new ArrayList/* */(); for (Iterator iterator = latestReport.getDependencies().iterator(); iterator.hasNext();) { IvyNode latest = (IvyNode) iterator.next(); boolean dependencyFound = false; for (Iterator iterator2 = originalReport.getDependencies().iterator(); iterator2 .hasNext();) { IvyNode originalDependency = (IvyNode) iterator2.next(); if (originalDependency.getModuleId().equals(latest.getModuleId())) { dependencyFound = true; } } if (!dependencyFound) { listOfNewDependencyOnLatest.add(latest.getId()); } } if (listOfNewDependencyOnLatest.size() > 0) { log("List of new dependency on latest resolve :"); for (Iterator iterator = listOfNewDependencyOnLatest.iterator(); iterator.hasNext();) { ModuleRevisionId moduleRevisionId = (ModuleRevisionId) iterator.next(); log("\t" + moduleRevisionId.toString()); } } } public String getRevisionToCheck() { return revisionToCheck; } public void setRevisionToCheck(String revisionToCheck) { this.revisionToCheck = revisionToCheck; } public boolean isDownload() { return download; } public void setDownload(boolean download) { this.download = download; } public boolean isShowTransitive() { return showTransitive; } public void setShowTransitive(boolean showTransitive) { this.showTransitive = showTransitive; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyExclude.java000066400000000000000000000047421226750426600230650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; public class IvyExclude { private String org; private String module; private String artifact; private String type; private String ext; private String matcher; public void setOrg(String org) { this.org = org; } public void setModule(String module) { this.module = module; } public void setArtifact(String artifact) { this.artifact = artifact; } public void setType(String type) { this.type = type; } public void setExt(String ext) { this.ext = ext; } public void setMatcher(String matcher) { this.matcher = matcher; } DefaultExcludeRule asRule(IvySettings settings) { String matcherName = matcher == null ? PatternMatcher.EXACT : matcher; String orgPattern = org == null ? PatternMatcher.ANY_EXPRESSION : org; String modulePattern = module == null ? PatternMatcher.ANY_EXPRESSION : module; String artifactPattern = artifact == null ? PatternMatcher.ANY_EXPRESSION : artifact; String typePattern = type == null ? PatternMatcher.ANY_EXPRESSION : type; String extPattern = ext == null ? typePattern : ext; ArtifactId aid = new ArtifactId(new ModuleId(orgPattern, modulePattern), artifactPattern, typePattern, extPattern); return new DefaultExcludeRule(aid, settings.getMatcher(matcherName), null); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyExtractFromSources.java000066400000000000000000000155111226750426600252720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.LineContainsRegExp; import org.apache.tools.ant.filters.TokenFilter; import org.apache.tools.ant.taskdefs.Concat; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FilterChain; import org.apache.tools.ant.types.RegularExpression; /** * Extracts imports from a set of java sources and generate corresponding ivy file */ public class IvyExtractFromSources extends Task { public static class Ignore { private String packageName; public String getPackage() { return packageName; } public void setPackage(String package1) { packageName = package1; } } private String organisation; private String module; private String revision; private String status; private List ignoredPackaged = new ArrayList(); // List (String package) private Map mapping = new HashMap(); // Map (String package -> ModuleRevisionId) private Concat concat = new Concat(); private File to; public void addConfiguredIgnore(Ignore ignore) { ignoredPackaged.add(ignore.getPackage()); } public File getTo() { return to; } public void setTo(File to) { this.to = to; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public void addConfiguredMapping(PackageMapping mapping) { this.mapping.put(mapping.getPackage(), mapping.getModuleRevisionId()); } public void addFileSet(FileSet fileSet) { concat.addFileset(fileSet); } public void execute() throws BuildException { configureConcat(); Writer out = new StringWriter(); concat.setWriter(out); concat.execute(); Set importsSet = new HashSet(Arrays.asList(out.toString().split("\n"))); Set dependencies = new HashSet(); for (Iterator iter = importsSet.iterator(); iter.hasNext();) { String pack = ((String) iter.next()).trim(); ModuleRevisionId mrid = getMapping(pack); if (mrid != null) { dependencies.add(mrid); } } try { PrintWriter writer = new PrintWriter(new FileOutputStream(to)); writer.println(""); writer.println("\t"); if (!dependencies.isEmpty()) { writer.println("\t"); for (Iterator iter = dependencies.iterator(); iter.hasNext();) { ModuleRevisionId mrid = (ModuleRevisionId) iter.next(); writer.println("\t\t"); } writer.println("\t"); } writer.println(""); writer.close(); log(dependencies.size() + " dependencies put in " + to); } catch (FileNotFoundException e) { throw new BuildException("impossible to create file " + to + ": " + e, e); } } /** * @param pack * @return */ private ModuleRevisionId getMapping(String pack) { String askedPack = pack; ModuleRevisionId ret = null; while (ret == null && pack.length() > 0) { if (ignoredPackaged.contains(pack)) { return null; } ret = (ModuleRevisionId) mapping.get(pack); int lastDotIndex = pack.lastIndexOf('.'); if (lastDotIndex != -1) { pack = pack.substring(0, lastDotIndex); } else { break; } } if (ret == null) { log("no mapping found for " + askedPack, Project.MSG_VERBOSE); } return ret; } private void configureConcat() { concat.setProject(getProject()); concat.setTaskName(getTaskName()); FilterChain filterChain = new FilterChain(); LineContainsRegExp lcre = new LineContainsRegExp(); RegularExpression regexp = new RegularExpression(); regexp.setPattern("^import .+;"); lcre.addConfiguredRegexp(regexp); filterChain.add(lcre); TokenFilter tf = new TokenFilter(); TokenFilter.ReplaceRegex rre = new TokenFilter.ReplaceRegex(); rre.setPattern("import (.+);.*"); rre.setReplace("\\1"); tf.add(rre); filterChain.add(tf); concat.addFilterChain(filterChain); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyFindRevision.java000066400000000000000000000061431226750426600240700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.settings.IvySettings; import org.apache.tools.ant.BuildException; /** * Look for the latest module in the repository matching the given criteria, and sets a set of * properties according to what was found. */ public class IvyFindRevision extends IvyTask { private String organisation; private String module; private String branch; private String revision; private String property = "ivy.revision"; public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public String getProperty() { return property; } public void setProperty(String prefix) { this.property = prefix; } public void doExecute() throws BuildException { if (organisation == null) { throw new BuildException("no organisation provided for ivy findrevision task"); } if (module == null) { throw new BuildException("no module name provided for ivy findrevision task"); } if (revision == null) { throw new BuildException("no revision provided for ivy findrevision task"); } Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); if (branch == null) { branch = settings.getDefaultBranch(new ModuleId(organisation, module)); } ResolvedModuleRevision rmr = ivy.findModule(ModuleRevisionId.newInstance(organisation, module, branch, revision)); if (rmr != null) { getProject().setProperty(property, rmr.getId().getRevision()); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyInfo.java000066400000000000000000000175101226750426600223640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.MalformedURLException; import java.text.ParseException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Parses information about an ivy file and make them available in ant. */ public class IvyInfo extends IvyTask { private File file = null; private String organisation; private String module; private String branch; private String revision; private String property = "ivy"; public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public String getProperty() { return property; } public void setProperty(String prefix) { this.property = prefix; } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); try { if (organisation != null || module != null || revision != null || branch != null) { if (organisation == null) { throw new BuildException("no organisation provided for ivy info task"); } if (module == null) { throw new BuildException("no module name provided for ivy info task"); } if (revision == null) { throw new BuildException("no revision provided for ivy info task"); } if (branch == null) { settings.getDefaultBranch(new ModuleId(organisation, module)); } ResolvedModuleRevision rmr = ivy.findModule(ModuleRevisionId.newInstance( organisation, module, branch, revision)); if (rmr != null) { ModuleDescriptor md = rmr.getDescriptor(); ModuleRevisionId mrid = rmr.getId(); setProperties(md, mrid); } } else { if (file == null) { file = getProject().resolveFile(getProperty(settings, "ivy.dep.file")); } ModuleDescriptor md = ModuleDescriptorParserRegistry.getInstance().parseDescriptor( settings, file.toURI().toURL(), doValidate(settings)); ModuleRevisionId mrid = md.getModuleRevisionId(); setProperties(md, mrid); } } catch (MalformedURLException e) { throw new BuildException("unable to convert given ivy file to url: " + file + ": " + e, e); } catch (ParseException e) { log(e.getMessage(), Project.MSG_ERR); throw new BuildException("syntax errors in ivy file: " + e, e); } catch (Exception e) { throw new BuildException("impossible to resolve dependencies: " + e, e); } } private void setProperties(ModuleDescriptor md, ModuleRevisionId mrid) { getProject().setProperty(property + ".organisation", mrid.getOrganisation()); getProject().setProperty(property + ".module", mrid.getName()); if (mrid.getBranch() != null) { getProject().setProperty(property + ".branch", mrid.getBranch()); } getProject().setProperty(property + ".revision", mrid.getRevision()); getProject().setProperty(property + ".status", md.getStatus()); if (md.getPublicationDate() != null) { getProject().setProperty(property + ".publication", Long.toString(md.getPublicationDate().getTime())); } Map extra = mrid.getExtraAttributes(); for (Iterator iter = extra.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry) iter.next(); getProject().setProperty(property + ".extra." + entry.getKey(), (String) entry.getValue()); } getProject().setProperty(property + ".configurations", mergeConfs(md.getConfigurationsNames())); // store the public configurations in a separate property Configuration[] configs = md.getConfigurations(); List publicConfigsList = new ArrayList(); for (int i = 0; i < configs.length; i++) { String name = configs[i].getName(); if (Visibility.PUBLIC.equals(configs[i].getVisibility())) { publicConfigsList.add(name); } if (configs[i].getDescription() != null) { getProject().setProperty(property + ".configuration." + name + ".desc", configs[i].getDescription()); } } String[] publicConfigs = (String[]) publicConfigsList.toArray(new String[publicConfigsList .size()]); getProject().setProperty(property + ".public.configurations", mergeConfs(publicConfigs)); Artifact[] artifacts = md.getAllArtifacts(); for (int i = 0; i < artifacts.length; i++) { int id = i + 1; getProject() .setProperty(property + ".artifact." + id + ".name", artifacts[i].getName()); getProject() .setProperty(property + ".artifact." + id + ".type", artifacts[i].getType()); getProject().setProperty(property + ".artifact." + id + ".ext", artifacts[i].getExt()); getProject().setProperty(property + ".artifact." + id + ".conf", mergeConfs(artifacts[i].getConfigurations())); Map artiExtra = artifacts[i].getExtraAttributes(); for (Iterator iter = artiExtra.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry) iter.next(); getProject().setProperty(property + ".artifact." + id + ".extra." + entry.getKey(), (String) entry.getValue()); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyInstall.java000066400000000000000000000155161226750426600231030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import org.apache.ivy.Ivy; import org.apache.ivy.core.install.InstallOptions; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.filter.FilterHelper; import org.apache.tools.ant.BuildException; /** * Allow to install a module or a set of module from repository to another one. */ public class IvyInstall extends IvyTask { private String organisation; private String module; private String revision; private String branch; private String conf = "*"; private boolean overwrite = false; private String from; private String to; private boolean transitive; private String type; private String matcher = PatternMatcher.EXACT; private boolean haltOnFailure = true; private boolean installOriginalMetadata = false; public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); if (organisation == null) { throw new BuildException("no organisation provided for ivy publish task: " + "It can either be set explicitely via the attribute 'organisation' " + "or via 'ivy.organisation' property or a prior call to "); } if (module == null && PatternMatcher.EXACT.equals(matcher)) { throw new BuildException("no module name provided for ivy publish task: " + "It can either be set explicitely via the attribute 'module' " + "or via 'ivy.module' property or a prior call to "); } else if (module == null && !PatternMatcher.EXACT.equals(matcher)) { module = PatternMatcher.ANY_EXPRESSION; } if (revision == null && PatternMatcher.EXACT.equals(matcher)) { throw new BuildException("no module revision provided for ivy publish task: " + "It can either be set explicitely via the attribute 'revision' " + "or via 'ivy.revision' property or a prior call to "); } else if (revision == null && !PatternMatcher.EXACT.equals(matcher)) { revision = PatternMatcher.ANY_EXPRESSION; } if (branch == null && PatternMatcher.EXACT.equals(matcher)) { branch = settings.getDefaultBranch(ModuleId.newInstance(organisation, module)); } else if (branch == null && !PatternMatcher.EXACT.equals(matcher)) { branch = PatternMatcher.ANY_EXPRESSION; } if (from == null) { throw new BuildException( "no from resolver name: please provide it through parameter 'from'"); } if (to == null) { throw new BuildException( "no to resolver name: please provide it through parameter 'to'"); } ModuleRevisionId mrid = ModuleRevisionId .newInstance(organisation, module, branch, revision); ResolveReport report; try { report = ivy.install( mrid, from, to, new InstallOptions().setTransitive(transitive).setValidate(doValidate(settings)) .setOverwrite(overwrite).setConfs(conf.split(",")) .setArtifactFilter(FilterHelper.getArtifactTypeFilter(type)) .setMatcherName(matcher) .setInstallOriginalMetadata(installOriginalMetadata)); } catch (Exception e) { throw new BuildException("impossible to install " + mrid + ": " + e, e); } if (report.hasError() && isHaltonfailure()) { throw new BuildException( "Problem happened while installing modules - see output for details"); } } public boolean isHaltonfailure() { return haltOnFailure; } public void setHaltonfailure(boolean haltOnFailure) { this.haltOnFailure = haltOnFailure; } public void setCache(File cache) { cacheAttributeNotSupported(); } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public boolean isOverwrite() { return overwrite; } public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public boolean isTransitive() { return transitive; } public void setTransitive(boolean transitive) { this.transitive = transitive; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getMatcher() { return matcher; } public void setMatcher(String matcher) { this.matcher = matcher; } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public boolean isInstallOriginalMetadata() { return installOriginalMetadata; } public void setInstallOriginalMetadata(boolean installOriginalMetadata) { this.installOriginalMetadata = installOriginalMetadata; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyListModules.java000066400000000000000000000112501226750426600237300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.search.SearchEngine; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.tools.ant.BuildException; /** * Look for modules in the repository matching the given criteria, and sets a set of properties * according to what was found. */ public class IvyListModules extends IvyTask { private String organisation; private String module; private String branch = PatternMatcher.ANY_EXPRESSION; private String revision; private String matcher = PatternMatcher.EXACT_OR_REGEXP; private String property; private String value; private String resolver; public String getMatcher() { return matcher; } public void setMatcher(String matcher) { this.matcher = matcher; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getProperty() { return property; } public void setProperty(String name) { this.property = name; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public void setResolver(String resolver) { this.resolver = resolver; } public String getResolver() { return resolver; } public void doExecute() throws BuildException { if (organisation == null) { throw new BuildException("no organisation provided for ivy listmodules task"); } if (module == null) { throw new BuildException("no module name provided for ivy listmodules task"); } if (revision == null) { throw new BuildException("no revision provided for ivy listmodules task"); } if (property == null) { throw new BuildException("no property provided for ivy listmodules task"); } if (value == null) { throw new BuildException("no value provided for ivy listmodules task"); } Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); SearchEngine searcher = new SearchEngine(settings); PatternMatcher patternMatcher = settings.getMatcher(matcher); ModuleRevisionId[] mrids; if (resolver == null) { mrids = searcher.listModules( ModuleRevisionId.newInstance(organisation, module, branch, revision), patternMatcher); } else { DependencyResolver depResolver = settings.getResolver(resolver); if (depResolver == null) { throw new BuildException("Unknown resolver: " + resolver); } mrids = searcher.listModules(depResolver, ModuleRevisionId.newInstance(organisation, module, branch, revision), patternMatcher); } for (int i = 0; i < mrids.length; i++) { String name = IvyPatternHelper.substitute(settings.substitute(property), mrids[i]); String value = IvyPatternHelper.substitute(settings.substitute(this.value), mrids[i]); getProject().setProperty(name, value); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyMakePom.java000066400000000000000000000207401226750426600230210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorWriter; import org.apache.ivy.plugins.parser.m2.PomWriterOptions; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.util.FileUtil; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Convert an ivy file to a pom */ public class IvyMakePom extends IvyTask { public class Mapping { private String conf; private String scope; public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } } public class Dependency { private String group = null; private String artifact = null; private String version = null; private String scope = null; private String type = null; private String classifier = null; private boolean optional = false; public String getGroup() { return group; } public void setGroup(String group) { this.group = group; } public String getArtifact() { return artifact; } public void setArtifact(String artifact) { this.artifact = artifact; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getClassifier() { return classifier; } public void setClassifier(String classifier) { this.classifier = classifier; } public boolean getOptional() { return optional; } public void setOptional(boolean optional) { this.optional = optional; } } private String artifactName; private String artifactPackaging; private File pomFile = null; private File headerFile = null; private File templateFile = null; private boolean printIvyInfo = true; private String conf; private File ivyFile = null; private String description; private Collection mappings = new ArrayList(); private Collection dependencies = new ArrayList(); public File getPomFile() { return pomFile; } public void setPomFile(File file) { pomFile = file; } public File getIvyFile() { return ivyFile; } public void setIvyFile(File ivyFile) { this.ivyFile = ivyFile; } public File getHeaderFile() { return headerFile; } public void setHeaderFile(File headerFile) { this.headerFile = headerFile; } public File getTemplateFile() { return templateFile; } public void setTemplateFile(File templateFile) { this.templateFile = templateFile; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public boolean isPrintIvyInfo() { return printIvyInfo; } public void setPrintIvyInfo(boolean printIvyInfo) { this.printIvyInfo = printIvyInfo; } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public String getArtifactName() { return artifactName; } public void setArtifactName(String artifactName) { this.artifactName = artifactName; } public String getArtifactPackaging() { return artifactPackaging; } public void setArtifactPackaging(String artifactPackaging) { this.artifactPackaging = artifactPackaging; } public Mapping createMapping() { Mapping mapping = new Mapping(); this.mappings.add(mapping); return mapping; } public Dependency createDependency() { Dependency dependency = new Dependency(); this.dependencies.add(dependency); return dependency; } public void doExecute() throws BuildException { try { if (ivyFile == null) { throw new BuildException("source ivy file is required for makepom task"); } if (pomFile == null) { throw new BuildException("destination pom file is required for makepom task"); } ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor( getSettings(), ivyFile.toURI().toURL(), false); PomModuleDescriptorWriter.write(md, pomFile, getPomWriterOptions()); } catch (MalformedURLException e) { throw new BuildException("unable to convert given ivy file to url: " + ivyFile + ": " + e, e); } catch (ParseException e) { log(e.getMessage(), Project.MSG_ERR); throw new BuildException("syntax errors in ivy file " + ivyFile + ": " + e, e); } catch (Exception e) { throw new BuildException("impossible convert given ivy file to pom file: " + e + " from=" + ivyFile + " to=" + pomFile, e); } } private PomWriterOptions getPomWriterOptions() throws IOException { PomWriterOptions options = new PomWriterOptions(); options.setConfs(splitConfs(conf)).setArtifactName(getArtifactName()) .setArtifactPackaging(getArtifactPackaging()).setPrintIvyInfo(isPrintIvyInfo()) .setDescription(getDescription()).setExtraDependencies(getDependencies()) .setTemplate(getTemplateFile()); if (!mappings.isEmpty()) { options.setMapping(new PomWriterOptions.ConfigurationScopeMapping(getMappingsMap())); } if (headerFile != null) { options.setLicenseHeader(FileUtil.readEntirely(getHeaderFile())); } return options; } private Map getMappingsMap() { Map mappingsMap = new HashMap(); for (Iterator iter = mappings.iterator(); iter.hasNext();) { Mapping mapping = (Mapping) iter.next(); String[] mappingConfs = splitConfs(mapping.getConf()); for (int i = 0; i < mappingConfs.length; i++) { if (!mappingsMap.containsKey(mappingConfs[i])) { mappingsMap.put(mappingConfs[i], mapping.getScope()); } } } return mappingsMap; } private List getDependencies() { List result = new ArrayList(); for (Iterator iter = dependencies.iterator(); iter.hasNext();) { Dependency dependency = (Dependency) iter.next(); result.add(new PomWriterOptions.ExtraDependency(dependency.getGroup(), dependency .getArtifact(), dependency.getVersion(), dependency.getScope(), dependency .getType(), dependency.getClassifier(), dependency.getOptional())); } return result; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyOverride.java000066400000000000000000000042371226750426600232520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; public class IvyOverride { private String org; private String module; private String branch; private String rev; private String matcher; public void setOrg(String org) { this.org = org; } public void setModule(String module) { this.module = module; } public void setBranch(String branch) { this.branch = branch; } public void setRev(String rev) { this.rev = rev; } public void setMatcher(String matcher) { this.matcher = matcher; } void addOverride(DefaultModuleDescriptor md, IvySettings settings) { String matcherName = matcher == null ? PatternMatcher.EXACT : matcher; String orgPattern = org == null ? PatternMatcher.ANY_EXPRESSION : org; String modulePattern = module == null ? PatternMatcher.ANY_EXPRESSION : module; md.addDependencyDescriptorMediator(new ModuleId(orgPattern, modulePattern), settings.getMatcher(matcherName), new OverrideDependencyDescriptorMediator(branch, rev)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyPostResolveTask.java000066400000000000000000000365701226750426600246100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import org.apache.ivy.Ivy; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.Message; import org.apache.ivy.util.StringUtils; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; import org.apache.tools.ant.BuildException; /** * Base class for tasks needing to be performed after a resolve. */ public abstract class IvyPostResolveTask extends IvyTask { private String conf; private boolean haltOnFailure = true; private boolean transitive = true; private boolean inline = false; private String organisation; private String branch = null; private String module; private String revision = "latest.integration"; private String resolveId; private String type; private File file; private Filter artifactFilter = null; private boolean useOrigin = false; private Boolean keep = null; private boolean refresh = false; private String resolveMode = null; private String log = ResolveOptions.LOG_DEFAULT; private boolean changing = false; private IvyResolve resolve = new IvyResolve(); public boolean isUseOrigin() { return useOrigin; } public void setUseOrigin(boolean useOrigin) { this.useOrigin = useOrigin; } public String getLog() { return log; } public void setLog(String log) { this.log = log; } public IvyDependency createDependency() { return resolve.createDependency(); } public IvyExclude createExclude() { return resolve.createExclude(); } public IvyConflict createConflict() { return resolve.createConflict(); } protected void prepareAndCheck() { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); boolean orgAndModSetManually = (organisation != null) && (module != null); organisation = getProperty(organisation, settings, "ivy.organisation"); module = getProperty(module, settings, "ivy.module"); if (file == null) { String fileName = getProperty(settings, "ivy.resolved.file", resolveId); if (fileName != null) { file = getProject().resolveFile(fileName); } } if (isInline()) { conf = conf == null ? "*" : conf; if (organisation == null) { throw new BuildException( "no organisation provided for ivy cache task in inline mode: " + "It can either be set explicitely via the attribute 'organisation' " + "or via 'ivy.organisation' property"); } if (module == null) { throw new BuildException( "no module name provided for ivy cache task in inline mode: " + "It can either be set explicitely via the attribute 'module' " + "or via 'ivy.module' property"); } String[] toResolve = getConfsToResolve(getOrganisation(), getModule() + "-caller", conf, true); // When we make an inline resolution, we can not resolve private confs. for (int i = 0; i < toResolve.length; i++) { if ("*".equals(toResolve[i])) { toResolve[i] = "*(public)"; } } if (toResolve.length > 0) { Message.verbose("using inline mode to resolve " + getOrganisation() + " " + getModule() + " " + getRevision() + " (" + StringUtils.join(toResolve, ", ") + ")"); IvyResolve resolve = setupResolve(isHaltonfailure(), isUseOrigin()); resolve.setOrganisation(getOrganisation()); resolve.setModule(getModule()); resolve.setBranch(getBranch()); resolve.setRevision(getRevision()); resolve.setInline(true); resolve.setChanging(isChanging()); resolve.setConf(conf); resolve.setResolveId(resolveId); resolve.setTransitive(isTransitive()); resolve.execute(); } else { Message.verbose("inline resolve already done for " + getOrganisation() + " " + getModule() + " " + getRevision() + " (" + conf + ")"); } if ("*".equals(conf)) { conf = StringUtils.join( getResolvedConfigurations(getOrganisation(), getModule() + "-caller", true), ", "); } } else { Message.debug("using standard ensure resolved"); // if the organization and module has been manually specified, we'll reuse the resolved // data from another build (there is no way to know which configurations were resolved // there (TODO: maybe we can check which reports exist and extract the configurations // from these report names?) if (!orgAndModSetManually) { ensureResolved(settings); } conf = getProperty(conf, settings, "ivy.resolved.configurations"); if ("*".equals(conf)) { conf = getProperty(settings, "ivy.resolved.configurations"); if (conf == null) { throw new BuildException("bad conf provided for ivy cache task: " + "'*' can only be used with a prior call to "); } } } organisation = getProperty(organisation, settings, "ivy.organisation"); module = getProperty(module, settings, "ivy.module"); if (organisation == null) { throw new BuildException("no organisation provided for ivy cache task: " + "It can either be set explicitely via the attribute 'organisation' " + "or via 'ivy.organisation' property or a prior call to "); } if (module == null) { throw new BuildException("no module name provided for ivy cache task: " + "It can either be set explicitely via the attribute 'module' " + "or via 'ivy.module' property or a prior call to "); } if (conf == null) { throw new BuildException("no conf provided for ivy cache task: " + "It can either be set explicitely via the attribute 'conf' or " + "via 'ivy.resolved.configurations' property or a prior call to "); } artifactFilter = FilterHelper.getArtifactTypeFilter(type); } protected void ensureResolved(IvySettings settings) { String requestedConfigs = getProperty(getConf(), settings, "ivy.resolved.configurations"); String[] confs = null; if (getResolveId() != null) { confs = getConfsToResolve(getResolveId(), requestedConfigs); } else { confs = getConfsToResolve(getOrganisation(), getModule(), requestedConfigs, false); } if (confs.length > 0) { IvyResolve resolve = setupResolve(isHaltonfailure(), isUseOrigin()); resolve.setFile(getFile()); resolve.setTransitive(isTransitive()); resolve.setConf(StringUtils.join(confs, ", ")); resolve.setResolveId(getResolveId()); resolve.execute(); } } protected String[] getConfsToResolve(String org, String module, String conf, boolean strict) { ModuleDescriptor reference = (ModuleDescriptor) getResolvedDescriptor(org, module, strict); String[] rconfs = getResolvedConfigurations(org, module, strict); return getConfsToResolve(reference, conf, rconfs); } protected String[] getConfsToResolve(String resolveId, String conf) { ModuleDescriptor reference = (ModuleDescriptor) getResolvedDescriptor(resolveId, false); if (reference == null) { // assume the module has been resolved outside this build, resolve the required // configurations again // TODO: find a way to discover which confs were resolved by that previous resolve if (conf == null) { return new String[] {"*"}; } else { return splitConfs(conf); } } String[] rconfs = (String[]) getProject().getReference( "ivy.resolved.configurations.ref." + resolveId); return getConfsToResolve(reference, conf, rconfs); } private String[] getConfsToResolve(ModuleDescriptor reference, String conf, String[] rconfs) { Message.debug("calculating configurations to resolve"); if (reference == null) { Message.debug("module not yet resolved, all confs still need to be resolved"); if (conf == null) { return new String[] {"*"}; } else { return splitConfs(conf); } } else if (conf != null) { String[] confs; if ("*".equals(conf)) { confs = reference.getConfigurationsNames(); } else { confs = splitConfs(conf); } HashSet rconfsSet = new HashSet(Arrays.asList(rconfs)); // for each resolved configuration, check if the report still exists ResolutionCacheManager cache = getSettings().getResolutionCacheManager(); for (Iterator it = rconfsSet.iterator(); it.hasNext();) { String resolvedConf = (String) it.next(); String resolveId = getResolveId(); if (resolveId == null) { resolveId = ResolveOptions.getDefaultResolveId(reference); } File report = cache.getConfigurationResolveReportInCache(resolveId, resolvedConf); if (!report.exists()) { // the report doesn't exist any longer, we have to recreate it... it.remove(); } } HashSet confsSet = new HashSet(Arrays.asList(confs)); Message.debug("resolved configurations: " + rconfsSet); Message.debug("asked configurations: " + confsSet); confsSet.removeAll(rconfsSet); Message.debug("to resolve configurations: " + confsSet); return (String[]) confsSet.toArray(new String[confsSet.size()]); } else { Message.debug("module already resolved, no configuration to resolve"); return new String[0]; } } protected IvyResolve setupResolve(boolean haltOnFailure, boolean useOrigin) { Message.verbose("no resolved descriptor found: launching default resolve"); resolve.setTaskName(getTaskName()); resolve.setProject(getProject()); resolve.setHaltonfailure(haltOnFailure); resolve.setUseOrigin(useOrigin); resolve.setValidate(doValidate(getSettings())); resolve.setKeep(isKeep()); resolve.setRefresh(isRefresh()); resolve.setLog(getLog()); resolve.setSettingsRef(getSettingsRef()); resolve.setResolveMode(getResolveMode()); return resolve; } protected ModuleRevisionId getResolvedMrid() { return new ModuleRevisionId(getResolvedModuleId(), getRevision() == null ? Ivy.getWorkingRevision() : getRevision()); } protected ModuleId getResolvedModuleId() { return isInline() ? new ModuleId(getOrganisation(), getModule() + "-caller") : new ModuleId(getOrganisation(), getModule()); } protected ResolveReport getResolvedReport() { return getResolvedReport(getOrganisation(), isInline() ? getModule() + "-caller" : getModule(), resolveId); } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public boolean isHaltonfailure() { return haltOnFailure; } public void setHaltonfailure(boolean haltOnFailure) { this.haltOnFailure = haltOnFailure; } public void setCache(File cache) { cacheAttributeNotSupported(); } public String getRevision() { return revision; } public void setRevision(String rev) { revision = rev; } public Filter getArtifactFilter() { return artifactFilter; } public boolean isTransitive() { return transitive; } public void setTransitive(boolean transitive) { this.transitive = transitive; } public boolean isInline() { return inline; } public void setInline(boolean inline) { this.inline = inline; } public void setResolveId(String resolveId) { this.resolveId = resolveId; } public String getResolveId() { return resolveId; } public void setFile(File file) { this.file = file; } public File getFile() { return file; } public void setKeep(boolean keep) { this.keep = Boolean.valueOf(keep); } public boolean isKeep() { return this.keep == null ? !isInline() : this.keep.booleanValue(); } public void setChanging(boolean changing) { this.changing = changing; } public boolean isChanging() { return this.changing; } public void setRefresh(boolean refresh) { this.refresh = refresh; } public boolean isRefresh() { return refresh; } public String getResolveMode() { return resolveMode; } public void setResolveMode(String resolveMode) { this.resolveMode = resolveMode; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyPublish.java000066400000000000000000000332751226750426600231050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.id.ArtifactRevisionId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.publish.PublishOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.DateUtil; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DynamicAttribute; /** * This task allow to publish a module revision to an Ivy repository. */ public class IvyPublish extends IvyTask { private String organisation; private String module; private String revision; private String pubRevision; private String srcivypattern; private String status; private String conf = null; private String pubdate; private String deliverTarget; private String publishResolverName = null; private List artifactspattern = new ArrayList(); private File deliveryList; private boolean publishivy = true; private boolean warnonmissing = true; private boolean haltonmissing = true; private boolean overwrite = false; private boolean update = false; private boolean merge = true; private boolean replacedynamicrev = true; private boolean forcedeliver; private Collection artifacts = new ArrayList(); private String pubBranch; public void setCache(File cache) { cacheAttributeNotSupported(); } public String getSrcivypattern() { return srcivypattern; } public void setSrcivypattern(String destivypattern) { srcivypattern = destivypattern; } /** * @deprecated use {@link #getSrcivypattern()} instead. */ @Deprecated public String getDeliverivypattern() { return srcivypattern; } /** * @deprecated use {@link #setSrcivypattern(String)} instead. */ @Deprecated public void setDeliverivypattern(String destivypattern) { srcivypattern = destivypattern; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getPubdate() { return pubdate; } public void setPubdate(String pubdate) { this.pubdate = pubdate; } public String getPubrevision() { return pubRevision; } public void setPubrevision(String pubRevision) { this.pubRevision = pubRevision; } public String getPubbranch() { return pubBranch; } public void setPubbranch(String pubBranch) { this.pubBranch = pubBranch; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public void setConf(String conf) { this.conf = conf; } public void setDelivertarget(String deliverTarget) { this.deliverTarget = deliverTarget; } public void setDeliveryList(File deliveryList) { this.deliveryList = deliveryList; } public String getResolver() { return publishResolverName; } public void setResolver(String publishResolverName) { this.publishResolverName = publishResolverName; } public String getArtifactspattern() { return (String) (artifactspattern.isEmpty() ? null : artifactspattern.get(0)); } public void setArtifactspattern(String artifactsPattern) { artifactspattern.clear(); artifactspattern.add(artifactsPattern); } public void addArtifactspattern(String artifactsPattern) { artifactspattern.add(artifactsPattern); } public void addConfiguredArtifacts(ArtifactsPattern p) { artifactspattern.add(p.getPattern()); } public boolean isReplacedynamicrev() { return replacedynamicrev; } public void setReplacedynamicrev(boolean replacedynamicrev) { this.replacedynamicrev = replacedynamicrev; } public boolean isMerge() { return merge; } public void setMerge(boolean merge) { this.merge = merge; } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); organisation = getProperty(organisation, settings, "ivy.organisation"); module = getProperty(module, settings, "ivy.module"); revision = getProperty(revision, settings, "ivy.revision"); pubBranch = getProperty(pubBranch, settings, "ivy.deliver.branch"); pubRevision = getProperty(pubRevision, settings, "ivy.deliver.revision"); if (artifactspattern.isEmpty()) { String p = getProperty(null, settings, "ivy.publish.src.artifacts.pattern"); if (p != null) { artifactspattern.add(p); } } if (srcivypattern == null) { srcivypattern = getArtifactspattern(); } status = getProperty(status, settings, "ivy.status"); if (organisation == null) { throw new BuildException("no organisation provided for ivy publish task: " + "It can either be set explicitely via the attribute 'organisation' " + "or via 'ivy.organisation' property or a prior call to "); } if (module == null) { throw new BuildException("no module name provided for ivy publish task: " + "It can either be set explicitely via the attribute 'module' " + "or via 'ivy.module' property or a prior call to "); } if (revision == null) { throw new BuildException("no module revision provided for ivy publish task: " + "It can either be set explicitely via the attribute 'revision' " + "or via 'ivy.revision' property or a prior call to "); } if (artifactspattern.isEmpty()) { throw new BuildException( "no artifacts pattern: either provide it through parameter or " + "through ivy.publish.src.artifacts.pattern property"); } if (publishResolverName == null) { throw new BuildException( "no publish deliver name: please provide it through parameter 'resolver'"); } if ("working".equals(revision)) { revision = Ivy.getWorkingRevision(); } Date pubdate = getPubDate(this.pubdate, new Date()); if (pubRevision == null) { if (revision.startsWith("working@")) { pubRevision = DateUtil.format(pubdate); } else { pubRevision = revision; } } if (status == null) { throw new BuildException("no status provided: either provide it as parameter " + "or through the ivy.status.default property"); } ModuleRevisionId mrid = ModuleRevisionId.newInstance(organisation, module, revision); try { File ivyFile = getProject().resolveFile( IvyPatternHelper.substitute(srcivypattern, organisation, module, pubRevision, "ivy", "ivy", "xml")); if (publishivy && (!ivyFile.exists() || forcedeliver)) { IvyDeliver deliver = new IvyDeliver(); deliver.setSettingsRef(getSettingsRef()); deliver.setTaskName(getTaskName()); deliver.setProject(getProject()); deliver.setDeliverpattern(getSrcivypattern()); deliver.setDelivertarget(deliverTarget); deliver.setDeliveryList(deliveryList); deliver.setModule(getModule()); deliver.setOrganisation(getOrganisation()); deliver.setPubdate(DateUtil.format(pubdate)); deliver.setPubrevision(getPubrevision()); deliver.setPubbranch(getPubbranch()); deliver.setRevision(getRevision()); deliver.setStatus(getStatus()); deliver.setValidate(doValidate(settings)); deliver.setReplacedynamicrev(isReplacedynamicrev()); deliver.setMerge(merge); deliver.setConf(conf); deliver.execute(); } ivy.publish( mrid, artifactspattern, publishResolverName, new PublishOptions() .setPubrevision(getPubrevision()) .setPubbranch(getPubbranch()) .setSrcIvyPattern(publishivy ? srcivypattern : null) .setStatus(getStatus()) .setPubdate(pubdate) .setExtraArtifacts( (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()])) .setValidate(doValidate(settings)).setOverwrite(overwrite) .setUpdate(update).setMerge(merge).setWarnOnMissing(warnonmissing) .setHaltOnMissing(haltonmissing).setConfs(splitConfs(conf))); } catch (Exception e) { if (e instanceof BuildException) { throw (BuildException) e; } throw new BuildException("impossible to publish artifacts for " + mrid + ": " + e, e); } } public PublishArtifact createArtifact() { PublishArtifact art = new PublishArtifact(); artifacts.add(art); return art; } public boolean isPublishivy() { return publishivy; } public void setPublishivy(boolean publishivy) { this.publishivy = publishivy; } public boolean isWarnonmissing() { return warnonmissing; } public void setWarnonmissing(boolean warnonmissing) { this.warnonmissing = warnonmissing; } public boolean isHaltonmissing() { return haltonmissing; } public void setHaltonmissing(boolean haltonmissing) { this.haltonmissing = haltonmissing; } public boolean isOverwrite() { return overwrite; } public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } public void setForcedeliver(boolean b) { forcedeliver = b; } public boolean isForcedeliver() { return forcedeliver; } public boolean isUpdate() { return update; } public void setUpdate(boolean update) { this.update = update; } public class PublishArtifact implements Artifact, DynamicAttribute { private String ext; private String name; private String type; private Map extra = new HashMap(); public String[] getConfigurations() { return null; } public String getExt() { return ext == null ? type : ext; } public ArtifactRevisionId getId() { return null; } public ModuleRevisionId getModuleRevisionId() { return null; } public String getName() { return name; } public Date getPublicationDate() { return null; } public String getType() { return type; } public URL getUrl() { return null; } public void setExt(String ext) { this.ext = ext; } public void setName(String name) { this.name = name; } public void setType(String type) { this.type = type; } public String getAttribute(String attName) { return (String) extra.get(attName); } public Map getAttributes() { return extra; } public String getExtraAttribute(String attName) { return (String) extra.get(attName); } public Map getExtraAttributes() { return extra; } public Map getQualifiedExtraAttributes() { return extra; } public boolean isMetadata() { return false; } public void setDynamicAttribute(String name, String value) { extra.put(name, value); } } public static class ArtifactsPattern { private String pattern; public String getPattern() { return pattern; } public void setPattern(String pattern) { this.pattern = pattern; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyReport.java000066400000000000000000000342711226750426600227470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.report.XmlReportOutputter; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.XSLTProcess; import org.apache.tools.ant.util.JAXPUtils; /** * This ant task let users generates reports (html, xml, graphml, ...) from the last resolve done. */ public class IvyReport extends IvyTask { private File todir; private String organisation; private String module; private String conf; private boolean graph = true; private boolean dot = false; private boolean xml = false; private boolean xsl = true; private File xslFile; private String outputpattern; private String xslext = "html"; private List params = new ArrayList(); private String resolveId; private ModuleRevisionId mRevId; public File getTodir() { return todir; } public void setTodir(File todir) { this.todir = todir; } public void setCache(File cache) { cacheAttributeNotSupported(); } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public boolean isGraph() { return graph; } public void setGraph(boolean graph) { this.graph = graph; } public File getXslfile() { return xslFile; } public void setXslfile(File xslFile) { this.xslFile = xslFile; } public String getOutputpattern() { return outputpattern; } public void setOutputpattern(String outputpattern) { this.outputpattern = outputpattern; } public String getResolveId() { return resolveId; } public void setResolveId(String resolveId) { this.resolveId = resolveId; } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); conf = getProperty(conf, settings, "ivy.resolved.configurations", resolveId); if ("*".equals(conf)) { conf = getProperty(settings, "ivy.resolved.configurations", resolveId); } if (conf == null) { throw new BuildException("no conf provided for ivy report task: " + "It can either be set explicitely via the attribute 'conf' or " + "via 'ivy.resolved.configurations' property or a prior call to "); } if (todir == null) { String t = getProperty(settings, "ivy.report.todir"); if (t != null) { todir = getProject().resolveFile(t); } } if (todir != null && todir.exists()) { todir.mkdirs(); } outputpattern = getProperty(outputpattern, settings, "ivy.report.output.pattern"); if (outputpattern == null) { outputpattern = "[organisation]-[module]-[conf].[ext]"; } if (todir != null && todir.exists() && !todir.isDirectory()) { throw new BuildException("destination directory should be a directory !"); } if (resolveId == null) { organisation = getProperty(organisation, settings, "ivy.organisation", resolveId); module = getProperty(module, settings, "ivy.module", resolveId); if (organisation == null) { throw new BuildException("no organisation provided for ivy report task: " + "It can either be set explicitely via the attribute 'organisation' or " + "via 'ivy.organisation' property or a prior call to "); } if (module == null) { throw new BuildException("no module name provided for ivy report task: " + "It can either be set explicitely via the attribute 'module' or " + "via 'ivy.module' property or a prior call to "); } resolveId = ResolveOptions.getDefaultResolveId(new ModuleId(organisation, module)); } try { String[] confs = splitConfs(conf); if (xsl) { genreport(confs); } if (xml) { genxml(confs); } if (graph) { genStyled(confs, getStylePath("ivy-report-graph.xsl"), "graphml"); } if (dot) { genStyled(confs, getStylePath("ivy-report-dot.xsl"), "dot"); } } catch (IOException e) { throw new BuildException("impossible to generate report: " + e, e); } } private void genxml(String[] confs) throws IOException { ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); for (int i = 0; i < confs.length; i++) { File xml = cacheMgr.getConfigurationResolveReportInCache(resolveId, confs[i]); File out; if (todir != null) { out = new File(todir, getOutputPattern(confs[i], "xml")); } else { out = getProject().resolveFile(getOutputPattern(confs[i], "xml")); } FileUtil.copy(xml, out, null); } } private void genreport(String[] confs) throws IOException { genStyled(confs, getReportStylePath(), xslext); // copy the css if required if (xslFile == null) { File css; if (todir != null) { css = new File(todir, "ivy-report.css"); } else { css = getProject().resolveFile("ivy-report.css"); } if (!css.exists()) { Message.debug("copying report css to " + css.getAbsolutePath()); FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.css"), css, null); } } } private File getReportStylePath() throws IOException { if (xslFile != null) { return xslFile; } // style should be a file (and not an url) // so we have to copy it from classpath to cache ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); File style = new File(cacheMgr.getResolutionCacheRoot(), "ivy-report.xsl"); if (!style.exists()) { Message.debug("copying ivy-report.xsl to " + style.getAbsolutePath()); FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.xsl"), style, null); } return style; } private String getOutputPattern(String conf, String ext) { if (mRevId == null) { ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); XmlReportParser parser = new XmlReportParser(); File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolveId, conf); try { parser.parse(reportFile); } catch (ParseException e) { throw new BuildException("Error occurred while parsing reportfile '" + reportFile.getAbsolutePath() + "'", e); } // get the resolve module mRevId = parser.getResolvedModule(); } return IvyPatternHelper.substitute(outputpattern, mRevId.getOrganisation(), mRevId.getName(), mRevId.getRevision(), "", "", ext, conf, mRevId.getQualifiedExtraAttributes(), null); } private void genStyled(String[] confs, File style, String ext) throws IOException { ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); // process the report with xslt to generate dot file File out; if (todir != null) { out = todir; } else { out = getProject().getBaseDir(); } InputStream xsltStream = null; try { // create stream to stylesheet xsltStream = new BufferedInputStream(new FileInputStream(style)); Source xsltSource = new StreamSource(xsltStream, JAXPUtils.getSystemId(style)); // create transformer TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(xsltSource); // add standard parameters transformer.setParameter("confs", conf); transformer.setParameter("extension", xslext); // add the provided XSLT parameters for (Iterator it = params.iterator(); it.hasNext();) { XSLTProcess.Param param = (XSLTProcess.Param) it.next(); transformer.setParameter(param.getName(), param.getExpression()); } // create the report for (int i = 0; i < confs.length; i++) { File reportFile = cacheMgr .getConfigurationResolveReportInCache(resolveId, confs[i]); File outFile = new File(out, getOutputPattern(confs[i], ext)); log("Processing " + reportFile + " to " + outFile); // make sure the output directory exist File outFileDir = outFile.getParentFile(); if (!outFileDir.exists()) { if (!outFileDir.mkdirs()) { throw new BuildException("Unable to create directory: " + outFileDir.getAbsolutePath()); } } InputStream inStream = null; OutputStream outStream = null; try { inStream = new BufferedInputStream(new FileInputStream(reportFile)); outStream = new BufferedOutputStream(new FileOutputStream(outFile)); StreamResult res = new StreamResult(outStream); Source src = new StreamSource(inStream, JAXPUtils.getSystemId(style)); transformer.transform(src, res); } catch (TransformerException e) { throw new BuildException(e); } finally { if (inStream != null) { try { inStream.close(); } catch (IOException e) { // ignore } } if (outStream != null) { try { outStream.close(); } catch (IOException e) { // ignore } } } } } catch (TransformerConfigurationException e) { throw new BuildException(e); } finally { if (xsltStream != null) { try { xsltStream.close(); } catch (IOException e) { // ignore } } } } private File getStylePath(String styleResourceName) throws IOException { // style should be a file (and not an url) // so we have to copy it from classpath to cache ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); File style = new File(cacheMgr.getResolutionCacheRoot(), styleResourceName); FileUtil.copy(XmlReportOutputter.class.getResourceAsStream(styleResourceName), style, null); return style; } public boolean isXml() { return xml; } public void setXml(boolean xml) { this.xml = xml; } public boolean isXsl() { return xsl; } public void setXsl(boolean xsl) { this.xsl = xsl; } public String getXslext() { return xslext; } public void setXslext(String xslext) { this.xslext = xslext; } public XSLTProcess.Param createParam() { XSLTProcess.Param result = new XSLTProcess.Param(); params.add(result); return result; } public boolean isDot() { return dot; } public void setDot(boolean dot) { this.dot = dot; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyRepositoryReport.java000066400000000000000000000251711226750426600250460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.ivy.Ivy; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.report.XmlReportOutputter; import org.apache.ivy.util.FileUtil; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.XSLTProcess; /** * Generates a report of dependencies of a set of modules in the repository. The set of modules is * specified using organisation/module and matcher. */ public class IvyRepositoryReport extends IvyTask { private String organisation = "*"; private String module; private String branch; private String revision = "latest.integration"; private String matcher = PatternMatcher.EXACT_OR_REGEXP; private File todir; private boolean graph = false; private boolean dot = false; private boolean xml = true; private boolean xsl = false; private String xslFile; private String outputname = "ivy-repository-report"; private String xslext = "html"; private List params = new ArrayList(); public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); if (xsl && xslFile == null) { throw new BuildException("xsl file is mandatory when using xsl generation"); } if (module == null && PatternMatcher.EXACT.equals(matcher)) { throw new BuildException("no module name provided for ivy repository graph task: " + "It can either be set explicitely via the attribute 'module' or " + "via 'ivy.module' property or a prior call to "); } else if (module == null && !PatternMatcher.EXACT.equals(matcher)) { module = PatternMatcher.ANY_EXPRESSION; } ModuleRevisionId mrid = ModuleRevisionId.newInstance(organisation, module, revision); try { ModuleRevisionId criteria = null; if ((revision == null) || settings.getVersionMatcher().isDynamic(mrid)) { criteria = new ModuleRevisionId(new ModuleId(organisation, module), branch, "*"); } else { criteria = new ModuleRevisionId(new ModuleId(organisation, module), branch, revision); } ModuleRevisionId[] mrids = ivy.listModules(criteria, settings.getMatcher(matcher)); // replace all found revisions with the original requested revision Set modules = new HashSet(); for (int i = 0; i < mrids.length; i++) { modules.add(ModuleRevisionId.newInstance(mrids[i], revision)); } mrids = (ModuleRevisionId[]) modules.toArray(new ModuleRevisionId[modules.size()]); ModuleDescriptor md = DefaultModuleDescriptor.newCallerInstance(mrids, true, false); String resolveId = ResolveOptions.getDefaultResolveId(md); ResolveReport report = ivy.resolve(md, new ResolveOptions().setResolveId(resolveId) .setValidate(doValidate(settings))); ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager(); new XmlReportOutputter().output(report, cacheMgr, new ResolveOptions()); if (graph) { gengraph(cacheMgr, md.getModuleRevisionId().getOrganisation(), md .getModuleRevisionId().getName()); } if (dot) { gendot(cacheMgr, md.getModuleRevisionId().getOrganisation(), md .getModuleRevisionId().getName()); } if (xml) { FileUtil.copy(cacheMgr.getConfigurationResolveReportInCache(resolveId, "default"), new File(getTodir(), outputname + ".xml"), null); } if (xsl) { genreport(cacheMgr, md.getModuleRevisionId().getOrganisation(), md .getModuleRevisionId().getName()); } } catch (Exception e) { throw new BuildException("impossible to generate graph for " + mrid + ": " + e, e); } } private void genreport(ResolutionCacheManager cache, String organisation, String module) throws IOException { // first process the report with xslt XSLTProcess xslt = new XSLTProcess(); xslt.setTaskName(getTaskName()); xslt.setProject(getProject()); xslt.init(); String resolveId = ResolveOptions.getDefaultResolveId(new ModuleId(organisation, module)); xslt.setIn(cache.getConfigurationResolveReportInCache(resolveId, "default")); xslt.setOut(new File(getTodir(), outputname + "." + xslext)); xslt.setStyle(xslFile); XSLTProcess.Param param = xslt.createParam(); param.setName("extension"); param.setExpression(xslext); // add the provided XSLT parameters for (Iterator it = params.iterator(); it.hasNext();) { param = (XSLTProcess.Param) it.next(); XSLTProcess.Param realParam = xslt.createParam(); realParam.setName(param.getName()); realParam.setExpression(param.getExpression()); } xslt.execute(); } private void gengraph(ResolutionCacheManager cache, String organisation, String module) throws IOException { gen(cache, organisation, module, getGraphStylePath(cache.getResolutionCacheRoot()), "graphml"); } private String getGraphStylePath(File cache) throws IOException { // style should be a file (and not an url) // so we have to copy it from classpath to cache File style = new File(cache, "ivy-report-graph-all.xsl"); FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report-graph-all.xsl"), style, null); return style.getAbsolutePath(); } private void gendot(ResolutionCacheManager cache, String organisation, String module) throws IOException { gen(cache, organisation, module, getDotStylePath(cache.getResolutionCacheRoot()), "dot"); } private String getDotStylePath(File cache) throws IOException { // style should be a file (and not an url) // so we have to copy it from classpath to cache File style = new File(cache, "ivy-report-dot-all.xsl"); FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report-dot-all.xsl"), style, null); return style.getAbsolutePath(); } private void gen(ResolutionCacheManager cache, String organisation, String module, String style, String ext) throws IOException { XSLTProcess xslt = new XSLTProcess(); xslt.setTaskName(getTaskName()); xslt.setProject(getProject()); xslt.init(); String resolveId = ResolveOptions.getDefaultResolveId(new ModuleId(organisation, module)); xslt.setIn(cache.getConfigurationResolveReportInCache(resolveId, "default")); xslt.setOut(new File(getTodir(), outputname + "." + ext)); xslt.setBasedir(cache.getResolutionCacheRoot()); xslt.setStyle(style); xslt.execute(); } public File getTodir() { if (todir == null && getProject() != null) { return getProject().getBaseDir(); } return todir; } public void setTodir(File todir) { this.todir = todir; } public boolean isGraph() { return graph; } public void setGraph(boolean graph) { this.graph = graph; } public String getXslfile() { return xslFile; } public void setXslfile(String xslFile) { this.xslFile = xslFile; } public boolean isXml() { return xml; } public void setXml(boolean xml) { this.xml = xml; } public boolean isXsl() { return xsl; } public void setXsl(boolean xsl) { this.xsl = xsl; } public String getXslext() { return xslext; } public void setXslext(String xslext) { this.xslext = xslext; } public XSLTProcess.Param createParam() { XSLTProcess.Param result = new XSLTProcess.Param(); params.add(result); return result; } public String getOutputname() { return outputname; } public void setOutputname(String outputpattern) { outputname = outputpattern; } public void setCache(File cache) { cacheAttributeNotSupported(); } public String getMatcher() { return matcher; } public void setMatcher(String matcher) { this.matcher = matcher; } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public boolean isDot() { return dot; } public void setDot(boolean dot) { this.dot = dot; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyResolve.java000066400000000000000000000445761226750426600231240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.net.MalformedURLException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.ivy.Ivy; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ExtendsDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolveProcessException; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.Message; import org.apache.ivy.util.filter.FilterHelper; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * This task allow to call the Ivy dependency resolution from ant. */ public class IvyResolve extends IvyTask { private File file = null; private String conf = null; private String organisation = null; private String module = null; private String branch = null; private String revision = null; private String pubdate = null; private boolean inline = false; private boolean haltOnFailure = true; private boolean showProgress = true; private boolean useCacheOnly = false; private String type = null; private boolean transitive = true; private boolean refresh = false; private boolean changing = false; private Boolean keep = null; private String failureProperty = null; private boolean useOrigin = false; private String resolveMode = null; private String resolveId = null; private String log = ResolveOptions.LOG_DEFAULT; private boolean checkIfChanged = true; // for backward compatibility private List/* */dependencies = new ArrayList(); private List/* */excludes = new ArrayList(); private List/* */conflicts = new ArrayList(); public boolean isUseOrigin() { return useOrigin; } public void setUseOrigin(boolean useOrigin) { this.useOrigin = useOrigin; } public String getDate() { return pubdate; } public void setDate(String pubdate) { this.pubdate = pubdate; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } public void setCache(File cache) { cacheAttributeNotSupported(); } public String getConf() { return conf; } public void setConf(String conf) { this.conf = conf; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } public boolean isHaltonfailure() { return haltOnFailure; } public void setHaltonfailure(boolean haltOnFailure) { this.haltOnFailure = haltOnFailure; } public void setShowprogress(boolean show) { this.showProgress = show; } public boolean isUseCacheOnly() { return useCacheOnly; } public void setUseCacheOnly(boolean useCacheOnly) { this.useCacheOnly = useCacheOnly; } public String getType() { return type; } public void setType(String type) { this.type = type; } public boolean isRefresh() { return refresh; } public void setRefresh(boolean refresh) { this.refresh = refresh; } public String getLog() { return log; } public void setLog(String log) { this.log = log; } /** * @deprecated Use {@link #setFailureProperty(String)} instead */ @Deprecated public void setFailurePropery(String failureProperty) { log("The 'failurepropery' attribute is deprecated. " + "Please use the 'failureproperty' attribute instead", Project.MSG_WARN); setFailureProperty(failureProperty); } public void setFailureProperty(String failureProperty) { this.failureProperty = failureProperty; } public String getFailureProperty() { return failureProperty; } public IvyDependency createDependency() { IvyDependency dep = new IvyDependency(); dependencies.add(dep); return dep; } public IvyExclude createExclude() { IvyExclude ex = new IvyExclude(); excludes.add(ex); return ex; } public IvyConflict createConflict() { IvyConflict c = new IvyConflict(); conflicts.add(c); return c; } protected void prepareTask() { super.prepareTask(); Message.setShowProgress(showProgress); } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); try { conf = getProperty(conf, settings, "ivy.configurations"); type = getProperty(type, settings, "ivy.resolve.default.type.filter"); String[] confs = splitConfs(conf); boolean childs = !dependencies.isEmpty() || !excludes.isEmpty() || !conflicts.isEmpty(); ResolveReport report; if (childs) { if (isInline()) { throw new BuildException("the inline mode is incompatible with child elements"); } if (organisation != null) { throw new BuildException("'organisation' is not allowed with child elements"); } if (module != null) { throw new BuildException("'module' is not allowed with child elements"); } if (file != null) { throw new BuildException("'file' not allowed with child elements"); } if (!getAllowedLogOptions().contains(log)) { throw new BuildException("invalid option for 'log': " + log + ". Available options are " + getAllowedLogOptions()); } ModuleRevisionId mrid = ModuleRevisionId.newInstance("", "", Ivy.getWorkingRevision()); DefaultModuleDescriptor md = DefaultModuleDescriptor.newBasicInstance(mrid, null); Iterator itDeps = dependencies.iterator(); while (itDeps.hasNext()) { IvyDependency dep = (IvyDependency) itDeps.next(); DependencyDescriptor dd = dep.asDependencyDescriptor(md, "default", settings); md.addDependency(dd); } Iterator itExcludes = excludes.iterator(); while (itExcludes.hasNext()) { IvyExclude exclude = (IvyExclude) itExcludes.next(); DefaultExcludeRule rule = exclude.asRule(settings); rule.addConfiguration("default"); md.addExcludeRule(rule); } Iterator itConflicts = conflicts.iterator(); while (itConflicts.hasNext()) { IvyConflict conflict = (IvyConflict) itConflicts.next(); conflict.addConflict(md, settings); } report = ivy .resolve(md, getResolveOptions(ivy, new String[] {"default"}, settings)); } else if (isInline()) { if (organisation == null) { throw new BuildException("'organisation' is required when using inline mode"); } if (module == null) { throw new BuildException("'module' is required when using inline mode"); } if (file != null) { throw new BuildException("'file' not allowed when using inline mode"); } if (!getAllowedLogOptions().contains(log)) { throw new BuildException("invalid option for 'log': " + log + ". Available options are " + getAllowedLogOptions()); } for (int i = 0; i < confs.length; i++) { if ("*".equals(confs[i])) { confs[i] = "*(public)"; } } if (revision == null) { revision = "latest.integration"; } report = ivy.resolve( ModuleRevisionId.newInstance(organisation, module, branch, revision), getResolveOptions(ivy, confs, settings), changing); } else { if (organisation != null) { throw new BuildException( "'organisation' not allowed when not using 'org' attribute"); } if (module != null) { throw new BuildException("'module' not allowed when not using 'org' attribute"); } if (file == null) { file = getProject().resolveFile(getProperty(settings, "ivy.dep.file")); } report = ivy.resolve(file.toURI().toURL(), getResolveOptions(ivy, confs, settings)); } if (report.hasError()) { if (failureProperty != null) { getProject().setProperty(failureProperty, "true"); } if (isHaltonfailure()) { throw new BuildException("resolve failed - see output for details"); } } setResolved(report, resolveId, isKeep()); confs = report.getConfigurations(); if (isKeep()) { ModuleDescriptor md = report.getModuleDescriptor(); // put resolved infos in ant properties and ivy variables // putting them in ivy variables is important to be able to change from one resolve // call to the other String mdOrg = md.getModuleRevisionId().getOrganisation(); String mdName = md.getModuleRevisionId().getName(); String mdRev = md.getResolvedModuleRevisionId().getRevision(); getProject().setProperty("ivy.organisation", mdOrg); settings.setVariable("ivy.organisation", mdOrg); getProject().setProperty("ivy.module", mdName); settings.setVariable("ivy.module", mdName); getProject().setProperty("ivy.revision", mdRev); settings.setVariable("ivy.revision", mdRev); for (int i = 0; i < md.getInheritedDescriptors().length; i++) { ExtendsDescriptor parent = md.getInheritedDescriptors()[i]; String parentOrg = parent.getResolvedParentRevisionId().getOrganisation(); String parentModule = parent.getResolvedParentRevisionId().getName(); String parentRevision = parent.getResolvedParentRevisionId().getRevision(); String parentBranch = parent.getResolvedParentRevisionId().getBranch(); getProject().setProperty("ivy.parent[" + i + "].organisation", parentOrg); settings.setVariable("ivy.parent[" + i + "].organisation", parentOrg); getProject().setProperty("ivy.parent[" + i + "].module", parentModule); settings.setVariable("ivy.parent[" + i + "].module", parentModule); getProject().setProperty("ivy.parent[" + i + "].revision", parentRevision); settings.setVariable("ivy.parent[" + i + "].revision", parentRevision); if (parentBranch != null) { getProject().setProperty("ivy.parent[" + i + "].branch", parentBranch); settings.setVariable("ivy.parent[" + i + "].branch", parentBranch); } } getProject().setProperty("ivy.parents.count", String.valueOf(md.getInheritedDescriptors().length)); settings.setVariable("ivy.parents.count", String.valueOf(md.getInheritedDescriptors().length)); Boolean hasChanged = null; if (getCheckIfChanged()) { hasChanged = Boolean.valueOf(report.hasChanged()); getProject().setProperty("ivy.deps.changed", hasChanged.toString()); settings.setVariable("ivy.deps.changed", hasChanged.toString()); } getProject().setProperty("ivy.resolved.configurations", mergeConfs(confs)); settings.setVariable("ivy.resolved.configurations", mergeConfs(confs)); if (file != null) { getProject().setProperty("ivy.resolved.file", file.getAbsolutePath()); settings.setVariable("ivy.resolved.file", file.getAbsolutePath()); } if (resolveId != null) { getProject().setProperty("ivy.organisation." + resolveId, mdOrg); settings.setVariable("ivy.organisation." + resolveId, mdOrg); getProject().setProperty("ivy.module." + resolveId, mdName); settings.setVariable("ivy.module." + resolveId, mdName); getProject().setProperty("ivy.revision." + resolveId, mdRev); settings.setVariable("ivy.revision." + resolveId, mdRev); if (getCheckIfChanged()) { // hasChanged has already been set earlier getProject().setProperty("ivy.deps.changed." + resolveId, hasChanged.toString()); settings.setVariable("ivy.deps.changed." + resolveId, hasChanged.toString()); } getProject().setProperty("ivy.resolved.configurations." + resolveId, mergeConfs(confs)); settings.setVariable("ivy.resolved.configurations." + resolveId, mergeConfs(confs)); if (file != null) { getProject().setProperty("ivy.resolved.file." + resolveId, file.getAbsolutePath()); settings.setVariable("ivy.resolved.file." + resolveId, file.getAbsolutePath()); } } } } catch (MalformedURLException e) { throw new BuildException("unable to convert given ivy file to url: " + file + ": " + e, e); } catch (ParseException e) { log(e.getMessage(), Project.MSG_ERR); throw new BuildException("syntax errors in ivy file: " + e, e); } catch (ResolveProcessException e) { throw new BuildException("impossible to resolve dependencies:\n\t" + e.getMessage(), e); } catch (Exception e) { throw new BuildException("impossible to resolve dependencies:\n\t" + e, e); } } protected Collection/* */getAllowedLogOptions() { return Arrays.asList(new String[] {LogOptions.LOG_DEFAULT, LogOptions.LOG_DOWNLOAD_ONLY, LogOptions.LOG_QUIET}); } private ResolveOptions getResolveOptions(Ivy ivy, String[] confs, IvySettings settings) { if (useOrigin) { settings.useDeprecatedUseOrigin(); } return ((ResolveOptions) new ResolveOptions().setLog(log)).setConfs(confs) .setValidate(doValidate(settings)) .setArtifactFilter(FilterHelper.getArtifactTypeFilter(type)).setRevision(revision) .setDate(getPubDate(pubdate, null)).setUseCacheOnly(useCacheOnly) .setRefresh(refresh).setTransitive(transitive).setResolveMode(resolveMode) .setResolveId(resolveId).setCheckIfChanged(checkIfChanged); } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public boolean isTransitive() { return transitive; } public void setTransitive(boolean transitive) { this.transitive = transitive; } public boolean isChanging() { return changing; } public void setChanging(boolean changing) { this.changing = changing; } public boolean isKeep() { return keep == null ? organisation == null : keep.booleanValue(); } public void setKeep(boolean keep) { this.keep = Boolean.valueOf(keep); } public boolean isInline() { return inline; } public void setInline(boolean inline) { this.inline = inline; } public String getResolveId() { return resolveId; } public void setResolveId(String resolveId) { this.resolveId = resolveId; } public String getResolveMode() { return resolveMode; } public void setResolveMode(String resolveMode) { this.resolveMode = resolveMode; } public boolean getCheckIfChanged() { return checkIfChanged; } public void setCheckIfChanged(boolean checkIfChanged) { this.checkIfChanged = checkIfChanged; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyResources.java000066400000000000000000000073411226750426600234440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Location; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.BaseResourceCollectionWrapper; import org.apache.tools.ant.types.resources.FileResource; public class IvyResources extends IvyCacheTask implements ResourceCollection { /** * Delegate for the implementation of the resource collection */ private class IvyBaseResourceCollectionWrapper extends BaseResourceCollectionWrapper { protected Collection getCollection() { return resolveResources(null); } } private IvyBaseResourceCollectionWrapper wrapper = new IvyBaseResourceCollectionWrapper(); // delegate the ProjectComponent API on the wrapper public void setLocation(Location location) { super.setLocation(location); wrapper.setLocation(location); } public void setProject(Project project) { super.setProject(project); wrapper.setProject(project); } public void setDescription(String desc) { super.setDescription(desc); wrapper.setDescription(desc); } // delegate the DataType API on the wrapper public void setRefid(Reference ref) { wrapper.setRefid(ref); } // delegate the AbstractResourceCollectionWrapper API on the wrapper public void setCache(boolean b) { wrapper.setCache(b); } // implementation of the Resource Collection API public boolean isFilesystemOnly() { return true; } public Iterator iterator() { return wrapper.iterator(); } public int size() { return wrapper.size(); } // convert the ivy reports into an Ant Resource collection private Collection resolveResources(String id) throws BuildException { prepareAndCheck(); try { List/* */resources = new ArrayList(); if (id != null) { getProject().addReference(id, this); } for (Iterator iter = getArtifactReports().iterator(); iter.hasNext();) { ArtifactDownloadReport a = (ArtifactDownloadReport) iter.next(); resources.add(new FileResource(a.getLocalFile())); } return resources; } catch (Exception ex) { throw new BuildException("impossible to build ivy resources: " + ex, ex); } } // implementation of the IvyPostResolveTask API public void doExecute() throws BuildException { // TODO : maybe there is a way to implement it ? throw new BuildException("ivy:resources should not be used as a Ant Task"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyRetrieve.java000066400000000000000000000172761226750426600232670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.retrieve.RetrieveOptions; import org.apache.ivy.core.retrieve.RetrieveReport; import org.apache.ivy.util.filter.Filter; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.PatternSet; import org.apache.tools.ant.util.FileNameMapper; /** * This task allow to retrieve dependencies from the cache to a local directory like a lib dir. */ public class IvyRetrieve extends IvyPostResolveTask { private static final Collection OVERWRITEMODE_VALUES = Arrays.asList(new String[] { RetrieveOptions.OVERWRITEMODE_ALWAYS, RetrieveOptions.OVERWRITEMODE_NEVER, RetrieveOptions.OVERWRITEMODE_NEWER, RetrieveOptions.OVERWRITEMODE_DIFFERENT}); private String pattern; private String ivypattern = null; private boolean sync = false; private boolean symlink = false; private boolean symlinkmass = false; private String overwriteMode = RetrieveOptions.OVERWRITEMODE_NEWER; private String pathId = null; private String setId = null; private Mapper mapper = null; public String getPattern() { return pattern; } public void setPattern(String pattern) { this.pattern = pattern; } public String getPathId() { return pathId; } public void setPathId(String pathId) { this.pathId = pathId; } public String getSetId() { return setId; } public void setSetId(String setId) { this.setId = setId; } public void doExecute() throws BuildException { prepareAndCheck(); if (!getAllowedLogOptions().contains(getLog())) { throw new BuildException("invalid option for 'log': " + getLog() + ". Available options are " + getAllowedLogOptions()); } pattern = getProperty(pattern, getSettings(), "ivy.retrieve.pattern"); try { Filter artifactFilter = getArtifactFilter(); RetrieveReport report = getIvyInstance().retrieve( getResolvedMrid(), ((RetrieveOptions) new RetrieveOptions().setLog(getLog())) .setConfs(splitConfs(getConf())).setDestArtifactPattern(pattern) .setDestIvyPattern(ivypattern).setArtifactFilter(artifactFilter) .setSync(sync).setOverwriteMode(getOverwriteMode()) .setUseOrigin(isUseOrigin()).setMakeSymlinks(symlink) .setMakeSymlinksInMass(symlinkmass).setResolveId(getResolveId()) .setMapper(mapper == null ? null : new MapperAdapter(mapper))); int targetsCopied = report.getNbrArtifactsCopied(); boolean haveTargetsBeenCopied = targetsCopied > 0; getProject().setProperty("ivy.nb.targets.copied", String.valueOf(targetsCopied)); getProject().setProperty("ivy.targets.copied", String.valueOf(haveTargetsBeenCopied)); if (getPathId() != null) { Path path = new Path(getProject()); getProject().addReference(getPathId(), path); for (Iterator iter = report.getRetrievedFiles().iterator(); iter.hasNext();) { path.createPathElement().setLocation((File) iter.next()); } } if (getSetId() != null) { FileSet fileset = new FileSet(); fileset.setProject(getProject()); getProject().addReference(getSetId(), fileset); fileset.setDir(report.getRetrieveRoot()); for (Iterator iter = report.getRetrievedFiles().iterator(); iter.hasNext();) { PatternSet.NameEntry ne = fileset.createInclude(); ne.setName(getPath(report.getRetrieveRoot(), (File) iter.next())); } } } catch (Exception ex) { throw new BuildException("impossible to ivy retrieve: " + ex, ex); } } protected Collection/* */getAllowedLogOptions() { return Arrays.asList(new String[] {LogOptions.LOG_DEFAULT, LogOptions.LOG_DOWNLOAD_ONLY, LogOptions.LOG_QUIET}); } public String getIvypattern() { return ivypattern; } public void setIvypattern(String ivypattern) { this.ivypattern = ivypattern; } public boolean isSync() { return sync; } public void setSync(boolean sync) { this.sync = sync; } /** * Option to create symlinks instead of copying. */ public void setSymlink(boolean symlink) { this.symlink = symlink; } /** * Option to create symlinks in one mass action, instead of separately. */ public void setSymlinkmass(boolean symlinkmass) { this.symlinkmass = symlinkmass; } public void setOverwriteMode(String overwriteMode) { if (!OVERWRITEMODE_VALUES.contains(overwriteMode)) { throw new IllegalArgumentException("invalid overwriteMode value '" + overwriteMode + "'. " + "Valid values are " + OVERWRITEMODE_VALUES); } this.overwriteMode = overwriteMode; } public String getOverwriteMode() { return overwriteMode; } /** * Add a mapper to convert the file names. * * @param mapper * a Mapper value. */ public void addMapper(Mapper mapper) { if (this.mapper != null) { throw new IllegalArgumentException("Cannot define more than one mapper"); } this.mapper = mapper; } /** * Add a nested filenamemapper. * * @param fileNameMapper * the mapper to add. */ public void add(FileNameMapper fileNameMapper) { Mapper m = new Mapper(getProject()); m.add(fileNameMapper); addMapper(m); } /** * Returns the path of the file relative to the given base directory. * * @param base * the parent directory to which the file must be evaluated. * @param file * the file for which the path should be returned * @return the path of the file relative to the given base directory. */ private String getPath(File base, File file) { String absoluteBasePath = base.getAbsolutePath(); int beginIndex = absoluteBasePath.length(); // checks if the basePath ends with the file separator (which can for instance // happen if the basePath is the root on unix) if (!absoluteBasePath.endsWith(File.separator)) { beginIndex++; // skip the seperator char as well } return file.getAbsolutePath().substring(beginIndex); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyTask.java000066400000000000000000000250041226750426600223700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.util.Date; import java.util.Locale; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.StringUtils; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Reference; /** * Base class for all ivy ant tasks, deal particularly with ivy instance storage in ant project. */ public abstract class IvyTask extends Task { public static final String ANT_PROJECT_CONTEXT_KEY = "ant-project"; private Boolean validate = null; private Reference antIvyEngineRef = null; protected boolean doValidate(IvySettings ivy) { if (validate != null) { return validate.booleanValue(); } return ivy.doValidate(); } public boolean isValidate() { return validate == null ? true : validate.booleanValue(); } public void setValidate(boolean validate) { this.validate = Boolean.valueOf(validate); } public void setSettingsRef(Reference ref) { antIvyEngineRef = ref; } public Reference getSettingsRef() { return antIvyEngineRef; } protected IvySettings getSettings() { return getIvyInstance().getSettings(); } protected Ivy getIvyInstance() { Object antIvyEngine; if (antIvyEngineRef != null) { antIvyEngine = antIvyEngineRef.getReferencedObject(getProject()); if (!antIvyEngine.getClass().getName().equals(IvyAntSettings.class.getName())) { throw new BuildException(antIvyEngineRef.getRefId() + " doesn't reference an ivy:settings", getLocation()); } if (!(antIvyEngine instanceof IvyAntSettings)) { throw new BuildException(antIvyEngineRef.getRefId() + " has been defined in a different classloader. " + "Please use the same loader when defining your task, or " + "redeclare your ivy:settings in this classloader", getLocation()); } } else { antIvyEngine = IvyAntSettings.getDefaultInstance(this); } Ivy ivy = ((IvyAntSettings) antIvyEngine).getConfiguredIvyInstance(this); AntMessageLogger.register(this, ivy); return ivy; } protected void setResolved(ResolveReport report, boolean keep) { ModuleDescriptor md = report.getModuleDescriptor(); String[] confs = report.getConfigurations(); if (keep) { getProject().addReference("ivy.resolved.report", report); getProject().addReference("ivy.resolved.configurations.ref", confs); getProject().addReference("ivy.resolved.descriptor", md); } String suffix = md.getModuleRevisionId().getModuleId().getOrganisation() + "." + md.getModuleRevisionId().getModuleId().getName(); getProject().addReference("ivy.resolved.report." + suffix, report); getProject().addReference("ivy.resolved.descriptor." + suffix, md); getProject().addReference("ivy.resolved.configurations.ref." + suffix, confs); } protected void setResolved(ResolveReport report, String resolveId, boolean keep) { setResolved(report, keep); if (resolveId != null) { ModuleDescriptor md = report.getModuleDescriptor(); String[] confs = report.getConfigurations(); getProject().addReference("ivy.resolved.report." + resolveId, report); getProject().addReference("ivy.resolved.descriptor." + resolveId, md); getProject().addReference("ivy.resolved.configurations.ref." + resolveId, confs); } } protected String[] getResolvedConfigurations(String org, String module, boolean strict) { return (String[]) getReference("ivy.resolved.configurations.ref", org, module, strict); } protected Object getResolvedDescriptor(String resolveId) { return getResolvedDescriptor(resolveId, true); } protected Object getResolvedDescriptor(String resolveId, boolean strict) { Object result = getProject().getReference("ivy.resolved.descriptor." + resolveId); if (strict && (result == null)) { throw new BuildException("ModuleDescriptor for resolve with id '" + resolveId + "' not found."); } return result; } protected Object getResolvedDescriptor(String org, String module) { return getResolvedDescriptor(org, module, false); } protected Object getResolvedDescriptor(String org, String module, boolean strict) { return getReference("ivy.resolved.descriptor", org, module, strict); } private Object getReference(String prefix, String org, String module, boolean strict) { Object reference = null; if (org != null && module != null) { reference = getProject().getReference(prefix + "." + org + "." + module); } if (!strict && reference == null) { reference = getProject().getReference(prefix); } return reference; } protected ResolveReport getResolvedReport(String org, String module, String resolveId) { ResolveReport result = null; if (resolveId == null) { result = (ResolveReport) getReference("ivy.resolved.report", org, module, false); } else { result = (ResolveReport) getReference("ivy.resolved.report." + resolveId, null, null, false); } return result; } protected String[] splitConfs(String conf) { if (conf == null) { return null; } String[] confs = conf.split(","); for (int i = 0; i < confs.length; i++) { confs[i] = confs[i].trim(); } return confs; } protected String mergeConfs(String[] conf) { return StringUtils.join(conf, ", "); } protected static Date getPubDate(String date, Date def) { if (date != null) { if ("now".equals(date.toLowerCase(Locale.US))) { return new Date(); } try { return DateUtil.parse(date); } catch (Exception ex) { throw new BuildException("Publication date provided in bad format. Should be '" + DateUtil.DATE_FORMAT_PATTERN + "' and not '" + date + "'!"); } } else { return def; } } protected String getProperty(String value, IvySettings ivy, String name) { if (value == null) { return getProperty(ivy, name); } else { value = ivy.substitute(value); Message.debug("parameter found as attribute value: " + name + "=" + value); return value; } } protected String getProperty(String value, IvySettings ivy, String name, String resolveId) { if (resolveId == null) { return getProperty(value, ivy, name); } else { return getProperty(value, ivy, name + "." + resolveId); } } protected String getProperty(IvySettings ivy, String name, String resolveId) { if (resolveId == null) { return getProperty(ivy, name); } else { return getProperty(ivy, name + "." + resolveId); } } protected String getProperty(IvySettings ivy, String name) { String val = ivy.getVariable(name); if (val == null) { val = ivy.substitute(getProject().getProperty(name)); if (val != null) { Message.debug("parameter found as ant project property: " + name + "=" + val); } else { Message.debug("parameter not found: " + name); } } else { val = ivy.substitute(val); Message.debug("parameter found as ivy variable: " + name + "=" + val); } return val; } /** * Called when task starts its execution. */ protected void prepareTask() { getProject().setProperty("ivy.version", Ivy.getIvyVersion()); // push current project and Ivy on the stack in context IvyContext.pushNewCopyContext(); IvyContext.getContext().setIvy(getIvyInstance()); IvyContext.getContext().push(ANT_PROJECT_CONTEXT_KEY, getProject()); } /** * Called when task is about to finish Should clean up all state related information (stacks for * example) */ protected void finalizeTask() { if (!IvyContext.getContext().pop(ANT_PROJECT_CONTEXT_KEY, getProject())) { Message.error("ANT project poped from stack not equals current !. Ignoring"); } IvyContext.popContext(); } /** * Ant task execute. Calls prepareTask, doExecute, finalzeTask */ public final void execute() throws BuildException { try { prepareTask(); doExecute(); } finally { finalizeTask(); } } /** * The real logic of task execution after project has been set in the context. MUST be * implemented by subclasses * * @throws BuildException */ public abstract void doExecute() throws BuildException; public String toString() { return getClass().getName() + ":" + getTaskName(); } /** * Informs the user that the cache attribute is not supported any more. */ protected void cacheAttributeNotSupported() { throw new BuildException( "cache attribute is not supported any more. See IVY-685 for details."); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/IvyVar.java000066400000000000000000000071711226750426600222230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.util.Iterator; import java.util.Properties; import org.apache.ivy.Ivy; import org.apache.ivy.core.settings.IvySettings; import org.apache.tools.ant.BuildException; /** * This task let user set ivy variables from ant. */ public class IvyVar extends IvyTask { private String name; private String value; private File file; private String url; private String prefix; public File getFile() { return file; } public void setFile(File aFile) { file = aFile; } public String getName() { return name; } public void setName(String aName) { name = aName; } public String getPrefix() { return prefix; } public void setPrefix(String aPrefix) { prefix = aPrefix; } public String getUrl() { return url; } public void setUrl(String aUrl) { url = aUrl; } public String getValue() { return value; } public void setValue(String aValue) { value = aValue; } public void doExecute() throws BuildException { Ivy ivy = getIvyInstance(); IvySettings settings = ivy.getSettings(); if (getName() != null) { settings.setVariable(getVarName(getName()), getValue()); } else { Properties props = new Properties(); InputStream is = null; try { if (getFile() != null) { is = new FileInputStream(getFile()); } else if (getUrl() != null) { is = new URL(getUrl()).openStream(); } else { throw new BuildException("specify either name or file or url to ivy var task"); } props.load(is); } catch (Exception ex) { throw new BuildException("impossible to load variables from file: " + ex, ex); } finally { if (is != null) { try { is.close(); } catch (Exception e) { // ignore } } } for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String value = (String) props.get(name); settings.setVariable(getVarName(name), value); } } } private String getVarName(String name) { String prefix = getPrefix(); if (prefix != null) { if (prefix.endsWith(".")) { return prefix + name; } else { return prefix + "." + name; } } return name; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/MapperAdapter.java000066400000000000000000000026121226750426600235230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.retrieve.FileNameMapper; import org.apache.tools.ant.types.Mapper; class MapperAdapter implements FileNameMapper { private static final String[] EMPTY = new String[0]; private Mapper mapper; MapperAdapter(Mapper mapper) { this.mapper = mapper; } public String[] mapFileName(String fileName) { String[] result = mapper.getImplementation().mapFileName(fileName); if (result == null) { result = EMPTY; } return result; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/PackageMapping.java000066400000000000000000000035311226750426600236460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.ant; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * Describes a mapping between a package name and an org name revision uple */ public class PackageMapping { private String pkg; private String organisation; private String module; private String revision; public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrganisation() { return organisation; } public void setOrganisation(String organisation) { this.organisation = organisation; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public String getPackage() { return pkg; } public void setPackage(String package1) { pkg = package1; } public ModuleRevisionId getModuleRevisionId() { return ModuleRevisionId.newInstance(organisation, module, revision); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/ant/antlib.xml000066400000000000000000000062301226750426600221260ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/000077500000000000000000000000001226750426600203005ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/ExecutionRelativeUrlResolver.java000066400000000000000000000024451226750426600270140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; import java.net.MalformedURLException; import java.net.URL; /** * Resolve relative url relatively to the current execution directory instead of relatively to the * context. This is was actually done prior 2.0. This class allow thus to work in a backward * compatible mode. */ public class ExecutionRelativeUrlResolver extends RelativeUrlResolver { public URL getURL(URL context, String url) throws MalformedURLException { return new URL(url); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/IvyContext.java000066400000000000000000000307631226750426600232700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import org.apache.ivy.Ivy; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.util.Message; import org.apache.ivy.util.MessageLogger; /** * This class represents an execution context of an Ivy action. It contains several getters to * retrieve information, like the used Ivy instance, the cache location... * * @see IvyThread */ public class IvyContext { private static ThreadLocal/* > */current = new ThreadLocal(); private Ivy defaultIvy; private WeakReference/* */ivy = new WeakReference(null); private Map contextMap = new HashMap(); private Thread operatingThread; private ResolveData resolveData; private DependencyDescriptor dd; public IvyContext() { } public IvyContext(IvyContext ctx) { defaultIvy = ctx.defaultIvy; ivy = ctx.ivy; contextMap = new HashMap(ctx.contextMap); operatingThread = ctx.operatingThread; resolveData = ctx.resolveData; dd = ctx.dd; } public static IvyContext getContext() { Stack cur = getCurrentStack(); if (cur.isEmpty()) { cur.push(new IvyContext()); } return (IvyContext) cur.peek(); } private static Stack/* */getCurrentStack() { Stack cur = (Stack) current.get(); if (cur == null) { cur = new Stack(); current.set(cur); } return cur; } /** * Creates a new IvyContext and pushes it as the current context in the current thread. *

* {@link #popContext()} should usually be called when the job for which this context has been * pushed is finished. *

* * @return the newly pushed context */ public static IvyContext pushNewContext() { return pushContext(new IvyContext()); } /** * Creates a new IvyContext as a copy of the current one and pushes it as the current context in * the current thread. *

* {@link #popContext()} should usually be called when the job for which this context has been * pushed is finished. *

* * @return the newly pushed context */ public static IvyContext pushNewCopyContext() { return pushContext(new IvyContext(getContext())); } /** * Changes the context associated with this thread. This is especially useful when launching a * new thread, to associate it with the same context as the initial one. Do not forget to call * {@link #popContext()} when done. * * @param context * the new context to use in this thread. * @return the pushed context */ public static IvyContext pushContext(IvyContext context) { getCurrentStack().push(context); return context; } /** * Pops one context used with this thread. This is usually called after having finished a task * for which a call to {@link #pushNewContext()} or {@link #pushContext(IvyContext)} was done * prior to beginning the task. * * @return the popped context */ public static IvyContext popContext() { return (IvyContext) getCurrentStack().pop(); } /** * Reads the first object from the list saved under given key in the first context from the * context stack in which this key is defined. If value under key in any of the contexts form * the stack represents non List object then a RuntimeException is thrown. *

* This methods does a similar job to {@link #peek(String)}, except that it considers the whole * context stack and not only one instance. *

* * @param key * context key for the string * @return top object from the list (index 0) of the first context in the stack containing this * key or null if no key or list empty in all contexts from the context stack * @see #peek(String) */ public static Object peekInContextStack(String key) { Object value = null; Stack contextStack = getCurrentStack(); for (int i = contextStack.size() - 1; i >= 0 && value == null; i--) { IvyContext ctx = (IvyContext) contextStack.get(i); value = ctx.peek(key); } return value; } /** * Returns the current ivy instance. *

* When calling any public ivy method on an ivy instance, a reference to this instance is put in * this context, and thus accessible using this method, until no code reference this instance * and the garbage collector collects it. *

*

* Then, or if no ivy method has been called, a default ivy instance is returned by this method, * so that it never returns null. *

* * @return the current ivy instance */ public Ivy getIvy() { Ivy ivy = peekIvy(); return ivy == null ? getDefaultIvy() : ivy; } /** * Returns the Ivy instance associated with this context, or null if no such * instance is currently associated with this context. *

* If you want get a default Ivy instance in case no instance if currently associated, use * {@link #getIvy()}. *

* * @return the current ivy instance, or null if there is no current ivy instance. */ public Ivy peekIvy() { Ivy ivy = (Ivy) this.ivy.get(); return ivy; } private Ivy getDefaultIvy() { if (defaultIvy == null) { defaultIvy = Ivy.newInstance(); try { defaultIvy.configureDefault(); } catch (Exception e) { Message.debug(e); // ??? } } return defaultIvy; } public void setIvy(Ivy ivy) { this.ivy = new WeakReference(ivy); operatingThread = Thread.currentThread(); } public IvySettings getSettings() { return getIvy().getSettings(); } public CircularDependencyStrategy getCircularDependencyStrategy() { return getSettings().getCircularDependencyStrategy(); } public Object get(String key) { WeakReference ref = (WeakReference) contextMap.get(key); return ref == null ? null : ref.get(); } public void set(String key, Object value) { contextMap.put(key, new WeakReference(value)); } /** * Reads the first object from the list saved under given key in the context. If value under key * represents non List object then a RuntimeException is thrown. * * @param key * context key for the string * @return top object from the list (index 0) or null if no key or list empty */ public Object peek(String key) { synchronized (contextMap) { Object o = contextMap.get(key); if (o == null) { return null; } if (o instanceof List) { if (((List) o).size() == 0) { return null; } Object ret = ((List) o).get(0); return ret; } else { throw new RuntimeException("Cannot top from non List object " + o); } } } /** * Removes and returns first object from the list saved under given key in the context. If value * under key represents non List object then a RuntimeException is thrown. * * @param key * context key for the string * @return top object from the list (index 0) or null if no key or list empty */ public Object pop(String key) { synchronized (contextMap) { Object o = contextMap.get(key); if (o == null) { return null; } if (o instanceof List) { if (((List) o).size() == 0) { return null; } Object ret = ((List) o).remove(0); return ret; } else { throw new RuntimeException("Cannot pop from non List object " + o); } } } /** * Removes and returns first object from the list saved under given key in the context but only * if it equals the given expectedValue - if not a false value is returned. If value under key * represents non List object then a RuntimeException is thrown. * * @param key * context key for the string * @return true if the r */ public boolean pop(String key, Object expectedValue) { synchronized (contextMap) { Object o = contextMap.get(key); if (o == null) { return false; } if (o instanceof List) { if (((List) o).size() == 0) { return false; } Object top = ((List) o).get(0); if (!top.equals(expectedValue)) { return false; } ((List) o).remove(0); return true; } else { throw new RuntimeException("Cannot pop from non List object " + o); } } } /** * Puts a new object at the start of the list saved under given key in the context. If value * under key represents non List object then a RuntimeException is thrown. If no list exists * under given key a new LinkedList is created. This is kept without WeakReference in opposite * to the put() results. * * @param key * key context key for the string * @param value * value to be saved under the key */ public void push(String key, Object value) { synchronized (contextMap) { if (!contextMap.containsKey(key)) { contextMap.put(key, new LinkedList()); } Object o = contextMap.get(key); if (o instanceof List) { ((List) o).add(0, value); } else { throw new RuntimeException("Cannot push to non List object " + o); } } } public Thread getOperatingThread() { return operatingThread; } public MessageLogger getMessageLogger() { // calling getIvy() instead of peekIvy() is not possible here: it will initialize a default // Ivy instance, with default settings, but settings themselves may log messages and lead to // a call to this method. So we use the current Ivy instance if any, or the default Ivy // instance, or the default MessageLogger. Ivy ivy = peekIvy(); if (ivy == null) { if (defaultIvy == null) { return Message.getDefaultLogger(); } else { return defaultIvy.getLoggerEngine(); } } else { return ivy.getLoggerEngine(); } } public EventManager getEventManager() { return getIvy().getEventManager(); } public void checkInterrupted() { getIvy().checkInterrupted(); } public void setResolveData(ResolveData data) { this.resolveData = data; } public ResolveData getResolveData() { return resolveData; } public void setDependencyDescriptor(DependencyDescriptor dd) { this.dd = dd; } public DependencyDescriptor getDependencyDescriptor() { return dd; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/IvyPatternHelper.java000066400000000000000000000506621226750426600244210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvyVariableContainer; import org.apache.ivy.core.settings.IvyVariableContainerImpl; import org.apache.ivy.util.Message; /** */ public final class IvyPatternHelper { private IvyPatternHelper() { // Helper class } public static final String CONF_KEY = "conf"; public static final String TYPE_KEY = "type"; public static final String EXT_KEY = "ext"; public static final String ARTIFACT_KEY = "artifact"; public static final String BRANCH_KEY = "branch"; public static final String REVISION_KEY = "revision"; public static final String MODULE_KEY = "module"; public static final String ORGANISATION_KEY = "organisation"; public static final String ORGANISATION_KEY2 = "organization"; public static final String ORGANISATION_PATH_KEY = "orgPath"; public static final String ORIGINAL_ARTIFACTNAME_KEY = "originalname"; private static final Pattern PARAM_PATTERN = Pattern.compile("\\@\\{(.*?)\\}"); private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\{(.*?)\\}"); public static String substitute(String pattern, ModuleRevisionId moduleRevision) { return substitute(pattern, moduleRevision.getOrganisation(), moduleRevision.getName(), moduleRevision.getBranch(), moduleRevision.getRevision(), "ivy", "ivy", "xml", null, null, moduleRevision.getQualifiedExtraAttributes(), null); } public static String substitute(String pattern, ModuleRevisionId moduleRevision, String artifact, String type, String ext) { return substitute(pattern, moduleRevision, new DefaultArtifact(moduleRevision, null, artifact, type, ext)); } public static String substitute(String pattern, Artifact artifact) { return substitute(pattern, artifact, (String) null); } public static String substitute(String pattern, Artifact artifact, ArtifactOrigin origin) { return substitute(pattern, artifact.getModuleRevisionId(), artifact, (String) null, origin); } public static String substitute(String pattern, Artifact artifact, String conf) { return substitute(pattern, artifact.getModuleRevisionId(), artifact, conf, (ArtifactOrigin) null); } public static String substitute(String pattern, ModuleRevisionId mrid, Artifact artifact) { return substitute(pattern, mrid, artifact, (String) null, (ArtifactOrigin) null); } public static String substitute(String pattern, ModuleRevisionId mrid, Artifact artifact, String conf, ArtifactOrigin origin) { return substitute(pattern, mrid.getOrganisation(), mrid.getName(), mrid.getBranch(), mrid.getRevision(), artifact.getName(), artifact.getType(), artifact.getExt(), conf, origin, mrid.getQualifiedExtraAttributes(), artifact.getQualifiedExtraAttributes()); } public static String substitute(String pattern, String org, String module, String revision, String artifact, String type, String ext) { return substitute(pattern, org, module, (String) null, revision, artifact, type, ext, (String) null, (ArtifactOrigin) null, (Map) null, (Map) null); } // CheckStyle:ParameterNumber OFF public static String substitute(String pattern, String org, String module, String revision, String artifact, String type, String ext, String conf) { return substitute(pattern, org, module, (String) null, revision, artifact, type, ext, conf, (ArtifactOrigin) null, (Map) null, (Map) null); } public static String substitute(String pattern, String org, String module, String revision, String artifact, String type, String ext, String conf, Map extraModuleAttributes, Map extraArtifactAttributes) { return substitute(pattern, org, module, (String) null, revision, artifact, type, ext, conf, (ArtifactOrigin) null, extraModuleAttributes, extraArtifactAttributes); } public static String substitute(String pattern, String org, String module, String branch, String revision, String artifact, String type, String ext, String conf, ArtifactOrigin origin, Map extraModuleAttributes, Map extraArtifactAttributes) { Map tokens = new HashMap(); if (extraModuleAttributes != null) { for (Iterator entries = extraModuleAttributes.entrySet().iterator(); entries.hasNext();) { Map.Entry entry = (Map.Entry) entries.next(); String token = (String) entry.getKey(); if (token.indexOf(':') > 0) { token = token.substring(token.indexOf(':') + 1); } tokens.put(token, entry.getValue()); } } if (extraArtifactAttributes != null) { for (Iterator entries = extraArtifactAttributes.entrySet().iterator(); entries .hasNext();) { Map.Entry entry = (Map.Entry) entries.next(); String token = (String) entry.getKey(); if (token.indexOf(':') > 0) { token = token.substring(token.indexOf(':') + 1); } tokens.put(token, entry.getValue()); } } tokens.put(ORGANISATION_KEY, org == null ? "" : org); tokens.put(ORGANISATION_KEY2, org == null ? "" : org); tokens.put(ORGANISATION_PATH_KEY, org == null ? "" : org.replace('.', '/')); tokens.put(MODULE_KEY, module == null ? "" : module); tokens.put(BRANCH_KEY, branch == null ? "" : branch); tokens.put(REVISION_KEY, revision == null ? "" : revision); tokens.put(ARTIFACT_KEY, artifact == null ? module : artifact); tokens.put(TYPE_KEY, type == null ? "jar" : type); tokens.put(EXT_KEY, ext == null ? "jar" : ext); tokens.put(CONF_KEY, conf == null ? "default" : conf); if (origin == null) { tokens.put(ORIGINAL_ARTIFACTNAME_KEY, new OriginalArtifactNameValue(org, module, branch, revision, artifact, type, ext, extraModuleAttributes, extraArtifactAttributes)); } else { tokens.put(ORIGINAL_ARTIFACTNAME_KEY, new OriginalArtifactNameValue(origin)); } return substituteTokens(pattern, tokens); } // CheckStyle:ParameterNumber ON public static String substituteVariables(String pattern, Map variables) { return substituteVariables(pattern, new IvyVariableContainerImpl(variables), new Stack()); } public static String substituteVariables(String pattern, IvyVariableContainer variables) { return substituteVariables(pattern, variables, new Stack()); } private static String substituteVariables(String pattern, IvyVariableContainer variables, Stack substituting) { // if you supply null, null is what you get if (pattern == null) { return null; } Matcher m = VAR_PATTERN.matcher(pattern); boolean useVariables = false; StringBuffer sb = null; while (m.find()) { if (!useVariables) { useVariables = true; sb = new StringBuffer(); } String var = m.group(1); String val = variables.getVariable(var); if (val != null) { int index = substituting.indexOf(var); if (index != -1) { List cycle = new ArrayList(substituting.subList(index, substituting.size())); cycle.add(var); throw new IllegalArgumentException("cyclic variable definition: cycle = " + cycle); } substituting.push(var); val = substituteVariables(val, variables, substituting); substituting.pop(); } else { val = m.group(); } m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "\\\\\\$")); } if (useVariables) { m.appendTail(sb); return sb.toString(); } else { return pattern; } } public static String substituteTokens(String pattern, Map tokens) { Map tokensCopy = new HashMap(tokens); if (tokensCopy.containsKey(ORGANISATION_KEY) && !tokensCopy.containsKey(ORGANISATION_KEY2)) { tokensCopy.put(ORGANISATION_KEY2, tokensCopy.get(ORGANISATION_KEY)); } if (tokensCopy.containsKey(ORGANISATION_KEY) && !tokensCopy.containsKey(ORGANISATION_PATH_KEY)) { String org = (String) tokensCopy.get(ORGANISATION_KEY); tokensCopy.put(ORGANISATION_PATH_KEY, org == null ? "" : org.replace('.', '/')); } StringBuffer buffer = new StringBuffer(); char[] chars = pattern.toCharArray(); StringBuffer optionalPart = null; StringBuffer tokenBuffer = null; boolean insideOptionalPart = false; boolean insideToken = false; boolean tokenSeen = false; boolean tokenHadValue = false; for (int i = 0; i < chars.length; i++) { switch (chars[i]) { case '(': if (insideOptionalPart) { throw new IllegalArgumentException( "invalid start of optional part at position " + i + " in pattern " + pattern); } optionalPart = new StringBuffer(); insideOptionalPart = true; tokenSeen = false; tokenHadValue = false; break; case ')': if (!insideOptionalPart || insideToken) { throw new IllegalArgumentException( "invalid end of optional part at position " + i + " in pattern " + pattern); } if (tokenHadValue) { buffer.append(optionalPart.toString()); } else if (!tokenSeen) { buffer.append('(').append(optionalPart.toString()).append(')'); } insideOptionalPart = false; break; case '[': if (insideToken) { throw new IllegalArgumentException("invalid start of token at position " + i + " in pattern " + pattern); } tokenBuffer = new StringBuffer(); insideToken = true; break; case ']': if (!insideToken) { throw new IllegalArgumentException("invalid end of token at position " + i + " in pattern " + pattern); } String token = tokenBuffer.toString(); Object tokenValue = tokensCopy.get(token); String value = (tokenValue == null) ? null : tokenValue.toString(); if (insideOptionalPart) { tokenHadValue = (value != null) && (value.length() > 0); optionalPart.append(value); } else { if (value == null) { // the token wasn't set, it's kept as is value = "[" + token + "]"; } buffer.append(value); } insideToken = false; tokenSeen = true; break; default: if (insideToken) { tokenBuffer.append(chars[i]); } else if (insideOptionalPart) { optionalPart.append(chars[i]); } else { buffer.append(chars[i]); } break; } } if (insideToken) { throw new IllegalArgumentException("last token hasn't been closed in pattern " + pattern); } if (insideOptionalPart) { throw new IllegalArgumentException("optional part hasn't been closed in pattern " + pattern); } return buffer.toString(); } public static String substituteVariable(String pattern, String variable, String value) { StringBuffer buf = new StringBuffer(pattern); substituteVariable(buf, variable, value); return buf.toString(); } public static void substituteVariable(StringBuffer buf, String variable, String value) { String from = "${" + variable + "}"; int fromLength = from.length(); for (int index = buf.indexOf(from); index != -1; index = buf.indexOf(from, index)) { buf.replace(index, index + fromLength, value); } } public static String substituteToken(String pattern, String token, String value) { StringBuffer buf = new StringBuffer(pattern); substituteToken(buf, token, value); return buf.toString(); } public static void substituteToken(StringBuffer buf, String token, String value) { String from = getTokenString(token); int fromLength = from.length(); for (int index = buf.indexOf(from); index != -1; index = buf.indexOf(from, index)) { buf.replace(index, index + fromLength, value); } } public static String getTokenString(String token) { return "[" + token + "]"; } public static String substituteParams(String pattern, Map params) { return substituteParams(pattern, new IvyVariableContainerImpl(params), new Stack()); } private static String substituteParams(String pattern, IvyVariableContainer params, Stack substituting) { // TODO : refactor this with substituteVariables // if you supply null, null is what you get if (pattern == null) { return null; } Matcher m = PARAM_PATTERN.matcher(pattern); StringBuffer sb = new StringBuffer(); while (m.find()) { String var = m.group(1); String val = params.getVariable(var); if (val != null) { int index = substituting.indexOf(var); if (index != -1) { List cycle = new ArrayList(substituting.subList(index, substituting.size())); cycle.add(var); throw new IllegalArgumentException("cyclic param definition: cycle = " + cycle); } substituting.push(var); val = substituteVariables(val, params, substituting); substituting.pop(); } else { val = m.group(); } m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\@", "\\\\\\@")); } m.appendTail(sb); return sb.toString(); } /** * This class returns the original name of the artifact 'on demand'. This is done to avoid * having to read the cached datafile containing the original location of the artifact if we * don't need it. */ private static class OriginalArtifactNameValue { // module properties private String org; private String moduleName; private String branch; private String revision; private Map extraModuleAttributes; // artifact properties private String artifactName; private String artifactType; private String artifactExt; private Map extraArtifactAttributes; // cached origin; private ArtifactOrigin origin; public OriginalArtifactNameValue(String org, String moduleName, String branch, String revision, String artifactName, String artifactType, String artifactExt, Map extraModuleAttributes, Map extraArtifactAttributes) { this.org = org; this.moduleName = moduleName; this.branch = branch; this.revision = revision; this.artifactName = artifactName; this.artifactType = artifactType; this.artifactExt = artifactExt; this.extraModuleAttributes = extraModuleAttributes; this.extraArtifactAttributes = extraArtifactAttributes; } /** * @param origin */ public OriginalArtifactNameValue(ArtifactOrigin origin) { this.origin = origin; } // Called by substituteTokens only if the original artifact name is needed public String toString() { if (origin == null) { ModuleRevisionId revId = ModuleRevisionId.newInstance(org, moduleName, branch, revision, extraModuleAttributes); Artifact artifact = new DefaultArtifact(revId, null, artifactName, artifactType, artifactExt, extraArtifactAttributes); // TODO cache: see how we could know which actual cache manager to use, since this // will fail when using a resolver in a chain with a specific cache manager RepositoryCacheManager cacheManager = IvyContext.getContext().getSettings() .getResolver(revId).getRepositoryCacheManager(); origin = cacheManager.getSavedArtifactOrigin(artifact); if (ArtifactOrigin.isUnknown(origin)) { Message.debug("no artifact origin found for " + artifact + " in " + cacheManager); return null; } } if (ArtifactOrigin.isUnknown(origin)) { return null; } // we assume that the original filename is the last part of the original file location String location = origin.getLocation(); int lastPathIndex = location.lastIndexOf('/'); if (lastPathIndex == -1) { lastPathIndex = location.lastIndexOf('\\'); } int lastColonIndex = location.lastIndexOf('.'); return location.substring(lastPathIndex + 1, lastColonIndex); } } public static String getTokenRoot(String pattern) { int index = pattern.indexOf('['); if (index == -1) { return pattern; } else { // it could be that pattern is something like "lib/([optional]/)[module]" // we don't want the '(' in the result int optionalIndex = pattern.indexOf('('); if (optionalIndex >= 0) { index = Math.min(index, optionalIndex); } return pattern.substring(0, index); } } public static String getFirstToken(String pattern) { if (pattern == null) { return null; } int startIndex = pattern.indexOf('['); if (startIndex == -1) { return null; } int endIndex = pattern.indexOf(']', startIndex); if (endIndex == -1) { return null; } return pattern.substring(startIndex + 1, endIndex); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/IvyThread.java000066400000000000000000000040441226750426600230440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; /** * A simple thread subclass associated the same IvyContext as the thread in which it is * instanciated. If you override the run target, then you will have to call initContext() to do the * association with the original IvyContext. * * @see IvyContext */ public class IvyThread extends Thread { private IvyContext context = IvyContext.getContext(); public IvyThread() { super(); } public IvyThread(Runnable target, String name) { super(target, name); } public IvyThread(Runnable target) { super(target); } public IvyThread(String name) { super(name); } public IvyThread(ThreadGroup group, Runnable target, String name, long stackSize) { super(group, target, name, stackSize); } public IvyThread(ThreadGroup group, Runnable target, String name) { super(group, target, name); } public IvyThread(ThreadGroup group, Runnable target) { super(group, target); } public IvyThread(ThreadGroup group, String name) { super(group, name); } public void run() { initContext(); super.run(); } protected void initContext() { IvyContext.pushContext(context); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/LogOptions.java000066400000000000000000000033461226750426600232460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; public class LogOptions { /** * Defaults log settings. Output all usual messages during the resolve process. */ public static final String LOG_DEFAULT = "default"; /** * This log setting disable all usual messages but download ones. */ public static final String LOG_DOWNLOAD_ONLY = "download-only"; /** * This log setting disable all usual messages during the resolve process. */ public static final String LOG_QUIET = "quiet"; /** * The log settings to use. One of {@link #LOG_DEFAULT}, {@link #LOG_DOWNLOAD_ONLY}, * {@link #LOG_QUIET} */ private String log = LOG_DEFAULT; public LogOptions() { } public LogOptions(LogOptions options) { log = options.log; } public String getLog() { return log; } public LogOptions setLog(String log) { this.log = log; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/NormalRelativeUrlResolver.java000066400000000000000000000022101226750426600262670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; import java.net.MalformedURLException; import java.net.URL; /** * Normal implementation of RelativeUrlResolver. */ public class NormalRelativeUrlResolver extends RelativeUrlResolver { public URL getURL(URL context, String url) throws MalformedURLException { return new URL(context, url); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/RelativeUrlResolver.java000066400000000000000000000044621226750426600251310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core; import java.io.File; import java.net.MalformedURLException; import java.net.URL; /** * Resolve an file or url relatively to its context. */ public abstract class RelativeUrlResolver { /** * Resolve the url in the context of context. * * @param context * The URL of the ressource containing the reference url * @param url * a relative or absolution url string * @throws MalformedURLException */ public abstract URL getURL(URL context, String url) throws MalformedURLException; /** * Relsovle file or url path relatively to a context. file is considered first. If file is not * defined, url will be considered. * * @param context * The URL of the ressource containing the reference file or url * @param file * a relative or absolute path * @param url * a relative or absolution url string * @return the resulting url or null if faile and url are null. * @throws MalformedURLException */ public URL getURL(URL context, String file, String url) throws MalformedURLException { if (file != null) { File f = new File(file); if (f.isAbsolute()) { return f.toURI().toURL(); } else { return getURL(context, file); } } else if (url != null) { return getURL(context, url); } else { return null; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/000077500000000000000000000000001226750426600213435ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ArtifactOrigin.java000066400000000000000000000120351226750426600251140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.util.Checks; /** * This class contains information about the origin of an artifact. * * @see org.apache.ivy.plugins.resolver.BasicResolver * @see org.apache.ivy.plugins.resolver.util.ResolvedResource */ public class ArtifactOrigin { private static final String UNKNOWN = "UNKNOWN"; /** * ArtifactOrigin instance used when the origin is unknown. */ public static final ArtifactOrigin unkwnown(Artifact artifact) { return new ArtifactOrigin(artifact, false, UNKNOWN); } public static final boolean isUnknown(ArtifactOrigin artifact) { return artifact == null || UNKNOWN.equals(artifact.getLocation()); } public static final boolean isUnknown(String location) { return location == null || UNKNOWN.equals(location); } private static final int MAGIC_HASH_VALUE = 31; private boolean isLocal; private String location; private Artifact artifact; private Long lastChecked; private boolean exists = true; /** * Create a new instance * * @param artifact * the artifact pointed by this location. Must not be null. * @param isLocal * boolean value indicating if the resource is local (on the * filesystem). * @param location * the location of the resource (normally a url). Must not be null. */ public ArtifactOrigin(Artifact artifact, boolean isLocal, String location) { Checks.checkNotNull(artifact, "artifact"); Checks.checkNotNull(location, "location"); this.artifact = artifact; this.isLocal = isLocal; this.location = location; } /** * Is this resource local to this host, i.e. is it on the file system? * * @return boolean value indicating if the resource is local. */ public boolean isLocal() { return isLocal; } /** * Return the location of the resource (normally a url) * * @return the location of the resource */ public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } /** * Return the artifact that this location is pointing at. * * @return the artifact that this location is pointing at. */ public Artifact getArtifact() { return artifact; } /** * The last time the resource was checked to be up to date. Maybe null if this * information is not actually used by in some case. * * @return */ public Long getLastChecked() { return lastChecked; } public void setLastChecked(Long lastChecked) { this.lastChecked = lastChecked; } public boolean isExists() { return exists; } public void setExist(boolean exists) { this.exists = exists; } public String toString() { return "ArtifactOrigin { isLocal=" + isLocal + ", location=" + location + ", lastChecked=" + lastChecked + ", exists=" + exists + "}"; } public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ArtifactOrigin that = (ArtifactOrigin) o; if (isLocal != that.isLocal) { return false; } if (!location.equals(that.location)) { return false; } if (lastChecked == null) { if (that.lastChecked != null) { return false; } } else if (!lastChecked.equals(that.lastChecked)) { return false; } if (exists != that.exists) { return false; } return true; } public int hashCode() { int result; result = (isLocal ? 1 : 0); result = MAGIC_HASH_VALUE * result + location.hashCode(); result = MAGIC_HASH_VALUE * result + ((lastChecked == null) ? 0 : lastChecked.hashCode()); result = MAGIC_HASH_VALUE * result + (exists ? 1 : 0); return result; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/CacheDownloadOptions.java000066400000000000000000000025171226750426600262620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; public class CacheDownloadOptions { private DownloadListener listener = null; private boolean force = false; public DownloadListener getListener() { return listener; } public CacheDownloadOptions setListener(DownloadListener listener) { this.listener = listener; return this; } public boolean isForce() { return force; } public CacheDownloadOptions setForce(boolean force) { this.force = force; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java000066400000000000000000000047731226750426600262410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import org.apache.ivy.plugins.namespace.Namespace; public class CacheMetadataOptions extends CacheDownloadOptions { private boolean validate = false; private Namespace namespace = Namespace.SYSTEM_NAMESPACE; private Boolean isCheckmodified = null; private String changingMatcherName = null; private String changingPattern = null; private boolean checkTTL = true; public Namespace getNamespace() { return namespace; } public CacheMetadataOptions setNamespace(Namespace namespace) { this.namespace = namespace; return this; } public boolean isValidate() { return validate; } public CacheMetadataOptions setValidate(boolean validate) { this.validate = validate; return this; } public Boolean isCheckmodified() { return isCheckmodified; } public CacheMetadataOptions setCheckmodified(Boolean isCheckmodified) { this.isCheckmodified = isCheckmodified; return this; } public String getChangingMatcherName() { return changingMatcherName; } public CacheMetadataOptions setChangingMatcherName(String changingMatcherName) { this.changingMatcherName = changingMatcherName; return this; } public String getChangingPattern() { return changingPattern; } public CacheMetadataOptions setChangingPattern(String changingPattern) { this.changingPattern = changingPattern; return this; } public CacheMetadataOptions setCheckTTL(boolean checkTTL) { this.checkTTL = checkTTL; return this; } public boolean isCheckTTL() { return checkTTL; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/CacheResourceOptions.java000066400000000000000000000021331226750426600262740ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; public class CacheResourceOptions extends CacheDownloadOptions { // by default, a ttl of 1 hour private long ttl = 1000 * 60 * 60; public void setTtl(long ttl) { this.ttl = ttl; } public long getTtl() { return ttl; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/CacheUtil.java000066400000000000000000000035431226750426600240540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; /** * Utility class providing some cache related facilities. * */ public final class CacheUtil { /** * Checks that the given pattern is acceptable as a cache pattern * * @param cachePattern * the pattern to check * @throws IllegalArgumentException * if the pattern isn't acceptable as cache pattern */ public static void checkCachePattern(String cachePattern) { if (cachePattern == null) { throw new IllegalArgumentException("null cache pattern not allowed."); } if (cachePattern.startsWith("..")) { throw new IllegalArgumentException("invalid cache pattern: '" + cachePattern + "': cache patterns must not lead outside cache directory"); } if (cachePattern.startsWith("/")) { throw new IllegalArgumentException("invalid cache pattern: '" + cachePattern + "': cache patterns must not be absolute"); } } private CacheUtil() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java000066400000000000000000002050301226750426600301110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.regex.Pattern; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ArtifactRevisionId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.core.pack.PackagingManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; import org.apache.ivy.plugins.lock.LockStrategy; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.matcher.NoMatcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.plugins.repository.ArtifactResourceResolver; import org.apache.ivy.plugins.repository.LocalizableResource; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.ResourceDownloader; import org.apache.ivy.plugins.repository.ResourceHelper; import org.apache.ivy.plugins.resolver.AbstractResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Checks; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.HexEncoder; import org.apache.ivy.util.Message; import org.apache.ivy.util.PropertiesFile; public class DefaultRepositoryCacheManager implements RepositoryCacheManager, IvySettingsAware { private static final String DEFAULT_ARTIFACT_PATTERN = "[organisation]/[module](/[branch])/[type]s/[artifact]-[revision](-[classifier])(.[ext])"; private static final String DEFAULT_DATA_FILE_PATTERN = "[organisation]/[module](/[branch])/ivydata-[revision].properties"; private static final String DEFAULT_IVY_PATTERN = "[organisation]/[module](/[branch])/ivy-[revision].xml"; private static final int DEFAULT_MEMORY_CACHE_SIZE = 150; private static MessageDigest SHA_DIGEST; static { try { SHA_DIGEST = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("The SHA1 algorithm is not available in your classpath", e); } } private IvySettings settings; private File basedir; private LockStrategy lockStrategy; private String name; private String ivyPattern; private String dataFilePattern = DEFAULT_DATA_FILE_PATTERN; private String artifactPattern; private String lockStrategyName; private String changingPattern; private String changingMatcherName = PatternMatcher.EXACT_OR_REGEXP; private Boolean checkmodified; private Boolean useOrigin; private ModuleRules/* */ttlRules = new ModuleRules(); private Long defaultTTL = null; private ModuleDescriptorMemoryCache memoryModuleDescrCache; private PackagingManager packagingManager = new PackagingManager(); public DefaultRepositoryCacheManager() { } public DefaultRepositoryCacheManager(String name, IvySettings settings, File basedir) { setName(name); setSettings(settings); setBasedir(basedir); } public IvySettings getSettings() { return settings; } public void setSettings(IvySettings settings) { this.settings = settings; packagingManager.setSettings(settings); } public File getIvyFileInCache(ModuleRevisionId mrid) { String file = IvyPatternHelper.substitute(getIvyPattern(), DefaultArtifact.newIvyArtifact(mrid, null)); return new File(getRepositoryCacheRoot(), file); } public String getIvyPattern() { if (ivyPattern == null) { if (settings != null) { ivyPattern = settings.getDefaultCacheIvyPattern(); } if (ivyPattern == null) { ivyPattern = DEFAULT_IVY_PATTERN; } } return ivyPattern; } public String getArtifactPattern() { if (artifactPattern == null) { if (settings != null) { artifactPattern = settings.getDefaultCacheArtifactPattern(); } if (artifactPattern == null) { artifactPattern = DEFAULT_ARTIFACT_PATTERN; } } return artifactPattern; } public void setArtifactPattern(String artifactPattern) { CacheUtil.checkCachePattern(artifactPattern); this.artifactPattern = artifactPattern; } public File getBasedir() { if (basedir == null) { basedir = settings.getDefaultRepositoryCacheBasedir(); } return basedir; } public void setBasedir(File cache) { this.basedir = cache; } public long getDefaultTTL() { if (defaultTTL == null) { defaultTTL = new Long(parseDuration(settings.getVariable("ivy.cache.ttl.default"))); } return defaultTTL.longValue(); } public void setDefaultTTL(long defaultTTL) { this.defaultTTL = new Long(defaultTTL); } public void setDefaultTTL(String defaultTTL) { this.defaultTTL = new Long(parseDuration(defaultTTL)); } public String getDataFilePattern() { return dataFilePattern; } public void setDataFilePattern(String dataFilePattern) { CacheUtil.checkCachePattern(dataFilePattern); this.dataFilePattern = dataFilePattern; } public void setIvyPattern(String ivyPattern) { CacheUtil.checkCachePattern(ivyPattern); this.ivyPattern = ivyPattern; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getChangingMatcherName() { return changingMatcherName; } public void setChangingMatcher(String changingMatcherName) { this.changingMatcherName = changingMatcherName; } public String getChangingPattern() { return changingPattern; } public void setChangingPattern(String changingPattern) { this.changingPattern = changingPattern; } public void addTTL(Map attributes, PatternMatcher matcher, long duration) { ttlRules.defineRule(new MapMatcher(attributes, matcher), new Long(duration)); } public void addConfiguredTtl(Map/* */attributes) { String duration = (String) attributes.remove("duration"); if (duration == null) { throw new IllegalArgumentException("'duration' attribute is mandatory for ttl"); } String matcher = (String) attributes.remove("matcher"); addTTL(attributes, matcher == null ? ExactPatternMatcher.INSTANCE : settings.getMatcher(matcher), parseDuration(duration)); } public void setMemorySize(int size) { memoryModuleDescrCache = new ModuleDescriptorMemoryCache(size); } public ModuleDescriptorMemoryCache getMemoryCache() { if (memoryModuleDescrCache == null) { memoryModuleDescrCache = new ModuleDescriptorMemoryCache(DEFAULT_MEMORY_CACHE_SIZE); } return memoryModuleDescrCache; } private static final Pattern DURATION_PATTERN = Pattern .compile("(?:(\\d+)d)? ?(?:(\\d+)h)? ?(?:(\\d+)m)? ?(?:(\\d+)s)? ?(?:(\\d+)ms)?"); private static final int MILLIS_IN_SECONDS = 1000; private static final int MILLIS_IN_MINUTES = 60 * MILLIS_IN_SECONDS; private static final int MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTES; private static final int MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; private long parseDuration(String duration) { if (duration == null) { return 0; } if ("eternal".equals(duration)) { return Long.MAX_VALUE; } java.util.regex.Matcher m = DURATION_PATTERN.matcher(duration); if (m.matches()) { // CheckStyle:MagicNumber| OFF int days = getGroupIntValue(m, 1); int hours = getGroupIntValue(m, 2); int minutes = getGroupIntValue(m, 3); int seconds = getGroupIntValue(m, 4); int millis = getGroupIntValue(m, 5); // CheckStyle:MagicNumber| ON return days * MILLIS_IN_DAY + hours * MILLIS_IN_HOUR + minutes * MILLIS_IN_MINUTES + seconds * MILLIS_IN_SECONDS + millis; } else { throw new IllegalArgumentException("invalid duration '" + duration + "': it must match " + DURATION_PATTERN.pattern() + " or 'eternal'"); } } private int getGroupIntValue(java.util.regex.Matcher m, int groupNumber) { String g = m.group(groupNumber); return g == null || g.length() == 0 ? 0 : Integer.parseInt(g); } /** * True if this cache should check lastmodified date to know if ivy files are up to date. * * @return */ public boolean isCheckmodified() { if (checkmodified == null) { if (getSettings() != null) { String check = getSettings().getVariable("ivy.resolver.default.check.modified"); return check != null ? Boolean.valueOf(check).booleanValue() : false; } else { return false; } } else { return checkmodified.booleanValue(); } } public void setCheckmodified(boolean check) { checkmodified = Boolean.valueOf(check); } /** * True if this cache should use artifacts original location when possible, false if they should * be copied to cache. */ public boolean isUseOrigin() { if (useOrigin == null) { if (getSettings() != null) { return getSettings().isDefaultUseOrigin(); } else { return false; } } else { return useOrigin.booleanValue(); } } public void setUseOrigin(boolean b) { useOrigin = Boolean.valueOf(b); } /** * Returns a File object pointing to where the artifact can be found on the local file system. * This is usually in the cache, but it can be directly in the repository if it is local and if * the resolve has been done with useOrigin = true */ public File getArchiveFileInCache(Artifact artifact) { ArtifactOrigin origin = getSavedArtifactOrigin(artifact); return getArchiveFileInCache(artifact, origin); } /** * Returns a File object pointing to where the artifact can be found on the local file system. * This is usually in the cache, but it can be directly in the repository if it is local and if * the resolve has been done with useOrigin = true */ public File getArchiveFileInCache(Artifact artifact, ArtifactOrigin origin) { File archive = new File(getRepositoryCacheRoot(), getArchivePathInCache(artifact, origin)); if (!archive.exists() && !ArtifactOrigin.isUnknown(origin) && origin.isLocal()) { File original = Checks.checkAbsolute(origin.getLocation(), artifact + " origin location"); if (original.exists()) { return original; } } return archive; } /** * Returns a File object pointing to where the artifact can be found on the local file system, * using or not the original location depending on the availability of origin information * provided as parameter and the setting of useOrigin. If useOrigin is false, this method will * always return the file in the cache. */ private File getArchiveFileInCache(Artifact artifact, ArtifactOrigin origin, boolean useOrigin) { if (useOrigin && !ArtifactOrigin.isUnknown(origin) && origin.isLocal()) { return Checks.checkAbsolute(origin.getLocation(), artifact + " origin location"); } else { return new File(getRepositoryCacheRoot(), getArchivePathInCache(artifact, origin)); } } public String getArchivePathInCache(Artifact artifact) { return IvyPatternHelper.substitute(getArtifactPattern(), artifact); } public String getArchivePathInCache(Artifact artifact, ArtifactOrigin origin) { if (isOriginalMetadataArtifact(artifact)) { return IvyPatternHelper.substitute(getIvyPattern() + ".original", artifact, origin); } else { return IvyPatternHelper.substitute(getArtifactPattern(), artifact, origin); } } /** * Saves the information of which resolver was used to resolve a md, so that this info can be * retrieve later (even after a jvm restart) by getSavedResolverName(ModuleDescriptor md) * * @param md * the module descriptor resolved * @param name * resolver name */ private void saveResolver(ModuleDescriptor md, String name) { // should always be called with a lock on module metadata artifact PropertiesFile cdf = getCachedDataFile(md); cdf.setProperty("resolver", name); cdf.save(); } /** * Saves the information of which resolver was used to resolve a md, so that this info can be * retrieve later (even after a jvm restart) by getSavedArtResolverName(ModuleDescriptor md) * * @param md * the module descriptor resolved * @param name * artifact resolver name */ public void saveResolvers(ModuleDescriptor md, String metadataResolverName, String artifactResolverName) { ModuleRevisionId mrid = md.getResolvedModuleRevisionId(); if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return; } try { PropertiesFile cdf = getCachedDataFile(md); cdf.setProperty("resolver", metadataResolverName); cdf.setProperty("artifact.resolver", artifactResolverName); cdf.save(); } finally { unlockMetadataArtifact(mrid); } } private String getSavedResolverName(ModuleDescriptor md) { // should always be called with a lock on module metadata artifact PropertiesFile cdf = getCachedDataFile(md); return cdf.getProperty("resolver"); } private String getSavedArtResolverName(ModuleDescriptor md) { // should always be called with a lock on module metadata artifact PropertiesFile cdf = getCachedDataFile(md); return cdf.getProperty("artifact.resolver"); } void saveArtifactOrigin(Artifact artifact, ArtifactOrigin origin) { // should always be called with a lock on module metadata artifact PropertiesFile cdf = getCachedDataFile(artifact.getModuleRevisionId()); cdf.setProperty(getIsLocalKey(artifact), String.valueOf(origin.isLocal())); cdf.setProperty(getLocationKey(artifact), origin.getLocation()); cdf.setProperty(getOriginalKey(artifact), getPrefixKey(origin.getArtifact())); if (origin.getLastChecked() != null) { cdf.setProperty(getLastCheckedKey(artifact), origin.getLastChecked().toString()); } cdf.setProperty(getExistsKey(artifact), Boolean.toString(origin.isExists())); cdf.save(); } private void removeSavedArtifactOrigin(Artifact artifact) { // should always be called with a lock on module metadata artifact PropertiesFile cdf = getCachedDataFile(artifact.getModuleRevisionId()); cdf.remove(getLocationKey(artifact)); cdf.remove(getIsLocalKey(artifact)); cdf.remove(getLastCheckedKey(artifact)); cdf.remove(getOriginalKey(artifact)); cdf.save(); } private static final Pattern ARTIFACT_KEY_PATTERN = Pattern .compile(".*:(.*)#(.*)#(.*)#(.*)(\\.location)?"); public ArtifactOrigin getSavedArtifactOrigin(Artifact artifact) { ModuleRevisionId mrid = artifact.getModuleRevisionId(); if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return ArtifactOrigin.unkwnown(artifact); } try { PropertiesFile cdf = getCachedDataFile(artifact.getModuleRevisionId()); String location = cdf.getProperty(getLocationKey(artifact)); String local = cdf.getProperty(getIsLocalKey(artifact)); String lastChecked = cdf.getProperty(getLastCheckedKey(artifact)); String exists = cdf.getProperty(getExistsKey(artifact)); String original = cdf.getProperty(getOriginalKey(artifact)); boolean isLocal = Boolean.valueOf(local).booleanValue(); if (location == null) { // origin has not been specified, return null return ArtifactOrigin.unkwnown(artifact); } if (original != null) { // original artifact key artifact:[name]#[type]#[ext]#[hashcode] java.util.regex.Matcher m = ARTIFACT_KEY_PATTERN.matcher(original); if (m.matches()) { String origName = m.group(1); String origType = m.group(2); String origExt = m.group(3); ArtifactRevisionId originArtifactId = ArtifactRevisionId.newInstance( artifact.getModuleRevisionId(), origName, origType, origExt); // second check: verify the hashcode of the cached artifact if (m.group(4).equals("" + originArtifactId.hashCode())) { try { artifact = new DefaultArtifact(originArtifactId, artifact.getPublicationDate(), new URL(location), true); } catch (MalformedURLException e) { Message.debug(e); } } } } else { // Fallback if cached with old version: // if the origin artifact has another extension (e.g. .pom) then make a synthetic // origin artifact for it if (!location.endsWith("." + artifact.getExt())) { // try to find other cached artifact info with same location. This must be the // origin. We must parse the key as we do not know for sure what the original // artifact is named. Iterator it = cdf.entrySet().iterator(); String ownLocationKey = getLocationKey(artifact); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); if (entry.getValue().equals(location) && !ownLocationKey.equals(entry.getKey())) { // found a match, key is // artifact:[name]#[type]#[ext]#[hashcode].location java.util.regex.Matcher m = ARTIFACT_KEY_PATTERN.matcher((String) entry .getKey()); if (m.matches()) { String origName = m.group(1); String origType = m.group(2); String origExt = m.group(3); // first check: the type should end in .original if (!origType.endsWith(".original")) { continue; } ArtifactRevisionId originArtifactId = ArtifactRevisionId .newInstance(artifact.getModuleRevisionId(), origName, origType, origExt); // second check: verify the hashcode of the cached artifact if (m.group(4).equals("" + originArtifactId.hashCode())) { try { artifact = new DefaultArtifact(originArtifactId, artifact.getPublicationDate(), new URL(location), true); } catch (MalformedURLException e) { Message.debug(e); } } break; } } } } } ArtifactOrigin origin = new ArtifactOrigin(artifact, isLocal, location); if (lastChecked != null) { origin.setLastChecked(Long.valueOf(lastChecked)); } if (exists != null) { origin.setExist(Boolean.valueOf(exists).booleanValue()); } return origin; } finally { unlockMetadataArtifact(mrid); } } /** * Creates the unique prefix key that will reference the artifact within the properties. * * @param artifact * the artifact to create the unique key from. Cannot be null. * @return the unique prefix key as a string. */ private String getPrefixKey(Artifact artifact) { // use the hashcode as a uuid for the artifact (fingers crossed) int hashCode = artifact.getId().hashCode(); // use just some visual cue return "artifact:" + artifact.getName() + "#" + artifact.getType() + "#" + artifact.getExt() + "#" + hashCode; } /** * Returns the key used to identify the location of the artifact. * * @param artifact * the artifact to generate the key from. Cannot be null. * @return the key to be used to reference the artifact location. */ private String getLocationKey(Artifact artifact) { String prefix = getPrefixKey(artifact); return prefix + ".location"; } /** * Returns the key used to identify if the artifact is local. * * @param artifact * the artifact to generate the key from. Cannot be null. * @return the key to be used to reference the artifact locality. */ private String getIsLocalKey(Artifact artifact) { String prefix = getPrefixKey(artifact); return prefix + ".is-local"; } /** * Returns the key used to identify the last time the artifact was checked to be up to date. * * @param artifact * the artifact to generate the key from. Cannot be null. * @return the key to be used to reference the artifact's last check date. */ private String getLastCheckedKey(Artifact artifact) { String prefix = getPrefixKey(artifact); return prefix + ".lastchecked"; } /** * Returns the key used to identify the existence of the remote artifact. * * @param artifact * the artifact to generate the key from. Cannot be null. * @return the key to be used to reference the existence of the artifact. */ private String getExistsKey(Artifact artifact) { String prefix = getPrefixKey(artifact); return prefix + ".exists"; } /** * Returns the key used to identify the original artifact. * * @param artifact * the artifact to generate the key from. Cannot be null. * @return the key to be used to reference the original artifact. */ private String getOriginalKey(Artifact artifact) { String prefix = getPrefixKey(artifact); return prefix + ".original"; } private PropertiesFile getCachedDataFile(ModuleDescriptor md) { return getCachedDataFile(md.getResolvedModuleRevisionId()); } private PropertiesFile getCachedDataFile(ModuleRevisionId mRevId) { return new PropertiesFile(new File(getRepositoryCacheRoot(), IvyPatternHelper.substitute( getDataFilePattern(), mRevId)), "ivy cached data file for " + mRevId); } public ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd, ModuleRevisionId requestedRevisionId, CacheMetadataOptions options, String expectedResolver) { ModuleRevisionId mrid = requestedRevisionId; if (isCheckmodified(dd, requestedRevisionId, options)) { Message.verbose("don't use cache for " + mrid + ": checkModified=true"); return null; } if (isChanging(dd, requestedRevisionId, options)) { Message.verbose("don't use cache for " + mrid + ": changing=true"); return null; } return doFindModuleInCache(mrid, options, expectedResolver); } private ResolvedModuleRevision doFindModuleInCache(ModuleRevisionId mrid, CacheMetadataOptions options, String expectedResolver) { if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return null; } boolean unlock = true; try { if (settings.getVersionMatcher().isDynamic(mrid)) { String resolvedRevision = getResolvedRevision(mrid, options); if (resolvedRevision != null) { Message.verbose("found resolved revision in cache: " + mrid + " => " + resolvedRevision); // we have found another module in the cache, make sure we unlock // the original module unlockMetadataArtifact(mrid); mrid = ModuleRevisionId.newInstance(mrid, resolvedRevision); // don't forget to request a lock on the new module! if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); // we couldn't lock the new module, so no need to unlock it unlock = false; return null; } } else { return null; } } File ivyFile = getIvyFileInCache(mrid); if (ivyFile.exists()) { // found in cache ! try { ModuleDescriptorParser parser = getModuleDescriptorParser(); ModuleDescriptor depMD = getMdFromCache(parser, options, ivyFile); String resolverName = getSavedResolverName(depMD); String artResolverName = getSavedArtResolverName(depMD); DependencyResolver resolver = settings.getResolver(resolverName); if (resolver == null) { Message.debug("\tresolver not found: " + resolverName + " => trying to use the one configured for " + mrid); resolver = settings.getResolver(depMD.getResolvedModuleRevisionId()); if (resolver != null) { Message.debug("\tconfigured resolver found for " + depMD.getResolvedModuleRevisionId() + ": " + resolver.getName() + ": saving this data"); saveResolver(depMD, resolver.getName()); } } DependencyResolver artResolver = settings.getResolver(artResolverName); if (artResolver == null) { artResolver = resolver; } if (resolver != null) { Message.debug("\tfound ivy file in cache for " + mrid + " (resolved by " + resolver.getName() + "): " + ivyFile); if (expectedResolver == null || expectedResolver.equals(resolver.getName())) { MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport( depMD.getMetadataArtifact()); madr.setDownloadStatus(DownloadStatus.NO); madr.setSearched(false); madr.setLocalFile(ivyFile); madr.setSize(ivyFile.length()); madr.setArtifactOrigin(getSavedArtifactOrigin(depMD .getMetadataArtifact())); if (madr.getArtifactOrigin().isExists()) { if (madr.getArtifactOrigin().isLocal() && madr.getArtifactOrigin().getArtifact().getUrl() != null) { madr.setOriginalLocalFile(new File(madr.getArtifactOrigin() .getArtifact().getUrl().toURI())); } else { // find locally cached file madr.setOriginalLocalFile(getArchiveFileInCache(madr .getArtifactOrigin().getArtifact())); } } return new ResolvedModuleRevision(resolver, artResolver, depMD, madr); } else { Message.debug("found module in cache but with a different resolver: " + "discarding: " + mrid + "; expected resolver=" + expectedResolver + "; resolver=" + resolver.getName()); } } else { Message.debug("\tresolver not found: " + resolverName + " => cannot use cached ivy file for " + mrid); } } catch (Exception e) { // will try with resolver Message.debug("\tproblem while parsing cached ivy file for: " + mrid, e); } } else { Message.debug("\tno ivy file in cache for " + mrid + ": tried " + ivyFile); } } finally { if (unlock) { unlockMetadataArtifact(mrid); } } return null; } protected ModuleDescriptorParser getModuleDescriptorParser() { return XmlModuleDescriptorParser.getInstance(); } private class MyModuleDescriptorProvider implements ModuleDescriptorProvider { private final ModuleDescriptorParser mdParser; private final ParserSettings settings; public MyModuleDescriptorProvider(ModuleDescriptorParser mdParser, ParserSettings settings) { this.mdParser = mdParser; this.settings = settings; } public ModuleDescriptor provideModule(ParserSettings ivySettings, File descriptorURL, boolean validate) throws ParseException, IOException { return mdParser.parseDescriptor(settings, descriptorURL.toURI().toURL(), validate); } } private ModuleDescriptor getMdFromCache(ModuleDescriptorParser mdParser, CacheMetadataOptions options, File ivyFile) throws ParseException, IOException { ModuleDescriptorMemoryCache cache = getMemoryCache(); ModuleDescriptorProvider mdProvider = new MyModuleDescriptorProvider(mdParser, settings); return cache.get(ivyFile, settings, options.isValidate(), mdProvider); } private ModuleDescriptor getStaledMd(ModuleDescriptorParser mdParser, CacheMetadataOptions options, File ivyFile, ParserSettings parserSettings) throws ParseException, IOException { ModuleDescriptorMemoryCache cache = getMemoryCache(); ModuleDescriptorProvider mdProvider = new MyModuleDescriptorProvider(mdParser, parserSettings); return cache.getStale(ivyFile, settings, options.isValidate(), mdProvider); } private String getResolvedRevision(ModuleRevisionId mrid, CacheMetadataOptions options) { if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return null; } try { String resolvedRevision = null; if (options.isForce()) { Message.verbose("refresh mode: no check for cached resolved revision for " + mrid); return null; } PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid); resolvedRevision = cachedResolvedRevision.getProperty("resolved.revision"); if (resolvedRevision == null) { Message.verbose(getName() + ": no cached resolved revision for " + mrid); return null; } String resolvedTime = cachedResolvedRevision.getProperty("resolved.time"); if (resolvedTime == null) { Message.verbose(getName() + ": inconsistent or old cache: no cached resolved time for " + mrid); saveResolvedRevision(mrid, resolvedRevision); return resolvedRevision; } if (options.isCheckTTL()) { long expiration = Long.parseLong(resolvedTime) + getTTL(mrid); if (expiration > 0 // negative expiration means that Long.MAX_VALUE has been // exceeded && System.currentTimeMillis() > expiration) { Message.verbose(getName() + ": cached resolved revision expired for " + mrid); return null; } } return resolvedRevision; } finally { unlockMetadataArtifact(mrid); } } public void saveResolvedRevision(ModuleRevisionId mrid, String revision) { if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return; } try { PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid); cachedResolvedRevision.setProperty("resolved.time", String.valueOf(System.currentTimeMillis())); cachedResolvedRevision.setProperty("resolved.revision", revision); cachedResolvedRevision.save(); } finally { unlockMetadataArtifact(mrid); } } public long getTTL(ModuleRevisionId mrid) { Long ttl = (Long) ttlRules.getRule(mrid); return ttl == null ? getDefaultTTL() : ttl.longValue(); } public String toString() { return name; } public File getRepositoryCacheRoot() { return getBasedir(); } public LockStrategy getLockStrategy() { if (lockStrategy == null) { if (lockStrategyName != null) { lockStrategy = settings.getLockStrategy(lockStrategyName); } else { lockStrategy = settings.getDefaultLockStrategy(); } } return lockStrategy; } public void setLockStrategy(LockStrategy lockStrategy) { this.lockStrategy = lockStrategy; } public void setLockStrategy(String lockStrategyName) { this.lockStrategyName = lockStrategyName; } public ArtifactDownloadReport download(Artifact artifact, ArtifactResourceResolver resourceResolver, ResourceDownloader resourceDownloader, CacheDownloadOptions options) { final ArtifactDownloadReport adr = new ArtifactDownloadReport(artifact); boolean useOrigin = isUseOrigin(); // TODO: see if we could lock on the artifact to download only, instead of the module // metadata artifact. We'd need to store artifact origin and is local in artifact specific // file to do so, or lock the metadata artifact only to update artifact origin, which would // mean acquiring nested locks, which can be a dangerous thing ModuleRevisionId mrid = artifact.getModuleRevisionId(); if (!lockMetadataArtifact(mrid)) { adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails("impossible to get lock for " + mrid); return adr; } try { DownloadListener listener = options.getListener(); if (listener != null) { listener.needArtifact(this, artifact); } ArtifactOrigin origin = getSavedArtifactOrigin(artifact); // if we can use origin file, we just ask ivy for the file in cache, and it will // return the original one if possible. If we are not in useOrigin mode, we use the // getArchivePath method which always return a path in the actual cache File archiveFile = getArchiveFileInCache(artifact, origin, useOrigin); if (archiveFile.exists() && !options.isForce()) { adr.setDownloadStatus(DownloadStatus.NO); adr.setSize(archiveFile.length()); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } else { long start = System.currentTimeMillis(); try { ResolvedResource artifactRef = resourceResolver.resolve(artifact); if (artifactRef != null) { Resource artifactRes = artifactRef.getResource(); origin = new ArtifactOrigin(artifact, artifactRes.isLocal(), artifactRes.getName()); if (useOrigin && artifactRes.isLocal()) { if (artifactRes instanceof LocalizableResource) { origin.setLocation(((LocalizableResource) artifactRes).getFile() .getAbsolutePath()); } saveArtifactOrigin(artifact, origin); archiveFile = getArchiveFileInCache(artifact, origin); adr.setDownloadStatus(DownloadStatus.NO); adr.setSize(archiveFile.length()); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } else { // refresh archive file now that we better now its origin archiveFile = getArchiveFileInCache(artifact, origin, useOrigin); if (ResourceHelper.equals(artifactRes, archiveFile)) { throw new IllegalStateException("invalid settings for '" + resourceResolver + "': pointing repository to ivy cache is forbidden !"); } if (listener != null) { listener.startArtifactDownload(this, artifactRef, artifact, origin); } resourceDownloader.download(artifact, artifactRes, archiveFile); adr.setSize(archiveFile.length()); saveArtifactOrigin(artifact, origin); adr.setDownloadTimeMillis(System.currentTimeMillis() - start); adr.setDownloadStatus(DownloadStatus.SUCCESSFUL); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } } else { adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails(ArtifactDownloadReport.MISSING_ARTIFACT); adr.setDownloadTimeMillis(System.currentTimeMillis() - start); } } catch (Exception ex) { Message.debug(ex); adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails(ex.getMessage()); adr.setDownloadTimeMillis(System.currentTimeMillis() - start); } } if (adr.getDownloadStatus() != DownloadStatus.FAILED) { unpackArtifact(artifact, adr, options); } if (listener != null) { listener.endArtifactDownload(this, artifact, adr, archiveFile); } return adr; } finally { unlockMetadataArtifact(mrid); } } private void unpackArtifact(Artifact artifact, ArtifactDownloadReport adr, CacheDownloadOptions options) { Artifact unpacked = packagingManager.getUnpackedArtifact(artifact); if (unpacked == null) { // nothing to unpack return; } File archiveFile = getArchiveFileInCache(unpacked, null, false); if (archiveFile.exists() && !options.isForce()) { adr.setUnpackedLocalFile(archiveFile); } else { Message.info("\tUnpacking " + artifact.getId()); try { packagingManager.unpackArtifact(artifact, adr.getLocalFile(), archiveFile); adr.setUnpackedLocalFile(archiveFile); } catch (Exception e) { Message.debug(e); adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails("The packed artifact " + artifact.getId() + " could not be unpacked (" + e.getMessage() + ")"); } } } public ArtifactDownloadReport downloadRepositoryResource(final Resource resource, String name, String type, String extension, CacheResourceOptions options, Repository repository) { String hash = computeResourceNameHash(resource); ModuleRevisionId mrid = ModuleRevisionId.newInstance("_repository_metadata_", hash, Ivy.getWorkingRevision()); Artifact artifact = new DefaultArtifact(mrid, null, name, type, extension); final ArtifactDownloadReport adr = new ArtifactDownloadReport(artifact); boolean useOrigin = isUseOrigin(); try { DownloadListener listener = options.getListener(); if (listener != null) { listener.needArtifact(this, artifact); } ArtifactOrigin savedOrigin = getSavedArtifactOrigin(artifact); File archiveFile = getArchiveFileInCache(artifact, savedOrigin, useOrigin); ArtifactOrigin origin = new ArtifactOrigin(artifact, resource.isLocal(), resource.getName()); if (!options.isForce() // if the local file has been checked to be up to date enough recently, don't download && checkCacheUptodate(archiveFile, resource, savedOrigin, origin, options.getTtl())) { if (archiveFile.exists()) { saveArtifactOrigin(artifact, origin); adr.setDownloadStatus(DownloadStatus.NO); adr.setSize(archiveFile.length()); adr.setArtifactOrigin(savedOrigin); adr.setLocalFile(archiveFile); } else { // we trust the cache to says that the resource doesn't exist adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails("Remote resource is known to not exist"); } } else { long start = System.currentTimeMillis(); origin.setLastChecked(new Long(start)); try { ResolvedResource artifactRef = new ResolvedResource(resource, Ivy.getWorkingRevision()); if (useOrigin && resource.isLocal()) { saveArtifactOrigin(artifact, origin); archiveFile = getArchiveFileInCache(artifact, origin); adr.setDownloadStatus(DownloadStatus.NO); adr.setSize(archiveFile.length()); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } else { if (listener != null) { listener.startArtifactDownload(this, artifactRef, artifact, origin); } // actual download if (archiveFile.exists()) { archiveFile.delete(); } File part = new File(archiveFile.getAbsolutePath() + ".part"); repository.get(resource.getName(), part); if (!part.renameTo(archiveFile)) { throw new IOException( "impossible to move part file to definitive one: " + part + " -> " + archiveFile); } adr.setSize(archiveFile.length()); saveArtifactOrigin(artifact, origin); adr.setDownloadTimeMillis(System.currentTimeMillis() - start); adr.setDownloadStatus(DownloadStatus.SUCCESSFUL); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } } catch (Exception ex) { Message.debug(ex); origin.setExist(false); saveArtifactOrigin(artifact, origin); adr.setDownloadStatus(DownloadStatus.FAILED); adr.setDownloadDetails(ex.getMessage()); adr.setDownloadTimeMillis(System.currentTimeMillis() - start); } } if (listener != null) { listener.endArtifactDownload(this, artifact, adr, archiveFile); } return adr; } finally { unlockMetadataArtifact(mrid); } } /** * Compute a SHA1 of the resource name, encoded in base64, so we can use it as a file name. * * @param resource * the resource which name will be hashed * @return the hash */ private String computeResourceNameHash(Resource resource) { byte[] shaDigest; try { shaDigest = SHA_DIGEST.digest(resource.getName().getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 not supported", e); } return HexEncoder.encode(shaDigest); } /** * Check that a cached file can be considered up to date and thus not downloaded * * @param archiveFile * the file in the cache * @param resource * the remote resource to check * @param savedOrigin * the saved origin which contains that last checked date * @param origin * the origin in which to store the new last checked date * @param ttl * the time to live to consider the cache up to date * @return true if the cache is considered up to date */ private boolean checkCacheUptodate(File archiveFile, Resource resource, ArtifactOrigin savedOrigin, ArtifactOrigin origin, long ttl) { long time = System.currentTimeMillis(); if (savedOrigin.getLastChecked() != null && (time - savedOrigin.getLastChecked().longValue()) < ttl) { // still in the ttl period, no need to check, trust the cache if (!archiveFile.exists()) { // but if the local archive doesn't exist, trust the cache only if the cached origin // says that the remote resource doesn't exist either return !savedOrigin.isExists(); } return true; } if (!archiveFile.exists()) { // the the file doesn't exist in the cache, obviously not up to date return false; } origin.setLastChecked(new Long(time)); // check if the local resource is up to date regarding the remote one return archiveFile.lastModified() >= resource.getLastModified(); } public void originalToCachedModuleDescriptor(DependencyResolver resolver, ResolvedResource orginalMetadataRef, Artifact requestedMetadataArtifact, ResolvedModuleRevision rmr, ModuleDescriptorWriter writer) { ModuleDescriptor md = rmr.getDescriptor(); Artifact originalMetadataArtifact = getOriginalMetadataArtifact(requestedMetadataArtifact); File mdFileInCache = getIvyFileInCache(md.getResolvedModuleRevisionId()); ModuleRevisionId mrid = requestedMetadataArtifact.getModuleRevisionId(); if (!lockMetadataArtifact(mrid)) { Message.warn("impossible to acquire lock for: " + mrid); return; } try { File originalFileInCache = getArchiveFileInCache(originalMetadataArtifact); writer.write(orginalMetadataRef, md, originalFileInCache, mdFileInCache); getMemoryCache().putInCache(mdFileInCache, new ParserSettingsMonitor(settings), true, md); saveResolvers(md, resolver.getName(), resolver.getName()); if (!md.isDefault()) { rmr.getReport().setOriginalLocalFile(originalFileInCache); } rmr.getReport().setLocalFile(mdFileInCache); } catch (RuntimeException e) { throw e; } catch (Exception e) { String metadataRef; if (orginalMetadataRef == null) { metadataRef = String.valueOf(md.getResolvedModuleRevisionId()); } else { metadataRef = String.valueOf(orginalMetadataRef); } Message.warn("impossible to put metadata file in cache: " + metadataRef, e); } finally { unlockMetadataArtifact(mrid); } } public ResolvedModuleRevision cacheModuleDescriptor(DependencyResolver resolver, final ResolvedResource mdRef, DependencyDescriptor dd, Artifact moduleArtifact, ResourceDownloader downloader, CacheMetadataOptions options) throws ParseException { Date cachedPublicationDate = null; ArtifactDownloadReport report; ModuleRevisionId mrid = moduleArtifact.getModuleRevisionId(); if (!lockMetadataArtifact(mrid)) { Message.error("impossible to acquire lock for " + mrid); return null; } BackupResourceDownloader backupDownloader = new BackupResourceDownloader(downloader); try { if (!moduleArtifact.isMetadata()) { // the descriptor we are trying to cache is a default one, not much to do // just make sure the old artifacts are deleted... if (isChanging(dd, mrid, options)) { long repoLastModified = mdRef.getLastModified(); Artifact transformedArtifact = NameSpaceHelper.transform(moduleArtifact, options.getNamespace().getToSystemTransformer()); ArtifactOrigin origin = getSavedArtifactOrigin(transformedArtifact); File artFile = getArchiveFileInCache(transformedArtifact, origin, false); if (artFile.exists() && repoLastModified > artFile.lastModified()) { // artifacts have changed, they should be downloaded again Message.verbose(mrid + " has changed: deleting old artifacts"); Message.debug("deleting " + artFile); if (!artFile.delete()) { Message.error("Couldn't delete outdated artifact from cache: " + artFile); return null; } removeSavedArtifactOrigin(transformedArtifact); } } return null; } // now let's see if we can find it in cache and if it is up to date ResolvedModuleRevision rmr = doFindModuleInCache(mrid, options, null); if (rmr != null) { if (rmr.getDescriptor().isDefault() && rmr.getResolver() != resolver) { Message.verbose("\t" + getName() + ": found revision in cache: " + mrid + " (resolved by " + rmr.getResolver().getName() + "): but it's a default one, maybe we can find a better one"); } else { if (!isCheckmodified(dd, mrid, options) && !isChanging(dd, mrid, options)) { Message.verbose("\t" + getName() + ": revision in cache: " + mrid); rmr.getReport().setSearched(true); return rmr; } long repLastModified = mdRef.getLastModified(); long cacheLastModified = rmr.getDescriptor().getLastModified(); if (!rmr.getDescriptor().isDefault() && repLastModified <= cacheLastModified) { Message.verbose("\t" + getName() + ": revision in cache (not updated): " + mrid); rmr.getReport().setSearched(true); return rmr; } else { Message.verbose("\t" + getName() + ": revision in cache is not up to date: " + mrid); if (isChanging(dd, mrid, options)) { // ivy file has been updated, we should see if it has a new publication // date to see if a new download is required (in case the dependency is // a changing one) cachedPublicationDate = rmr.getDescriptor() .getResolvedPublicationDate(); } } } } Artifact originalMetadataArtifact = getOriginalMetadataArtifact(moduleArtifact); // now download module descriptor and parse it report = download(originalMetadataArtifact, new ArtifactResourceResolver() { public ResolvedResource resolve(Artifact artifact) { return mdRef; } }, backupDownloader, new CacheDownloadOptions().setListener(options.getListener()) .setForce(true)); Message.verbose("\t" + report); if (report.getDownloadStatus() == DownloadStatus.FAILED) { Message.warn("problem while downloading module descriptor: " + mdRef.getResource() + ": " + report.getDownloadDetails() + " (" + report.getDownloadTimeMillis() + "ms)"); return null; } try { ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance() .getParser(mdRef.getResource()); ParserSettings parserSettings = settings; if (resolver instanceof AbstractResolver) { parserSettings = ((AbstractResolver) resolver).getParserSettings(); } ModuleDescriptor md = getStaledMd(parser, options, report.getLocalFile(), parserSettings); if (md == null) { throw new IllegalStateException( "module descriptor parser returned a null module descriptor, " + "which is not allowed. " + "parser=" + parser + "; parser class=" + parser.getClass().getName() + "; module descriptor resource=" + mdRef.getResource()); } Message.debug("\t" + getName() + ": parsed downloaded md file for " + mrid + "; parsed=" + md.getModuleRevisionId()); // check if we should delete old artifacts boolean deleteOldArtifacts = false; if (cachedPublicationDate != null && !cachedPublicationDate.equals(md.getResolvedPublicationDate())) { // artifacts have changed, they should be downloaded again Message.verbose(mrid + " has changed: deleting old artifacts"); deleteOldArtifacts = true; } if (deleteOldArtifacts) { String[] confs = md.getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { Artifact[] arts = md.getArtifacts(confs[i]); for (int j = 0; j < arts.length; j++) { Artifact transformedArtifact = NameSpaceHelper.transform(arts[j], options.getNamespace().getToSystemTransformer()); ArtifactOrigin origin = getSavedArtifactOrigin(transformedArtifact); File artFile = getArchiveFileInCache(transformedArtifact, origin, false); if (artFile.exists()) { Message.debug("deleting " + artFile); if (!artFile.delete()) { // Old artifacts couldn't get deleted! // Restore the original ivy file so the next time we // resolve the old artifacts are deleted again backupDownloader.restore(); Message.error("Couldn't delete outdated artifact from cache: " + artFile); return null; } } removeSavedArtifactOrigin(transformedArtifact); } } } else if (isChanging(dd, mrid, options)) { Message.verbose(mrid + " is changing, but has not changed: will trust cached artifacts if any"); } MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport( md.getMetadataArtifact()); madr.setSearched(true); madr.setDownloadStatus(report.getDownloadStatus()); madr.setDownloadDetails(report.getDownloadDetails()); madr.setArtifactOrigin(report.getArtifactOrigin()); madr.setDownloadTimeMillis(report.getDownloadTimeMillis()); madr.setOriginalLocalFile(report.getLocalFile()); madr.setSize(report.getSize()); Artifact transformedMetadataArtifact = NameSpaceHelper.transform( md.getMetadataArtifact(), options.getNamespace().getToSystemTransformer()); saveArtifactOrigin(transformedMetadataArtifact, report.getArtifactOrigin()); return new ResolvedModuleRevision(resolver, resolver, md, madr); } catch (IOException ex) { Message.warn("io problem while parsing ivy file: " + mdRef.getResource(), ex); return null; } } finally { unlockMetadataArtifact(mrid); backupDownloader.cleanUp(); } } // lock used to lock all metadata related information access private boolean lockMetadataArtifact(ModuleRevisionId mrid) { Artifact artifact = getDefaultMetadataArtifact(mrid); try { // we need to provide an artifact origin to be sure we do not end up in a stack overflow // if the cache pattern is using original name, and the substitution thus trying to get // the saved artifact origin value which in turns calls this method return getLockStrategy().lockArtifact(artifact, getArchiveFileInCache(artifact, getDefaultMetadataArtifactOrigin(mrid))); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // reset interrupt status throw new RuntimeException("operation interrupted"); } } private void unlockMetadataArtifact(ModuleRevisionId mrid) { Artifact artifact = getDefaultMetadataArtifact(mrid); getLockStrategy().unlockArtifact(artifact, getArchiveFileInCache(artifact, getDefaultMetadataArtifactOrigin(mrid))); } private ArtifactOrigin getDefaultMetadataArtifactOrigin(ModuleRevisionId mrid) { // it's important to say the origin is not local to make sure it won't ever be used for // anything else than original token return new ArtifactOrigin(DefaultArtifact.newIvyArtifact(mrid, null), false, getIvyFileInCache(mrid).getPath()); } private Artifact getDefaultMetadataArtifact(ModuleRevisionId mrid) { return new DefaultArtifact(mrid, new Date(), "metadata", "metadata", "ivy", true); } // not used any more, but maybe useful for finer grain locking when downloading artifacts // private boolean lockArtifact(Artifact artifact) { // try { // return getLockStrategy().lockArtifact(artifact, // getArchiveFileInCache(artifact, null)); // } catch (InterruptedException e) { // Thread.currentThread().interrupt(); // reset interrupt status // throw new RuntimeException("operation interrupted"); // } // } // // private void unlockArtifact(Artifact artifact) { // getLockStrategy().unlockArtifact(artifact, getArchiveFileInCache(artifact, null)); // } public Artifact getOriginalMetadataArtifact(Artifact moduleArtifact) { return DefaultArtifact.cloneWithAnotherType(moduleArtifact, moduleArtifact.getType() + ".original"); } private boolean isOriginalMetadataArtifact(Artifact artifact) { return artifact.isMetadata() && artifact.getType().endsWith(".original"); } private boolean isChanging(DependencyDescriptor dd, ModuleRevisionId requestedRevisionId, CacheMetadataOptions options) { return dd.isChanging() || getChangingMatcher(options).matches(requestedRevisionId.getRevision()); } private Matcher getChangingMatcher(CacheMetadataOptions options) { String changingPattern = options.getChangingPattern() != null ? options .getChangingPattern() : this.changingPattern; if (changingPattern == null) { return NoMatcher.INSTANCE; } String changingMatcherName = options.getChangingMatcherName() != null ? options .getChangingMatcherName() : this.changingMatcherName; PatternMatcher matcher = settings.getMatcher(changingMatcherName); if (matcher == null) { throw new IllegalStateException("unknown matcher '" + changingMatcherName + "'. It is set as changing matcher in " + this); } return matcher.getMatcher(changingPattern); } private boolean isCheckmodified(DependencyDescriptor dd, ModuleRevisionId requestedRevisionId, CacheMetadataOptions options) { if (options.isCheckmodified() != null) { return options.isCheckmodified().booleanValue(); } return isCheckmodified(); } public void clean() { FileUtil.forceDelete(getBasedir()); } public void dumpSettings() { Message.verbose("\t" + getName()); Message.debug("\t\tivyPattern: " + getIvyPattern()); Message.debug("\t\tartifactPattern: " + getArtifactPattern()); Message.debug("\t\tlockingStrategy: " + getLockStrategy().getName()); Message.debug("\t\tchangingPattern: " + getChangingPattern()); Message.debug("\t\tchangingMatcher: " + getChangingMatcherName()); } /** * Resource downloader which makes a copy of the previously existing file before overriding it. *

* The backup file can be restored or cleanuped later */ private final class BackupResourceDownloader implements ResourceDownloader { private ResourceDownloader delegate; private File backup; private String originalPath; private BackupResourceDownloader(ResourceDownloader delegate) { this.delegate = delegate; } public void download(Artifact artifact, Resource resource, File dest) throws IOException { // keep a copy of the original file if (dest.exists()) { originalPath = dest.getAbsolutePath(); backup = new File(dest.getAbsolutePath() + ".backup"); FileUtil.copy(dest, backup, null, true); } delegate.download(artifact, resource, dest); } public void restore() throws IOException { if ((backup != null) && backup.exists()) { File original = new File(originalPath); FileUtil.copy(backup, original, null, true); backup.delete(); } } public void cleanUp() { if ((backup != null) && backup.exists()) { backup.delete(); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/DefaultResolutionCacheManager.java000066400000000000000000000244001226750426600300750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.util.Map; import java.util.Properties; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.RelativeUrlResolver; import org.apache.ivy.core.module.descriptor.ExtendsDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.FileUtil; public class DefaultResolutionCacheManager implements ResolutionCacheManager, IvySettingsAware { private static final String DEFAULT_CACHE_RESOLVED_IVY_PATTERN = "resolved-[organisation]-[module]-[revision].xml"; private static final String DEFAULT_CACHE_RESOLVED_IVY_PROPERTIES_PATTERN = "resolved-[organisation]-[module]-[revision].properties"; private String resolvedIvyPattern = DEFAULT_CACHE_RESOLVED_IVY_PATTERN; private String resolvedIvyPropertiesPattern = DEFAULT_CACHE_RESOLVED_IVY_PROPERTIES_PATTERN; private File basedir; private String name = "resolution-cache"; private IvySettings settings; public DefaultResolutionCacheManager() { } public DefaultResolutionCacheManager(File basedir) { setBasedir(basedir); } public void setSettings(IvySettings settings) { this.settings = settings; } public File getResolutionCacheRoot() { return basedir; } public File getBasedir() { return basedir; } public void setBasedir(File basedir) { this.basedir = basedir; } public String getResolvedIvyPattern() { return resolvedIvyPattern; } public void setResolvedIvyPattern(String cacheResolvedIvyPattern) { this.resolvedIvyPattern = cacheResolvedIvyPattern; } public String getResolvedIvyPropertiesPattern() { return resolvedIvyPropertiesPattern; } public void setResolvedIvyPropertiesPattern(String cacheResolvedIvyPropertiesPattern) { this.resolvedIvyPropertiesPattern = cacheResolvedIvyPropertiesPattern; } public String getName() { return name; } public void setName(String name) { this.name = name; } public File getResolvedIvyFileInCache(ModuleRevisionId mrid) { String file = IvyPatternHelper.substitute(getResolvedIvyPattern(), mrid.getOrganisation(), mrid.getName(), mrid.getRevision(), "ivy", "ivy", "xml"); return new File(getResolutionCacheRoot(), file); } public File getResolvedIvyPropertiesInCache(ModuleRevisionId mrid) { String file = IvyPatternHelper.substitute(getResolvedIvyPropertiesPattern(), mrid.getOrganisation(), mrid.getName(), mrid.getRevision(), "ivy", "ivy", "xml"); return new File(getResolutionCacheRoot(), file); } public File getConfigurationResolveReportInCache(String resolveId, String conf) { return new File(getResolutionCacheRoot(), resolveId + "-" + conf + ".xml"); } public File[] getConfigurationResolveReportsInCache(final String resolveId) { final String prefix = resolveId + "-"; final String suffix = ".xml"; return getResolutionCacheRoot().listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return (name.startsWith(prefix) && name.endsWith(suffix)); } }); } public ModuleDescriptor getResolvedModuleDescriptor(ModuleRevisionId mrid) throws ParseException, IOException { File ivyFile = getResolvedIvyFileInCache(mrid); if (!ivyFile.exists()) { throw new IllegalStateException("Ivy file not found in cache for " + mrid + "!"); } Properties paths = new Properties(); File parentsFile = getResolvedIvyPropertiesInCache(ModuleRevisionId.newInstance(mrid, mrid.getRevision() + "-parents")); if (parentsFile.exists()) { FileInputStream in = new FileInputStream(parentsFile); paths.load(in); in.close(); } ParserSettings pSettings = new CacheParserSettings(settings, paths); URL ivyFileURL = ivyFile.toURI().toURL(); return getModuleDescriptorParser().parseDescriptor(pSettings, ivyFileURL, false); } protected ModuleDescriptorParser getModuleDescriptorParser() { return XmlModuleDescriptorParser.getInstance(); } public void saveResolvedModuleDescriptor(ModuleDescriptor md) throws ParseException, IOException { ModuleRevisionId mrevId = md.getResolvedModuleRevisionId(); File ivyFileInCache = getResolvedIvyFileInCache(mrevId); md.toIvyFile(ivyFileInCache); Properties paths = new Properties(); saveLocalParents(mrevId, md, ivyFileInCache, paths); if (!paths.isEmpty()) { File parentsFile = getResolvedIvyPropertiesInCache(ModuleRevisionId.newInstance(mrevId, mrevId.getRevision() + "-parents")); FileOutputStream out = new FileOutputStream(parentsFile); paths.store(out, null); out.close(); } } private void saveLocalParents(ModuleRevisionId baseMrevId, ModuleDescriptor md, File mdFile, Properties paths) throws ParseException, IOException { ExtendsDescriptor[] parents = md.getInheritedDescriptors(); for (int i = 0; i < parents.length; i++) { if (!parents[i].isLocal()) { // we store only local parents in the cache! continue; } ModuleDescriptor parent = parents[i].getParentMd(); ModuleRevisionId pRevId = ModuleRevisionId.newInstance(baseMrevId, baseMrevId.getRevision() + "-parent." + paths.size()); File parentFile = getResolvedIvyFileInCache(pRevId); parent.toIvyFile(parentFile); paths.setProperty(mdFile.getName() + "|" + parents[i].getLocation(), parentFile.getAbsolutePath()); saveLocalParents(baseMrevId, parent, parentFile, paths); } } public String toString() { return name; } public void clean() { FileUtil.forceDelete(getBasedir()); } private static class CacheParserSettings implements ParserSettings { private ParserSettings delegate; private Map parentPaths; public CacheParserSettings(ParserSettings delegate, Map parentPaths) { this.delegate = delegate; this.parentPaths = parentPaths; } public String substitute(String value) { return delegate.substitute(value); } public Map substitute(Map strings) { return delegate.substitute(strings); } public ResolutionCacheManager getResolutionCacheManager() { return delegate.getResolutionCacheManager(); } public ConflictManager getConflictManager(String name) { return delegate.getConflictManager(name); } public PatternMatcher getMatcher(String matcherName) { return delegate.getMatcher(matcherName); } public Namespace getNamespace(String namespace) { return delegate.getNamespace(namespace); } public StatusManager getStatusManager() { return delegate.getStatusManager(); } public RelativeUrlResolver getRelativeUrlResolver() { return new MapURLResolver(parentPaths, delegate.getRelativeUrlResolver()); } public DependencyResolver getResolver(ModuleRevisionId mRevId) { return delegate.getResolver(mRevId); } public File resolveFile(String filename) { return delegate.resolveFile(filename); } public String getDefaultBranch(ModuleId moduleId) { return delegate.getDefaultBranch(moduleId); } public Namespace getContextNamespace() { return delegate.getContextNamespace(); } } private static class MapURLResolver extends RelativeUrlResolver { private Map paths; private RelativeUrlResolver delegate; private MapURLResolver(Map paths, RelativeUrlResolver delegate) { this.paths = paths; this.delegate = delegate; } public URL getURL(URL context, String url) throws MalformedURLException { String path = context.getPath(); if (path.indexOf('/') >= 0) { String file = path.substring(path.lastIndexOf('/') + 1); if (paths.containsKey(file + "|" + url)) { File result = new File(paths.get(file + "|" + url).toString()); return result.toURI().toURL(); } } return delegate.getURL(context, url); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/DownloadListener.java000066400000000000000000000026641226750426600254730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.plugins.resolver.util.ResolvedResource; public interface DownloadListener { public void needArtifact(RepositoryCacheManager cache, Artifact artifact); public void startArtifactDownload(RepositoryCacheManager cache, ResolvedResource rres, Artifact artifact, ArtifactOrigin origin); public void endArtifactDownload(RepositoryCacheManager cache, Artifact artifact, ArtifactDownloadReport adr, File archiveFile); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java000066400000000000000000000117721226750426600276170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.Iterator; import java.util.LinkedHashMap; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.util.Message; /** * Cache ModuleDescriptors so that when the same module is used twice (in multi-module build for * instance), it is parsed only once. This cache is has a limited size, and keep the most recently * used entries. The entry in the cache are invalidated if there is a change to one variable used in * the module descriptor. */ class ModuleDescriptorMemoryCache { private final int maxSize; private final LinkedHashMap/* */valueMap; /** * Create a cache of the given size * * @param size */ public ModuleDescriptorMemoryCache(int size) { this.maxSize = size; this.valueMap = new LinkedHashMap(size); } public ModuleDescriptor get(File ivyFile, ParserSettings ivySettings, boolean validated, ModuleDescriptorProvider mdProvider) throws ParseException, IOException { ModuleDescriptor descriptor = getFromCache(ivyFile, ivySettings, validated); if (descriptor == null) { descriptor = getStale(ivyFile, ivySettings, validated, mdProvider); } return descriptor; } /** * Get the module descriptor from the mdProvider and store it into the cache. */ public ModuleDescriptor getStale(File ivyFile, ParserSettings ivySettings, boolean validated, ModuleDescriptorProvider mdProvider) throws ParseException, IOException { ParserSettingsMonitor settingsMonitor = new ParserSettingsMonitor(ivySettings); ModuleDescriptor descriptor = mdProvider.provideModule( settingsMonitor.getMonitoredSettings(), ivyFile, validated); putInCache(ivyFile, settingsMonitor, validated, descriptor); return descriptor; } ModuleDescriptor getFromCache(File ivyFile, ParserSettings ivySettings, boolean validated) { if (maxSize <= 0) { // cache is disbaled return null; } CacheEntry entry = (CacheEntry) valueMap.get(ivyFile); if (entry != null) { if (entry.isStale(validated, ivySettings)) { Message.debug("Entry is found in the ModuleDescriptorCache but entry should be " + "reevaluated : " + ivyFile); valueMap.remove(ivyFile); return null; } else { // Move the entry at the end of the list valueMap.remove(ivyFile); valueMap.put(ivyFile, entry); Message.debug("Entry is found in the ModuleDescriptorCache : " + ivyFile); return entry.md; } } else { Message.debug("No entry is found in the ModuleDescriptorCache : " + ivyFile); return null; } } void putInCache(File url, ParserSettingsMonitor ivySettingsMonitor, boolean validated, ModuleDescriptor descriptor) { if (maxSize <= 0) { // cache is disabled return; } if (valueMap.size() >= maxSize) { Message.debug("ModuleDescriptorCache is full, remove one entry"); Iterator it = valueMap.values().iterator(); it.next(); it.remove(); } valueMap.put(url, new CacheEntry(descriptor, validated, ivySettingsMonitor)); } private static class CacheEntry { private final ModuleDescriptor md; private final boolean validated; private final ParserSettingsMonitor parserSettingsMonitor; CacheEntry(ModuleDescriptor md, boolean validated, ParserSettingsMonitor parserSettingsMonitor) { this.md = md; this.validated = validated; this.parserSettingsMonitor = parserSettingsMonitor; } boolean isStale(boolean validated, ParserSettings newParserSettings) { return (validated && !this.validated) || parserSettingsMonitor.hasChanged(newParserSettings); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java000066400000000000000000000023421226750426600272060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.IOException; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.parser.ParserSettings; interface ModuleDescriptorProvider { public ModuleDescriptor provideModule(ParserSettings ivySettings, File descriptorFile, boolean validate) throws ParseException, IOException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ModuleDescriptorWriter.java000066400000000000000000000023471226750426600266750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.IOException; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.resolver.util.ResolvedResource; public interface ModuleDescriptorWriter { public void write(ResolvedResource originalMdResource, ModuleDescriptor md, File src, File dest) throws IOException, ParseException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java000066400000000000000000000125221226750426600265350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.RelativeUrlResolver; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; /** * Keep traces of the usage of a ParserSettings in order to check afterwards that the relevant * settings didn't changed. *

* A ParserSettingsMonitor provide a ParserSettings that must be used in place of the orignal one. *

*

* The current implementation consider that a settings changed iff one of the used variable has * changed. *

*/ class ParserSettingsMonitor { private ParserSettings delegatedSettings; private final Map/* */substitutes; public ParserSettingsMonitor(ParserSettings settings) { this.delegatedSettings = settings; this.substitutes = new HashMap(); } /** * @return The parser settings that must be used in place of the orignal settings The returned * object delegates all the call to the original settings. */ public ParserSettings getMonitoredSettings() { return monitoredSettings; } /** * Free the ressource used during the monitoring, keeping only the info required to evaluate * hasChanged. */ public void endMonitoring() { monitoredSettings = null; delegatedSettings = null; } /** * Check if the newSettings is compatible with the original settings that has been monitored. * Only the info that was actually used is compared. */ public boolean hasChanged(ParserSettings newSettings) { for (Iterator it = substitutes.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); String key = (String) entry.getKey(); Object oldValue = entry.getValue(); String newValue = newSettings.substitute(key); if (!oldValue.equals(newValue)) { Message.debug("settings variable has changed for : " + entry.getKey()); return true; } } return false; } private ParserSettings monitoredSettings = new ParserSettings() { public ConflictManager getConflictManager(String name) { return delegatedSettings.getConflictManager(name); } public PatternMatcher getMatcher(String matcherName) { return delegatedSettings.getMatcher(matcherName); } public Namespace getNamespace(String namespace) { return delegatedSettings.getNamespace(namespace); } public RelativeUrlResolver getRelativeUrlResolver() { return delegatedSettings.getRelativeUrlResolver(); } public ResolutionCacheManager getResolutionCacheManager() { return delegatedSettings.getResolutionCacheManager(); } public DependencyResolver getResolver(ModuleRevisionId mRevId) { return delegatedSettings.getResolver(mRevId); } public StatusManager getStatusManager() { return delegatedSettings.getStatusManager(); } public File resolveFile(String filename) { return delegatedSettings.resolveFile(filename); } public String getDefaultBranch(ModuleId moduleId) { return delegatedSettings.getDefaultBranch(moduleId); } public Namespace getContextNamespace() { return delegatedSettings.getContextNamespace(); } public Map substitute(Map strings) { Map substituted = new LinkedHashMap(); for (Iterator it = strings.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); substituted.put(entry.getKey(), substitute((String) entry.getValue())); } return substituted; } public String substitute(String value) { String r = delegatedSettings.substitute(value); if (value != null && value != r) { substitutes.put(value, r); } return r; } }; } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java000066400000000000000000000206371226750426600266140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.repository.ArtifactResourceResolver; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.ResourceDownloader; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.util.ResolvedResource; public interface RepositoryCacheManager { /** * Returns the name of the repository cache manager. * * @return the name of the repository cache manager. */ public abstract String getName(); /** * Saves the information of which resolvers were used to resolve a module (both for metadata and * artifact), so that this info can be loaded later (even after a jvm restart) for the use of * {@link #findModuleInCache(DependencyDescriptor, CacheMetadataOptions, String)}. * * @param md * the module descriptor resolved * @param metadataResolverName * metadata resolver name * @param artifactResolverName * artifact resolver name */ public abstract void saveResolvers(ModuleDescriptor descriptor, String metadataResolverName, String artifactResolverName); /** * Returns the artifact origin of the given artifact as saved in this cache. *

* If the origin is unknown, the returned ArtifactOrigin instance will return true when * {@link ArtifactOrigin#isUnknown(ArtifactOrigin)} is called. * * @param artifact * the artifact for which the saved artifact origin should be returned. * @return the artifact origin of the given artifact as saved in this cache */ public abstract ArtifactOrigin getSavedArtifactOrigin(Artifact artifact); /** * Search a module descriptor in cache for a mrid * * @param dd * the dependency descriptor identifying the module to search * @param requestedRevisionId * the requested dependency module revision id identifying the module to search * @param options * options on how caching should be handled * @param expectedResolver * the resolver with which the md in cache must have been resolved to be returned, * null if this doesn't matter * @return the ResolvedModuleRevision corresponding to the module found, null if none correct * has been found in cache */ public abstract ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd, ModuleRevisionId requestedRevisionId, CacheMetadataOptions options, String expectedResolver); /** * Downloads an artifact to this cache. * * @param artifact * the artifact to download * @param resourceResolver * a resource resolver to use if the artifact needs to be resolved to a Resource for * downloading * @param resourceDownloader * a resource downloader to use if actual download of the resource is needed * @param options * a set of options to adjust the download * @return a report indicating how the download was performed */ public abstract ArtifactDownloadReport download(Artifact artifact, ArtifactResourceResolver resourceResolver, ResourceDownloader resourceDownloader, CacheDownloadOptions options); /** * Download some repository resource and put it in the cache. *

* If the cached version is considered enough up to date, no downloading is done. * * @param resource * the resource of the file to put in cache * @param name * the descriptive name of the resource (helps while manually looking into the cache * files) * @param type * the type of the resource (helps while manually looking into the cache files) * @param extension * the extension of the resource (helps while manually looking into the cache files) * @param options * a set of options to adjust the download * @param repository * the repository which resolve the content of the resource * @return a report indicating how the download was performed */ public ArtifactDownloadReport downloadRepositoryResource(Resource resource, String name, String type, String extension, CacheResourceOptions options, Repository repository); /** * Caches an original module descriptor. *

* After this call, the original module descriptor file (with no modification nor conversion) * should be available as a local file. *

* * @param resolver * the dependency resolver from which the cache request comes from * @param orginalMetadataRef * a resolved resource pointing to the remote original module descriptor * @param dd * the dependency descriptor for which the module descriptor should be cached * @param requestedMetadataArtifact * the module descriptor artifact as requested originally * @param downloader * a ResourceDownloader able to download the original module descriptor resource if * required by this cache implementation * @param options * options to apply to cache this module descriptor * @return a {@link ResolvedModuleRevision} representing the local cached module descriptor, or * null if it failed * @throws ParseException * if an exception occurred while parsing the module descriptor */ public ResolvedModuleRevision cacheModuleDescriptor(DependencyResolver resolver, ResolvedResource orginalMetadataRef, DependencyDescriptor dd, Artifact requestedMetadataArtifact, ResourceDownloader downloader, CacheMetadataOptions options) throws ParseException; /** * Stores a standardized version of an original module descriptor in the cache for later use. * * @param resolver * the dependency resolver from which the cache request comes from * @param orginalMetadataRef * a resolved resource pointing to the remote original module descriptor * @param requestedMetadataArtifact * the module descriptor artifact as requested originally * @param rmr * the {@link ResolvedModuleRevision} representing the local cached module descriptor * @param writer * a {@link ModuleDescriptorWriter} able to write the module descriptor to a stream. */ public void originalToCachedModuleDescriptor(DependencyResolver resolver, ResolvedResource orginalMetadataRef, Artifact requestedMetadataArtifact, ResolvedModuleRevision rmr, ModuleDescriptorWriter writer); /** * Cleans the whole cache. */ public void clean(); /** * Caches a dynamic revision constraint resolution. * * @param dynamicMrid * the dynamic module revision id * @param revision * the resolved revision */ public void saveResolvedRevision(ModuleRevisionId dynamicMrid, String revision); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/cache/ResolutionCacheManager.java000066400000000000000000000032421226750426600265710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.cache; import java.io.File; import java.io.IOException; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; public interface ResolutionCacheManager { File getResolutionCacheRoot(); File getResolvedIvyFileInCache(ModuleRevisionId mrid); File getResolvedIvyPropertiesInCache(ModuleRevisionId mrid); File getConfigurationResolveReportInCache(String resolveId, String conf); File[] getConfigurationResolveReportsInCache(final String resolveId); ModuleDescriptor getResolvedModuleDescriptor(ModuleRevisionId mrid) throws ParseException, IOException; void saveResolvedModuleDescriptor(ModuleDescriptor md) throws ParseException, IOException; /** * Cleans the whole cache. */ void clean(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/check/000077500000000000000000000000001226750426600213555ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/check/CheckEngine.java000066400000000000000000000140151226750426600243640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.check; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; public class CheckEngine { private CheckEngineSettings settings; private ResolveEngine resolveEngine; public CheckEngine(CheckEngineSettings settings, ResolveEngine resolveEngine) { this.settings = settings; this.resolveEngine = resolveEngine; } /** * Checks the given ivy file using current settings to see if all dependencies are available, * with good confs. If a resolver name is given, it also checks that the declared publications * are available in the corresponding resolver. Note that the check is not performed * recursively, i.e. if a dependency has itself dependencies badly described or not available, * this check will not discover it. */ public boolean check(URL ivyFile, String resolvername) { try { boolean result = true; // parse ivy file ModuleDescriptor md = ModuleDescriptorParserRegistry.getInstance().parseDescriptor( settings, ivyFile, settings.doValidate()); // check publications if possible if (resolvername != null) { DependencyResolver resolver = settings.getResolver(resolvername); String[] confs = md.getConfigurationsNames(); Set artifacts = new HashSet(); for (int i = 0; i < confs.length; i++) { artifacts.addAll(Arrays.asList(md.getArtifacts(confs[i]))); } for (Iterator iter = artifacts.iterator(); iter.hasNext();) { Artifact art = (Artifact) iter.next(); if (!resolver.exists(art)) { Message.info("declared publication not found: " + art); result = false; } } } // check dependencies DependencyDescriptor[] dds = md.getDependencies(); ResolveData data = new ResolveData(resolveEngine, new ResolveOptions()); for (int i = 0; i < dds.length; i++) { // check master confs String[] masterConfs = dds[i].getModuleConfigurations(); for (int j = 0; j < masterConfs.length; j++) { if (!"*".equals(masterConfs[j].trim()) && md.getConfiguration(masterConfs[j]) == null) { Message.info("dependency required in non existing conf for " + ivyFile + " \n\tin " + dds[i] + ": " + masterConfs[j]); result = false; } } // resolve DependencyResolver resolver = settings .getResolver(dds[i].getDependencyRevisionId()); ResolvedModuleRevision rmr = resolver.getDependency(dds[i], data); if (rmr == null) { Message.info("dependency not found in " + ivyFile + ":\n\t" + dds[i]); result = false; } else { String[] depConfs = dds[i].getDependencyConfigurations(md .getConfigurationsNames()); for (int j = 0; j < depConfs.length; j++) { if (!Arrays.asList(rmr.getDescriptor().getConfigurationsNames()).contains( depConfs[j])) { Message.info("dependency configuration is missing for " + ivyFile + "\n\tin " + dds[i] + ": " + depConfs[j]); result = false; } Artifact[] arts = rmr.getDescriptor().getArtifacts(depConfs[j]); for (int k = 0; k < arts.length; k++) { if (!resolver.exists(arts[k])) { Message.info("dependency artifact is missing for " + ivyFile + "\n\t in " + dds[i] + ": " + arts[k]); result = false; } } } } } return result; } catch (ParseException e) { Message.info("parse problem on " + ivyFile, e); return false; } catch (IOException e) { Message.info("io problem on " + ivyFile, e); return false; } catch (Exception e) { Message.info("problem on " + ivyFile, e); return false; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/check/CheckEngineSettings.java000066400000000000000000000021341226750426600261040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.check; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.resolver.DependencyResolver; public interface CheckEngineSettings extends ParserSettings { boolean doValidate(); DependencyResolver getResolver(String resolvername); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/000077500000000000000000000000001226750426600217325ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/DefaultPublishingDRResolver.java000066400000000000000000000023341226750426600301600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.deliver; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; public class DefaultPublishingDRResolver implements PublishingDependencyRevisionResolver { public String resolve(ModuleDescriptor published, String publishedStatus, ModuleRevisionId depMrid, String status) { return depMrid.getRevision(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/DeliverEngine.java000066400000000000000000000236531226750426600253260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.deliver; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.text.ParseException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.parser.xml.UpdateOptions; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorUpdater; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.ConfigurationUtils; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; public class DeliverEngine { private DeliverEngineSettings settings; public DeliverEngine(DeliverEngineSettings settings) { this.settings = settings; } /** * Delivers a resolved ivy file based upon last resolve call status. If resolve report file * cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been * called before ?). * * @param revision * the revision to which the module should be delivered * @param destIvyPattern * the pattern to which the delivered ivy file should be written * @param options * the options with which deliver should be done */ public void deliver(String revision, String destIvyPattern, DeliverOptions options) throws IOException, ParseException { String resolveId = options.getResolveId(); if (resolveId == null) { throw new IllegalArgumentException("A resolveId must be specified for delivering."); } File[] files = getCache().getConfigurationResolveReportsInCache(resolveId); if (files.length == 0) { throw new IllegalStateException("No previous resolve found for id '" + resolveId + "' Please resolve dependencies before delivering."); } XmlReportParser parser = new XmlReportParser(); parser.parse(files[0]); ModuleRevisionId mrid = parser.getResolvedModule(); deliver(mrid, revision, destIvyPattern, options); } private ResolutionCacheManager getCache() { return settings.getResolutionCacheManager(); } /** * Delivers a resolved ivy file based upon last resolve call status. If resolve report file * cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been * called before ?). * * @param mrid * the module revision id of the module to deliver * @param revision * the revision to which the module should be delivered * @param destIvyPattern * the pattern to which the delivered ivy file should be written * @param options * the options with which deliver should be done */ public void deliver(ModuleRevisionId mrid, String revision, String destIvyPattern, DeliverOptions options) throws IOException, ParseException { Message.info(":: delivering :: " + mrid + " :: " + revision + " :: " + options.getStatus() + " :: " + options.getPubdate()); Message.verbose("\toptions = " + options); long start = System.currentTimeMillis(); destIvyPattern = settings.substitute(destIvyPattern); // 1) find the resolved module descriptor in cache ModuleDescriptor md = getCache().getResolvedModuleDescriptor(mrid); md.setResolvedModuleRevisionId(ModuleRevisionId.newInstance(md.getModuleRevisionId(), options.getPubBranch() == null ? mrid.getBranch() : options.getPubBranch(), revision)); md.setResolvedPublicationDate(options.getPubdate()); // 2) parse resolvedRevisions From properties file Map resolvedRevisions = new HashMap(); // Map (ModuleId -> String revision) Map resolvedBranches = new HashMap(); // Map (ModuleId -> String branch) Map dependenciesStatus = new HashMap(); // Map (ModuleId -> String status) File ivyProperties = getCache().getResolvedIvyPropertiesInCache(mrid); if (!ivyProperties.exists()) { throw new IllegalStateException("ivy properties not found in cache for " + mrid + "; please resolve dependencies before delivering!"); } Properties props = new Properties(); FileInputStream in = new FileInputStream(ivyProperties); props.load(in); in.close(); for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { String depMridStr = (String) iter.next(); String[] parts = props.getProperty(depMridStr).split(" "); ModuleRevisionId decodedMrid = ModuleRevisionId.decode(depMridStr); if (options.isResolveDynamicRevisions()) { resolvedRevisions.put(decodedMrid, parts[0]); if (parts.length >= 4) { if (parts[3] != null && !"null".equals(parts[3])) { resolvedBranches.put(decodedMrid, parts[3]); } } } dependenciesStatus.put(decodedMrid, parts[1]); if (options.isReplaceForcedRevisions()) { if (parts.length <= 2) { // maybe the properties file was generated by an older Ivy version // so it is possible that this part doesn't exist. throw new IllegalStateException("ivy properties file generated by an older" + " version of Ivy which doesn't support replacing forced revisions!"); } resolvedRevisions.put(decodedMrid, parts[2]); } } // 3) use pdrResolver to resolve dependencies info Map resolvedDependencies = new HashMap(); // Map (ModuleRevisionId -> String revision) DependencyDescriptor[] dependencies = md.getDependencies(); for (int i = 0; i < dependencies.length; i++) { String rev = (String) resolvedRevisions.get(dependencies[i].getDependencyRevisionId()); if (rev == null) { rev = dependencies[i].getDependencyRevisionId().getRevision(); } String bra = (String) resolvedBranches.get(dependencies[i].getDependencyRevisionId()); if (bra == null || "null".equals(bra)) { bra = dependencies[i].getDependencyRevisionId().getBranch(); } String depStatus = (String) dependenciesStatus.get(dependencies[i] .getDependencyRevisionId()); ModuleRevisionId mrid2 = null; if (bra == null) { mrid2 = ModuleRevisionId .newInstance(dependencies[i].getDependencyRevisionId(), rev); } else { mrid2 = ModuleRevisionId.newInstance(dependencies[i].getDependencyRevisionId(), bra, rev); } resolvedDependencies.put(dependencies[i].getDependencyRevisionId(), options .getPdrResolver().resolve(md, options.getStatus(), mrid2, depStatus)); } // 4) copy the source resolved ivy to the destination specified, // updating status, revision and dependency revisions obtained by // PublishingDependencyRevisionResolver File publishedIvy = settings.resolveFile(IvyPatternHelper.substitute(destIvyPattern, md.getResolvedModuleRevisionId())); Message.info("\tdelivering ivy file to " + publishedIvy); String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md); Set confsToRemove = new HashSet(Arrays.asList(md.getConfigurationsNames())); confsToRemove.removeAll(Arrays.asList(confs)); try { UpdateOptions opts = new UpdateOptions() .setSettings(settings) .setResolvedRevisions(resolvedDependencies) .setStatus(options.getStatus()) .setRevision(revision) .setBranch(options.getPubBranch()) .setPubdate(options.getPubdate()) .setGenerateRevConstraint(options.isGenerateRevConstraint()) .setMerge(options.isMerge()) .setMergedDescriptor(md) .setConfsToExclude( (String[]) confsToRemove.toArray(new String[confsToRemove.size()])); if (!resolvedBranches.isEmpty()) { opts = opts.setResolvedBranches(resolvedBranches); } Resource res = md.getResource(); XmlModuleDescriptorUpdater.update(res.openStream(), res, publishedIvy, opts); } catch (SAXException ex) { throw new RuntimeException("bad ivy file in cache for " + mrid, ex); } Message.verbose("\tdeliver done (" + (System.currentTimeMillis() - start) + "ms)"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/DeliverEngineSettings.java000066400000000000000000000017771226750426600270520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.deliver; import org.apache.ivy.plugins.parser.ParserSettings; public interface DeliverEngineSettings extends ParserSettings { String substitute(String destIvyPattern); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/DeliverOptions.java000066400000000000000000000212561226750426600255510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.deliver; import java.util.Date; import org.apache.ivy.core.settings.IvySettings; /** * A set of options used to do a deliver. */ public class DeliverOptions { private String status; private Date pubdate; private PublishingDependencyRevisionResolver pdrResolver = new DefaultPublishingDRResolver(); private boolean validate = true; private boolean resolveDynamicRevisions = true; private boolean replaceForcedRevisions = false; private String resolveId; private String[] confs; private String pubBranch; /** * True to indicate that the revConstraint attribute should be generated if applicable, false to * never generate the revConstraint attribute. */ private boolean generateRevConstraint = true; /** true to merge parent descriptor elements into delivered child descriptor */ private boolean merge = true; /** * Returns an instance of DeliverOptions with options corresponding to default values taken from * the given settings. * * @param settings * The settings to use to get default option values * @return a DeliverOptions instance ready to be used or customized */ public static DeliverOptions newInstance(IvySettings settings) { return new DeliverOptions(null, new Date(), new DefaultPublishingDRResolver(), settings.doValidate(), true, null); } /** * Creates an instance of DeliverOptions which require to be configured using the appropriate * setters. */ public DeliverOptions() { } /** * Creates an instance of DeliverOptions with all options explicitly set. */ public DeliverOptions(String status, Date pubDate, PublishingDependencyRevisionResolver pdrResolver, boolean validate, boolean resolveDynamicRevisions, String[] confs) { this.status = status; this.pubdate = pubDate; this.pdrResolver = pdrResolver; this.validate = validate; this.resolveDynamicRevisions = resolveDynamicRevisions; this.confs = confs; } /** * Return the pdrResolver that will be used during deliver for each dependency to get its * published information. This can particularly useful when the deliver is made for a release, * and when we wish to deliver each dependency which is still in integration. The * PublishingDependencyRevisionResolver can then do the delivering work for the dependency and * return the new (delivered) dependency info (with the delivered revision). Note that * PublishingDependencyRevisionResolver is only called for each direct dependency. * * @return the pdrResolver that will be used during deliver */ public PublishingDependencyRevisionResolver getPdrResolver() { return pdrResolver; } /** * Sets the pdrResolver that will be used during deliver for each dependency to get its * published information. This can particularly useful when the deliver is made for a release, * and when we wish to deliver each dependency which is still in integration. The * PublishingDependencyRevisionResolver can then do the delivering work for the dependency and * return the new (delivered) dependency info (with the delivered revision). Note that * PublishingDependencyRevisionResolver is only called for each direct dependency. * * @return the instance of DeliverOptions on which the method has been called, for easy method * chaining */ public DeliverOptions setPdrResolver(PublishingDependencyRevisionResolver pdrResolver) { this.pdrResolver = pdrResolver; return this; } public boolean isResolveDynamicRevisions() { return resolveDynamicRevisions; } public DeliverOptions setResolveDynamicRevisions(boolean resolveDynamicRevisions) { this.resolveDynamicRevisions = resolveDynamicRevisions; return this; } public boolean isReplaceForcedRevisions() { return replaceForcedRevisions; } public DeliverOptions setReplaceForcedRevisions(boolean replaceForcedRevisions) { this.replaceForcedRevisions = replaceForcedRevisions; return this; } public boolean isValidate() { return validate; } public DeliverOptions setValidate(boolean validate) { this.validate = validate; return this; } public Date getPubdate() { return pubdate; } public DeliverOptions setPubdate(Date pubdate) { this.pubdate = pubdate; return this; } /** * Returns the status to which the module should be delivered, or null if the current status * should be kept. * * @return the status to which the module should be delivered */ public String getStatus() { return status; } /** * Sets the status to which the module should be delivered, use null if the current status * should be kept. * * @return the instance of DeliverOptions on which the method has been called, for easy method * chaining */ public DeliverOptions setStatus(String status) { this.status = status; return this; } /** * Returns the id of a previous resolve to use for delivering. * * @return the id of a previous resolve */ public String getResolveId() { return resolveId; } /** * Sets the id of a previous resolve to use for delivering. * * @param resolveId * the id of a previous resolve * @return the instance of DeliverOptions on which the method has been called, for easy method * chaining */ public DeliverOptions setResolveId(String resolveId) { this.resolveId = resolveId; return this; } /** * Return the configurations which must be deliverd. Returns null if all configurations * has to be deliverd. Attention: the returned array can contain wildcards! * * @return the configurations to deliver */ public String[] getConfs() { return confs; } /** * Sets the configurations to deliver. * * @param confs * the configurations to deliver * @return the instance of DeliverOptions on which the method has been called, for easy method * chaining */ public DeliverOptions setConfs(String[] confs) { this.confs = confs; return this; } /** * Returns the branch with which the Ivy file should be delivered, or null if * branch info shouldn't be changed. * * @return the branch with which the Ivy file should be delivered */ public String getPubBranch() { return pubBranch; } /** * Sets the branch with which the Ivy file should be delivered. * * @param pubBranch * the branch with which the Ivy file should be delivered * @return the instance of DeliverOptions on which the method has been called, for easy method * chaining */ public DeliverOptions setPubBranch(String pubBranch) { this.pubBranch = pubBranch; return this; } public boolean isGenerateRevConstraint() { return generateRevConstraint; } public DeliverOptions setGenerateRevConstraint(boolean generateRevConstraint) { this.generateRevConstraint = generateRevConstraint; return this; } public boolean isMerge() { return merge; } public DeliverOptions setMerge(boolean merge) { this.merge = merge; return this; } public String toString() { return "status=" + status + " pubdate=" + pubdate + " validate=" + validate + " resolveDynamicRevisions=" + resolveDynamicRevisions + " merge=" + merge + " resolveId=" + resolveId + " pubBranch=" + pubBranch; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/deliver/PublishingDependencyRevisionResolver.java000066400000000000000000000026701226750426600321460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.deliver; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * */ public interface PublishingDependencyRevisionResolver { /** * Returns the revision of the dependency for the publishing of the 'published' module in * 'publishedStatus' status. * * @param published * @param publishedStatus * @param depMrid * @param status * @return the revision of the dependency */ String resolve(ModuleDescriptor published, String publishedStatus, ModuleRevisionId depMrid, String status); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/000077500000000000000000000000001226750426600214215ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/EventManager.java000066400000000000000000000067361226750426600246540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event; import java.util.Arrays; import javax.swing.event.EventListenerList; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.plugins.repository.TransferListener; import org.apache.ivy.util.filter.Filter; public class EventManager implements TransferListener { private EventListenerList listeners = new EventListenerList(); public void addIvyListener(IvyListener listener) { listeners.add(IvyListener.class, listener); } public void addIvyListener(IvyListener listener, String eventName) { addIvyListener(listener, new IvyEventFilter(eventName, null, null)); } public void addIvyListener(IvyListener listener, Filter filter) { listeners.add(IvyListener.class, new FilteredIvyListener(listener, filter)); } public void removeIvyListener(IvyListener listener) { listeners.remove(IvyListener.class, listener); IvyListener[] listeners = this.listeners.getListeners(IvyListener.class); for (int i = 0; i < listeners.length; i++) { if (listeners[i] instanceof FilteredIvyListener) { if (listener.equals(((FilteredIvyListener) listeners[i]).getIvyListener())) { this.listeners.remove(IvyListener.class, listeners[i]); } } } } public boolean hasIvyListener(IvyListener listener) { return Arrays.asList(listeners.getListeners(IvyListener.class)).contains(listener); } public void fireIvyEvent(IvyEvent evt) { Object[] listeners = this.listeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == IvyListener.class) { ((IvyListener) listeners[i + 1]).progress(evt); } } } public void addTransferListener(TransferListener listener) { listeners.add(TransferListener.class, listener); } public void removeTransferListener(TransferListener listener) { listeners.remove(TransferListener.class, listener); } public boolean hasTransferListener(TransferListener listener) { return Arrays.asList(listeners.getListeners(TransferListener.class)).contains(listener); } protected void fireTransferEvent(TransferEvent evt) { Object[] listeners = this.listeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TransferListener.class) { ((TransferListener) listeners[i + 1]).transferProgress(evt); } } } public void transferProgress(TransferEvent evt) { fireTransferEvent(evt); fireIvyEvent(evt); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/FilteredIvyListener.java000066400000000000000000000026261226750426600262260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event; import org.apache.ivy.util.filter.Filter; public class FilteredIvyListener implements IvyListener { private IvyListener listener; private Filter filter; public FilteredIvyListener(IvyListener listener, Filter filter) { this.listener = listener; this.filter = filter; } public IvyListener getIvyListener() { return listener; } public Filter getFilter() { return filter; } public void progress(IvyEvent event) { if (filter.accept(event)) { listener.progress(event); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/IvyEvent.java000066400000000000000000000105041226750426600240350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event; import java.util.HashMap; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.StringUtils; /** * The root of all ivy events Any ivy event knows which ivy instance triggered the event (the * source) and also has a name and a map of attributes. The name of the event represents the event * type, usually there is a one - one mapping between event names and IvyEvent subclass, even if * this is not mandatory. Example: pre-resolve pre-resolve-dependency post-download The map of * attributes is a Map from String keys to String values. It is especially useful to filter events, * and to get some of their essential data in some context where access to Java types is not easy * (in an ant build file, for example), Example: pre-resolve (organisation=foo, module=bar, * revision=1.0, conf=default) post-download (organisation=foo, module=bar, revision=1.0, * artifact=foo-test, type=jar, ext=jar) */ public class IvyEvent { private EventManager source; private String name; private Map attributes = new HashMap(); protected IvyEvent(String name) { this.source = IvyContext.getContext().getEventManager(); this.name = name; } /** * Should only be called during event object construction, since events should be immutable * * @param key * @param value */ protected void addAttribute(String key, String value) { attributes.put(key, value); } protected void addMDAttributes(ModuleDescriptor md) { addMridAttributes(md.getResolvedModuleRevisionId()); } protected void addMridAttributes(ModuleRevisionId mrid) { addModuleIdAttributes(mrid.getModuleId()); addAttribute("revision", mrid.getRevision()); addAttribute("branch", mrid.getBranch()); addAttributes(mrid.getQualifiedExtraAttributes()); addAttributes(mrid.getExtraAttributes()); } protected void addModuleIdAttributes(ModuleId moduleId) { addAttribute("organisation", moduleId.getOrganisation()); addAttribute("module", moduleId.getName()); } protected void addConfsAttribute(String[] confs) { addAttribute("conf", StringUtils.join(confs, ", ")); } protected void addAttributes(Map attributes) { this.attributes.putAll(attributes); } public EventManager getSource() { return source; } public String getName() { return name; } /** * Returns the attributes of this event, as a Map(String->String) * * @return the attributes of this event, as a Map(String->String) */ public Map getAttributes() { return new HashMap(attributes); } public String toString() { return getName() + " " + getAttributes(); } public boolean equals(Object obj) { if (!(obj instanceof IvyEvent)) { return false; } IvyEvent e = (IvyEvent) obj; return getSource().equals(e.getSource()) && getName().equals(e.getName()) && attributes.equals(e.attributes); } public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 37; hash = 13 * hash + getSource().hashCode(); hash = 13 * hash + getName().hashCode(); hash = 13 * hash + attributes.hashCode(); // CheckStyle:MagicNumber| ON return hash; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/IvyEventFilter.java000066400000000000000000000150011226750426600252000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.filter.AndFilter; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.NoFilter; import org.apache.ivy.util.filter.NotFilter; import org.apache.ivy.util.filter.OrFilter; /** * A filter implementation filtering {@link IvyEvent} based upon an event name and a filter * expression. The name will be matched against the event name using the {@link PatternMatcher} used * to construct this object. The filter expression is a string describing how the event should be * filtered according to its attributes values. The matching between the filter values and the event * attribute values is done using the {@link PatternMatcher} used to construct this object. Here are * some examples: * * * * * * * * * * * * * * * * * * * * * * * * * *
expressioneffect
type=zipaccepts event with a type attribute matching zip
type=zip,jaraccepts event with a type attribute matching zip or jar
type=src AND ext=zipaccepts event with a type attribute matching src AND an ext attribute matching zip
type=src OR ext=zipaccepts event with a type attribute matching src OR an ext attribute matching zip
NOT type=srcaccepts event with a type attribute NOT matching src
* Combination of these can be used, but no parentheses are supported right now, so only the default * priority can be used. The priority order is this one: AND OR NOT = This means that artifact=foo * AND ext=zip OR type=src will match event with artifact matching foo AND (ext matching zip OR type * matching src) * * @since 1.4 */ public class IvyEventFilter implements Filter { private static final String NOT = "NOT "; private static final String OR = " OR "; private static final String AND = " AND "; private PatternMatcher matcher; private Filter nameFilter; private Filter attFilter; public IvyEventFilter(String event, String filterExpression, PatternMatcher matcher) { this.matcher = matcher == null ? ExactPatternMatcher.INSTANCE : matcher; if (event == null) { nameFilter = NoFilter.INSTANCE; } else { final Matcher eventNameMatcher = this.matcher.getMatcher(event); nameFilter = new Filter() { public boolean accept(Object o) { IvyEvent e = (IvyEvent) o; return eventNameMatcher.matches(e.getName()); } }; } attFilter = filterExpression == null || filterExpression.trim().length() == 0 ? NoFilter.INSTANCE : parseExpression(filterExpression); } private Filter parseExpression(String filterExpression) { // expressions handled for the moment: (informal grammar) // EXP := SIMPLE_EXP | AND_EXP | OR_EXP | NOT_EXP // AND_EXP := EXP && EXP // OR_EXP := EXP || EXP // NOT_EXP := ! EXP // SIMPLE_EXP := attname = comma, separated, list, of, accepted, values // example: organisation = foo && module = bar, baz filterExpression = filterExpression.trim(); int index = filterExpression.indexOf(AND); if (index == -1) { index = filterExpression.indexOf(OR); if (index == -1) { if (filterExpression.startsWith(NOT)) { return new NotFilter(parseExpression(filterExpression.substring(NOT.length()))); } else { index = filterExpression.indexOf("="); if (index == -1) { throw new IllegalArgumentException("bad filter expression: " + filterExpression + ": no equal sign found"); } final String attname = filterExpression.substring(0, index).trim(); String[] values = filterExpression.substring(index + 1).trim().split(","); final Matcher[] matchers = new Matcher[values.length]; for (int i = 0; i < values.length; i++) { matchers[i] = matcher.getMatcher(values[i].trim()); } return new Filter() { public boolean accept(Object o) { IvyEvent e = (IvyEvent) o; String val = (String) e.getAttributes().get(attname); if (val == null) { return false; } for (int i = 0; i < matchers.length; i++) { if (matchers[i].matches(val)) { return true; } } return false; } }; } } else { return new OrFilter(parseExpression(filterExpression.substring(0, index)), parseExpression(filterExpression.substring(index + OR.length()))); } } else { return new AndFilter(parseExpression(filterExpression.substring(0, index)), parseExpression(filterExpression.substring(index + AND.length()))); } } public boolean accept(Object o) { if (!(o instanceof IvyEvent)) { return false; } return nameFilter.accept(o) && attFilter.accept(o); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/IvyListener.java000066400000000000000000000017271226750426600245500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event; import java.util.EventListener; public interface IvyListener extends EventListener { public void progress(IvyEvent event); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/000077500000000000000000000000001226750426600232305ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/DownloadEvent.java000066400000000000000000000027771226750426600266610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.download; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.Artifact; public abstract class DownloadEvent extends IvyEvent { private Artifact artifact; public DownloadEvent(String name, Artifact artifact) { super(name); this.artifact = artifact; addArtifactAttributes(this.artifact); } protected void addArtifactAttributes(Artifact artifact) { addMridAttributes(artifact.getModuleRevisionId()); addAttributes(artifact.getAttributes()); addAttribute("metadata", String.valueOf(artifact.isMetadata())); } public Artifact getArtifact() { return artifact; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/EndArtifactDownloadEvent.java000066400000000000000000000046511226750426600307570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.download; import java.io.File; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.plugins.resolver.DependencyResolver; public class EndArtifactDownloadEvent extends DownloadEvent { public static final String NAME = "post-download-artifact"; private DependencyResolver resolver; private ArtifactDownloadReport report; public EndArtifactDownloadEvent(DependencyResolver resolver, Artifact artifact, ArtifactDownloadReport report, File dest) { super(NAME, artifact); this.resolver = resolver; this.report = report; addAttribute("resolver", this.resolver.getName()); addAttribute("status", this.report.getDownloadStatus().toString()); addAttribute("details", this.report.getDownloadDetails()); addAttribute("size", String.valueOf(this.report.getSize())); addAttribute("file", dest.getAbsolutePath()); addAttribute("duration", String.valueOf(this.report.getDownloadTimeMillis())); ArtifactOrigin origin = report.getArtifactOrigin(); if (!ArtifactOrigin.isUnknown(origin)) { addAttribute("origin", origin.getLocation()); addAttribute("local", String.valueOf(origin.isLocal())); } else { addAttribute("origin", ""); addAttribute("local", ""); } } public ArtifactDownloadReport getReport() { return report; } public DependencyResolver getResolver() { return resolver; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/NeedArtifactEvent.java000066400000000000000000000026141226750426600274310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.download; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.DependencyResolver; public class NeedArtifactEvent extends DownloadEvent { public static final String NAME = "need-artifact"; private DependencyResolver resolver; public NeedArtifactEvent(DependencyResolver resolver, Artifact artifact) { super(NAME, artifact); this.resolver = resolver; addAttribute("resolver", this.resolver.getName()); } public DependencyResolver getResolver() { return resolver; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/PrepareDownloadEvent.java000066400000000000000000000024251226750426600301660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.download; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.Artifact; public class PrepareDownloadEvent extends IvyEvent { public static final String NAME = "prepare-download"; private Artifact[] artifacts; public PrepareDownloadEvent(Artifact[] artifacts) { super(NAME); this.artifacts = artifacts; } public Artifact[] getArtifacts() { return artifacts; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/download/StartArtifactDownloadEvent.java000066400000000000000000000033711226750426600313440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.download; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.DependencyResolver; public class StartArtifactDownloadEvent extends DownloadEvent { public static final String NAME = "pre-download-artifact"; private DependencyResolver resolver; private ArtifactOrigin origin; public StartArtifactDownloadEvent(DependencyResolver resolver, Artifact artifact, ArtifactOrigin origin) { super(NAME, artifact); this.resolver = resolver; this.origin = origin; addAttribute("resolver", this.resolver.getName()); addAttribute("origin", origin.getLocation()); addAttribute("local", String.valueOf(origin.isLocal())); } public DependencyResolver getResolver() { return resolver; } public ArtifactOrigin getOrigin() { return origin; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/publish/000077500000000000000000000000001226750426600230675ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/publish/EndArtifactPublishEvent.java000066400000000000000000000040321226750426600304460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.publish; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.DependencyResolver; /** * Event fired after artifact publication has finished (possibly in error). Triggers registered on * {@link #NAME} will be notified of these events. * * @see DependencyResolver#publish(Artifact, File, boolean) */ public class EndArtifactPublishEvent extends PublishEvent { private static final long serialVersionUID = -65690169431499422L; public static final String NAME = "post-publish-artifact"; public static final String STATUS_SUCCESSFUL = "successful"; public static final String STATUS_FAILED = "failed"; private final boolean successful; public EndArtifactPublishEvent(DependencyResolver resolver, Artifact artifact, File data, boolean overwrite, boolean successful) { super(NAME, resolver, artifact, data, overwrite); this.successful = successful; addAttribute("status", isSuccessful() ? STATUS_SUCCESSFUL : STATUS_FAILED); } /** * @return true iff no errors were encountered during the publication */ public boolean isSuccessful() { return successful; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/publish/PublishEvent.java000066400000000000000000000047761226750426600263600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.publish; import java.io.File; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.DependencyResolver; /** * Base class for events fired during {@link DependencyResolver#publish(Artifact, File, boolean)}. * * @see StartArtifactPublishEvent * @see EndArtifactPublishEvent */ public abstract class PublishEvent extends IvyEvent { private final DependencyResolver resolver; private final Artifact artifact; private final File data; private final boolean overwrite; protected PublishEvent(String name, DependencyResolver resolver, Artifact artifact, File data, boolean overwrite) { super(name); this.resolver = resolver; this.artifact = artifact; this.data = data; this.overwrite = overwrite; addMridAttributes(artifact.getModuleRevisionId()); addAttributes(artifact.getAttributes()); addAttribute("resolver", resolver.getName()); addAttribute("file", data.getAbsolutePath()); addAttribute("overwrite", String.valueOf(overwrite)); } /** @return the resolver into which the artifact is being published */ public DependencyResolver getResolver() { return resolver; } /** @return a local file containing the artifact data */ public File getData() { return data; } /** @return metadata about the artifact being published */ public Artifact getArtifact() { return artifact; } /** @return true iff this event overwrites existing resolver data for this artifact */ public boolean isOverwrite() { return overwrite; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/publish/StartArtifactPublishEvent.java000066400000000000000000000031101226750426600310310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.publish; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.DependencyResolver; /** * Event fired just before an artifact is published into a resolver. Triggers registered on * {@link #NAME} will be notified of these events. * * @see DependencyResolver#publish(Artifact, File, boolean) */ public class StartArtifactPublishEvent extends PublishEvent { private static final long serialVersionUID = -1134274781039590219L; public static final String NAME = "pre-publish-artifact"; public StartArtifactPublishEvent(DependencyResolver resolver, Artifact artifact, File data, boolean overwrite) { super(NAME, resolver, artifact, data, overwrite); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/000077500000000000000000000000001226750426600231005ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/EndResolveDependencyEvent.java000066400000000000000000000061611226750426600310160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.resolver.DependencyResolver; public class EndResolveDependencyEvent extends ResolveDependencyEvent { public static final String NAME = "post-resolve-dependency"; private ResolvedModuleRevision module; private long duration; public EndResolveDependencyEvent(DependencyResolver resolver, DependencyDescriptor dd, ModuleRevisionId requestedRevisionId, ResolvedModuleRevision module, long duration) { super(NAME, resolver, dd, requestedRevisionId); this.module = module; this.duration = duration; addAttribute("duration", String.valueOf(duration)); if (this.module != null) { // override revision from the dependency descriptor addAttribute("revision", this.module.getDescriptor().getResolvedModuleRevisionId() .getRevision()); // now that we have loaded the dependency descriptor, we can put the extra attributes // contained in the descriptor too addAttributes(this.module.getDescriptor().getResolvedModuleRevisionId() .getQualifiedExtraAttributes()); addAttributes(this.module.getDescriptor().getResolvedModuleRevisionId() .getExtraAttributes()); addAttribute("resolved", "true"); } else { addAttribute("resolved", "false"); } } public ResolvedModuleRevision getModule() { return module; } /** * Returns the time elapsed to resolve the dependency. *

* The time elapsed to resolve a dependency includes the time required to locate the the actual * revision if the dependency descriptor use a version constraint, and to download the module * metadata if necessary. It doesn't include any conflict management operations nor transitive * dependency management. It's basically the time elapsed since the corresponding * {@link StartResolveDependencyEvent} *

* * @return the time elapsed to resolve the dependency. */ public long getDuration() { return duration; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/EndResolveEvent.java000066400000000000000000000034621226750426600270200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.report.ResolveReport; public class EndResolveEvent extends ResolveEvent { public static final String NAME = "post-resolve"; private ResolveReport report; public EndResolveEvent(ModuleDescriptor md, String[] confs, ResolveReport report) { super(NAME, md, confs); this.report = report; addAttribute("resolve-id", String.valueOf(report.getResolveId())); addAttribute("nb-dependencies", String.valueOf(report.getDependencies().size())); addAttribute("nb-artifacts", String.valueOf(report.getArtifacts().size())); addAttribute("resolve-duration", String.valueOf(report.getResolveTime())); addAttribute("download-duration", String.valueOf(report.getDownloadTime())); addAttribute("download-size", String.valueOf(report.getDownloadSize())); } public ResolveReport getReport() { return report; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/ResolveDependencyEvent.java000066400000000000000000000044011226750426600303620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.resolver.DependencyResolver; public class ResolveDependencyEvent extends IvyEvent { private DependencyResolver resolver; private DependencyDescriptor dd; protected ResolveDependencyEvent(String name, DependencyResolver resolver, DependencyDescriptor dd, ModuleRevisionId requestedRevisionId) { super(name); this.resolver = resolver; this.dd = dd; addAttribute("resolver", this.resolver.getName()); addMridAttributes(this.dd.getDependencyRevisionId()); addAttributes(this.dd.getQualifiedExtraAttributes()); addAttributes(this.dd.getExtraAttributes()); addAttribute("req-revision", requestedRevisionId.getRevision()); addAttribute("req-revision-default", dd.getDependencyRevisionId().getRevision()); addAttribute("req-revision-dynamic", dd.getDynamicConstraintDependencyRevisionId() .getRevision()); addAttribute("req-branch", requestedRevisionId.getBranch()); addAttribute("req-branch-default", dd.getDependencyRevisionId().getBranch()); } public DependencyDescriptor getDependencyDescriptor() { return dd; } public DependencyResolver getResolver() { return resolver; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/ResolveEvent.java000066400000000000000000000024461226750426600263720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; public class ResolveEvent extends IvyEvent { private ModuleDescriptor md; protected ResolveEvent(String name, ModuleDescriptor md, String[] confs) { super(name); this.md = md; addMDAttributes(md); addConfsAttribute(confs); } public ModuleDescriptor getModuleDescriptor() { return md; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/StartResolveDependencyEvent.java000066400000000000000000000025601226750426600314040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.resolver.DependencyResolver; public class StartResolveDependencyEvent extends ResolveDependencyEvent { public static final String NAME = "pre-resolve-dependency"; public StartResolveDependencyEvent(DependencyResolver resolver, DependencyDescriptor dd, ModuleRevisionId requestedRevisionId) { super(NAME, resolver, dd, requestedRevisionId); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/resolve/StartResolveEvent.java000066400000000000000000000021661226750426600274070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.resolve; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; public class StartResolveEvent extends ResolveEvent { public static final String NAME = "pre-resolve"; public StartResolveEvent(ModuleDescriptor md, String[] confs) { super(NAME, md, confs); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/000077500000000000000000000000001226750426600232465ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/EndRetrieveArtifactEvent.java000066400000000000000000000022711226750426600310070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import java.io.File; import org.apache.ivy.core.report.ArtifactDownloadReport; public class EndRetrieveArtifactEvent extends RetrieveArtifactEvent { public static final String NAME = "post-retrieve-artifact"; public EndRetrieveArtifactEvent(ArtifactDownloadReport report, File destFile) { super(NAME, report, destFile); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/EndRetrieveEvent.java000066400000000000000000000054501226750426600273330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.retrieve.RetrieveOptions; public class EndRetrieveEvent extends RetrieveEvent { public static final String NAME = "post-retrieve"; private long duration; private int nbCopied; private int nbUpToDate; private long totalCopiedSize; public EndRetrieveEvent(ModuleRevisionId mrid, String[] confs, long elapsedTime, int targetsCopied, int targetsUpToDate, long totalCopiedSize, RetrieveOptions options) { super(NAME, mrid, confs, options); this.duration = elapsedTime; this.nbCopied = targetsCopied; this.nbUpToDate = targetsUpToDate; this.totalCopiedSize = totalCopiedSize; addAttribute("duration", String.valueOf(elapsedTime)); addAttribute("size", String.valueOf(totalCopiedSize)); addAttribute("nbCopied", String.valueOf(targetsCopied)); addAttribute("nbUptodate", String.valueOf(targetsUpToDate)); } /** * Duration of the retrieve operation, in ms. * * @return Duration of the retrieve operation, in ms. */ public long getDuration() { return duration; } /** * Number of artifacts which were copied (or symlinked) during the retrieve * * @return Number of artifacts which were copied during the retrieve. */ public int getNbCopied() { return nbCopied; } /** * Number of artifacts which were not copied since they were already present and up to date. * * @return Number of artifacts which were not copied since they were already present and up to * date. */ public int getNbUpToDate() { return nbUpToDate; } /** * Total size of all copied (or symlinked) artifacts, in bytes. * * @return Total size of all copied (or symlinked) artifacts, in bytes. */ public long getTotalCopiedSize() { return totalCopiedSize; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/RetrieveArtifactEvent.java000066400000000000000000000037101226750426600303570ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import java.io.File; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.report.ArtifactDownloadReport; public class RetrieveArtifactEvent extends IvyEvent { private ArtifactDownloadReport report; private File destFile; public RetrieveArtifactEvent(String name, ArtifactDownloadReport report, File destFile) { super(name); addArtifactAttributes(report.getArtifact()); this.report = report; this.destFile = destFile; addAttribute("from", report.getLocalFile().getAbsolutePath()); addAttribute("to", destFile.getAbsolutePath()); addAttribute("size", String.valueOf(destFile.length())); } protected void addArtifactAttributes(Artifact artifact) { addMridAttributes(artifact.getModuleRevisionId()); addAttributes(artifact.getAttributes()); addAttribute("metadata", String.valueOf(artifact.isMetadata())); } public File getDestFile() { return destFile; } public ArtifactDownloadReport getReport() { return report; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/RetrieveEvent.java000066400000000000000000000032431226750426600267020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.retrieve.RetrieveOptions; public class RetrieveEvent extends IvyEvent { private ModuleRevisionId mrid; private RetrieveOptions options; protected RetrieveEvent(String name, ModuleRevisionId mrid, String[] confs, RetrieveOptions options) { super(name); this.mrid = mrid; addMridAttributes(mrid); addConfsAttribute(confs); addAttribute("symlink", String.valueOf(options.isMakeSymlinks())); addAttribute("sync", String.valueOf(options.isSync())); this.options = options; } public ModuleRevisionId getModuleRevisionId() { return mrid; } public RetrieveOptions getOptions() { return options; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/StartRetrieveArtifactEvent.java000066400000000000000000000022741226750426600314010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import java.io.File; import org.apache.ivy.core.report.ArtifactDownloadReport; public class StartRetrieveArtifactEvent extends RetrieveArtifactEvent { public static final String NAME = "pre-retrieve-artifact"; public StartRetrieveArtifactEvent(ArtifactDownloadReport report, File destFile) { super(NAME, report, destFile); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/event/retrieve/StartRetrieveEvent.java000066400000000000000000000023151226750426600277170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.event.retrieve; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.retrieve.RetrieveOptions; public class StartRetrieveEvent extends RetrieveEvent { public static final String NAME = "pre-retrieve"; public StartRetrieveEvent(ModuleRevisionId mrid, String[] confs, RetrieveOptions options) { super(NAME, mrid, confs, options); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/install/000077500000000000000000000000001226750426600217465ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/install/InstallEngine.java000066400000000000000000000244161226750426600253540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.install; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Date; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.search.SearchEngine; import org.apache.ivy.plugins.conflict.NoConflictManager; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; public class InstallEngine { private InstallEngineSettings settings; private ResolveEngine resolveEngine; private SearchEngine searchEngine; public InstallEngine(InstallEngineSettings settings, SearchEngine searchEngine, ResolveEngine resolveEngine) { this.settings = settings; this.searchEngine = searchEngine; this.resolveEngine = resolveEngine; } public ResolveReport install(ModuleRevisionId mrid, String from, String to, InstallOptions options) throws IOException { DependencyResolver fromResolver = settings.getResolver(from); DependencyResolver toResolver = settings.getResolver(to); if (fromResolver == null) { throw new IllegalArgumentException("unknown resolver " + from + ". Available resolvers are: " + settings.getResolverNames()); } if (toResolver == null) { throw new IllegalArgumentException("unknown resolver " + to + ". Available resolvers are: " + settings.getResolverNames()); } PatternMatcher matcher = settings.getMatcher(options.getMatcherName()); if (matcher == null) { throw new IllegalArgumentException("unknown matcher " + options.getMatcherName() + ". Available matchers are: " + settings.getMatcherNames()); } // build module file declaring the dependency Message.info(":: installing " + mrid + " ::"); DependencyResolver oldDicator = resolveEngine.getDictatorResolver(); boolean log = settings.logNotConvertedExclusionRule(); try { settings.setLogNotConvertedExclusionRule(true); resolveEngine.setDictatorResolver(fromResolver); DefaultModuleDescriptor md = new DefaultModuleDescriptor(ModuleRevisionId.newInstance( "apache", "ivy-install", "1.0"), settings.getStatusManager().getDefaultStatus(), new Date()); String resolveId = ResolveOptions.getDefaultResolveId(md); md.addConfiguration(new Configuration("default")); md.addConflictManager(new ModuleId(ExactPatternMatcher.ANY_EXPRESSION, ExactPatternMatcher.ANY_EXPRESSION), ExactPatternMatcher.INSTANCE, new NoConflictManager()); for (int c = 0; c < options.getConfs().length; c++) { final String[] depConfs = options.getConfs(); for (int j = 0; j < depConfs.length; j++) { final String depConf = depConfs[j].trim(); if (MatcherHelper.isExact(matcher, mrid)) { DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, mrid, false, false, options.isTransitive()); dd.addDependencyConfiguration("default", depConf); md.addDependency(dd); } else { ModuleRevisionId[] mrids = searchEngine.listModules(fromResolver, mrid, matcher); for (int i = 0; i < mrids.length; i++) { Message.info("\tfound " + mrids[i] + " to install: adding to the list"); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, mrids[i], false, false, options.isTransitive()); dd.addDependencyConfiguration("default", depConf); md.addDependency(dd); } } } } // resolve using appropriate resolver ResolveReport report = new ResolveReport(md, resolveId); Message.info(":: resolving dependencies ::"); ResolveOptions resolveOptions = new ResolveOptions().setResolveId(resolveId) .setConfs(new String[] {"default"}).setValidate(options.isValidate()); IvyNode[] dependencies = resolveEngine.getDependencies(md, resolveOptions, report); report.setDependencies(Arrays.asList(dependencies), options.getArtifactFilter()); Message.info(":: downloading artifacts to cache ::"); resolveEngine.downloadArtifacts(report, options.getArtifactFilter(), new DownloadOptions()); // now that everything is in cache, we can publish all these modules Message.info(":: installing in " + to + " ::"); for (int i = 0; i < dependencies.length; i++) { ModuleDescriptor depmd = dependencies[i].getDescriptor(); if (depmd != null) { ModuleRevisionId depMrid = depmd.getModuleRevisionId(); Message.verbose("installing " + depMrid); boolean successfullyPublished = false; try { toResolver.beginPublishTransaction(depMrid, options.isOverwrite()); // publish artifacts ArtifactDownloadReport[] artifacts = report.getArtifactsReports(depMrid); for (int j = 0; j < artifacts.length; j++) { if (artifacts[j].getLocalFile() != null) { toResolver.publish(artifacts[j].getArtifact(), artifacts[j].getLocalFile(), options.isOverwrite()); } } // publish metadata MetadataArtifactDownloadReport artifactDownloadReport = dependencies[i] .getModuleRevision().getReport(); File localIvyFile = artifactDownloadReport.getLocalFile(); toResolver.publish(depmd.getMetadataArtifact(), localIvyFile, options.isOverwrite()); if (options.isInstallOriginalMetadata()) { if (artifactDownloadReport.getArtifactOrigin() != null && artifactDownloadReport.getArtifactOrigin().isExists() && !ArtifactOrigin.isUnknown(artifactDownloadReport .getArtifactOrigin()) && artifactDownloadReport.getArtifactOrigin().getArtifact() != null && artifactDownloadReport.getArtifactOrigin().getArtifact() .getType().endsWith(".original") && !artifactDownloadReport .getArtifactOrigin() .getArtifact() .getType() .equals( depmd.getMetadataArtifact().getType() + ".original")) { // publish original metadata artifact, too, as it has a different // type toResolver.publish(artifactDownloadReport.getArtifactOrigin() .getArtifact(), artifactDownloadReport .getOriginalLocalFile(), options.isOverwrite()); } } // end module publish toResolver.commitPublishTransaction(); successfullyPublished = true; } finally { if (!successfullyPublished) { toResolver.abortPublishTransaction(); } } } } Message.info(":: install resolution report ::"); // output report resolveEngine .outputReport(report, settings.getResolutionCacheManager(), resolveOptions); return report; } finally { // IVY-834: log the problems if there were any... Message.sumupProblems(); resolveEngine.setDictatorResolver(oldDicator); settings.setLogNotConvertedExclusionRule(log); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/install/InstallEngineSettings.java000066400000000000000000000030641226750426600270710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.install; import java.util.Collection; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.report.ReportOutputter; import org.apache.ivy.plugins.resolver.DependencyResolver; public interface InstallEngineSettings extends ParserSettings { DependencyResolver getResolver(String from); Collection getResolverNames(); ReportOutputter[] getReportOutputters(); void setLogNotConvertedExclusionRule(boolean log); StatusManager getStatusManager(); boolean logNotConvertedExclusionRule(); PatternMatcher getMatcher(String matcherName); Collection getMatcherNames(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/install/InstallOptions.java000066400000000000000000000054441226750426600256020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.install; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; public class InstallOptions { private boolean transitive = true; private boolean validate = true; private boolean overwrite = false; private boolean installOriginalMetadata = false; private String[] confs = {"*"}; private Filter artifactFilter = FilterHelper.NO_FILTER; private String matcherName = PatternMatcher.EXACT; public boolean isTransitive() { return transitive; } public InstallOptions setTransitive(boolean transitive) { this.transitive = transitive; return this; } public boolean isValidate() { return validate; } public InstallOptions setValidate(boolean validate) { this.validate = validate; return this; } public boolean isOverwrite() { return overwrite; } public InstallOptions setOverwrite(boolean overwrite) { this.overwrite = overwrite; return this; } public Filter getArtifactFilter() { return artifactFilter; } public InstallOptions setArtifactFilter(Filter artifactFilter) { this.artifactFilter = artifactFilter == null ? FilterHelper.NO_FILTER : artifactFilter; return this; } public String getMatcherName() { return matcherName; } public InstallOptions setMatcherName(String matcherName) { this.matcherName = matcherName; return this; } public String[] getConfs() { return confs; } public InstallOptions setConfs(String[] conf) { this.confs = conf; return this; } public boolean isInstallOriginalMetadata() { return installOriginalMetadata; } public InstallOptions setInstallOriginalMetadata(boolean installOriginalMetadata) { this.installOriginalMetadata = installOriginalMetadata; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/000077500000000000000000000000001226750426600215655ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/000077500000000000000000000000001226750426600237435ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/AbstractArtifact.java000066400000000000000000000053141226750426600300320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.Map; /** * */ public abstract class AbstractArtifact implements Artifact { public AbstractArtifact() { } public boolean equals(Object obj) { if (!(obj instanceof Artifact)) { return false; } Artifact art = (Artifact) obj; return getModuleRevisionId().equals(art.getModuleRevisionId()) && getPublicationDate() == null ? (art.getPublicationDate() == null) : getPublicationDate().equals(art.getPublicationDate()) && getName().equals(art.getName()) && getExt().equals(art.getExt()) && getType().equals(art.getType()) && getQualifiedExtraAttributes().equals(art.getQualifiedExtraAttributes()); } public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 33; hash = hash * 17 + getModuleRevisionId().hashCode(); if (getPublicationDate() != null) { hash = hash * 17 + getPublicationDate().hashCode(); } hash = hash * 17 + getName().hashCode(); hash = hash * 17 + getExt().hashCode(); hash = hash * 17 + getType().hashCode(); hash = hash * 17 + getQualifiedExtraAttributes().hashCode(); // CheckStyle:MagicNumber| ON return hash; } public String toString() { return String.valueOf(getId()); } public String getAttribute(String attName) { return getId().getAttribute(attName); } public Map getAttributes() { return getId().getAttributes(); } public String getExtraAttribute(String attName) { return getId().getExtraAttribute(attName); } public Map getExtraAttributes() { return getId().getExtraAttributes(); } public Map getQualifiedExtraAttributes() { return getId().getQualifiedExtraAttributes(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/AbstractIncludeExcludeRule.java000066400000000000000000000060771226750426600320310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.extendable.UnmodifiableExtendableItem; /** * Abstract class used as implementation for both {@link IncludeRule} and {@link ExcludeRule}, since * their contract is almost identical */ public abstract class AbstractIncludeExcludeRule extends UnmodifiableExtendableItem implements ConfigurationAware { private ArtifactId id; private Collection confs = new ArrayList(); private PatternMatcher patternMatcher; public AbstractIncludeExcludeRule(ArtifactId aid, PatternMatcher matcher, Map extraAttributes) { super(null, extraAttributes); id = aid; patternMatcher = matcher; initStandardAttributes(); } private void initStandardAttributes() { setStandardAttribute(IvyPatternHelper.ORGANISATION_KEY, id.getModuleId().getOrganisation()); setStandardAttribute(IvyPatternHelper.MODULE_KEY, id.getModuleId().getName()); setStandardAttribute(IvyPatternHelper.ARTIFACT_KEY, id.getName()); setStandardAttribute(IvyPatternHelper.TYPE_KEY, id.getType()); setStandardAttribute(IvyPatternHelper.EXT_KEY, id.getExt()); setStandardAttribute("matcher", patternMatcher.getName()); } public boolean equals(Object obj) { if (!(obj instanceof AbstractIncludeExcludeRule)) { return false; } AbstractIncludeExcludeRule rule = (AbstractIncludeExcludeRule) obj; return getId().equals(rule.getId()); } public int hashCode() { return getId().hashCode(); } /** * Add a configuration for this rule * * @param conf */ public void addConfiguration(String conf) { confs.add(conf); } public ArtifactId getId() { return id; } public String[] getConfigurations() { return (String[]) confs.toArray(new String[confs.size()]); } public PatternMatcher getMatcher() { return patternMatcher; } public String toString() { return id + "(" + confs + ")"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/Artifact.java000066400000000000000000000063731226750426600263540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.net.URL; import java.util.Date; import org.apache.ivy.core.module.id.ArtifactRevisionId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.extendable.ExtendableItem; /** * Representation of a published 'file' in the development environment. An artifact is generally a * file that is produced by a project build. This is typically a jar, a * war, an ear, a zip, a deb, etc. */ public interface Artifact extends ExtendableItem { /** * Returns the resolved module revision id for this artifact * * @return the resolved module revision id. */ ModuleRevisionId getModuleRevisionId(); /** * Returns the resolved publication date for this artifact * * @return the resolved publication date. Never null. */ Date getPublicationDate(); /** * Return the name of the artifact, generally 'part' of the basename of the file. * * @return the name of the artifact. Never null. */ String getName(); /** * Returns the type of the artifact, typically 'jar', 'source', 'javadoc', 'debian', ... * * @return the type of the artifact. Never null. */ String getType(); /** * Retrieve the extension of the artifact. The extension is without dot (ie. 'jar' and not * '.jar') * * @return the extension of the artifact. Never null. */ String getExt(); /** * Returns the url at which this artifact can be found independently of ivy configuration. This * can be null (and is usually for standard artifacts) * * @return url at which this artifact can be found independently of ivy configuration */ URL getUrl(); /** * Returns the list of configurations where this artifact is associated to. * * @return the list of configuration this artifact is associated to. Never null. */ String[] getConfigurations(); /** * Return the specific identifier of this artifact. * * @return the id of the artifact */ ArtifactRevisionId getId(); /** * Returns true if this artifact represents a module metadata artifact, false if it's a * published artifact * * @return true if this artifact represents a module metadata artifact, false if it's a * published artifact */ boolean isMetadata(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/Configuration.java000066400000000000000000000171401226750426600274200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.extendable.DefaultExtendableItem; /** * Represents a module configuration */ public class Configuration extends DefaultExtendableItem implements InheritableItem { public static final class Visibility { public static final Visibility PUBLIC = new Visibility("public"); public static final Visibility PRIVATE = new Visibility("private"); public static Visibility getVisibility(String name) { if ("private".equals(name)) { return PRIVATE; } else if ("public".equals(name)) { return PUBLIC; } else { throw new IllegalArgumentException("unknwon visibility " + name); } } private String name; private Visibility(String name) { this.name = name; } public String toString() { return name; } } public static Collection/* */findConfigurationExtending(String conf, Configuration[] confs) { Collection extendingConfs = new ArrayList(); for (int i = 0; i < confs.length; i++) { if (confs[i] != null && Arrays.asList(confs[i].getExtends()).contains(conf)) { extendingConfs.add(confs[i]); extendingConfs.addAll(findConfigurationExtending(confs[i].getName(), confs)); } } return extendingConfs; } private String name; private String description; private String[] extendsFrom; private Visibility visibility; private boolean transitive = true; private String deprecated; private ModuleRevisionId sourceModule; /** * Creates a new configuration. * * @param name * the name of the configuration */ public Configuration(String name) { this(name, Visibility.PUBLIC, null, null, true, null); } public Configuration(Configuration source, ModuleRevisionId sourceModule) { this(source.getAttributes(), source.getQualifiedExtraAttributes(), source.getName(), source .getVisibility(), source.getDescription(), source.getExtends(), source .isTransitive(), source.getDeprecated(), sourceModule); } /** * Creates a new configuration. * * @param name * the name of the configuration * @param visibility * the visibility of the configuration * @param description * a description * @param ext * the configurations to extend from * @param transitive * indicates if the configuration is transitive * @param deprecated * the deprecation message */ public Configuration(String name, Visibility visibility, String description, String[] ext, boolean transitive, String deprecated) { this(null, null, name, visibility, description, ext, transitive, deprecated, null); } private Configuration(Map attributes, Map extraAttributes, String name, Visibility visibility, String description, String[] ext, boolean transitive, String deprecated, ModuleRevisionId sourceModule) { super(attributes, extraAttributes); if (name == null) { throw new NullPointerException("null configuration name not allowed"); } if (visibility == null) { throw new NullPointerException("null visibility not allowed"); } this.name = name; this.visibility = visibility; this.description = description; if (ext == null) { extendsFrom = new String[0]; } else { extendsFrom = new String[ext.length]; for (int i = 0; i < ext.length; i++) { extendsFrom[i] = ext[i].trim(); } } this.transitive = transitive; this.deprecated = deprecated; this.sourceModule = sourceModule; } /** * Returns the deprecation message, or null if not specified. * * @return Returns the deprecation message. */ public String getDeprecated() { return deprecated; } /** * @return Returns the description. It may be null. */ public String getDescription() { return description; } /** * @return Returns the extends. May be empty, but never null. */ public String[] getExtends() { return extendsFrom; } /** * @return Returns the name. Never null; */ public String getName() { return name; } /** * @return Returns the visibility. Never null. */ public Visibility getVisibility() { return visibility; } /** * @return Returns the transitive. */ public final boolean isTransitive() { return transitive; } public ModuleRevisionId getSourceModule() { return sourceModule; } public String toString() { return name; } public boolean equals(Object obj) { if (!(obj instanceof Configuration)) { return false; } return ((Configuration) obj).getName().equals(getName()); } public int hashCode() { return getName().hashCode(); } public void replaceWildcards(ModuleDescriptor md) { if (this != md.getConfiguration(name)) { throw new IllegalArgumentException( "The given ModuleDescriptor doesn't own this configuration!"); } Configuration[] configs = md.getConfigurations(); Set newExtends = new LinkedHashSet(); for (int j = 0; j < extendsFrom.length; j++) { if ("*".equals(extendsFrom[j])) { addOther(configs, null, newExtends); } else if ("*(public)".equals(extendsFrom[j])) { addOther(configs, Visibility.PUBLIC, newExtends); } else if ("*(private)".equals(extendsFrom[j])) { addOther(configs, Visibility.PRIVATE, newExtends); } else { newExtends.add(extendsFrom[j]); } } this.extendsFrom = (String[]) newExtends.toArray(new String[newExtends.size()]); } private void addOther(Configuration[] allConfigs, Visibility visibility, Set configs) { for (int i = 0; i < allConfigs.length; i++) { String currentName = allConfigs[i].getName(); if (!name.equals(currentName) && ((visibility == null) || visibility.equals(allConfigs[i].getVisibility()))) { configs.add(currentName); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ConfigurationAware.java000066400000000000000000000030131226750426600303720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; /** * Objects implementing this interface are aware of module configurations, and can thus be added to * configurations, and list their configurations. */ public interface ConfigurationAware { /** * Returns the configurations of the module to which the object is attached * * @return an array of configuration names to which the object is attached */ public String[] getConfigurations(); /** * Tells this object that it will now be part of the given configuration * * @param confName * the name of the configuration to which the object is now attached */ public void addConfiguration(String confName); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ConfigurationGroup.java000066400000000000000000000053301226750426600304330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.Iterator; import java.util.Map; /** * A configuration which is actually a group of several configurations. */ public class ConfigurationGroup extends Configuration { private final Map/* */members; public ConfigurationGroup(String confName, Map /* */members) { super(confName); this.members = members; } /** * Returns the list of configurations' names this object is a group of. *

* This list is built from the configuration name, if some of these configuration names have * actually not been recognized in the module, they will be null when accessed from * {@link #getIntersectedConfiguration(String)}. *

* * @return the list of configurations' names this object is an intersection of. */ public String[] getMembersConfigurationNames() { return (String[]) members.keySet().toArray(new String[members.size()]); } /** * Returns the {@link Configuration} object for the given conf name, or null if the * given conf name is not part of this group or if this conf name isn't defined in the module in * which this group has been built. * * @param confName * the name of the configuration to return. * @return the member {@link Configuration} object for the given conf name */ public Configuration getMemberConfiguration(String confName) { return (Configuration) members.get(confName); } public Visibility getVisibility() { for (Iterator it = members.values().iterator(); it.hasNext();) { Configuration c = (Configuration) it.next(); if (c != null && Visibility.PRIVATE.equals(c.getVisibility())) { return Visibility.PRIVATE; } } return Visibility.PUBLIC; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ConfigurationIntersection.java000066400000000000000000000055631226750426600320150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.Iterator; import java.util.Map; /** * A configuration which is actually the intersection of several configurations. */ public class ConfigurationIntersection extends Configuration { private final Map/* */intersectedConfs; public ConfigurationIntersection(String confName, Map /* */intersectedConfs) { super(confName); this.intersectedConfs = intersectedConfs; } /** * Returns the list of configurations' names this object is an intersection of. *

* This list is built from the configuration name, if some of these configuration names have * actually not been recognized in the module, they will be null when accessed from * {@link #getIntersectedConfiguration(String)}. *

* * @return the list of configurations' names this object is an intersection of. */ public String[] getIntersectedConfigurationNames() { return (String[]) intersectedConfs.keySet().toArray(new String[intersectedConfs.size()]); } /** * Returns the intersected {@link Configuration} object for the given conf name, or * null if the given conf name is not part of this intersection or if this conf * name isn't defined in the module in which this intersection has been built. * * @param confName * the name of the configuration to return. * @return the intersected {@link Configuration} object for the given conf name */ public Configuration getIntersectedConfiguration(String confName) { return (Configuration) intersectedConfs.get(confName); } public Visibility getVisibility() { for (Iterator it = intersectedConfs.values().iterator(); it.hasNext();) { Configuration c = (Configuration) it.next(); if (c != null && Visibility.PRIVATE.equals(c.getVisibility())) { return Visibility.PRIVATE; } } return Visibility.PUBLIC; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultArtifact.java000066400000000000000000000120571226750426600276550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.net.URL; import java.util.Date; import java.util.Map; import org.apache.ivy.core.module.id.ArtifactRevisionId; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * */ public class DefaultArtifact extends AbstractArtifact { public static Artifact newIvyArtifact(ModuleRevisionId mrid, Date pubDate) { return new DefaultArtifact(mrid, pubDate, "ivy", "ivy", "xml", true); } public static Artifact newPomArtifact(ModuleRevisionId mrid, Date pubDate) { return new DefaultArtifact(mrid, pubDate, mrid.getName(), "pom", "pom", true); } public static Artifact cloneWithAnotherExt(Artifact artifact, String newExt) { return cloneWithAnotherTypeAndExt(artifact, artifact.getType(), newExt); } public static Artifact cloneWithAnotherType(Artifact artifact, String newType) { return cloneWithAnotherTypeAndExt(artifact, newType, artifact.getExt()); } public static Artifact cloneWithAnotherTypeAndExt(Artifact artifact, String newType, String newExt) { return new DefaultArtifact(ArtifactRevisionId.newInstance(artifact.getModuleRevisionId(), artifact.getName(), newType, newExt, artifact.getQualifiedExtraAttributes()), artifact.getPublicationDate(), artifact.getUrl(), artifact.isMetadata()); } public static Artifact cloneWithAnotherName(Artifact artifact, String name) { return new DefaultArtifact(ArtifactRevisionId.newInstance(artifact.getModuleRevisionId(), name, artifact.getType(), artifact.getExt(), artifact.getQualifiedExtraAttributes()), artifact.getPublicationDate(), artifact.getUrl(), artifact.isMetadata()); } public static Artifact cloneWithAnotherMrid(Artifact artifact, ModuleRevisionId mrid) { return new DefaultArtifact(ArtifactRevisionId.newInstance(mrid, artifact.getName(), artifact.getType(), artifact.getExt(), artifact.getQualifiedExtraAttributes()), artifact.getPublicationDate(), artifact.getUrl(), artifact.isMetadata()); } private Date publicationDate; private ArtifactRevisionId arid; private URL url; private boolean isMetadata = false; public DefaultArtifact(ModuleRevisionId mrid, Date publicationDate, String name, String type, String ext) { this(mrid, publicationDate, name, type, ext, null, null); } public DefaultArtifact(ModuleRevisionId mrid, Date publicationDate, String name, String type, String ext, boolean isMetadata) { this(mrid, publicationDate, name, type, ext, null, null); this.isMetadata = isMetadata; } public DefaultArtifact(ModuleRevisionId mrid, Date publicationDate, String name, String type, String ext, Map extraAttributes) { this(mrid, publicationDate, name, type, ext, null, extraAttributes); } public DefaultArtifact(ModuleRevisionId mrid, Date publicationDate, String name, String type, String ext, URL url, Map extraAttributes) { this(ArtifactRevisionId.newInstance(mrid, name, type, ext, extraAttributes), publicationDate, url, false); } public DefaultArtifact(ArtifactRevisionId arid, Date publicationDate, URL url, boolean isMetadata) { if (arid == null) { throw new NullPointerException("null arid not allowed"); } if (publicationDate == null) { publicationDate = new Date(); } this.publicationDate = publicationDate; this.arid = arid; this.url = url; this.isMetadata = isMetadata; } public ModuleRevisionId getModuleRevisionId() { return arid.getModuleRevisionId(); } public String getName() { return arid.getName(); } public Date getPublicationDate() { return publicationDate; } public String getType() { return arid.getType(); } public String getExt() { return arid.getExt(); } public ArtifactRevisionId getId() { return arid; } public String[] getConfigurations() { return new String[0]; } public URL getUrl() { return url; } public boolean isMetadata() { return isMetadata; } } DefaultDependencyArtifactDescriptor.java000066400000000000000000000067121226750426600336350ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.util.Checks; import org.apache.ivy.util.extendable.UnmodifiableExtendableItem; public class DefaultDependencyArtifactDescriptor extends UnmodifiableExtendableItem implements DependencyArtifactDescriptor, ConfigurationAware { private Collection confs = new ArrayList(); private URL url; private String name; private String type; private String ext; private DependencyDescriptor dd; /** * @param dd * @param name * @param type * @param url */ public DefaultDependencyArtifactDescriptor(DependencyDescriptor dd, String name, String type, String ext, URL url, Map extraAttributes) { super(null, extraAttributes); Checks.checkNotNull(dd, "dd"); Checks.checkNotNull(name, "name"); Checks.checkNotNull(type, "type"); Checks.checkNotNull(ext, "ext"); this.dd = dd; this.name = name; this.type = type; this.ext = ext; this.url = url; initStandardAttributes(); } private void initStandardAttributes() { setStandardAttribute(IvyPatternHelper.ARTIFACT_KEY, getName()); setStandardAttribute(IvyPatternHelper.TYPE_KEY, getType()); setStandardAttribute(IvyPatternHelper.EXT_KEY, getExt()); setStandardAttribute("url", url != null ? String.valueOf(url) : ""); } public boolean equals(Object obj) { if (!(obj instanceof DependencyArtifactDescriptor)) { return false; } DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor) obj; return getAttributes().equals(dad.getAttributes()); } public int hashCode() { return getAttributes().hashCode(); } /** * Add a configuration for this artifact. * * @param conf */ public void addConfiguration(String conf) { confs.add(conf); } public DependencyDescriptor getDependencyDescriptor() { return dd; } public String getName() { return name; } public String getType() { return type; } public String getExt() { return ext; } public String[] getConfigurations() { return (String[]) confs.toArray(new String[confs.size()]); } public URL getUrl() { return url; } public String toString() { return "DA:" + name + "." + ext + "(" + type + ") " + "(" + confs + ")" + (url == null ? "" : url.toString()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultDependencyDescriptor.java000066400000000000000000000705531226750426600322420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.namespace.NamespaceTransformer; import org.apache.ivy.util.Checks; /** * This class can be used as the default implementation for DependencyDescriptor. It implements * required methods and enables to fill dependency information with the addDependencyConfiguration * method. */ public class DefaultDependencyDescriptor implements DependencyDescriptor { private static final Pattern SELF_FALLBACK_PATTERN = Pattern .compile("@(\\+[^\\(]+)?(\\(.*\\))?"); private static final Pattern THIS_FALLBACK_PATTERN = Pattern .compile("#(\\+[^\\(]+)?(\\(.*\\))?"); /** * Transforms the given dependency descriptor of the given namespace and return a new dependency * descriptor in the system namespace. Note that exclude rules are not converted in system * namespace, because they aren't transformable (the name space hasn't the ability to convert * regular expressions). However, method doesExclude will work with system artifacts. * * @param dd * @param ns * @return */ public static DependencyDescriptor transformInstance(DependencyDescriptor dd, Namespace ns) { NamespaceTransformer t = ns.getToSystemTransformer(); if (t.isIdentity()) { return dd; } DefaultDependencyDescriptor newdd = transformInstance(dd, t, false); newdd.namespace = ns; return newdd; } /** * Transforms a dependency descriptor using the given transformer. Note that no namespace info * will be attached to the transformed dependency descriptor, so calling doesExclude is not * recommended (doesExclude only works when namespace is properly set) * * @param dd * @param t * @return */ public static DefaultDependencyDescriptor transformInstance(DependencyDescriptor dd, NamespaceTransformer t, boolean fromSystem) { ModuleRevisionId transformParentId = t.transform(dd.getParentRevisionId()); ModuleRevisionId transformMrid = t.transform(dd.getDependencyRevisionId()); ModuleRevisionId transformDynamicMrid = t.transform(dd .getDynamicConstraintDependencyRevisionId()); DefaultDependencyDescriptor newdd = new DefaultDependencyDescriptor(null, transformMrid, transformDynamicMrid, dd.isForce(), dd.isChanging(), dd.isTransitive()); newdd.parentId = transformParentId; ModuleRevisionId sourceModule = dd.getSourceModule(); if (sourceModule != null) { newdd.sourceModule = t.transform(sourceModule); } String[] moduleConfs = dd.getModuleConfigurations(); if (moduleConfs.length == 1 && "*".equals(moduleConfs[0])) { if (dd instanceof DefaultDependencyDescriptor) { DefaultDependencyDescriptor ddd = (DefaultDependencyDescriptor) dd; newdd.confs = new LinkedHashMap(ddd.confs); newdd.setExcludeRules(new LinkedHashMap(ddd.getExcludeRules())); newdd.setIncludeRules(new LinkedHashMap(ddd.getIncludeRules())); newdd.setDependencyArtifacts(new LinkedHashMap(ddd.getDependencyArtifacts())); } else { throw new IllegalArgumentException( "dependency descriptor transformation does not support * module confs " + "with descriptors which aren't DefaultDependencyDescriptor"); } } else { for (int i = 0; i < moduleConfs.length; i++) { newdd.confs.put(moduleConfs[i], new ArrayList(Arrays.asList(dd.getDependencyConfigurations(moduleConfs[i])))); newdd.getExcludeRules().put(moduleConfs[i], new ArrayList(Arrays.asList(dd.getExcludeRules(moduleConfs[i])))); newdd.getIncludeRules().put(moduleConfs[i], new ArrayList(Arrays.asList(dd.getIncludeRules(moduleConfs[i])))); newdd.getDependencyArtifacts().put(moduleConfs[i], new ArrayList(Arrays.asList(dd.getDependencyArtifacts(moduleConfs[i])))); } } if (fromSystem) { newdd.asSystem = dd; } return newdd; } private final ModuleRevisionId revId; private ModuleRevisionId dynamicRevId; private Map/* > */confs = new LinkedHashMap(); // Map (String masterConf -> Collection(DependencyArtifactDescriptor)) private Map dependencyArtifacts; // initialized on demand only for memory consumption reason // Map (String masterConf -> Collection(IncludeRule)) private Map includeRules; // initialized on demand only for memory consumption reason // Map (String masterConf -> Collection(ExcludeRule)) private Map excludeRules; // initialized on demand only for memory consumption reason /** * Used to indicate that this revision must be used in case of conflicts, independently of * conflicts manager */ private boolean isForce; /** * Used to indicate that the dependency is a changing one, i.e. that ivy should not rely on the * version to know if it can trust artifacts in cache */ private boolean isChanging; private ModuleRevisionId parentId; private boolean isTransitive = true; /** * This namespace should be used to check */ private Namespace namespace = null; private final ModuleDescriptor md; private DependencyDescriptor asSystem = this; private ModuleRevisionId sourceModule; private DefaultDependencyDescriptor(DefaultDependencyDescriptor dd, ModuleRevisionId revision) { Checks.checkNotNull(dd, "dd"); Checks.checkNotNull(revision, "revision"); if (!revision.getModuleId().equals(dd.getDependencyId())) { throw new IllegalArgumentException( "new ModuleRevisionId MUST have the same ModuleId as original one." + " original = " + dd.getDependencyId() + " new = " + revision.getModuleId()); } md = dd.md; parentId = dd.parentId; revId = revision; dynamicRevId = dd.dynamicRevId; isForce = dd.isForce; isChanging = dd.isChanging; isTransitive = dd.isTransitive; namespace = dd.namespace; confs.putAll(dd.confs); excludeRules = dd.excludeRules == null ? null : new LinkedHashMap(dd.excludeRules); includeRules = dd.includeRules == null ? null : new LinkedHashMap(dd.includeRules); dependencyArtifacts = dd.dependencyArtifacts == null ? null : new LinkedHashMap( dd.dependencyArtifacts); sourceModule = dd.sourceModule; } public DefaultDependencyDescriptor(ModuleDescriptor md, ModuleRevisionId mrid, boolean force, boolean changing, boolean transitive) { this(md, mrid, mrid, force, changing, transitive); } public DefaultDependencyDescriptor(ModuleRevisionId mrid, boolean force) { this(mrid, force, false); } public DefaultDependencyDescriptor(ModuleRevisionId mrid, boolean force, boolean changing) { this(null, mrid, mrid, force, changing, true); } public DefaultDependencyDescriptor(ModuleDescriptor md, ModuleRevisionId mrid, ModuleRevisionId dynamicConstraint, boolean force, boolean changing, boolean transitive) { Checks.checkNotNull(mrid, "mrid"); Checks.checkNotNull(dynamicConstraint, "dynamicConstraint"); this.md = md; revId = mrid; dynamicRevId = dynamicConstraint; isForce = force; isChanging = changing; isTransitive = transitive; sourceModule = md == null ? null : md.getModuleRevisionId(); } public ModuleId getDependencyId() { return getDependencyRevisionId().getModuleId(); } public ModuleRevisionId getDependencyRevisionId() { return revId; } public ModuleRevisionId getDynamicConstraintDependencyRevisionId() { return dynamicRevId; } public String[] getModuleConfigurations() { return (String[]) confs.keySet().toArray(new String[confs.keySet().size()]); } public String[] getDependencyConfigurations(String moduleConfiguration) { return getDependencyConfigurations(moduleConfiguration, moduleConfiguration); } /** * Return the dependency configurations mapped to the given moduleConfiguration, actually * resolved because of the given requestedConfiguration *

* Usually requestedConfiguration and moduleConfiguration are the same, except when a conf * extends another, then the moduleConfiguration is the configuration currently resolved (the * extended one), and requestedConfiguration is the one actually requested initially (the * extending one). Both moduleConfiguration and requestedConfiguration are configurations of the * caller, the array returned is composed of the required configurations of the dependency * described by this descriptor. */ public String[] getDependencyConfigurations(String moduleConfiguration, String requestedConfiguration) { if (md != null) { Configuration c = md.getConfiguration(moduleConfiguration); if (c instanceof ConfigurationIntersection) { ConfigurationIntersection intersection = (ConfigurationIntersection) c; Set /* */intersectedDepConfs = new HashSet(); String[] intersected = intersection.getIntersectedConfigurationNames(); for (int i = 0; i < intersected.length; i++) { Collection depConfs = getDependencyConfigurationsIncludingExtending( intersected[i], requestedConfiguration); if (intersectedDepConfs.isEmpty()) { intersectedDepConfs.addAll(depConfs); } else { if (intersectedDepConfs.contains("*")) { intersectedDepConfs.remove("*"); intersectedDepConfs.addAll(depConfs); } else if (depConfs.contains("*")) { // nothing to do, intersection of 'something' // with 'everything' is 'something' } else { Set /* */intersectedDepConfsCopy = intersectedDepConfs; intersectedDepConfs = new HashSet(); for (Iterator it = intersectedDepConfsCopy.iterator(); it.hasNext();) { String intersectedDepConf = (String) it.next(); if (depConfs.contains(intersectedDepConf)) { // the conf is present in both sets, // so it is in the intersection intersectedDepConfs.add(intersectedDepConf); continue; } /* * we do not handle special confs like *!sg or [cond]* in right hand * confs yet: it would require supporting parenthesis grouping in * configurations intersection interpretation * * for (Iterator it2 = depConfs.iterator(); it2.hasNext();) { String * depConf = (String) it2.next(); if (depConf.startsWith("*")) { if * (intersectedDepConf .indexOf("(" + depConf + ")") != -1) { * intersectedDepConfs.add(intersectedDepConf); } else { * intersectedDepConfs.add( "(" + intersectedDepConf + ")+(" + * depConf + ")"); } } else if (intersectedDepConf.startsWith("*")) * { if (depConf .indexOf("(" + intersectedDepConf + ")") != -1) { * intersectedDepConfs.add(depConf); } else { * intersectedDepConfs.add( depConf + "+" + intersectedDepConf); } } * } */ } } } } List confsList = (List) confs.get(moduleConfiguration); if (confsList != null) { intersectedDepConfs.addAll(confsList); } if (intersectedDepConfs.isEmpty()) { List defConfs = (List) confs.get("*"); if (defConfs != null) { for (Iterator it = defConfs.iterator(); it.hasNext();) { String mappedConf = (String) it.next(); if (mappedConf != null && mappedConf.startsWith("@+")) { return new String[] {moduleConfiguration + mappedConf.substring(1)}; } else if (mappedConf != null && mappedConf.equals("@")) { return new String[] {moduleConfiguration}; } } } } return (String[]) intersectedDepConfs .toArray(new String[intersectedDepConfs.size()]); } else if (c instanceof ConfigurationGroup) { ConfigurationGroup group = (ConfigurationGroup) c; Set /* */groupDepConfs = new HashSet(); String[] members = group.getMembersConfigurationNames(); for (int i = 0; i < members.length; i++) { Collection depConfs = getDependencyConfigurationsIncludingExtending(members[i], requestedConfiguration); groupDepConfs.addAll(depConfs); } return (String[]) groupDepConfs.toArray(new String[groupDepConfs.size()]); } } List confsList = (List) confs.get(moduleConfiguration); if (confsList == null) { // there is no mapping defined for this configuration, add the 'other' mappings. confsList = (List) confs.get("%"); } List defConfs = (List) confs.get("*"); Collection ret = new LinkedHashSet(); if (confsList != null) { ret.addAll(confsList); } if (defConfs != null) { ret.addAll(defConfs); } Collection replacedRet = new LinkedHashSet(); for (Iterator iter = ret.iterator(); iter.hasNext();) { String c = (String) iter.next(); String replacedConf = replaceSelfFallbackPattern(c, moduleConfiguration); if (replacedConf == null) { replacedConf = replaceThisFallbackPattern(c, requestedConfiguration); } if (replacedConf != null) { c = replacedConf; } replacedRet.add(c); } ret = replacedRet; if (ret.remove("*")) { StringBuffer r = new StringBuffer("*"); // merge excluded configurations as one conf like *!A!B for (Iterator iter = ret.iterator(); iter.hasNext();) { String c = (String) iter.next(); if (c.startsWith("!")) { r.append(c); } } return new String[] {r.toString()}; } return (String[]) ret.toArray(new String[ret.size()]); } private Collection getDependencyConfigurationsIncludingExtending(String conf, String requestedConfiguration) { Set/* */allDepConfs = new LinkedHashSet(); allDepConfs .addAll(Arrays.asList(getDependencyConfigurations(conf, requestedConfiguration))); Collection extendingConfs = Configuration.findConfigurationExtending(conf, md.getConfigurations()); for (Iterator it = extendingConfs.iterator(); it.hasNext();) { Configuration extendingConf = (Configuration) it.next(); allDepConfs.addAll(Arrays.asList(getDependencyConfigurations(extendingConf.getName(), requestedConfiguration))); } return allDepConfs; } protected static String replaceSelfFallbackPattern(final String conf, final String moduleConfiguration) { return replaceFallbackConfigurationPattern(SELF_FALLBACK_PATTERN, conf, moduleConfiguration); } protected static String replaceThisFallbackPattern(final String conf, final String requestedConfiguration) { return replaceFallbackConfigurationPattern(THIS_FALLBACK_PATTERN, conf, requestedConfiguration); } /** * Replaces fallback patterns with correct values if fallback pattern exists. * * @param pattern * pattern to look for * @param conf * configuration mapping from dependency element * @param moduleConfiguration * module's configuration to use for replacement * @return Replaced string if pattern matched. Otherwise null. */ protected static String replaceFallbackConfigurationPattern(final Pattern pattern, final String conf, final String moduleConfiguration) { Matcher matcher = pattern.matcher(conf); if (matcher.matches()) { String mappedConf = moduleConfiguration; if (matcher.group(1) != null) { mappedConf = mappedConf + matcher.group(1); } if (matcher.group(2) != null) { mappedConf = mappedConf + matcher.group(2); } return mappedConf; } return null; } public String[] getDependencyConfigurations(String[] moduleConfigurations) { Set confs = new LinkedHashSet(); for (int i = 0; i < moduleConfigurations.length; i++) { confs.addAll(Arrays.asList(getDependencyConfigurations(moduleConfigurations[i]))); } if (confs.contains("*")) { return new String[] {"*"}; } return (String[]) confs.toArray(new String[confs.size()]); } public DependencyArtifactDescriptor[] getDependencyArtifacts(String moduleConfiguration) { Collection artifacts = getCollectionForConfiguration(moduleConfiguration, dependencyArtifacts); return (DependencyArtifactDescriptor[]) artifacts .toArray(new DependencyArtifactDescriptor[artifacts.size()]); } public IncludeRule[] getIncludeRules(String moduleConfiguration) { Collection rules = getCollectionForConfiguration(moduleConfiguration, includeRules); return (IncludeRule[]) rules.toArray(new IncludeRule[rules.size()]); } public ExcludeRule[] getExcludeRules(String moduleConfiguration) { Collection rules = getCollectionForConfiguration(moduleConfiguration, excludeRules); return (ExcludeRule[]) rules.toArray(new ExcludeRule[rules.size()]); } private Set getCollectionForConfiguration(String moduleConfiguration, Map collectionMap) { if (collectionMap == null || collectionMap.isEmpty()) { return Collections.EMPTY_SET; } Collection artifacts = (Collection) collectionMap.get(moduleConfiguration); Collection defArtifacts = (Collection) collectionMap.get("*"); Set ret = new LinkedHashSet(); if (artifacts != null) { ret.addAll(artifacts); } if (defArtifacts != null) { ret.addAll(defArtifacts); } return ret; } public DependencyArtifactDescriptor[] getDependencyArtifacts(String[] moduleConfigurations) { Set artifacts = new LinkedHashSet(); for (int i = 0; i < moduleConfigurations.length; i++) { artifacts.addAll(Arrays.asList(getDependencyArtifacts(moduleConfigurations[i]))); } return (DependencyArtifactDescriptor[]) artifacts .toArray(new DependencyArtifactDescriptor[artifacts.size()]); } public IncludeRule[] getIncludeRules(String[] moduleConfigurations) { Set rules = new LinkedHashSet(); for (int i = 0; i < moduleConfigurations.length; i++) { rules.addAll(Arrays.asList(getIncludeRules(moduleConfigurations[i]))); } return (IncludeRule[]) rules.toArray(new IncludeRule[rules.size()]); } public ExcludeRule[] getExcludeRules(String[] moduleConfigurations) { Set rules = new LinkedHashSet(); for (int i = 0; i < moduleConfigurations.length; i++) { rules.addAll(Arrays.asList(getExcludeRules(moduleConfigurations[i]))); } return (ExcludeRule[]) rules.toArray(new ExcludeRule[rules.size()]); } public DependencyArtifactDescriptor[] getAllDependencyArtifacts() { if (dependencyArtifacts == null) { return new DependencyArtifactDescriptor[0]; } Set ret = mergeAll(dependencyArtifacts); return (DependencyArtifactDescriptor[]) ret.toArray(new DependencyArtifactDescriptor[ret .size()]); } public IncludeRule[] getAllIncludeRules() { if (includeRules == null) { return new IncludeRule[0]; } Set ret = mergeAll(includeRules); return (IncludeRule[]) ret.toArray(new IncludeRule[ret.size()]); } public ExcludeRule[] getAllExcludeRules() { if (excludeRules == null) { return new ExcludeRule[0]; } Set ret = mergeAll(excludeRules); return (ExcludeRule[]) ret.toArray(new ExcludeRule[ret.size()]); } private Set mergeAll(Map artifactsMap) { Set ret = new LinkedHashSet(); for (Iterator it = artifactsMap.values().iterator(); it.hasNext();) { Collection artifacts = (Collection) it.next(); ret.addAll(artifacts); } return ret; } public void addDependencyConfiguration(String masterConf, String depConf) { if ((md != null) && !"*".equals(masterConf) && !"%".equals(masterConf)) { Configuration config; if (masterConf.startsWith("!")) { config = md.getConfiguration(masterConf.substring(1)); } else { config = md.getConfiguration(masterConf); } if (config == null) { throw new IllegalArgumentException("Cannot add dependency '" + revId + "' to configuration '" + masterConf + "' of module " + md.getModuleRevisionId() + " because this configuration doesn't exist!"); } if (config instanceof ConfigurationGroup) { ConfigurationGroup group = (ConfigurationGroup) config; String[] members = group.getMembersConfigurationNames(); for (int i = 0; i < members.length; i++) { addDependencyConfiguration(members[i], depConf); } return; } } List confsList = (List) confs.get(masterConf); if (confsList == null) { confsList = new ArrayList(); confs.put(masterConf, confsList); } if (!confsList.contains(depConf)) { confsList.add(depConf); } } public void addDependencyArtifact(String masterConf, DependencyArtifactDescriptor dad) { addObjectToConfiguration(masterConf, dad, getDependencyArtifacts()); } public void addIncludeRule(String masterConf, IncludeRule rule) { addObjectToConfiguration(masterConf, rule, getIncludeRules()); } public void addExcludeRule(String masterConf, ExcludeRule rule) { addObjectToConfiguration(masterConf, rule, getExcludeRules()); } private void addObjectToConfiguration(String callerConf, Object toAdd, Map confsMap) { Collection col = (Collection) confsMap.get(callerConf); if (col == null) { col = new ArrayList(); confsMap.put(callerConf, col); } col.add(toAdd); } /** * only works when namespace is properly set. The behaviour is not specified if namespace is not * set */ public boolean doesExclude(String[] moduleConfigurations, ArtifactId artifactId) { if (namespace != null) { artifactId = NameSpaceHelper .transform(artifactId, namespace.getFromSystemTransformer()); } ExcludeRule[] rules = getExcludeRules(moduleConfigurations); for (int i = 0; i < rules.length; i++) { if (MatcherHelper.matches(rules[i].getMatcher(), rules[i].getId(), artifactId)) { return true; } } return false; } /** * Returns true if this descriptor contains any exclusion rule * * @return */ public boolean canExclude() { return excludeRules != null && !excludeRules.isEmpty(); } public String toString() { return "dependency: " + revId + " " + confs; } public boolean isForce() { return isForce; } public ModuleRevisionId getParentRevisionId() { return md != null ? md.getResolvedModuleRevisionId() : parentId; } public boolean isChanging() { return isChanging; } public boolean isTransitive() { return isTransitive; } public Namespace getNamespace() { return namespace; } public String getAttribute(String attName) { return revId.getAttribute(attName); } public Map getAttributes() { return revId.getAttributes(); } public String getExtraAttribute(String attName) { return revId.getExtraAttribute(attName); } public Map getExtraAttributes() { return revId.getExtraAttributes(); } public Map getQualifiedExtraAttributes() { return revId.getQualifiedExtraAttributes(); } public DependencyDescriptor asSystem() { return asSystem; } private void setDependencyArtifacts(Map dependencyArtifacts) { this.dependencyArtifacts = dependencyArtifacts; } private Map getDependencyArtifacts() { if (dependencyArtifacts == null) { dependencyArtifacts = new LinkedHashMap(); } return dependencyArtifacts; } private void setIncludeRules(Map includeRules) { this.includeRules = includeRules; } private Map getIncludeRules() { if (includeRules == null) { includeRules = new LinkedHashMap(); } return includeRules; } private void setExcludeRules(Map excludeRules) { this.excludeRules = excludeRules; } private Map getExcludeRules() { if (excludeRules == null) { excludeRules = new LinkedHashMap(); } return excludeRules; } public ModuleRevisionId getSourceModule() { return sourceModule; } public DependencyDescriptor clone(ModuleRevisionId revision) { return new DefaultDependencyDescriptor(this, revision); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultExcludeRule.java000066400000000000000000000024361226750426600303410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.Map; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.plugins.matcher.PatternMatcher; public class DefaultExcludeRule extends AbstractIncludeExcludeRule implements ExcludeRule { public DefaultExcludeRule(ArtifactId aid, PatternMatcher matcher, Map extraAttributes) { super(aid, matcher, extraAttributes); } public String toString() { return "E:" + super.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultExtendsDescriptor.java000066400000000000000000000054311226750426600315670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.ArrayList; import java.util.List; import org.apache.ivy.core.module.id.ModuleRevisionId; public class DefaultExtendsDescriptor implements ExtendsDescriptor { private ModuleDescriptor parent; private String location; private List extendsTypes; private boolean local; public DefaultExtendsDescriptor(ModuleDescriptor parent, String location, String[] types) { this(parent, location, types, false); } public DefaultExtendsDescriptor(ModuleDescriptor parent, String location, String[] types, boolean local) { this.parent = parent; this.location = location; this.local = local; this.extendsTypes = new ArrayList(types.length); for (int i = 0; i < types.length; ++i) { extendsTypes.add(types[i]); } } public ModuleRevisionId getParentRevisionId() { return parent.getModuleRevisionId(); } public ModuleRevisionId getResolvedParentRevisionId() { return parent.getResolvedModuleRevisionId(); } public ModuleDescriptor getParentMd() { return parent; } public String getLocation() { return location; } public String[] getExtendsTypes() { return (String[]) extendsTypes.toArray(new String[extendsTypes.size()]); } public boolean isAllInherited() { return extendsTypes.contains("all"); } public boolean isInfoInherited() { return isAllInherited() || extendsTypes.contains("info"); } public boolean isDescriptionInherited() { return isAllInherited() || extendsTypes.contains("description"); } public boolean areConfigurationsInherited() { return isAllInherited() || extendsTypes.contains("configurations"); } public boolean areDependenciesInherited() { return isAllInherited() || extendsTypes.contains("dependencies"); } public boolean isLocal() { return local; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultIncludeRule.java000066400000000000000000000024361226750426600303330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.Map; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.plugins.matcher.PatternMatcher; public class DefaultIncludeRule extends AbstractIncludeExcludeRule implements IncludeRule { public DefaultIncludeRule(ArtifactId aid, PatternMatcher matcher, Map extraAttributes) { super(aid, matcher, extraAttributes); } public String toString() { return "I:" + super.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DefaultModuleDescriptor.java000066400000000000000000000752411226750426600314100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.namespace.NamespaceTransformer; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; /** * */ public class DefaultModuleDescriptor implements ModuleDescriptor { public static DefaultModuleDescriptor newDefaultInstance(ModuleRevisionId mrid) { return newDefaultInstance(mrid, null); } public static DefaultModuleDescriptor newCallerInstance(ModuleRevisionId mrid, String[] confs, boolean transitive, boolean changing) { DefaultModuleDescriptor moduleDescriptor = new DefaultModuleDescriptor( ModuleRevisionId.newInstance(mrid.getOrganisation(), mrid.getName() + "-caller", "working"), "integration", null, true); for (int i = 0; i < confs.length; i++) { moduleDescriptor.addConfiguration(new Configuration(confs[i])); } moduleDescriptor.setLastModified(System.currentTimeMillis()); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(moduleDescriptor, mrid, true, changing, transitive); for (int j = 0; j < confs.length; j++) { dd.addDependencyConfiguration(confs[j], confs[j]); } moduleDescriptor.addDependency(dd); return moduleDescriptor; } public static DefaultModuleDescriptor newCallerInstance(ModuleRevisionId[] mrid, boolean transitive, boolean changing) { DefaultModuleDescriptor moduleDescriptor = new DefaultModuleDescriptor( ModuleRevisionId.newInstance("caller", "all-caller", "working"), "integration", null, true); moduleDescriptor.addConfiguration(new Configuration(DEFAULT_CONFIGURATION)); moduleDescriptor.setLastModified(System.currentTimeMillis()); for (int i = 0; i < mrid.length; i++) { DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(moduleDescriptor, mrid[i], true, changing, transitive); dd.addDependencyConfiguration(DEFAULT_CONFIGURATION, "*"); moduleDescriptor.addDependency(dd); } return moduleDescriptor; } public static DefaultModuleDescriptor newDefaultInstance(ModuleRevisionId mrid, DependencyArtifactDescriptor[] artifacts) { DefaultModuleDescriptor moduleDescriptor = new DefaultModuleDescriptor(mrid, "release", null, true); moduleDescriptor.addConfiguration(new Configuration(DEFAULT_CONFIGURATION)); if (artifacts != null && artifacts.length > 0) { for (int i = 0; i < artifacts.length; i++) { moduleDescriptor.addArtifact(DEFAULT_CONFIGURATION, new MDArtifact(moduleDescriptor, artifacts[i].getName(), artifacts[i].getType(), artifacts[i].getExt(), artifacts[i].getUrl(), artifacts[i].getExtraAttributes())); } } else { moduleDescriptor.addArtifact(DEFAULT_CONFIGURATION, new MDArtifact(moduleDescriptor, mrid.getName(), "jar", "jar")); } moduleDescriptor.setLastModified(System.currentTimeMillis()); return moduleDescriptor; } public static DefaultModuleDescriptor newBasicInstance(ModuleRevisionId mrid, Date publicationDate) { DefaultModuleDescriptor moduleDescriptor = new DefaultModuleDescriptor(mrid, "release", publicationDate, false); moduleDescriptor.addConfiguration(new Configuration(DEFAULT_CONFIGURATION)); moduleDescriptor.addArtifact(DEFAULT_CONFIGURATION, new MDArtifact(moduleDescriptor, mrid.getName(), "jar", "jar")); return moduleDescriptor; } /** * Transforms the given module descriptor of the given namespace and return a new module * descriptor in the system namespace. Note that dependency exclude rules are not converted * in system namespace, because they aren't transformable (the name space hasn't the ability to * convert regular expressions) * * @param md * @param ns * @return */ public static ModuleDescriptor transformInstance(ModuleDescriptor md, Namespace ns) { NamespaceTransformer t = ns.getToSystemTransformer(); if (t.isIdentity()) { return md; } DefaultModuleDescriptor nmd = new DefaultModuleDescriptor(md.getParser(), md.getResource()); nmd.revId = t.transform(md.getModuleRevisionId()); nmd.resolvedRevId = t.transform(md.getResolvedModuleRevisionId()); nmd.status = md.getStatus(); nmd.publicationDate = md.getPublicationDate(); nmd.resolvedPublicationDate = md.getResolvedPublicationDate(); ExtendsDescriptor[] ed = md.getInheritedDescriptors(); for (int i = 0; i < ed.length; ++i) { ModuleDescriptor parentMd = ed[i].getParentMd(); DefaultModuleDescriptor parentNmd = new DefaultModuleDescriptor(parentMd.getParser(), parentMd.getResource()); parentNmd.revId = t.transform(parentMd.getModuleRevisionId()); parentNmd.resolvedRevId = t.transform(parentMd.getResolvedModuleRevisionId()); parentNmd.status = parentMd.getStatus(); parentNmd.publicationDate = parentMd.getPublicationDate(); parentNmd.resolvedPublicationDate = parentMd.getResolvedPublicationDate(); nmd.inheritedDescriptors.add(new DefaultExtendsDescriptor(parentNmd, ed[i] .getLocation(), ed[i].getExtendsTypes())); } DependencyDescriptor[] dd = md.getDependencies(); for (int i = 0; i < dd.length; i++) { nmd.dependencies.add(NameSpaceHelper.toSystem(dd[i], ns)); } Configuration[] confs = md.getConfigurations(); for (int i = 0; i < confs.length; i++) { nmd.configurations.put(confs[i].getName(), confs[i]); Artifact[] arts = md.getArtifacts(confs[i].getName()); for (int j = 0; j < arts.length; j++) { nmd.addArtifact(confs[i].getName(), NameSpaceHelper.transform(arts[j], t)); } } nmd.setDefault(md.isDefault()); if (md instanceof DefaultModuleDescriptor) { DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md; nmd.conflictManagers = (ModuleRules) dmd.conflictManagers.clone(); nmd.dependencyDescriptorMediators = (ModuleRules) dmd.dependencyDescriptorMediators .clone(); } else { Message.warn("transformed module descriptor is not a default module descriptor: " + "impossible to copy conflict manager and version mediation configuration: " + md); } nmd.licenses.addAll(Arrays.asList(md.getLicenses())); nmd.homePage = md.getHomePage(); nmd.description = md.getDescription(); nmd.lastModified = md.getLastModified(); nmd.extraAttributesNamespaces = md.getExtraAttributesNamespaces(); nmd.extraInfo = md.getExtraInfo(); nmd.extraInfos = md.getExtraInfos(); nmd.namespace = ns; return nmd; } private ModuleRevisionId revId; private ModuleRevisionId resolvedRevId; private String status = StatusManager.getCurrent().getDefaultStatus(); private Date publicationDate; private Date resolvedPublicationDate; private List dependencies = new ArrayList(); // List (DependencyDescriptor) private Map configurations = new LinkedHashMap(); // Map(String conf -> Configuration) private Map artifactsByConf = new HashMap(); // Map (String conf -> Collection(Artifact)) private Collection artifacts = new LinkedHashSet(); // Collection(Artifact) // all artifacts could also be found in the artifactsByConf map, but here we can // preserve the order private boolean isDefault = false; private ModuleRules conflictManagers = new ModuleRules(); private ModuleRules dependencyDescriptorMediators = new ModuleRules(); private List licenses = new ArrayList(); // List(License) private String homePage; private String description = ""; private long lastModified = 0; private Namespace namespace; private String defaultConf; private String defaultConfMapping; private boolean mappingOverride; private ModuleDescriptorParser parser; private Resource resource; private List excludeRules = new ArrayList(); // List(ExcludeRule) private Artifact metadataArtifact; private List inheritedDescriptors = new ArrayList(); // List(ExtendsDescriptor) private Map/* */extraAttributesNamespaces = new LinkedHashMap(); private Map/* */extraInfo = new HashMap(); private List extraInfos = new ArrayList(); public DefaultModuleDescriptor(ModuleRevisionId id, String status, Date pubDate) { this(id, status, pubDate, false); } public DefaultModuleDescriptor(ModuleRevisionId id, String status, Date pubDate, boolean isDefault) { if (id == null) { throw new NullPointerException("null module revision id not allowed"); } if (status == null) { throw new NullPointerException("null status not allowed"); } this.revId = id; this.resolvedRevId = id; this.status = status; this.publicationDate = pubDate; this.resolvedPublicationDate = publicationDate == null ? new Date() : publicationDate; this.isDefault = isDefault; this.parser = XmlModuleDescriptorParser.getInstance(); } /** * IMPORTANT : at least call setModuleRevisionId and setResolvedPublicationDate with instances * created by this constructor ! */ public DefaultModuleDescriptor(ModuleDescriptorParser parser, Resource res) { this.parser = parser; resource = res; } public Artifact getMetadataArtifact() { if (metadataArtifact == null) { metadataArtifact = DefaultArtifact.newIvyArtifact(resolvedRevId, resolvedPublicationDate); } return metadataArtifact; } public void setModuleArtifact(Artifact moduleArtifact) { this.metadataArtifact = moduleArtifact; } public boolean isDefault() { return isDefault; } public void setPublicationDate(Date publicationDate) { this.publicationDate = publicationDate; if (resolvedPublicationDate == null) { resolvedPublicationDate = publicationDate == null ? new Date() : publicationDate; } } public Date getPublicationDate() { return publicationDate; } public void setResolvedPublicationDate(Date publicationDate) { if (publicationDate == null) { throw new NullPointerException("null publication date not allowed"); } resolvedPublicationDate = publicationDate; } public Date getResolvedPublicationDate() { return resolvedPublicationDate; } public String getRevision() { return getResolvedModuleRevisionId().getRevision(); } public void setModuleRevisionId(ModuleRevisionId revId) { if (revId == null) { throw new NullPointerException("null module revision id not allowed"); } this.revId = revId; if (resolvedRevId == null) { resolvedRevId = revId; } } public void setResolvedModuleRevisionId(ModuleRevisionId revId) { resolvedRevId = revId; } public void setStatus(String status) { this.status = status; } public void addInheritedDescriptor(ExtendsDescriptor descriptor) { inheritedDescriptors.add(descriptor); } public void addDependency(DependencyDescriptor dependency) { dependencies.add(dependency); } public void addConfiguration(Configuration conf) { configurations.put(conf.getName(), conf); } /** * Artifact configurations are not used since added artifact may not be entirely completed, so * its configurations data may not be accurate * * @param conf * @param artifact */ public void addArtifact(String conf, Artifact artifact) { Configuration c = getConfiguration(conf); if (c == null) { throw new IllegalArgumentException("Cannot add artifact '" + artifact.getId().getArtifactId().getShortDescription() + "' to configuration '" + conf + "' of module " + revId + " because this configuration doesn't exist!"); } if (c instanceof ConfigurationGroup) { ConfigurationGroup group = (ConfigurationGroup) c; String[] members = group.getMembersConfigurationNames(); for (int i = 0; i < members.length; i++) { addArtifact(members[i], artifact); } } else { Collection artifacts = (Collection) artifactsByConf.get(conf); if (artifacts == null) { artifacts = new ArrayList(); artifactsByConf.put(conf, artifacts); } artifacts.add(artifact); this.artifacts.add(artifact); } } public ModuleRevisionId getModuleRevisionId() { return revId; } public ModuleRevisionId getResolvedModuleRevisionId() { return resolvedRevId; } public String getStatus() { return status; } public ExtendsDescriptor[] getInheritedDescriptors() { return (ExtendsDescriptor[]) inheritedDescriptors .toArray(new ExtendsDescriptor[inheritedDescriptors.size()]); } public Configuration[] getConfigurations() { return (Configuration[]) configurations.values().toArray( new Configuration[configurations.size()]); } public String[] getConfigurationsNames() { return (String[]) configurations.keySet().toArray(new String[configurations.size()]); } public String[] getPublicConfigurationsNames() { List ret = new ArrayList(); for (Iterator iter = configurations.values().iterator(); iter.hasNext();) { Configuration conf = (Configuration) iter.next(); if (conf.getVisibility() == Configuration.Visibility.PUBLIC) { ret.add(conf.getName()); } } return (String[]) ret.toArray(new String[ret.size()]); } /** * Returns the configuration object with the given name in the current module descriptor, null * if not found. */ public Configuration getConfiguration(String confName) { Configuration configuration = (Configuration) configurations.get(confName); if (configuration == null && confName != null) { // let's first check if the configuration is a conf group Matcher m = Pattern.compile("\\*\\[([^=]+)\\=([^\\]]+)\\]").matcher(confName); if (m.matches()) { String attName = m.group(1); String attValue = m.group(2); // this is a conf group, let's search for its members Map /* */members = new LinkedHashMap(); for (Iterator it = configurations.values().iterator(); it.hasNext();) { Configuration conf = (Configuration) it.next(); if (attValue.equals(conf.getAttribute(attName))) { members.put(conf.getName(), conf); } } return new ConfigurationGroup(confName, members); } // let's see if a configuration intersection is requested String[] confs = confName.split("\\+"); if (confs.length <= 1) { return null; } Map /* */intersectedConfs = new LinkedHashMap(); for (int i = 0; i < confs.length; i++) { Configuration c = (Configuration) configurations.get(confs[i]); if (c == null) { Message.verbose("missing configuration '" + confs[i] + "' from intersection " + confName + " in " + this); return null; } intersectedConfs.put(confs[i], c); } return new ConfigurationIntersection(confName, intersectedConfs); } return configuration; } public Artifact[] getArtifacts(String conf) { Configuration c = getConfiguration(conf); if (c == null) { return new Artifact[0]; } Collection artifacts = (Collection) artifactsByConf.get(conf); if (c instanceof ConfigurationIntersection) { ConfigurationIntersection intersection = (ConfigurationIntersection) c; String[] intersected = intersection.getIntersectedConfigurationNames(); Set/* */intersectedArtifacts = new LinkedHashSet(); for (int j = 0; j < intersected.length; j++) { Collection arts = getArtifactsIncludingExtending(intersected[j]); if (intersectedArtifacts.isEmpty()) { intersectedArtifacts.addAll(arts); } else { intersectedArtifacts.retainAll(arts); } } if (artifacts != null) { intersectedArtifacts.addAll(artifacts); } return (Artifact[]) intersectedArtifacts.toArray(new Artifact[intersectedArtifacts .size()]); } else if (c instanceof ConfigurationGroup) { ConfigurationGroup group = (ConfigurationGroup) c; String[] members = group.getMembersConfigurationNames(); Set/* */groupArtifacts = new LinkedHashSet(); for (int i = 0; i < members.length; i++) { groupArtifacts.addAll(getArtifactsIncludingExtending(members[i])); } if (artifacts != null) { groupArtifacts.addAll(artifacts); } return (Artifact[]) groupArtifacts.toArray(new Artifact[groupArtifacts.size()]); } else { if (artifacts == null) { return new Artifact[0]; } else { return (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()]); } } } private Collection/* */getArtifactsIncludingExtending(String conf) { Collection extendingConfs = Configuration.findConfigurationExtending(conf, getConfigurations()); Set/* */artifacts = new LinkedHashSet(); Collection arts = (Collection) artifactsByConf.get(conf); if (arts != null) { artifacts.addAll(arts); } for (Iterator it = extendingConfs.iterator(); it.hasNext();) { Configuration extendingConf = (Configuration) it.next(); arts = (Collection) artifactsByConf.get(extendingConf.getName()); if (arts != null) { artifacts.addAll(arts); } } return artifacts; } public Artifact[] getAllArtifacts() { return (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()]); } public DependencyDescriptor[] getDependencies() { return (DependencyDescriptor[]) dependencies.toArray(new DependencyDescriptor[dependencies .size()]); } public boolean dependsOn(VersionMatcher matcher, ModuleDescriptor md) { for (Iterator iter = dependencies.iterator(); iter.hasNext();) { DependencyDescriptor dd = (DependencyDescriptor) iter.next(); if (dd.getDependencyId().equals(md.getModuleRevisionId().getModuleId())) { if (md.getResolvedModuleRevisionId().getRevision() == null) { return true; } else if (matcher.accept(dd.getDependencyRevisionId(), md)) { return true; } } } return false; } public void toIvyFile(File destFile) throws ParseException, IOException { if (parser != null && resource != null) { parser.toIvyFile(resource.openStream(), resource, destFile, this); } else { XmlModuleDescriptorWriter.write(this, destFile); } } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((revId == null) ? 0 : revId.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DefaultModuleDescriptor other = (DefaultModuleDescriptor) obj; if (revId == null) { if (other.revId != null) { return false; } } else if (!revId.equals(other.revId)) { return false; } return true; } public String toString() { return "module: " + revId + " status=" + status + " publication=" + publicationDate + " configurations=" + configurations + " artifacts=" + artifactsByConf + " dependencies=" + dependencies; } public void setDefault(boolean b) { isDefault = b; } /** * regular expressions as explained in Pattern class may be used in ModuleId organisation and * name * * @param moduleId * @param matcher * @param resolverName */ public void addConflictManager(ModuleId moduleId, PatternMatcher matcher, ConflictManager manager) { conflictManagers.defineRule(new MapMatcher(moduleId.getAttributes(), matcher), manager); } public ConflictManager getConflictManager(ModuleId moduleId) { return (ConflictManager) conflictManagers.getRule(moduleId); } public void addDependencyDescriptorMediator(ModuleId moduleId, PatternMatcher matcher, DependencyDescriptorMediator ddm) { dependencyDescriptorMediators.defineRule(new MapMatcher(moduleId.getAttributes(), matcher), ddm); } public DependencyDescriptor mediate(DependencyDescriptor dd) { Object[] mediators = dependencyDescriptorMediators.getRules(dd.getDependencyId()); for (int i = 0; i < mediators.length; i++) { dd = ((DependencyDescriptorMediator) mediators[i]).mediate(dd); } return dd; } public ModuleRules/* */getAllDependencyDescriptorMediators() { return (ModuleRules) dependencyDescriptorMediators.clone(); } public void addLicense(License license) { licenses.add(license); } public License[] getLicenses() { return (License[]) licenses.toArray(new License[licenses.size()]); } public String getHomePage() { return homePage; } public void setHomePage(String homePage) { this.homePage = homePage; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public long getLastModified() { return lastModified; } public void setLastModified(long lastModified) { this.lastModified = lastModified; } public Namespace getNamespace() { return namespace; } public boolean isNamespaceUseful() { for (Iterator iter = dependencies.iterator(); iter.hasNext();) { DependencyDescriptor dd = (DependencyDescriptor) iter.next(); if (dd.getAllExcludeRules().length > 0) { return true; } } return false; } public void setNamespace(Namespace ns) { namespace = ns; } /** * Throws an exception if the module descriptor is inconsistent For the moment, only extended * configurations existence and cycles are checked */ public void check() { Stack confs = new Stack(); for (Iterator iter = configurations.values().iterator(); iter.hasNext();) { Configuration conf = (Configuration) iter.next(); String[] ext = conf.getExtends(); for (int i = 0; i < ext.length; i++) { confs.push(conf.getName()); checkConf(confs, ext[i].trim()); confs.pop(); } } } private void checkConf(Stack confs, String confName) { int index = confs.indexOf(confName); if (index != -1) { StringBuffer cycle = new StringBuffer(); for (; index < confs.size(); index++) { cycle.append(confs.get(index)).append(" => "); } cycle.append(confName); throw new IllegalStateException("illegal cycle detected in configuration extension: " + cycle); } Configuration conf = getConfiguration(confName); if (conf == null) { throw new IllegalStateException("unknown configuration '" + confName + "'. It is extended by " + confs.get(confs.size() - 1)); } String[] ext = conf.getExtends(); for (int i = 0; i < ext.length; i++) { confs.push(conf.getName()); checkConf(confs, ext[i].trim()); confs.pop(); } } public String getDefaultConf() { return defaultConf; } public void setDefaultConf(String defaultConf) { this.defaultConf = defaultConf; } public String getDefaultConfMapping() { return defaultConfMapping; } public void setDefaultConfMapping(String defaultConfMapping) { this.defaultConfMapping = defaultConfMapping; } public void setMappingOverride(boolean override) { mappingOverride = override; } public boolean isMappingOverride() { return mappingOverride; } public String getAttribute(String attName) { return resolvedRevId.getAttribute(attName); } public Map getAttributes() { return resolvedRevId.getAttributes(); } public String getExtraAttribute(String attName) { return resolvedRevId.getExtraAttribute(attName); } public Map getExtraAttributes() { return resolvedRevId.getExtraAttributes(); } public Map getQualifiedExtraAttributes() { return resolvedRevId.getQualifiedExtraAttributes(); } public ModuleDescriptorParser getParser() { return parser; } public Resource getResource() { return resource; } public void addExcludeRule(ExcludeRule rule) { excludeRules.add(rule); } public boolean canExclude() { return !excludeRules.isEmpty(); } /** * only works when namespace is properly set. The behaviour is not specified if namespace is not * set */ public boolean doesExclude(String[] moduleConfigurations, ArtifactId artifactId) { if (namespace != null) { artifactId = NameSpaceHelper .transform(artifactId, namespace.getFromSystemTransformer()); } ExcludeRule[] rules = getExcludeRules(moduleConfigurations); for (int i = 0; i < rules.length; i++) { if (MatcherHelper.matches(rules[i].getMatcher(), rules[i].getId(), artifactId)) { return true; } } return false; } public ExcludeRule[] getAllExcludeRules() { return (ExcludeRule[]) excludeRules.toArray(new ExcludeRule[excludeRules.size()]); } public ExcludeRule[] getExcludeRules(String[] moduleConfigurations) { Set rules = new LinkedHashSet(); for (Iterator iter = excludeRules.iterator(); iter.hasNext();) { ExcludeRule rule = (ExcludeRule) iter.next(); String[] ruleConfs = rule.getConfigurations(); if (containsAny(ruleConfs, moduleConfigurations)) { rules.add(rule); } } return (ExcludeRule[]) rules.toArray(new ExcludeRule[rules.size()]); } private boolean containsAny(String[] arr1, String[] arr2) { return new ArrayList(Arrays.asList(arr1)).removeAll(Arrays.asList(arr2)); } public Map getExtraAttributesNamespaces() { return extraAttributesNamespaces; } public void addExtraAttributeNamespace(String prefix, String namespace) { extraAttributesNamespaces.put(prefix, namespace); } public void addExtraInfo(String infoKey, String value) { extraInfo.put(infoKey, value); } public Map getExtraInfo() { return extraInfo; } public List getExtraInfos() { return extraInfos; } public void addExtraInfo(ExtraInfoHolder extraInfo) { extraInfos.add(extraInfo); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DependencyArtifactDescriptor.java000066400000000000000000000041361226750426600324050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.net.URL; import org.apache.ivy.util.extendable.ExtendableItem; /** * This describes an artifact that is asked for a dependency. It is used to define an (additional) * artifact not declared by a dependency module descriptor. */ public interface DependencyArtifactDescriptor extends ExtendableItem { /** * Returns the dependency descriptor in which this dependency artifact descriptor is declared. * * @return the dependency descriptor in which this dependency artifact descriptor is declared. */ public DependencyDescriptor getDependencyDescriptor(); /** * Returns the name of the artifact asked * * @return */ public String getName(); /** * Returns the type of the artifact asked * * @return */ public String getType(); /** * Returns the ext of the artifact asked * * @return */ public String getExt(); /** * Returns the url to look this artifact at * * @return */ public URL getUrl(); /** * Returns the configurations of the module in which the artifact is asked * * @return an array of configuration names in which the artifact is asked */ public String[] getConfigurations(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DependencyDescriptor.java000066400000000000000000000125221226750426600307250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.util.extendable.ExtendableItem; /** * Describes a dependency from a depender to a dependee. *

* The main information this descriptor contains is the constraint on the dependency. There is * actually two kind of dependency constraints: the default dependency constraint, which can be * obtained with {@link #getDependencyRevisionId()}, and corresponds to the rev * attribute in Ivy files. This is the constraint as it should be honored by Ivy in default resolve * mode. *

*

* Then there is the dynamic constraint, which can either be the same as the default constraint, or * the original dependency constraint when an Ivy file is delivered an published to a repository. * This dynamic constraint is returned by {@link #getDynamicConstraintDependencyRevisionId()}, and * corresponds to the revconstraint attribute in the Ivy file. In some resolve mode, * this constraint can be used instead of the default dependency constraint when performing * dependency resolution. *

*/ public interface DependencyDescriptor extends ExtendableItem, InheritableItem { ModuleId getDependencyId(); /** * Used to indicate that this revision must be used in case of conflicts, independently of * conflicts manager. This only works for direct dependencies, and not transitive ones. * * @return true if this dependency should be used, false if conflicts manager can do its work. */ boolean isForce(); /** * Used to indicate that this dependency is a changing one. A changing dependency in ivy means * that the revision may have its artifacts modified without revision change. When new artifacts * are published a new ivy file should also be published with a new publication date to indicate * to ivy that artifacts have changed and that they should be downloaded again. * * @return true if this dependency is a changing one */ boolean isChanging(); boolean isTransitive(); ModuleRevisionId getParentRevisionId(); /** * Returns the constraint on dependency this descriptor represents. * * @return the constraint on dependency. */ ModuleRevisionId getDependencyRevisionId(); /** * Returns the dynamic constraint on dependency this descriptor represents. * * @return the dynamic constraint on dependency, or exact constraint if no dynamic constraint is * specified. */ ModuleRevisionId getDynamicConstraintDependencyRevisionId(); String[] getModuleConfigurations(); String[] getDependencyConfigurations(String moduleConfiguration, String requestedConfiguration); String[] getDependencyConfigurations(String moduleConfiguration); String[] getDependencyConfigurations(String[] moduleConfigurations); Namespace getNamespace(); DependencyArtifactDescriptor[] getAllDependencyArtifacts(); DependencyArtifactDescriptor[] getDependencyArtifacts(String moduleConfigurations); DependencyArtifactDescriptor[] getDependencyArtifacts(String[] moduleConfigurations); IncludeRule[] getAllIncludeRules(); IncludeRule[] getIncludeRules(String moduleConfigurations); IncludeRule[] getIncludeRules(String[] moduleConfigurations); ExcludeRule[] getAllExcludeRules(); ExcludeRule[] getExcludeRules(String moduleConfigurations); ExcludeRule[] getExcludeRules(String[] moduleConfigurations); /** * Returns true if * * @param moduleConfigurations * @param artifactId * @return */ boolean doesExclude(String[] moduleConfigurations, ArtifactId artifactId); /** * Returns true if this descriptor contains any exclusion rule * * @return true if this descriptor contains any exclusion rule */ public boolean canExclude(); DependencyDescriptor asSystem(); /** * Clones current dependency descriptor with another revision. * * @param revision * the revision of the cloned dependency descriptor * @return the cloned dependency descriptor * @throws IllegalArgumentException * if the given {@link ModuleRevisionId} has not the same {@link ModuleId} as the * {@link ModuleRevisionId} of this descriptor. */ DependencyDescriptor clone(ModuleRevisionId revision); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/DependencyDescriptorMediator.java000066400000000000000000000035301226750426600324110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; /** * A DependencyDescriptorMediator is responsible for dependency descriptor mediation. *

* Dependency descriptor mediation consists in adjusting dependency descriptors according to a * context, environment, the stack of dependers, ... *

*/ public interface DependencyDescriptorMediator { /** * Mediates the given {@link DependencyDescriptor} according to this {@link ModuleDescriptor}. *

* This method gives the opportunity to a ModuleDescriptor to override dependency version * information of any of its transitive dependencies, since it is called by dependency resolvers * before actually resolving a dependency. *

* * @param dd * the dependency descriptor which should be mediated. * @return the mediated {@link DependencyDescriptor}, or the original * {@link DependencyDescriptor} if no mediation is required by this ModuleDescriptor. */ DependencyDescriptor mediate(DependencyDescriptor dd); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ExcludeRule.java000066400000000000000000000033771226750426600270410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.extendable.ExtendableItem; /** * This describes a rule of exclusion. It is used to restrict the artifacts asked for a dependency, * by excluding a whole module or some artifacts of a dependency. */ public interface ExcludeRule extends ExtendableItem { /** * Returns the id of the described artifact, without revision information * * @return */ public ArtifactId getId(); /** * Returns the configurations of the module in which the artifact is asked * * @return an array of configuration names in which the artifact is asked */ public String[] getConfigurations(); /** * Returns the matcher to use to know if an artifact match the current descriptor * * @return */ public PatternMatcher getMatcher(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ExtendsDescriptor.java000066400000000000000000000050641226750426600302640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * Describes parent descriptor information for a module descriptor. */ public interface ExtendsDescriptor { /** get the module revision id of the declared parent descriptor */ public ModuleRevisionId getParentRevisionId(); /** * get the resolved revision id for {@link #getParentRevisionId}, see * {@link org.apache.ivy.core.module.descriptor.ModuleDescriptor#getResolvedModuleRevisionId()} */ public ModuleRevisionId getResolvedParentRevisionId(); public ModuleDescriptor getParentMd(); /** * If there is an explicit path to check for the parent descriptor, return it. Otherwise returns * null. */ public String getLocation(); /** * Get the parts of the parent descriptor that are inherited. Default supported types are * info, description, configurations, * dependencies, and/or all. Ivy extensions may add support for * additional extends types. */ public String[] getExtendsTypes(); /** @return true if the all extend type is specified, implying all other types */ public boolean isAllInherited(); /** @return true if parent info attributes are inherited (organisation, branch, revision, etc) */ public boolean isInfoInherited(); /** @return true if parent description is inherited */ public boolean isDescriptionInherited(); /** @return true if parent configurations are inherited */ public boolean areConfigurationsInherited(); /** @return true if parent dependencies are inherited */ public boolean areDependenciesInherited(); public boolean isLocal(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ExtraInfoHolder.java000066400000000000000000000041221226750426600276420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class ExtraInfoHolder { private String name; private Map attributes = new LinkedHashMap(); private String content; private List nestedExtraInfoHolder = new ArrayList(); public ExtraInfoHolder() { } public ExtraInfoHolder(String name, String content) { this.name = name; this.content = content; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Map getAttributes() { return attributes; } public void setAttributes(Map attributes) { this.attributes = attributes; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public List getNestedExtraInfoHolder() { return nestedExtraInfoHolder; } public void setNestedExtraInfoHolder(List nestedExtraInfoHolder) { this.nestedExtraInfoHolder = nestedExtraInfoHolder; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/IncludeRule.java000066400000000000000000000034101226750426600270170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.extendable.ExtendableItem; /** * This describes a rule of inclusion. It is used to resctrict the artifacts and modules asked for a * dependency, by including only modules and artifacts matching the rule */ public interface IncludeRule extends ExtendableItem { /** * Returns the id of the described artifact, without revision information * * @return */ public ArtifactId getId(); /** * Returns the configurations of the module in which the artifact is asked * * @return an array of configuration names in which the artifact is asked */ public String[] getConfigurations(); /** * Returns the matcher to use to know if an artifact match the current descriptor * * @return */ public PatternMatcher getMatcher(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/InheritableItem.java000066400000000000000000000024631226750426600276600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * Interface for elements that can be inherited from a parent descriptor by a child descriptor. * * @see Configuration * @see DependencyDescriptor */ public interface InheritableItem { /** * @return the module in which this item was actually defined, if different from the module in * which the item appears. May be null. */ public ModuleRevisionId getSourceModule(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/License.java000066400000000000000000000022061226750426600261700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; public class License { private String name; private String url; public License(String name, String url) { this.name = name; this.url = url; } public String getName() { return name; } public String getUrl() { return url; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/MDArtifact.java000066400000000000000000000070011226750426600265620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.id.ArtifactRevisionId; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * */ public class MDArtifact extends AbstractArtifact { public static Artifact newIvyArtifact(ModuleDescriptor md) { return new MDArtifact(md, "ivy", "ivy", "xml", true); } private ModuleDescriptor md; private String name; private String type; private String ext; private List/* */confs = new ArrayList(); private Map extraAttributes = null; private URL url; private boolean isMetadata = false; public MDArtifact(ModuleDescriptor md, String name, String type, String ext) { this(md, name, type, ext, null, null); } public MDArtifact(ModuleDescriptor md, String name, String type, String ext, boolean isMetadata) { this(md, name, type, ext, null, null); this.isMetadata = isMetadata; } public MDArtifact(ModuleDescriptor md, String name, String type, String ext, URL url, Map extraAttributes) { if (md == null) { throw new NullPointerException("null module descriptor not allowed"); } if (name == null) { throw new NullPointerException("null name not allowed"); } if (type == null) { throw new NullPointerException("null type not allowed"); } if (ext == null) { throw new NullPointerException("null ext not allowed"); } this.md = md; this.name = name; this.type = type; this.ext = ext; this.url = url; this.extraAttributes = extraAttributes; } public ModuleRevisionId getModuleRevisionId() { return md.getResolvedModuleRevisionId(); } public Date getPublicationDate() { return md.getResolvedPublicationDate(); } public ArtifactRevisionId getId() { // do not cache the result because the resolvedModuleRevisionId can change! return ArtifactRevisionId.newInstance(md.getResolvedModuleRevisionId(), name, type, ext, extraAttributes); } public String getName() { return name; } public String getType() { return type; } public String getExt() { return ext; } public String[] getConfigurations() { return (String[]) confs.toArray(new String[confs.size()]); } public void addConfiguration(String conf) { confs.add(conf); } public URL getUrl() { return url; } public boolean isMetadata() { return isMetadata; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/ModuleDescriptor.java000066400000000000000000000216011226750426600300720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.extendable.ExtendableItem; /** * Descriptor of a module. This is the Java representation of an ivy.xml */ public interface ModuleDescriptor extends ExtendableItem, ArtifactInfo, DependencyDescriptorMediator { public static final String DEFAULT_CONFIGURATION = "default"; public static final String CALLER_ALL_CONFIGURATION = "all"; /** * Returns true if this descriptor is a default one, i.e. one generated for a module not * actually having one. * * @return */ boolean isDefault(); ModuleRevisionId getModuleRevisionId(); /** * The module revision id returned here is the resolved one, i.e. it is never a latest one. If * the revision has not been resolved, a null revision should be returned by getRevision() of * the returned ModuleRevisionId. This revision must be the same as the module descriptor * resolved revision id unless no module descriptor is defined * * @return */ ModuleRevisionId getResolvedModuleRevisionId(); /** * This method update the resolved module revision id * * @param revId */ void setResolvedModuleRevisionId(ModuleRevisionId revId); /** * Get the list of parent descriptors imported via an <extends> element. Only directly * imported descriptors are included; the parent's parents are not included. */ ExtendsDescriptor[] getInheritedDescriptors(); /** * This method update the resolved publication date * * @param publicationDate */ void setResolvedPublicationDate(Date publicationDate); String getStatus(); /** * May be null if unknown in the descriptor itself. * * @return The publication date or null when not knwon. */ Date getPublicationDate(); /** * The publication date of the module revision should be the date at which it has been * published, i.e. in general the date of any of its published artifacts, since all published * artifact of a module should follow the same publishing cycle. */ Date getResolvedPublicationDate(); /** * Returns all the configurations declared by this module as an array. This array is never empty * (a 'default' conf is assumed when none is declared in the ivy file) * * @return all the configurations declared by this module as an array. */ Configuration[] getConfigurations(); String[] getConfigurationsNames(); String[] getPublicConfigurationsNames(); Artifact[] getArtifacts(String conf); /** * Returns all artifacts of this module, excluding the artifact corresponding to the module * descriptor. * * @return all published artifacts of this module * @see #getMetadataArtifact() */ Artifact[] getAllArtifacts(); /** * @retun The dependencies of the module. If there is no dependencies return an empty array (non * null) */ DependencyDescriptor[] getDependencies(); /** * Returns true if the module described by this descriptor dependes directly upon the given * module descriptor * * @param md * @return */ boolean dependsOn(VersionMatcher matcher, ModuleDescriptor md); /** * @param confName * @return */ Configuration getConfiguration(String confName); /** * Returns the conflict manager to use for the given ModuleId, or null if no * specific conflict manager is associated with the given module id in this module descriptor. * * @param id * @return */ ConflictManager getConflictManager(ModuleId id); /** * Returns the licenses of the module described by this descriptor * * @return */ License[] getLicenses(); String getHomePage(); String getDescription(); long getLastModified(); /** * Writes this module descriptor as an ivy file. If this descriptor was obtained through the * parsing of an ivy file, it should keep the layout of the file the most possible similar to * the original one. * * @param ivyFile * the destination ivy file */ void toIvyFile(File ivyFile) throws ParseException, IOException; /** * The ModuleDescriptorParser used to parse this module descriptor, null is no parser was used. * * @return */ ModuleDescriptorParser getParser(); /** * The resource being the source of this module descriptor, null if no resource corresponds to * this module descriptor * * @return */ Resource getResource(); /** * Returns the Artifact representing this module descriptor itself. *

* Even though the module descriptor is never described as a published artifact of a module in * the module descriptor itself, it is often useful to consider it as any other artifact of the * module. This method allows to access to the Artifact object representing this module * descriptor for this purpose. *

* * @return the Artifact representing this module descriptor itself. */ Artifact getMetadataArtifact(); /** * Returns true if this descriptor contains any exclusion rule * * @return true if this descriptor contains any exclusion rule */ boolean canExclude(); /** * Returns true if an exclude rule of this module attached to any of the given configurations * matches the given artifact id, and thus exclude it * * @param moduleConfs * @param artifactId * @return */ boolean doesExclude(String[] moduleConfs, ArtifactId artifactId); /** * Returns an array of all the exclude rules this module descriptor currently holds. Module * Descriptor exclude rules are used to exclude (usually transitive) dependencies for the whole * module. * * @return an array of {@link ExcludeRule} this module descriptor holds */ public ExcludeRule[] getAllExcludeRules(); /** * Returns all the dependency descriptor mediators used by this {@link ModuleDescriptor}, as an * instance of {@link ModuleRules}. *

* All rules in the {@link ModuleRules} object returned are {@link DependencyDescriptorMediator} * . *

* * @return all the dependency descriptor mediators used by this {@link ModuleDescriptor}. */ public ModuleRules/* */getAllDependencyDescriptorMediators(); /** * Returns the list of xml namespaces used by extra attributes, as Map from prefix to namespace * URIs. *

* The returned list is never null, it is empty when no extra attribute is used or * if extra attributes are used without xml namespaces *

* * @return the list of xml namespaces used by extra attributes, as Map from prefix to namespace * URIs. */ Map/* */getExtraAttributesNamespaces(); /** * Returns the custom info provided in the info tag. All the tags except the description are * given. The key is the name of the tag, the value is its content. * * @return */ @Deprecated Map/* */getExtraInfo(); /** * Returns a list of extras infos (tag name, attributes and content). All the tags except the * description are given. * * @return */ List getExtraInfos(); } OverrideDependencyDescriptorMediator.java000066400000000000000000000062471226750426600340420ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/descriptor/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.descriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * DependencyDescriptorMediator used to override some dependency descriptors values, such as the * branch or version of the dependency. */ public class OverrideDependencyDescriptorMediator implements DependencyDescriptorMediator { private String version; private String branch; /** * Constructs a new instance. * * @param branch * the branch to give to mediated dependency descriptors, null to keep * the original branch. * @param version * the version to give to mediated dependency descriptors, null to keep * the original one. */ public OverrideDependencyDescriptorMediator(String branch, String version) { this.branch = branch; this.version = version; } /** * Returns the version this mediator will give to mediated descriptors, or null if * this mediator does not override version. * * @return the version this mediator will give to mediated descriptors. */ public String getVersion() { return version; } /** * Returns the branch this mediator will give to mediated descriptors, or null if * this mediator does not override branch. * * @return the branch this mediator will give to mediated descriptors. */ public String getBranch() { return branch; } public DependencyDescriptor mediate(DependencyDescriptor dd) { ModuleRevisionId mrid = dd.getDependencyRevisionId(); if ((version == null || version.equals(mrid.getRevision())) && (branch == null || branch.equals(mrid.getBranch()))) { return dd; } String version = this.version == null ? mrid.getRevision() : this.version; String branch = this.branch == null ? mrid.getBranch() : this.branch; // if this is a noop, do not construct any new object if (version.equals(dd.getDependencyRevisionId().getRevision()) && branch.equals(dd.getDependencyRevisionId().getBranch())) { return dd; } return dd.clone(ModuleRevisionId.newInstance(mrid.getOrganisation(), mrid.getName(), branch, version, mrid.getQualifiedExtraAttributes())); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/000077500000000000000000000000001226750426600221615ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/ArtifactId.java000066400000000000000000000056231226750426600250440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.id; /** * Identifies an artifact in a module, without revision information * * @see org.apache.ivy.core.module.id */ public class ArtifactId { private ModuleId mid; private String name; private String type; private String ext; /** * @param mid * The ModuleId, which is the base of this artifact. * @param name * The name of the artifact. * @param type * The type of the artifact. */ public ArtifactId(ModuleId mid, String name, String type, String ext) { this.mid = mid; this.name = name; this.type = type; this.ext = ext; } /** {@inheritDoc} */ public boolean equals(Object obj) { if (!(obj instanceof ArtifactId)) { return false; } ArtifactId aid = (ArtifactId) obj; return getModuleId().equals(aid.getModuleId()) && getName().equals(aid.getName()) && getExt().equals(aid.getExt()) && getType().equals(aid.getType()); } /** {@inheritDoc} */ public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 17; hash += getModuleId().hashCode() * 37; hash += getName().hashCode() * 37; hash += getType().hashCode() * 37; // CheckStyle:MagicNumber| OFF return hash; } /** {@inheritDoc} */ public String toString() { return getModuleId() + "!" + getShortDescription(); } public String getShortDescription() { return getName() + "." + getExt() + (getType().equals(getExt()) ? "" : "(" + getType() + ")"); } /** * @return Returns the module id. */ public ModuleId getModuleId() { return mid; } /** * @return Returns the name. */ public String getName() { return name; } /** * @return Returns the type. */ public String getType() { return type; } /** * @return Returns the ext. */ public String getExt() { return ext; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/ArtifactRevisionId.java000066400000000000000000000100621226750426600265540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.id; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.util.extendable.UnmodifiableExtendableItem; /** * Identifies an artifact in a particular module revision * * @see org.apache.ivy.core.module.id */ public class ArtifactRevisionId extends UnmodifiableExtendableItem { public static ArtifactRevisionId newInstance(ModuleRevisionId mrid, String name, String type, String ext) { return newInstance(mrid, name, type, ext, null); } public static ArtifactRevisionId newInstance(ModuleRevisionId mrid, String name, String type, String ext, Map extraAttributes) { return new ArtifactRevisionId(new ArtifactId(mrid.getModuleId(), name, type, ext), mrid, extraAttributes); } private ArtifactId artifactId; private ModuleRevisionId mrid; public ArtifactRevisionId(ArtifactId artifactId, ModuleRevisionId mrid) { this(artifactId, mrid, null); } public ArtifactRevisionId(ArtifactId artfId, ModuleRevisionId mdlRevId, Map extraAttributes) { super(null, extraAttributes); artifactId = artfId; mrid = mdlRevId; setStandardAttribute(IvyPatternHelper.ORGANISATION_KEY, getModuleRevisionId() .getOrganisation()); setStandardAttribute(IvyPatternHelper.MODULE_KEY, getModuleRevisionId().getName()); setStandardAttribute(IvyPatternHelper.REVISION_KEY, getModuleRevisionId().getRevision()); setStandardAttribute(IvyPatternHelper.ARTIFACT_KEY, getName()); setStandardAttribute(IvyPatternHelper.TYPE_KEY, getType()); setStandardAttribute(IvyPatternHelper.EXT_KEY, getExt()); } public boolean equals(Object obj) { if (!(obj instanceof ArtifactRevisionId)) { return false; } ArtifactRevisionId arid = (ArtifactRevisionId) obj; return getArtifactId().equals(arid.getArtifactId()) && getModuleRevisionId().equals(arid.getModuleRevisionId()) && getQualifiedExtraAttributes().equals(arid.getQualifiedExtraAttributes()); } public int hashCode() { // WARN: uniqueness needs to be relatively strong here // CheckStyle:MagicNumber| OFF int hash = 17; hash += getArtifactId().hashCode() * 37; hash += getModuleRevisionId().hashCode() * 37; hash += getQualifiedExtraAttributes().hashCode() * 37; // CheckStyle:MagicNumber| ON return hash; } public String toString() { return getModuleRevisionId() + "!" + getName() + "." + getExt() + (getType().equals(getExt()) ? "" : "(" + getType() + ")"); } /** * @return Returns the artifactId. */ public ArtifactId getArtifactId() { return artifactId; } public ModuleRevisionId getModuleRevisionId() { return mrid; } public String getName() { return artifactId.getName(); } public String getType() { return artifactId.getType(); } public String getExt() { return artifactId.getExt(); } /** * @return Returns the revision. */ public String getRevision() { return mrid.getRevision(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/ModuleId.java000066400000000000000000000160051226750426600245300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.id; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.IvyPatternHelper; /** * Identifies a module, without revision information * * @see org.apache.ivy.core.module.id */ public class ModuleId implements Comparable { static final String ENCODE_SEPARATOR = ":#@#:"; private static final Map/* > */CACHE = new WeakHashMap(); /** * Returns a ModuleId for the given organization and module name. * * @param org * the module's organization, can be null * @param name * the module's name, must not be null * @return a ModuleId instance */ public static ModuleId newInstance(String org, String name) { return intern(new ModuleId(org, name)); } /** * Returns an intern instance of a ModuleId equals to the given ModuleId if any, or the given * ModuleId. *

* This is useful to reduce the number of instances of ModuleId kept in memory, and thus reduce * memory footprint. *

* * @param moduleId * the module id to return * @return a unit instance of the given module id. */ public static ModuleId intern(ModuleId moduleId) { ModuleId r = null; synchronized (CACHE) { WeakReference ref = (WeakReference) CACHE.get(moduleId); if (ref != null) { r = (ModuleId) ref.get(); } if (r == null) { r = moduleId; CACHE.put(r, new WeakReference(r)); } } return r; } private String organisation; private String name; private int hash; private Map/* */attributes = new HashMap(); /** * Constructor. * * @param organisation * The organisation which creates the module. * @param name * The name of the module. */ public ModuleId(String organisation, String name) { if (name == null) { throw new IllegalArgumentException("null name not allowed"); } this.organisation = organisation; this.name = name; attributes.put(IvyPatternHelper.ORGANISATION_KEY, organisation); attributes.put(IvyPatternHelper.MODULE_KEY, name); } /** * Returns the name of the module. * * @return The name of the module. */ public String getName() { return name; } /** * Returns the name of the organisation. * * @return The name of the organisation. */ public String getOrganisation() { return organisation; } /** {@inheritDoc} */ public boolean equals(Object obj) { if (!(obj instanceof ModuleId)) { return false; } ModuleId other = (ModuleId) obj; if (other.organisation == null) { return organisation == null && other.name.equals(name); } else { return other.organisation.equals(organisation) && other.name.equals(name); } } /** {@inheritDoc} */ public int hashCode() { if (hash == 0) { // CheckStyle:MagicNumber| OFF hash = 31; hash = hash * 13 + (organisation == null ? 0 : organisation.hashCode()); hash = hash * 13 + name.hashCode(); // CheckStyle:MagicNumber| ON } return hash; } /** {@inheritDoc} */ public String toString() { return organisation + "#" + name; } /** {@inheritDoc} */ public int compareTo(Object obj) { ModuleId that = (ModuleId) obj; int result = organisation.compareTo(that.organisation); if (result == 0) { result = name.compareTo(that.name); } return result; } /** * Returns the encoded String representing this ModuleId. * * @return The ModuleId encoded as String. */ public String encodeToString() { return getOrganisation() + ENCODE_SEPARATOR + getName(); } /** * Returns a Map of all attributes of this module id. The Map keys are attribute names as * Strings, and values are corresponding attribute values (as String too). * * @return A Map instance containing all the attributes and their values. */ public Map getAttributes() { return attributes; } /** * Returns a ModuleId * * @param encoded * @return The new ModuleId. * @throws IllegalArgumentException * If the given String could not be decoded. */ public static ModuleId decode(String encoded) { String[] parts = encoded.split(ENCODE_SEPARATOR); if (parts.length != 2) { throw new IllegalArgumentException("badly encoded module id: '" + encoded + "'"); } return new ModuleId(parts[0], parts[1]); } /** * Pattern to use to matched mid text representation. * * @see #parse(String) */ public static final Pattern MID_PATTERN = Pattern.compile("(" + ModuleRevisionId.STRICT_CHARS_PATTERN + "*)" + "#(" + ModuleRevisionId.STRICT_CHARS_PATTERN + "+)"); /** * Parses the module id text representation and returns it as a {@link ModuleId} instance. * * @param mid * the module id text representation to parse * @return the ModuleId instance corresponding to the representation * @throws IllegalArgumentException * if the given text representation cannot be parsed */ public static ModuleId parse(String mid) { Matcher m = MID_PATTERN.matcher(mid); if (!m.matches()) { throw new IllegalArgumentException( "module text representation do not match expected pattern." + " given mid='" + mid + "' expected form=" + MID_PATTERN.pattern()); } // CheckStyle:MagicNumber| OFF return newInstance(m.group(1), m.group(2)); // CheckStyle:MagicNumber| ON } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java000066400000000000000000000331421226750426600262500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.id; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.util.extendable.UnmodifiableExtendableItem; /** * Identifies a module in a particular version * * @see org.apache.ivy.core.module.id */ public class ModuleRevisionId extends UnmodifiableExtendableItem { private static final String ENCODE_SEPARATOR = ModuleId.ENCODE_SEPARATOR; private static final String ENCODE_PREFIX = "+"; private static final String NULL_ENCODE = "@#:NULL:#@"; static final String STRICT_CHARS_PATTERN = "[a-zA-Z0-9\\-/\\._+=]"; private static final String REV_STRICT_CHARS_PATTERN = "[a-zA-Z0-9\\-/\\._+=,\\[\\]\\{\\}\\(\\):@]"; private static final Map/* */CACHE = new WeakHashMap(); /** * Pattern to use to matched mrid text representation. * * @see #parse(String) */ public static final Pattern MRID_PATTERN = Pattern.compile("(" + STRICT_CHARS_PATTERN + "*)" + "#(" + STRICT_CHARS_PATTERN + "+)" + "(?:#(" + STRICT_CHARS_PATTERN + "+))?" + ";(" + REV_STRICT_CHARS_PATTERN + "+)"); /** * Same as MRID_PATTERN but using non capturing groups, useful to build larger regexp */ public static final Pattern NON_CAPTURING_PATTERN = Pattern.compile("(?:" + STRICT_CHARS_PATTERN + "*)" + "#(?:" + STRICT_CHARS_PATTERN + "+)" + "(?:#(?:" + STRICT_CHARS_PATTERN + "+))?" + ";(?:" + REV_STRICT_CHARS_PATTERN + "+)"); /** * Parses a module revision id text representation and returns a new {@link ModuleRevisionId} * instance corresponding to the parsed String. *

* The result is unspecified if the module doesn't respect strict name conventions. *

* * @param mrid * the text representation of the module (as returned by {@link #toString()}). Must * not be null. * @return a {@link ModuleRevisionId} corresponding to the given text representation * @throws IllegalArgumentException * if the given text representation does not match the {@link ModuleRevisionId} text * representation rules. */ public static ModuleRevisionId parse(String mrid) { Matcher m = MRID_PATTERN.matcher(mrid.trim()); if (!m.matches()) { throw new IllegalArgumentException( "module revision text representation do not match expected pattern." + " given mrid='" + mrid + "' expected form=" + MRID_PATTERN.pattern()); } // CheckStyle:MagicNumber| OFF return newInstance(m.group(1), m.group(2), m.group(3), m.group(4)); // CheckStyle:MagicNumber| ON } public static ModuleRevisionId newInstance(String organisation, String name, String revision) { return intern(new ModuleRevisionId(ModuleId.newInstance(organisation, name), revision)); } public static ModuleRevisionId newInstance(String organisation, String name, String revision, Map extraAttributes) { return intern(new ModuleRevisionId(ModuleId.newInstance(organisation, name), revision, extraAttributes)); } public static ModuleRevisionId newInstance(String organisation, String name, String branch, String revision) { return intern(new ModuleRevisionId(ModuleId.newInstance(organisation, name), branch, revision)); } public static ModuleRevisionId newInstance(String organisation, String name, String branch, String revision, Map extraAttributes) { return intern(new ModuleRevisionId(ModuleId.newInstance(organisation, name), branch, revision, extraAttributes)); } public static ModuleRevisionId newInstance(String organisation, String name, String branch, String revision, Map extraAttributes, boolean replaceNullBranchWithDefault) { return intern(new ModuleRevisionId(ModuleId.newInstance(organisation, name), branch, revision, extraAttributes, replaceNullBranchWithDefault)); } public static ModuleRevisionId newInstance(ModuleRevisionId mrid, String rev) { return intern(new ModuleRevisionId(mrid.getModuleId(), mrid.getBranch(), rev, mrid.getQualifiedExtraAttributes())); } public static ModuleRevisionId newInstance(ModuleRevisionId mrid, String branch, String rev) { return intern(new ModuleRevisionId(mrid.getModuleId(), branch, rev, mrid.getQualifiedExtraAttributes())); } /** * Returns an intern instance of the given ModuleRevisionId if any, or put the given * ModuleRevisionId in a cache of intern instances and returns it. *

* This method should be called on ModuleRevisionId created with one of the constructor to * decrease memory footprint. *

*

* When using static newInstances methods, this method is already called. *

* * @param moduleRevisionId * the module revision id to intern * @return an interned ModuleRevisionId */ public static ModuleRevisionId intern(ModuleRevisionId moduleRevisionId) { ModuleRevisionId r = null; synchronized (CACHE) { WeakReference ref = (WeakReference) CACHE.get(moduleRevisionId); if (ref != null) { r = (ModuleRevisionId) ref.get(); } if (r == null) { r = moduleRevisionId; CACHE.put(r, new WeakReference(r)); } } return r; } private final ModuleId moduleId; private final String branch; private final String revision; private int hash; // TODO: make these constructors private and use only static factory methods public ModuleRevisionId(ModuleId moduleId, String revision) { this(moduleId, null, revision, null); } public ModuleRevisionId(ModuleId moduleId, String branch, String revision) { this(moduleId, branch, revision, null); } private ModuleRevisionId(ModuleId moduleId, String revision, Map extraAttributes) { this(moduleId, null, revision, extraAttributes); } private ModuleRevisionId(ModuleId moduleId, String branch, String revision, Map extraAttributes) { this(moduleId, branch, revision, extraAttributes, true); } private ModuleRevisionId(ModuleId moduleId, String branch, String revision, Map extraAttributes, boolean replaceNullBranchWithDefault) { super(null, extraAttributes); this.moduleId = moduleId; IvyContext context = IvyContext.getContext(); this.branch = (replaceNullBranchWithDefault && branch == null) // we test if there's already an Ivy instance loaded, to avoid loading a default one // just to get the default branch ? (context.peekIvy() == null ? null : context.getSettings().getDefaultBranch(moduleId)) : branch; this.revision = revision == null ? Ivy.getWorkingRevision() : normalizeRevision(revision); setStandardAttribute(IvyPatternHelper.ORGANISATION_KEY, this.moduleId.getOrganisation()); setStandardAttribute(IvyPatternHelper.MODULE_KEY, this.moduleId.getName()); setStandardAttribute(IvyPatternHelper.BRANCH_KEY, this.branch); setStandardAttribute(IvyPatternHelper.REVISION_KEY, this.revision); } public ModuleId getModuleId() { return moduleId; } public String getName() { return getModuleId().getName(); } public String getOrganisation() { return getModuleId().getOrganisation(); } public String getRevision() { return revision; } public boolean equals(Object obj) { if (!(obj instanceof ModuleRevisionId)) { return false; } ModuleRevisionId other = (ModuleRevisionId) obj; if (!other.getRevision().equals(getRevision())) { return false; } else if (other.getBranch() == null && getBranch() != null) { return false; } else if (other.getBranch() != null && !other.getBranch().equals(getBranch())) { return false; } else if (!other.getModuleId().equals(getModuleId())) { return false; } else { return other.getQualifiedExtraAttributes().equals(getQualifiedExtraAttributes()); } } public int hashCode() { if (hash == 0) { // CheckStyle:MagicNumber| OFF hash = 31; hash = hash * 13 + (getBranch() == null ? 0 : getBranch().hashCode()); hash = hash * 13 + getRevision().hashCode(); hash = hash * 13 + getModuleId().hashCode(); hash = hash * 13 + getQualifiedExtraAttributes().hashCode(); // CheckStyle:MagicNumber| ON } return hash; } public String toString() { return moduleId + (branch == null || branch.length() == 0 ? "" : "#" + branch) + ";" + (revision == null ? "NONE" : revision); } public String encodeToString() { StringBuffer buf = new StringBuffer(); Map attributes = new HashMap(getAttributes()); attributes.keySet().removeAll(getExtraAttributes().keySet()); attributes.putAll(getQualifiedExtraAttributes()); for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { String attName = (String) iter.next(); String value = (String) attributes.get(attName); value = value == null ? NULL_ENCODE : value; buf.append(ENCODE_PREFIX).append(attName).append(ENCODE_SEPARATOR) .append(ENCODE_PREFIX).append(value).append(ENCODE_SEPARATOR); } return buf.toString(); } public static ModuleRevisionId decode(String encoded) { String[] parts = encoded.split(ENCODE_SEPARATOR); if (parts.length % 2 != 0) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "'"); } Map attributes = new HashMap(); for (int i = 0; i < parts.length; i += 2) { String attName = parts[i]; if (!attName.startsWith(ENCODE_PREFIX)) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "': " + attName + " doesn't start with " + ENCODE_PREFIX); } else { attName = attName.substring(1); } String attValue = parts[i + 1]; if (!attValue.startsWith(ENCODE_PREFIX)) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "': " + attValue + " doesn't start with " + ENCODE_PREFIX); } else { attValue = attValue.substring(1); } if (NULL_ENCODE.equals(attValue)) { attValue = null; } attributes.put(attName, attValue); } String org = (String) attributes.remove(IvyPatternHelper.ORGANISATION_KEY); String mod = (String) attributes.remove(IvyPatternHelper.MODULE_KEY); String rev = (String) attributes.remove(IvyPatternHelper.REVISION_KEY); String branch = (String) attributes.remove(IvyPatternHelper.BRANCH_KEY); if (org == null) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "': no organisation"); } if (mod == null) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "': no module name"); } if (rev == null) { throw new IllegalArgumentException("badly encoded module revision id: '" + encoded + "': no revision"); } return newInstance(org, mod, branch, rev, attributes); } public String getBranch() { return branch; } /** * [revision] is a valid revision in maven. This method strips the '[' and ']' characters. Cfr. * http://docs.codehaus.org/x/IGU */ private static String normalizeRevision(String revision) { if (revision.startsWith("[") && revision.endsWith("]") && revision.indexOf(',') == -1) { if (IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY).equals(revision)) { // this is the case when listing dynamic revions return revision; } return revision.substring(1, revision.length() - 1); } else { return revision; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/ModuleRules.java000066400000000000000000000225441226750426600252730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.id; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Message; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.NoFilter; /** * A list of module specific rules. *

* This class defines a list of module specific rules. For each module only one rule apply, * sometimes none. *

*

* To know which rule to apply, they are configured using matchers. So you can define a rule * applying to all module from one particular organization, or to all modules with a revisions * matching a pattern, and so on. *

*

* Rules condition are evaluated in order, so the first matching rule is returned. *

*

* Rules themselves can be represented by any object, depending on the purpose of the rule (define * which resolver to use, which TTL in cache, ...) *

*/ public class ModuleRules { private Map/* */rules = new LinkedHashMap(); /** * Constructs an empty ModuleRules. */ public ModuleRules() { } private ModuleRules(Map/* */rules) { this.rules = new LinkedHashMap(rules); } /** * Defines a new rule for the given condition. * * @param condition * the condition for which the rule should be applied. Must not be null. * @param rule * the rule to apply. Must not be null. */ public void defineRule(MapMatcher condition, Object rule) { Checks.checkNotNull(condition, "condition"); Checks.checkNotNull(rule, "rule"); rules.put(condition, rule); } /** * Returns the rule object matching the given {@link ModuleId}, or null if no rule * applies. * * @param mid * the {@link ModuleId} to search the rule for. Must not be null. * @return the rule object matching the given {@link ModuleId}, or null if no rule * applies. * @see #getRule(ModuleId, Filter) */ public Object getRule(ModuleId mid) { return getRule(mid, NoFilter.INSTANCE); } /** * Returns the rules objects matching the given {@link ModuleId}, or an empty array if no rule * applies. * * @param mid * the {@link ModuleId} to search the rule for. Must not be null. * @return an array of rule objects matching the given {@link ModuleId}. */ public Object[] getRules(ModuleId mid) { return getRules(mid.getAttributes(), NoFilter.INSTANCE); } /** * Returns the rule object matching the given {@link ModuleRevisionId}, or null if * no rule applies. * * @param mrid * the {@link ModuleRevisionId} to search the rule for. Must not be null * . * @return the rule object matching the given {@link ModuleRevisionId}, or null if * no rule applies. * @see #getRule(ModuleRevisionId, Filter) */ public Object getRule(ModuleRevisionId mrid) { return getRule(mrid, NoFilter.INSTANCE); } /** * Returns the rule object matching the given {@link ModuleId} and accepted by the given * {@link Filter}, or null if no rule applies. * * @param mrid * the {@link ModuleRevisionId} to search the rule for. Must not be null * . * @param filter * the filter to use to filter the rule to return. The {@link Filter#accept(Object)} * method will be called only with rule objects matching the given {@link ModuleId}, * and the first rule object accepted by the filter will be returned. Must not be * null. * @return the rule object matching the given {@link ModuleId}, or null if no rule * applies. * @see #getRule(ModuleRevisionId, Filter) */ public Object getRule(ModuleId mid, Filter filter) { Checks.checkNotNull(mid, "mid"); return getRule(mid.getAttributes(), filter); } /** * Returns the rule object matching the given {@link ModuleRevisionId} and accepted by the given * {@link Filter}, or null if no rule applies. * * @param mrid * the {@link ModuleRevisionId} to search the rule for. Must not be null * . * @param filter * the filter to use to filter the rule to return. The {@link Filter#accept(Object)} * method will be called only with rule objects matching the given * {@link ModuleRevisionId}, and the first rule object accepted by the filter will be * returned. Must not be null. * @return the rule object matching the given {@link ModuleRevisionId}, or null if * no rule applies. * @see #getRule(ModuleRevisionId) */ public Object getRule(ModuleRevisionId mrid, Filter filter) { Checks.checkNotNull(mrid, "mrid"); Checks.checkNotNull(filter, "filter"); Map moduleAttributes = mrid.getAttributes(); return getRule(moduleAttributes, filter); } private Object getRule(Map moduleAttributes, Filter filter) { for (Iterator iter = rules.entrySet().iterator(); iter.hasNext();) { Map.Entry ruleEntry = (Entry) iter.next(); MapMatcher midm = (MapMatcher) ruleEntry.getKey(); if (midm.matches(moduleAttributes)) { Object rule = ruleEntry.getValue(); if (filter.accept(rule)) { return rule; } } } return null; } /** * Returns the rules object matching the given {@link ModuleRevisionId} and accepted by the * given {@link Filter}, or an empty array if no rule applies. * * @param mrid * the {@link ModuleRevisionId} to search the rule for. Must not be null * . * @param filter * the filter to use to filter the rule to return. The {@link Filter#accept(Object)} * method will be called only with rule objects matching the given * {@link ModuleRevisionId}. Must not be null. * @return an array of rule objects matching the given {@link ModuleRevisionId}. */ public Object[] getRules(ModuleRevisionId mrid, Filter filter) { Checks.checkNotNull(mrid, "mrid"); Checks.checkNotNull(filter, "filter"); Map moduleAttributes = mrid.getAttributes(); return getRules(moduleAttributes, filter); } private Object[] getRules(Map moduleAttributes, Filter filter) { List matchingRules = new ArrayList(); for (Iterator iter = rules.entrySet().iterator(); iter.hasNext();) { Map.Entry ruleEntry = (Entry) iter.next(); MapMatcher midm = (MapMatcher) ruleEntry.getKey(); if (midm.matches(moduleAttributes)) { Object rule = ruleEntry.getValue(); if (filter.accept(rule)) { matchingRules.add(rule); } } } return matchingRules.toArray(); } /** * Dump the list of rules to {@link Message#debug(String)} * * @param prefix * the prefix to use for each line dumped */ public void dump(String prefix) { if (rules.isEmpty()) { Message.debug(prefix + "NONE"); } else { for (Iterator iter = rules.keySet().iterator(); iter.hasNext();) { MapMatcher midm = (MapMatcher) iter.next(); Object rule = rules.get(midm); Message.debug(prefix + midm + " -> " + rule); } } } /** * Returns an unmodifiable view of all the rules defined on this ModuleRules. *

* The rules are returned in a Map where they keys are the MapMatchers matching the rules * object, and the values are the rules object themselves. *

* * @return an unmodifiable view of all the rules defined on this ModuleRules. */ public Map/* */getAllRules() { return Collections.unmodifiableMap(rules); } public Object clone() { return new ModuleRules(rules); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/id/package.html000066400000000000000000000054451226750426600244520ustar00rootroot00000000000000

This packages gathers classes used to represent identifiers of objects involved in dependency management.

As identifiers, they do not store any information on the module content and detailed metadata (like dependencies).

Classes

  • ModuleId
  • is used as the identifier of module, without considering its version. It's basically an organization and module name couple.
  • ModuleRevisionId
  • is used as the identifier of a module in a particular version or version constraint. It is composed of a ModuleId, a revision, and optionally a branch and extra attributes.
  • ArtifactId
  • identifies an artifact without considering its version. It's basically a ModuleId and an artifact name, type and extension, plus optional extra attributes.
  • ArtifactRevisionId
  • identifies an artifact of a module in a particular version. It is composed of a ModuleRevisionId along with artifact identifier like the name type and extension.

Text Representation

These classes share an homogeneous text representation, which can be easily obtained through the toString() method.

The general pattern is: [organisation]#[module]#[branch];[revision]![artifact].[ext]([type]) The # before the branch is present only if the branch is not empty.
The type and surrounding parenthesis are present only if different from the extension.

A textual representation can be parsed into an object (supported for ModuleRevisionId only yet), as long as a strict set of characters is used for each field (which is recommended).
Allowed characters are:

  • organisation
  • a-z A-Z 0-9 - / . _ + =
  • module
  • a-z A-Z 0-9 - / . _ + =
  • branch
  • a-z A-Z 0-9 - / . _ + =
  • revision
  • a-z A-Z 0-9 - / . _ + = , [ ] { } ( ) : @
  • artifact
  • a-z A-Z 0-9 - / . _ + =
  • extension
  • a-z A-Z 0-9 - / . _ + =
  • type
  • a-z A-Z 0-9 - / . _ + =
ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/status/000077500000000000000000000000001226750426600231105ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/status/Status.java000066400000000000000000000025731226750426600252450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.status; public class Status { private String name; private boolean integration; public Status() { } public Status(String name, boolean integration) { this.name = name; this.integration = integration; } public boolean isIntegration() { return integration; } public void setIntegration(boolean integration) { this.integration = integration; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/module/status/StatusManager.java000066400000000000000000000116371226750426600265410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.module.status; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.util.Message; /** * Note: update methods (such as addStatus) should only be called BEFORE any call to accessor * methods */ public class StatusManager { public static StatusManager newDefaultInstance() { return new StatusManager(new Status[] {new Status("release", false), new Status("milestone", false), new Status("integration", true)}, "integration"); } public static StatusManager getCurrent() { return IvyContext.getContext().getSettings().getStatusManager(); } private List status = new ArrayList(); private String defaultStatus; // for easier querying only private Map statusPriorityMap; private Map statusIntegrationMap; private String deliveryStatusListString; public StatusManager(Status[] status, String defaultStatus) { this.status.addAll(Arrays.asList(status)); this.defaultStatus = defaultStatus; computeMaps(); } public StatusManager() { } public void addStatus(Status status) { this.status.add(status); } public void setDefaultStatus(String defaultStatus) { this.defaultStatus = defaultStatus; } public List getStatuses() { return status; } private void computeMaps() { if (status.isEmpty()) { throw new IllegalStateException("badly configured statuses: no status found"); } statusPriorityMap = new HashMap(); for (ListIterator iter = status.listIterator(); iter.hasNext();) { Status status = (Status) iter.next(); statusPriorityMap.put(status.getName(), new Integer(iter.previousIndex())); } statusIntegrationMap = new HashMap(); for (Iterator iter = status.iterator(); iter.hasNext();) { Status status = (Status) iter.next(); statusIntegrationMap.put(status.getName(), Boolean.valueOf(status.isIntegration())); } } public boolean isStatus(String status) { if (statusPriorityMap == null) { computeMaps(); } return statusPriorityMap.containsKey(status); } public int getPriority(String status) { if (statusPriorityMap == null) { computeMaps(); } Integer priority = (Integer) statusPriorityMap.get(status); if (priority == null) { Message.debug("unknown status " + status + ": assuming lowest priority"); return Integer.MAX_VALUE; } return priority.intValue(); } public boolean isIntegration(String status) { if (statusIntegrationMap == null) { computeMaps(); } Boolean isIntegration = (Boolean) statusIntegrationMap.get(status); if (isIntegration == null) { Message.debug("unknown status " + status + ": assuming integration"); return true; } return isIntegration.booleanValue(); } public String getDeliveryStatusListString() { if (deliveryStatusListString == null) { StringBuffer ret = new StringBuffer(); for (Iterator iter = status.iterator(); iter.hasNext();) { Status status = (Status) iter.next(); if (!status.isIntegration()) { ret.append(status.getName()).append(","); } } if (ret.length() > 0) { ret.deleteCharAt(ret.length() - 1); } deliveryStatusListString = ret.toString(); } return deliveryStatusListString; } public String getDefaultStatus() { if (defaultStatus == null) { if (status.isEmpty()) { throw new IllegalStateException("badly configured statuses: no status found"); } defaultStatus = ((Status) status.get(status.size() - 1)).getName(); } return defaultStatus; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/000077500000000000000000000000001226750426600212165ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/ArchivePacking.java000066400000000000000000000022101226750426600247320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.io.File; import java.io.IOException; import java.io.InputStream; public abstract class ArchivePacking { public abstract String[] getNames(); public abstract void unpack(InputStream packed, File dest) throws IOException; public abstract String getUnpackedExtension(String ext); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/Pack200Packing.java000066400000000000000000000051511226750426600244600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.jar.JarOutputStream; import java.util.jar.Pack200; import java.util.jar.Pack200.Unpacker; import java.util.zip.GZIPInputStream; public class Pack200Packing extends StreamPacking { private static final String[] NAMES = {"pack200"}; @Override public String[] getNames() { return NAMES; } @Override public String getUnpackedExtension(String ext) { if (ext.endsWith("pack.gz")) { ext = ext.substring(0, ext.length() - 7); if (ext.endsWith(".")) { ext = ext.substring(0, ext.length() - 1); } } else if (ext.endsWith("pack")) { ext = ext.substring(0, ext.length() - 4); if (ext.endsWith(".")) { ext = ext.substring(0, ext.length() - 1); } } return ext; } @Override public InputStream unpack(InputStream packed) throws IOException { BufferedInputStream buffered = new BufferedInputStream(packed); buffered.mark(4); byte[] magic = new byte[4]; buffered.read(magic, 0, 4); buffered.reset(); InputStream in = buffered; if (magic[0] == (byte) 0x1F && magic[1] == (byte) 0x8B && magic[2] == (byte) 0x08) { // this is a gziped pack200 in = new GZIPInputStream(in); } Unpacker unpacker = Pack200.newUnpacker(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); JarOutputStream jar = new JarOutputStream(baos); unpacker.unpack(in, jar); jar.close(); return new ByteArrayInputStream(baos.toByteArray()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/PackagingManager.java000066400000000000000000000110411226750426600252350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; public class PackagingManager implements IvySettingsAware { private IvySettings settings; public void setSettings(IvySettings settings) { this.settings = settings; } public Artifact getUnpackedArtifact(Artifact artifact) { String packaging = artifact.getExtraAttribute("packaging"); if (packaging == null) { // not declared as packed, nothing to do return null; } String ext = artifact.getExt(); String[] packings = packaging.split(","); for (int i = packings.length - 1; i >= 1; i--) { ArchivePacking packing = settings.getPackingRegistry().get(packings[i]); if (packing == null) { throw new IllegalStateException("Unknown packing type '" + packings[i] + "' in the packing chain: " + packaging); } if (!(packing instanceof StreamPacking)) { throw new IllegalStateException("Unsupported archive only packing type '" + packings[i] + "' in the streamed chain: " + packaging); } ext = ((StreamPacking) packing).getUnpackedExtension(ext); } ArchivePacking packing = settings.getPackingRegistry().get(packings[0]); if (packing == null) { throw new IllegalStateException("Unknown packing type '" + packings[0] + "' in the packing chain: " + packaging); } ext = packing.getUnpackedExtension(ext); DefaultArtifact unpacked = new DefaultArtifact(artifact.getModuleRevisionId(), artifact.getPublicationDate(), artifact.getName(), artifact.getType() + "_unpacked", ext); return unpacked; } public void unpackArtifact(Artifact artifact, File localFile, File archiveFile) throws IOException { String packaging = artifact.getExtraAttribute("packaging"); if (packaging == null) { // not declared as packed, nothing to do return; } String[] packings = packaging.split(","); InputStream in = null; try { in = new FileInputStream(localFile); for (int i = packings.length - 1; i >= 1; i--) { ArchivePacking packing = settings.getPackingRegistry().get(packings[i]); if (packing == null) { throw new IllegalStateException("Unknown packing type '" + packings[i] + "' in the packing chain: " + packaging); } if (!(packing instanceof StreamPacking)) { throw new IllegalStateException("Unsupported archive only packing type '" + packings[i] + "' in the streamed chain: " + packaging); } in = ((StreamPacking) packing).unpack(in); } ArchivePacking packing = settings.getPackingRegistry().get(packings[0]); if (packing == null) { throw new IllegalStateException("Unknown packing type '" + packings[0] + "' in the packing chain: " + packaging); } packing.unpack(in, archiveFile); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/PackingRegistry.java000066400000000000000000000026051226750426600251710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.util.HashMap; import java.util.Map; public class PackingRegistry { private Map packings = new HashMap(); public PackingRegistry() { // register defaults register(new ZipPacking()); register(new Pack200Packing()); } public void register(ArchivePacking packing) { for (String name : packing.getNames()) { packings.put(name, packing); } } public ArchivePacking get(String type) { return packings.get(type); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/StreamPacking.java000066400000000000000000000023531226750426600246140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.io.File; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.util.FileUtil; public abstract class StreamPacking extends ArchivePacking { public abstract InputStream unpack(InputStream packed) throws IOException; @Override public void unpack(InputStream packed, File dest) throws IOException { FileUtil.copy(unpack(packed), dest, null); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/pack/ZipPacking.java000066400000000000000000000060261226750426600241240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.pack; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; public class ZipPacking extends ArchivePacking { private static final String[] NAMES = {"zip", "jar", "war"}; @Override public String[] getNames() { return NAMES; } @Override public String getUnpackedExtension(String ext) { if (ext.endsWith("zip") || ext.endsWith("jar") || ext.endsWith("war")) { ext = ext.substring(0, ext.length() - 3); if (ext.endsWith(".")) { ext = ext.substring(0, ext.length() - 1); } } return ext; } @Override public void unpack(InputStream packed, File dest) throws IOException { ZipInputStream zip = null; try { zip = new ZipInputStream(packed); ZipEntry entry = null; while (((entry = zip.getNextEntry()) != null)) { File f = new File(dest, entry.getName()); Message.verbose("\t\texpanding " + entry.getName() + " to " + f); // create intermediary directories - sometimes zip don't add them File dirF = f.getParentFile(); if (dirF != null) { dirF.mkdirs(); } if (entry.isDirectory()) { f.mkdirs(); } else { FileOutputStream out = new FileOutputStream(f); try { FileUtil.copy(zip, out, null, false); } finally { try { out.close(); } catch (IOException e) { // ignore } } } f.setLastModified(entry.getTime()); } } finally { if (zip != null) { try { zip.close(); } catch (IOException e) { // ignore } } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/publish/000077500000000000000000000000001226750426600217465ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/publish/PublishEngine.java000066400000000000000000000335161226750426600253550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.publish; import java.io.File; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.event.publish.EndArtifactPublishEvent; import org.apache.ivy.core.event.publish.StartArtifactPublishEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.MDArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.parser.xml.UpdateOptions; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorUpdater; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.ConfigurationUtils; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; public class PublishEngine { private PublishEngineSettings settings; private EventManager eventManager; public PublishEngine(PublishEngineSettings settings, EventManager eventManager) { this.settings = settings; this.eventManager = eventManager; } /** * Publishes a module to the repository. The publish can update the ivy file to publish if * update is set to true. In this case it will use the given pubrevision, pubdate and status. If * pubdate is null it will default to the current date. If status is null it will default to the * current ivy file status (which itself defaults to integration if none is found). If update is * false, then if the revision is not the same in the ivy file than the one expected (given as * parameter), this method will fail with an IllegalArgumentException. pubdate and status are * not used if update is false. extra artifacts can be used to publish more artifacts than * actually declared in the ivy file. This can be useful to publish additional metadata or * reports. The extra artifacts array can be null (= no extra artifacts), and if non null only * the name, type, ext url and extra attributes of the artifacts are really used. Other methods * can return null safely. */ public Collection publish(ModuleRevisionId mrid, Collection srcArtifactPattern, String resolverName, PublishOptions options) throws IOException { Message.info(":: publishing :: " + mrid.getModuleId()); Message.verbose("\tvalidate = " + options.isValidate()); long start = System.currentTimeMillis(); options.setSrcIvyPattern(settings.substitute(options.getSrcIvyPattern())); if (options.getPubBranch() == null) { options.setPubbranch(mrid.getBranch()); } if (options.getPubrevision() == null) { options.setPubrevision(mrid.getRevision()); } ModuleRevisionId pubmrid = ModuleRevisionId.newInstance(mrid, options.getPubBranch(), options.getPubrevision()); // let's find the resolved module descriptor ModuleDescriptor md = null; if (options.getSrcIvyPattern() != null) { File ivyFile = settings.resolveFile(IvyPatternHelper.substitute( options.getSrcIvyPattern(), DefaultArtifact.newIvyArtifact(pubmrid, new Date()))); if (!ivyFile.exists()) { throw new IllegalArgumentException("ivy file to publish not found for " + mrid + ": call deliver before (" + ivyFile + ")"); } URL ivyFileURL = ivyFile.toURI().toURL(); try { md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFileURL, false); if (options.isUpdate()) { File tmp = File.createTempFile("ivy", ".xml"); tmp.deleteOnExit(); String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md); Set confsToRemove = new HashSet(Arrays.asList(md.getConfigurationsNames())); confsToRemove.removeAll(Arrays.asList(confs)); try { XmlModuleDescriptorUpdater.update( ivyFileURL, tmp, new UpdateOptions() .setSettings(settings) .setStatus( options.getStatus() == null ? md.getStatus() : options .getStatus()) .setRevision(options.getPubrevision()) .setBranch(options.getPubBranch()) .setPubdate( options.getPubdate() == null ? new Date() : options .getPubdate()) .setMerge(options.isMerge()) .setMergedDescriptor(md) .setConfsToExclude( (String[]) confsToRemove.toArray(new String[confsToRemove .size()]))); ivyFile = tmp; // we parse the new file to get updated module descriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFile.toURI().toURL(), false); options.setSrcIvyPattern(ivyFile.getAbsolutePath()); } catch (SAXException e) { throw new IllegalStateException("bad ivy file for " + mrid + ": " + ivyFile + ": " + e); } } else if (!options.getPubrevision().equals(md.getModuleRevisionId().getRevision())) { throw new IllegalArgumentException("cannot publish " + ivyFile + " as " + options.getPubrevision() + ": bad revision found in ivy file (Revision: " + md.getModuleRevisionId().getRevision() + "). Use forcedeliver or update."); } } catch (ParseException e) { throw new IllegalStateException("bad ivy file for " + mrid + ": " + ivyFile + ": " + e); } } else { ResolutionCacheManager cacheManager = settings.getResolutionCacheManager(); try { md = cacheManager.getResolvedModuleDescriptor(mrid); } catch (ParseException e) { throw new IllegalStateException("bad ivy file in cache for " + mrid + ": " + e); } md.setResolvedModuleRevisionId(pubmrid); } DependencyResolver resolver = settings.getResolver(resolverName); if (resolver == null) { throw new IllegalArgumentException("unknown resolver " + resolverName); } // collect all declared artifacts of this module Collection missing = publish(md, srcArtifactPattern, resolver, options); Message.verbose("\tpublish done (" + (System.currentTimeMillis() - start) + "ms)"); return missing; } public Collection publish(ModuleDescriptor md, Collection srcArtifactPattern, DependencyResolver resolver, PublishOptions options) throws IOException { Collection missing = new ArrayList(); Set artifactsSet = new LinkedHashSet(); String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md); for (int i = 0; i < confs.length; i++) { Artifact[] artifacts = md.getArtifacts(confs[i]); for (int j = 0; j < artifacts.length; j++) { artifactsSet.add(artifacts[j]); } } Artifact[] extraArtifacts = options.getExtraArtifacts(); if (extraArtifacts != null) { for (int i = 0; i < extraArtifacts.length; i++) { artifactsSet.add(new MDArtifact(md, extraArtifacts[i].getName(), extraArtifacts[i] .getType(), extraArtifacts[i].getExt(), extraArtifacts[i].getUrl(), extraArtifacts[i].getQualifiedExtraAttributes())); } } // now collects artifacts files Map/* */artifactsFiles = new LinkedHashMap(); for (Iterator iter = artifactsSet.iterator(); iter.hasNext();) { Artifact artifact = (Artifact) iter.next(); for (Iterator iterator = srcArtifactPattern.iterator(); iterator.hasNext();) { String pattern = (String) iterator.next(); File artifactFile = settings.resolveFile(IvyPatternHelper.substitute( settings.substitute(pattern), artifact)); if (artifactFile.exists()) { artifactsFiles.put(artifact, artifactFile); break; } } if (!artifactsFiles.containsKey(artifact)) { StringBuffer sb = new StringBuffer(); sb.append("missing artifact " + artifact + ":\n"); for (Iterator iterator = srcArtifactPattern.iterator(); iterator.hasNext();) { String pattern = (String) iterator.next(); sb.append("\t" + settings.resolveFile(IvyPatternHelper.substitute(pattern, artifact)) + " file does not exist\n"); } if (options.isWarnOnMissing() || options.isHaltOnMissing()) { Message.warn(sb.toString()); } else { Message.verbose(sb.toString()); } if (options.isHaltOnMissing()) { throw new IOException("missing artifact " + artifact); } missing.add(artifact); } } if (options.getSrcIvyPattern() != null) { Artifact artifact = MDArtifact.newIvyArtifact(md); File artifactFile = settings.resolveFile(IvyPatternHelper.substitute( options.getSrcIvyPattern(), artifact)); if (!artifactFile.exists()) { String msg = "missing ivy file for " + md.getModuleRevisionId() + ": \n" + artifactFile + " file does not exist"; if (options.isWarnOnMissing() || options.isHaltOnMissing()) { Message.warn(msg); } else { Message.verbose(msg); } if (options.isHaltOnMissing()) { throw new IOException("missing ivy artifact " + artifact); } missing.add(artifact); } else { artifactsFiles.put(artifact, artifactFile); } } // and now do actual publishing boolean successfullyPublished = false; try { resolver.beginPublishTransaction(md.getModuleRevisionId(), options.isOverwrite()); // for each declared published artifact in this descriptor, do: for (Iterator iter = artifactsFiles.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Entry) iter.next(); Artifact artifact = (Artifact) entry.getKey(); File artifactFile = (File) entry.getValue(); publish(artifact, artifactFile, resolver, options.isOverwrite()); } resolver.commitPublishTransaction(); successfullyPublished = true; } finally { if (!successfullyPublished) { resolver.abortPublishTransaction(); } } return missing; } private void publish(Artifact artifact, File src, DependencyResolver resolver, boolean overwrite) throws IOException { IvyContext.getContext().checkInterrupted(); // notify triggers that an artifact is about to be published eventManager .fireIvyEvent(new StartArtifactPublishEvent(resolver, artifact, src, overwrite)); boolean successful = false; // set to true once the publish succeeds try { if (src.exists()) { resolver.publish(artifact, src, overwrite); successful = true; } } finally { // notify triggers that the publish is finished, successfully or not. eventManager.fireIvyEvent(new EndArtifactPublishEvent(resolver, artifact, src, overwrite, successful)); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/publish/PublishEngineSettings.java000066400000000000000000000022461226750426600270720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.publish; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.resolver.DependencyResolver; /** * Settings specific to the publish engine */ public interface PublishEngineSettings extends ParserSettings { String substitute(String srcIvyPattern); DependencyResolver getResolver(String resolverName); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/publish/PublishOptions.java000066400000000000000000000115061226750426600255760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.publish; import java.util.Date; import org.apache.ivy.core.module.descriptor.Artifact; /** * A set of options used during publish related tasks The publish can update the ivy file to publish * if update is set to true. In this case it will use the given pubrevision, pubdate and status. If * pudate is null it will default to the current date. If status is null it will default to the * current ivy file status (which itself defaults to integration if none is found). If update is * false, then if the revision is not the same in the ivy file than the one expected (given as * parameter), this method will fail with an IllegalArgumentException. pubdate and status are not * used if update is false. extra artifacts can be used to publish more artifacts than actually * declared in the ivy file. This can be useful to publish additional metadata or reports. The extra * artifacts array can be null (= no extra artifacts), and if non null only the name, type, ext url * and extra attributes of the artifacts are really used. Other methods (on the artifacts) can * return null safely. * * @see PublishEngine */ public class PublishOptions { private String srcIvyPattern; private String pubrevision; private String status; private Date pubdate; private Artifact[] extraArtifacts; private boolean validate; private boolean overwrite; private boolean update; private boolean merge = true; private String[] confs; private boolean haltonmissing; private String pubBranch; private boolean warnonmissing; public String[] getConfs() { return confs; } public PublishOptions setConfs(String[] confs) { this.confs = confs; return this; } public Artifact[] getExtraArtifacts() { return extraArtifacts; } public PublishOptions setExtraArtifacts(Artifact[] extraArtifacts) { this.extraArtifacts = extraArtifacts; return this; } public boolean isOverwrite() { return overwrite; } public PublishOptions setOverwrite(boolean overwrite) { this.overwrite = overwrite; return this; } public Date getPubdate() { return pubdate; } public PublishOptions setPubdate(Date pubdate) { this.pubdate = pubdate; return this; } public String getPubrevision() { return pubrevision; } public PublishOptions setPubrevision(String pubrevision) { this.pubrevision = pubrevision; return this; } public String getSrcIvyPattern() { return srcIvyPattern; } public PublishOptions setSrcIvyPattern(String srcIvyPattern) { this.srcIvyPattern = srcIvyPattern; return this; } public String getStatus() { return status; } public PublishOptions setStatus(String status) { this.status = status; return this; } public boolean isUpdate() { return update; } public PublishOptions setUpdate(boolean update) { this.update = update; return this; } public boolean isMerge() { return merge; } public PublishOptions setMerge(boolean merge) { this.merge = merge; return this; } public boolean isValidate() { return validate; } public PublishOptions setValidate(boolean validate) { this.validate = validate; return this; } public boolean isHaltOnMissing() { return haltonmissing; } public PublishOptions setHaltOnMissing(boolean haltonmissing) { this.haltonmissing = haltonmissing; return this; } public String getPubBranch() { return pubBranch; } public PublishOptions setPubbranch(String pubbranch) { this.pubBranch = pubbranch; return this; } public boolean isWarnOnMissing() { return warnonmissing; } public PublishOptions setWarnOnMissing(boolean warnonmissing) { this.warnonmissing = warnonmissing; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/000077500000000000000000000000001226750426600216135ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/ArtifactDownloadReport.java000066400000000000000000000126351226750426600271060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.io.File; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; /** * Report on the download of an artifact from a repository to a local (cached) file. *

* Note that depending on cache implementation, the artifact may not be actually downloaded, but * used directly from its original location. *

*/ public class ArtifactDownloadReport { /** * download details used when the download "fails" when the artifact is simply missing on the * remote repository. *

* For historical reason the status can't be used to distinguish a real failure from a missing * artifact by using the status, in both cases it's DownloadStatus.FAILED. The details message * can be used for this purpose though. *

*/ public static final String MISSING_ARTIFACT = "missing artifact"; private Artifact artifact; private ArtifactOrigin origin; private File localFile; private DownloadStatus downloadStatus; private long size; private String downloadDetails = ""; private long downloadTimeMillis; private File unpackedLocalFile; public ArtifactDownloadReport(Artifact artifact) { this.artifact = artifact; } public DownloadStatus getDownloadStatus() { return downloadStatus; } public void setDownloadStatus(DownloadStatus downloadStatus) { this.downloadStatus = downloadStatus; } public String getName() { return artifact.getName(); } /** * * @return the type of the downloaded artifact */ public String getType() { return artifact.getType(); } public Artifact getArtifact() { return artifact; } public String getExt() { return artifact.getExt(); } public long getSize() { return size; } public void setSize(long size) { this.size = size; } public void setArtifactOrigin(ArtifactOrigin origin) { this.origin = origin; } public ArtifactOrigin getArtifactOrigin() { return origin; } public void setDownloadDetails(String message) { downloadDetails = message; } public String getDownloadDetails() { return downloadDetails; } public void setDownloadTimeMillis(long l) { downloadTimeMillis = l; } public long getDownloadTimeMillis() { return downloadTimeMillis; } public String toString() { if (downloadStatus == DownloadStatus.SUCCESSFUL) { return "[SUCCESSFUL ] " + artifact + " (" + downloadTimeMillis + "ms)"; } else if (downloadStatus == DownloadStatus.FAILED) { if (downloadDetails == MISSING_ARTIFACT) { return "[NOT FOUND ] " + artifact + " (" + downloadTimeMillis + "ms)"; } else { return "[FAILED ] " + artifact + ": " + downloadDetails + " (" + downloadTimeMillis + "ms)"; } } else if (downloadStatus == DownloadStatus.NO) { return "[NOT REQUIRED] " + artifact; } else { return super.toString(); } } /** * Returns the File where the artifact is available on the local filesystem, or * null if and only if the artifact caching failed. * * @return the file where the artifact is now available on the local filesystem. */ public File getLocalFile() { return localFile; } public void setLocalFile(File localFile) { this.localFile = localFile; } public boolean isDownloaded() { return DownloadStatus.SUCCESSFUL == downloadStatus; } public void setUnpackedLocalFile(File unpackedLocalFile) { this.unpackedLocalFile = unpackedLocalFile; } public File getUnpackedLocalFile() { return unpackedLocalFile; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((artifact == null) ? 0 : artifact.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ArtifactDownloadReport other = (ArtifactDownloadReport) obj; if (artifact == null) { if (other.artifact != null) { return false; } } else if (!artifact.equals(other.artifact)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/ConfigurationResolveReport.java000066400000000000000000000323331226750426600300250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.sort.SortOptions; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.util.Message; /** * Represents a whole resolution report for a module but for a specific configuration */ public class ConfigurationResolveReport { private final ModuleDescriptor md; private final String conf; private final Date date; private final ResolveOptions options; private Map> dependencyReports = new LinkedHashMap>(); private Map dependencies = new LinkedHashMap(); private final ResolveEngine resolveEngine; private Map> modulesIdsMap = new LinkedHashMap>(); private List modulesIds; private Boolean hasChanged = null; public ConfigurationResolveReport(ResolveEngine resolveEngine, ModuleDescriptor md, String conf, Date date, ResolveOptions options) { this.resolveEngine = resolveEngine; this.md = md; this.conf = conf; this.date = date; this.options = options; } /** * Check if the set of dependencies has changed since the previous execution of a resolution.
* This function use the report file found in the cache. So the function must be called before * the new report is serialized there.
This function also use the internal dependencies * that must already be filled. This function might be 'heavy' because it may have to parse the * previous report. * * @return */ public void checkIfChanged() { ResolutionCacheManager cache = resolveEngine.getSettings().getResolutionCacheManager(); String resolveId = options.getResolveId(); File previousReportFile = cache.getConfigurationResolveReportInCache(resolveId, conf); if (previousReportFile.exists()) { try { XmlReportParser parser = new XmlReportParser(); parser.parse(previousReportFile); List previousDeps = Arrays.asList(parser .getDependencyRevisionIds()); HashSet previousDepSet = new HashSet( previousDeps); hasChanged = Boolean.valueOf(!previousDepSet.equals(getModuleRevisionIds())); } catch (Exception e) { Message.warn("Error while parsing configuration resolve report " + previousReportFile.getAbsolutePath(), e); hasChanged = Boolean.TRUE; } } else { hasChanged = Boolean.TRUE; } } /** * @pre checkIfChanged has been called. */ public boolean hasChanged() { return hasChanged.booleanValue(); } /** * Returns all non evicted and non error dependency mrids The returned set is ordered so that a * dependency will always be found before their own dependencies * * @return all non evicted and non error dependency mrids */ public Set getModuleRevisionIds() { Set mrids = new LinkedHashSet(); for (IvyNode node : getDependencies()) { if (!node.isEvicted(getConfiguration()) && !node.hasProblem()) { mrids.add(node.getResolvedId()); } } return mrids; } public void addDependency(IvyNode node) { dependencies.put(node.getId(), node); dependencies.put(node.getResolvedId(), node); dependencyReports.put(node, Collections. emptyList()); } public void updateDependency(ModuleRevisionId mrid, IvyNode node) { dependencies.put(mrid, node); } public void addDependency(IvyNode node, DownloadReport report) { dependencies.put(node.getId(), node); dependencies.put(node.getResolvedId(), node); List adrs = new ArrayList(); Artifact[] artifacts = node.getArtifacts(conf); for (Artifact artifact : artifacts) { ArtifactDownloadReport artifactReport = report.getArtifactReport(artifact); if (artifactReport != null) { adrs.add(artifactReport); } else { Message.debug("no report found for " + artifact); } } dependencyReports.put(node, adrs); } public String getConfiguration() { return conf; } public Date getDate() { return date; } public ModuleDescriptor getModuleDescriptor() { return md; } public IvyNode[] getUnresolvedDependencies() { List unresolved = new ArrayList(); for (IvyNode node : getDependencies()) { if (node.hasProblem()) { unresolved.add(node); } } return unresolved.toArray(new IvyNode[unresolved.size()]); } private Collection getDependencies() { return new LinkedHashSet(dependencies.values()); } public IvyNode[] getEvictedNodes() { List evicted = new ArrayList(); for (IvyNode node : getDependencies()) { if (node.isEvicted(conf)) { evicted.add(node); } } return evicted.toArray(new IvyNode[evicted.size()]); } private Set getEvictedMrids() { Set evicted = new LinkedHashSet(); IvyNode[] evictedNodes = getEvictedNodes(); for (IvyNode node : evictedNodes) { evicted.add(node.getId()); } return evicted; } public IvyNode[] getDownloadedNodes() { List downloaded = new ArrayList(); for (IvyNode node : getDependencies()) { if (node.isDownloaded() && node.getRealNode() == node) { downloaded.add(node); } } return downloaded.toArray(new IvyNode[downloaded.size()]); } public IvyNode[] getSearchedNodes() { List downloaded = new ArrayList(); for (IvyNode node : getDependencies()) { if (node.isSearched() && node.getRealNode() == node) { downloaded.add(node); } } return downloaded.toArray(new IvyNode[downloaded.size()]); } public ArtifactDownloadReport[] getDownloadReports(ModuleRevisionId mrid) { Collection col = dependencyReports.get(getDependency(mrid)); if (col == null) { return new ArtifactDownloadReport[0]; } return col.toArray(new ArtifactDownloadReport[col.size()]); } public IvyNode getDependency(ModuleRevisionId mrid) { return dependencies.get(mrid); } /** * gives all the modules ids concerned by this report, from the most dependent to the least one * * @return a list of ModuleId */ public List getModuleIds() { if (modulesIds == null) { List sortedDependencies = resolveEngine.getSortEngine().sortNodes( getDependencies(), SortOptions.SILENT); Collections.reverse(sortedDependencies); for (IvyNode dependency : sortedDependencies) { ModuleId mid = dependency.getResolvedId().getModuleId(); Collection deps = modulesIdsMap.get(mid); if (deps == null) { deps = new LinkedHashSet(); modulesIdsMap.put(mid, deps); } deps.add(dependency); } modulesIds = new ArrayList(modulesIdsMap.keySet()); } return Collections.unmodifiableList(modulesIds); } public Collection getNodes(ModuleId mid) { if (modulesIds == null) { getModuleIds(); } return modulesIdsMap.get(mid); } public ResolveEngine getResolveEngine() { return resolveEngine; } public int getArtifactsNumber() { int total = 0; for (Collection reports : dependencyReports.values()) { total += reports == null ? 0 : reports.size(); } return total; } /** * Get every report on the download requests. * * @return the list of reports, never null */ public ArtifactDownloadReport[] getAllArtifactsReports() { return getArtifactsReports(null, true); } /** * Get the report on the download requests. The list of download report can be restricted to a * specific download status, and also remove the download report for the evicted modules. * * @param downloadStatus * the status of download to retreive. Set it to null for no restriction * on the download status * @param withEvicted * set it to true if the report for the evicted modules have to be * retrieved. * @return the list of reports, never null * @see ArtifactDownloadReport */ public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus downloadStatus, boolean withEvicted) { Collection all = new LinkedHashSet(); Collection evictedMrids = null; if (!withEvicted) { evictedMrids = getEvictedMrids(); } for (Collection reports : dependencyReports.values()) { for (ArtifactDownloadReport report : reports) { if (downloadStatus != null && report.getDownloadStatus() != downloadStatus) { continue; } if (withEvicted || !evictedMrids.contains(report.getArtifact().getModuleRevisionId())) { all.add(report); } } } return all.toArray(new ArtifactDownloadReport[all.size()]); } /** * Get the report on the sucessfull download requests with the evicted modules * * @return the list of reports, never null */ public ArtifactDownloadReport[] getDownloadedArtifactsReports() { return getArtifactsReports(DownloadStatus.SUCCESSFUL, true); } /** * Get the report on the failed download requests with the evicted modules * * @return the list of reports, never null */ public ArtifactDownloadReport[] getFailedArtifactsReports() { ArtifactDownloadReport[] allFailedReports = getArtifactsReports(DownloadStatus.FAILED, true); return filterOutMergedArtifacts(allFailedReports); } public boolean hasError() { return getUnresolvedDependencies().length > 0 || getFailedArtifactsReports().length > 0; } public int getNodesNumber() { return getDependencies().size(); } public static ArtifactDownloadReport[] filterOutMergedArtifacts( ArtifactDownloadReport[] allFailedReports) { Collection adrs = new ArrayList( Arrays.asList(allFailedReports)); for (Iterator iterator = adrs.iterator(); iterator.hasNext();) { ArtifactDownloadReport adr = iterator.next(); if (adr.getArtifact().getExtraAttribute("ivy:merged") != null) { iterator.remove(); } } return adrs.toArray(new ArtifactDownloadReport[adrs.size()]); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/DownloadReport.java000066400000000000000000000040421226750426600254210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.descriptor.Artifact; /** * */ public class DownloadReport { private Map artifacts = new HashMap(); public void addArtifactReport(ArtifactDownloadReport adr) { artifacts.put(adr.getArtifact(), adr); } public ArtifactDownloadReport[] getArtifactsReports() { return (ArtifactDownloadReport[]) artifacts.values().toArray( new ArtifactDownloadReport[artifacts.size()]); } public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus status) { List ret = new ArrayList(artifacts.size()); for (Iterator iter = artifacts.values().iterator(); iter.hasNext();) { ArtifactDownloadReport adr = (ArtifactDownloadReport) iter.next(); if (adr.getDownloadStatus() == status) { ret.add(adr); } } return (ArtifactDownloadReport[]) ret.toArray(new ArtifactDownloadReport[ret.size()]); } public ArtifactDownloadReport getArtifactReport(Artifact artifact) { return (ArtifactDownloadReport) artifacts.get(artifact); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/DownloadStatus.java000066400000000000000000000040601226750426600254310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; /** * */ public final class DownloadStatus { private String name; private DownloadStatus(String name) { this.name = name; } /** * means that download was not required */ public static final DownloadStatus NO = new DownloadStatus("no"); public static final DownloadStatus SUCCESSFUL = new DownloadStatus("successful"); public static final DownloadStatus FAILED = new DownloadStatus("failed"); /** * Returns the {@link DownloadStatus} corresponding to the given String representation. * * @return the {@link DownloadStatus} corresponding to the given String representation. * @throws IllegalArgumentException * if the given String does not correspond to any {@link DownloadStatus}. */ public static final DownloadStatus fromString(String status) { if (NO.name.equals(status)) { return NO; } if (SUCCESSFUL.name.equals(status)) { return SUCCESSFUL; } if (FAILED.name.equals(status)) { return FAILED; } throw new IllegalArgumentException("unknown download status '" + status + "'"); } public String toString() { return name; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/MetadataArtifactDownloadReport.java000066400000000000000000000042301226750426600305370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; public class MetadataArtifactDownloadReport extends ArtifactDownloadReport { private boolean isSearched; private File originalLocalFile; public MetadataArtifactDownloadReport(Artifact artifact) { super(artifact); } /** * Returns true if the resolution of this metadata artifact required at least one * access to the repository, or false if only provisioned data was used. * * @return true if the resolution of this metadata artifact required at least one * access to the repository */ public boolean isSearched() { return isSearched; } public void setSearched(boolean isSearched) { this.isSearched = isSearched; } /** * Returns the location on the local filesystem where the original metadata artifact is * provisioned, or null if the provisioning failed. * * @return the location on the local filesystem where the original metadata artifact is * provisioned. */ public File getOriginalLocalFile() { return originalLocalFile; } public void setOriginalLocalFile(File originalLocalFile) { this.originalLocalFile = originalLocalFile; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/report/ResolveReport.java000066400000000000000000000406051226750426600252760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.report; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.report.ReportOutputter; import org.apache.ivy.util.filter.Filter; /** * Represents a whole resolution report for a module */ public class ResolveReport { private ModuleDescriptor md; /** String conf -> ConfigurationResolveReport report */ private Map confReports = new LinkedHashMap(); private List problemMessages = new ArrayList(); /** * the list of all dependencies resolved, ordered from the more dependent to the less dependent */ private List/* */dependencies = new ArrayList(); private List/* */artifacts = new ArrayList(); private long resolveTime; private long downloadTime; private String resolveId; private long downloadSize; public ResolveReport(ModuleDescriptor md) { this(md, ResolveOptions.getDefaultResolveId(md)); } public ResolveReport(ModuleDescriptor md, String resolveId) { this.md = md; this.resolveId = resolveId; } public void addReport(String conf, ConfigurationResolveReport report) { confReports.put(conf, report); } public ConfigurationResolveReport getConfigurationReport(String conf) { return (ConfigurationResolveReport) confReports.get(conf); } public String[] getConfigurations() { return (String[]) confReports.keySet().toArray(new String[confReports.size()]); } public boolean hasError() { boolean hasError = false; for (Iterator it = confReports.values().iterator(); it.hasNext() && !hasError;) { ConfigurationResolveReport report = (ConfigurationResolveReport) it.next(); hasError |= report.hasError(); } return hasError; } public void output(ReportOutputter[] outputters, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException { for (int i = 0; i < outputters.length; i++) { outputters[i].output(this, cacheMgr, options); } } public ModuleDescriptor getModuleDescriptor() { return md; } public IvyNode[] getEvictedNodes() { Collection all = new LinkedHashSet(); for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); all.addAll(Arrays.asList(report.getEvictedNodes())); } return (IvyNode[]) all.toArray(new IvyNode[all.size()]); } public IvyNode[] getUnresolvedDependencies() { Collection all = new LinkedHashSet(); for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); all.addAll(Arrays.asList(report.getUnresolvedDependencies())); } return (IvyNode[]) all.toArray(new IvyNode[all.size()]); } /** * Get every report on the download requests. * * @return the list of reports, never null */ public ArtifactDownloadReport[] getFailedArtifactsReports() { return ConfigurationResolveReport.filterOutMergedArtifacts(getArtifactsReports( DownloadStatus.FAILED, true)); } /** * Get every report on the download requests. * * @return the list of reports, never null */ public ArtifactDownloadReport[] getAllArtifactsReports() { return getArtifactsReports(null, true); } /** * Get the report on the download requests. The list of download report can be restricted to a * specific download status, and also remove the download report for the evicted modules. * * @param downloadStatus * the status of download to retreive. Set it to null for no restriction * on the download status * @param withEvicted * set it to true if the report for the evicted modules have to be * retrieved, false to exclude reports from modules evicted in all * configurations. * @return the list of reports, never null * @see ConfigurationResolveReport#getArtifactsReports(DownloadStatus, boolean) */ public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus downloadStatus, boolean withEvicted) { Collection all = new LinkedHashSet(); for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); ArtifactDownloadReport[] reports = report.getArtifactsReports(downloadStatus, withEvicted); all.addAll(Arrays.asList(reports)); } return (ArtifactDownloadReport[]) all.toArray(new ArtifactDownloadReport[all.size()]); } public ArtifactDownloadReport[] getArtifactsReports(ModuleRevisionId mrid) { Collection all = new LinkedHashSet(); for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); all.addAll(Arrays.asList(report.getDownloadReports(mrid))); } return (ArtifactDownloadReport[]) all.toArray(new ArtifactDownloadReport[all.size()]); } public void checkIfChanged() { for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); report.checkIfChanged(); } } /** Can only be called if checkIfChanged has been called */ public boolean hasChanged() { for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport report = (ConfigurationResolveReport) iter.next(); if (report.hasChanged()) { return true; } } return false; } public void setProblemMessages(List problems) { problemMessages = problems; } public List getProblemMessages() { return problemMessages; } public List getAllProblemMessages() { List ret = new ArrayList(problemMessages); for (Iterator iter = confReports.values().iterator(); iter.hasNext();) { ConfigurationResolveReport r = (ConfigurationResolveReport) iter.next(); IvyNode[] unresolved = r.getUnresolvedDependencies(); for (int i = 0; i < unresolved.length; i++) { String errMsg = unresolved[i].getProblemMessage(); if (errMsg.length() > 0) { ret.add("unresolved dependency: " + unresolved[i].getId() + ": " + errMsg); } else { ret.add("unresolved dependency: " + unresolved[i].getId()); } } ArtifactDownloadReport[] adrs = r.getFailedArtifactsReports(); for (int i = 0; i < adrs.length; i++) { ret.add("download failed: " + adrs[i].getArtifact()); } } return ret; } public void setDependencies(List dependencies, Filter artifactFilter) { this.dependencies = dependencies; // collect list of artifacts artifacts = new ArrayList(); for (Iterator iter = dependencies.iterator(); iter.hasNext();) { IvyNode dependency = (IvyNode) iter.next(); if (!dependency.isCompletelyEvicted() && !dependency.hasProblem()) { artifacts.addAll(Arrays.asList(dependency.getSelectedArtifacts(artifactFilter))); } // update the configurations reports with the dependencies // these reports will be completed later with download information, if any String[] dconfs = dependency.getRootModuleConfigurations(); for (int j = 0; j < dconfs.length; j++) { ConfigurationResolveReport configurationReport = getConfigurationReport(dconfs[j]); if (configurationReport != null) { configurationReport.addDependency(dependency); } } } } /** * Returns the list of all dependencies concerned by this report as a List of IvyNode ordered * from the more dependent to the least one * * @return The list of all dependencies. */ public List/* */getDependencies() { return dependencies; } /** * Returns the list of all artifacts which should be downloaded per this resolve To know if the * artifact have actually been downloaded use information found in ConfigurationResolveReport. * * @return The list of all artifacts. */ public List/* */getArtifacts() { return artifacts; } /** * gives all the modules ids concerned by this report, from the most dependent to the least one * * @return a list of ModuleId */ public List getModuleIds() { List ret = new ArrayList(); List sortedDependencies = new ArrayList(dependencies); for (Iterator iter = sortedDependencies.iterator(); iter.hasNext();) { IvyNode dependency = (IvyNode) iter.next(); ModuleId mid = dependency.getResolvedId().getModuleId(); if (!ret.contains(mid)) { ret.add(mid); } } return ret; } public void setResolveTime(long elapsedTime) { resolveTime = elapsedTime; } public long getResolveTime() { return resolveTime; } public void setDownloadTime(long elapsedTime) { downloadTime = elapsedTime; } public long getDownloadTime() { return downloadTime; } public void setDownloadSize(long size) { this.downloadSize = size; } /** * The total size of downloaded artifacts, in bytes. *

* This only includes artifacts actually downloaded to cache (DownloadStatus.SUCCESSFUL), and * not artifacts already in cache or used at their original location. *

* * @return The total size of downloaded artifacts, in bytes. */ public long getDownloadSize() { return downloadSize; } public String getResolveId() { return resolveId; } /** * Get every configuration which extends the specified one. The returned list also includes the * specified one. * * @param extended * @return */ private String[] getExtendingConfs(String extended) { String[] allConfs = md.getConfigurationsNames(); Set extendingConfs = new HashSet(); extendingConfs.add(extended); for (int i = 0; i < allConfs.length; i++) { gatherExtendingConfs(extendingConfs, allConfs[i], extended); } return extendingConfs.toArray(new String[extendingConfs.size()]); } private boolean gatherExtendingConfs(Set extendingConfs, String conf, String extended) { if (extendingConfs.contains(conf)) { return true; } String[] ext = md.getConfiguration(conf).getExtends(); if (ext == null || ext.length == 0) { return false; } for (int i = 0; i < ext.length; i++) { if (extendingConfs.contains(ext[i])) { extendingConfs.add(conf); return true; } if (ext[i].equals(extended)) { extendingConfs.add(conf); return true; } if (gatherExtendingConfs(extendingConfs, ext[i], extended)) { extendingConfs.add(conf); return true; } } return false; } public ModuleDescriptor toFixedModuleDescriptor(IvySettings settings, List midToKeep) { DefaultModuleDescriptor fixedmd = new DefaultModuleDescriptor(md.getModuleRevisionId(), md.getStatus(), new Date()); // copy configurations List resolvedConfs = Arrays.asList(getConfigurations()); for (String conf : resolvedConfs) { fixedmd.addConfiguration(new Configuration(conf)); } if (midToKeep != null && !midToKeep.isEmpty()) { // add dependency we want to keep from the original module descriptor DependencyDescriptor[] deps = md.getDependencies(); for (int i = 0; i < deps.length; i++) { if (midToKeep.contains(deps[i].getDependencyId())) { DefaultDependencyDescriptor dep = new DefaultDependencyDescriptor(fixedmd, deps[i].getDependencyRevisionId(), true, false, false); List confs = Arrays.asList(deps[i].getModuleConfigurations()); if (confs.size() == 1 && confs.get(0).equals("*")) { confs = resolvedConfs; } for (String conf : confs) { String[] extendedConfs = getExtendingConfs(conf); String[] depConfs = deps[i].getDependencyConfigurations(conf); for (String extendedConf : extendedConfs) { if (resolvedConfs.contains(extendedConf)) { for (String depConf : depConfs) { dep.addDependencyConfiguration(extendedConf, depConf); } } } } fixedmd.addDependency(dep); } } } // add resolved dependencies for (int i = 0; i < dependencies.size(); i++) { IvyNode node = (IvyNode) dependencies.get(i); if (midToKeep != null && midToKeep.contains(node.getModuleId())) { continue; } String[] rootConfs = node.getRootModuleConfigurations(); for (int j = 0; j < rootConfs.length; j++) { if (node.isEvicted(rootConfs[j])) { continue; } if (node.getAllArtifacts().length == 0) { // no artifact: it was probably useful transitively, hence it is useless here break; } DefaultDependencyDescriptor dep = new DefaultDependencyDescriptor(fixedmd, node.getResolvedId(), true, false, false); String[] targetConfs = node.getConfigurations(rootConfs[j]); for (int k = 0; k < targetConfs.length; k++) { dep.addDependencyConfiguration(rootConfs[j], targetConfs[k]); } fixedmd.addDependency(dep); } } return fixedmd; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/repository/000077500000000000000000000000001226750426600225175ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/repository/RepositoryManagementEngine.java000066400000000000000000000307021226750426600306660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.repository; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.TreeSet; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.SearchEngine; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.matcher.RegexpPatternMatcher; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.MemoryUtil; import org.apache.ivy.util.Message; /** * The repository management can be used to load all metadata from a repository, analyze them, and * provide a bunch of information about the whole repository state. *

* Since loading all metadata from a repository is not a light task, this engine should only be used * on a machine having good access to the repository (on the same filesystem being usually the best * suited). *

*

* To access information, you usually have before to call a method to init the data: {@link #load()} * is used to load repository metadata, {@link #analyze()} is used to analyze them. These methods * being very time consuming, they must always be called explicitly. *

*

* On a large repository, this engine can be very memory consuming to use, it is not suited to be * used in a long running process, but rather in short process loading data and taking action about * the current state of the repository. *

*

* This engine is not intended to be used concurrently with publish, the order of repository loaded * being undeterministic and long, it could end up in having an inconsistent in memory state. *

*

* For better performance, we strongly suggest using this engine with cache in useOrigin mode. *

*/ public class RepositoryManagementEngine { private static final double THOUSAND = 1000.0; private static final int KILO = 1024; // ///////////////////////////////////////// // state loaded on #load() // ///////////////////////////////////////// /** * True if the repository has already been loaded, false otherwise. */ private boolean loaded; /** * ModuleDescriptors stored by ModuleRevisionId */ private Map/* */revisions = new HashMap(); /** * ModuleRevisionId for which loading was not possible, with corresponding error message. */ private Map/* */errors = new HashMap(); /** * List of ModuleRevisionId per ModuleId. */ private Map/* > */modules = new HashMap(); // ///////////////////////////////////////// // state loaded on #analyze() // ///////////////////////////////////////// /** * True when the repository has been analyzed, false otherwise */ private boolean analyzed; /** * Cache from requested module revision id to actual module revision id. */ private Map/* */cache = new HashMap(); /** * list of dependers per ModuleRevisionId. */ private Map/* > */dependers = new HashMap(); // ///////////////////////////////////////// // dependencies // ///////////////////////////////////////// private SearchEngine searchEngine; private ResolveEngine resolveEngine; private RepositoryManagementEngineSettings settings; public RepositoryManagementEngine(RepositoryManagementEngineSettings settings, SearchEngine searchEngine, ResolveEngine resolveEngine) { this.settings = settings; this.searchEngine = searchEngine; this.resolveEngine = resolveEngine; } /** * Loads data from the repository. *

* This method usually takes a long time to proceed. It should never be called from event * dispatch thread in a GUI. *

*/ public void load() { long startingMemoryUse = 0; if (settings.dumpMemoryUsage()) { startingMemoryUse = MemoryUtil.getUsedMemory(); } long startTime = System.currentTimeMillis(); Message.rawinfo("searching modules... "); ModuleRevisionId[] mrids = searchModules(); Message.info("loading repository metadata..."); for (int i = 0; i < mrids.length; i++) { try { loadModuleRevision(mrids[i]); } catch (Exception e) { Message.debug(e); errors.put(mrids[i], e.getMessage()); } } long endTime = System.currentTimeMillis(); Message.info("\nrepository loaded: " + modules.size() + " modules; " + revisions.size() + " revisions; " + (settings.dumpMemoryUsage() ? (MemoryUtil.getUsedMemory() - startingMemoryUse) / KILO + "kB; " : "") + (endTime - startTime) / THOUSAND + "s"); loaded = true; } /** * Analyze data in the repository. *

* This method may take a long time to proceed. It should never be called from event dispatch * thread in a GUI. *

* * @throws IllegalStateException * if the repository has not been loaded yet * @see #load() */ public void analyze() { ensureLoaded(); Message.info("\nanalyzing dependencies..."); for (Iterator iterator = revisions.values().iterator(); iterator.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) iterator.next(); DependencyDescriptor[] dds = md.getDependencies(); for (int i = 0; i < dds.length; i++) { ModuleRevisionId dep = getDependency(dds[i]); if (dep == null) { Message.warn("inconsistent repository: declared dependency not found: " + dds[i]); } else { getDependers(dep).add(md.getModuleRevisionId()); } } Message.progress(); } analyzed = true; } /** * Returns the number of Module Revision in the repository. * * @return the number of module revisions in the repository. * @throws IllegalStateException * if the repository has not been loaded yet * @see #load() */ public int getRevisionsNumber() { ensureLoaded(); return revisions.size(); } /** * Returns the number of ModuleId in the repository. * * @return the number of ModuleId in the repository. * @throws IllegalStateException * if the repository has not been loaded yet * @see #load() */ public int getModuleIdsNumber() { ensureLoaded(); return modules.size(); } /** * Returns Module Revisions which have no dependers. * * @return a Collection of the {@link ModuleRevisionId} of module revisions which have no * dependers in the repository. * @throws IllegalStateException * if the repository has not been analyzed yet * @see #analyze() */ public Collection getOrphans() { ensureAnalyzed(); Collection orphans = new HashSet(revisions.keySet()); orphans.removeAll(dependers.keySet()); return orphans; } private ModuleRevisionId[] searchModules() { ModuleRevisionId[] mrids = searchEngine.listModules(ModuleRevisionId.newInstance( PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION), RegexpPatternMatcher.INSTANCE); return mrids; } private ModuleRevisionId getDependency(DependencyDescriptor dd) { ModuleRevisionId askedMrid = dd.getDependencyRevisionId(); VersionMatcher vmatcher = settings.getVersionMatcher(); if (vmatcher.isDynamic(askedMrid)) { ModuleRevisionId mrid = (ModuleRevisionId) cache.get(askedMrid); if (mrid == null) { Collection revs = getAllRevisions(askedMrid); for (Iterator iterator = revs.iterator(); iterator.hasNext();) { ModuleDescriptor md = (ModuleDescriptor) iterator.next(); if (vmatcher.needModuleDescriptor(askedMrid, md.getResolvedModuleRevisionId())) { if (vmatcher.accept(askedMrid, md)) { mrid = md.getResolvedModuleRevisionId(); break; } } else { if (vmatcher.accept(askedMrid, md.getResolvedModuleRevisionId())) { mrid = md.getResolvedModuleRevisionId(); break; } } } if (mrid == null) { return null; } else { cache.put(askedMrid, mrid); } } return mrid; } else { return askedMrid; } } private Collection getDependers(ModuleRevisionId id) { Collection depders = (Collection) dependers.get(id); if (depders == null) { depders = new ArrayList(); dependers.put(id, depders); } return depders; } private void loadModuleRevision(ModuleRevisionId mrid) throws Exception { ResolvedModuleRevision module = settings.getResolver(mrid).getDependency( new DefaultDependencyDescriptor(mrid, false), newResolveData()); if (module == null) { Message.warn("module not found while listed: " + mrid); } else { revisions.put(module.getId(), module.getDescriptor()); getAllRevisions(module.getId()).add(module.getDescriptor()); } Message.progress(); } private Collection getAllRevisions(ModuleRevisionId id) { Collection revisions = (Collection) modules.get(id.getModuleId()); if (revisions == null) { revisions = new TreeSet(new Comparator() { public int compare(Object o1, Object o2) { ModuleDescriptor md1 = (ModuleDescriptor) o1; ModuleDescriptor md2 = (ModuleDescriptor) o2; // we use reverse order compared to latest revision, to have latest revision // first return settings.getDefaultLatestStrategy().sort(new ArtifactInfo[] {md1, md2}) .get(0).equals(md1) ? 1 : -1; } }); modules.put(id.getModuleId(), revisions); } return revisions; } private ResolveData newResolveData() { return new ResolveData(resolveEngine, new ResolveOptions()); } private void ensureAnalyzed() { if (!analyzed) { throw new IllegalStateException( "repository must have been analyzed to perform this method"); } } private void ensureLoaded() { if (!loaded) { throw new IllegalStateException("repository must have be loaded to perform this method"); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/repository/RepositoryManagementEngineSettings.java000066400000000000000000000020211226750426600324000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.repository; import org.apache.ivy.core.resolve.ResolveEngineSettings; public interface RepositoryManagementEngineSettings extends ResolveEngineSettings { public boolean dumpMemoryUsage(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/000077500000000000000000000000001226750426600217575ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/DownloadOptions.java000066400000000000000000000017321226750426600257500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import org.apache.ivy.core.LogOptions; public class DownloadOptions extends LogOptions { public DownloadOptions() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/IvyNode.java000066400000000000000000001514511226750426600242060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.event.resolve.EndResolveDependencyEvent; import org.apache.ivy.core.event.resolve.StartResolveDependencyEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.IncludeRule; import org.apache.ivy.core.module.descriptor.MDArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNodeCallers.Caller; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.conflict.LatestCompatibleConflictManager; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; import org.apache.ivy.util.StringUtils; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; public class IvyNode implements Comparable { private static final Pattern FALLBACK_CONF_PATTERN = Pattern.compile("(.+)\\((.*)\\)"); // //////// CONTEXT private ResolveData data; private ResolveEngineSettings settings; // //////// DELEGATES private IvyNodeCallers callers; private IvyNodeEviction eviction; // //////// MAIN DATA private IvyNode root; // id as requested, i.e. may be with latest rev private ModuleRevisionId id; // set only when node has been built or updated from a DependencyDescriptor // Map(IvyNode parent -> DependencyDescriptor) private Map dds = new HashMap(); // Set when data has been loaded only, or when constructed from a module descriptor private ModuleDescriptor md; private ResolvedModuleRevision module; // //////// LOADING METADATA private Exception problem = null; private boolean downloaded = false; private boolean searched = false; private Collection confsToFetch = new HashSet(); private Collection fetchedConfigurations = new HashSet(); private Collection loadedRootModuleConfs = new HashSet(); // //////// USAGE DATA private IvyNodeUsage usage = new IvyNodeUsage(this); // usage information merged from evicted nodes this node is "replacing" private Map/* */mergedUsages = new LinkedHashMap(); public IvyNode(ResolveData data, IvyNode parent, DependencyDescriptor dd) { id = dd.getDependencyRevisionId(); dds.put(parent, dd); root = parent.getRoot(); init(data); } public IvyNode(ResolveData data, ModuleDescriptor md) { id = md.getModuleRevisionId(); this.md = md; root = this; init(data); } private void init(ResolveData data) { this.data = data; settings = data.getSettings(); eviction = new IvyNodeEviction(this); callers = new IvyNodeCallers(this); } /** * After the call node may be discarded. To avoid using discarded node, make sure to get the * real node after the call IvyNode node = ... node.loadData(); node = node.getRealNode(); ... */ public boolean loadData(String rootModuleConf, IvyNode parent, String parentConf, String conf, boolean shouldBePublic, IvyNodeUsage usage) { Message.debug("loadData of " + this.toString() + " of rootConf=" + rootModuleConf); if (!isRoot() && (data.getReport() != null)) { data.getReport().addDependency(this); } boolean loaded = false; if (hasProblem()) { Message.debug("Node has problem. Skip loading"); } else if (isEvicted(rootModuleConf)) { Message.debug(rootModuleConf + " is evicted. Skip loading"); } else if (!hasConfigurationsToLoad() && isRootModuleConfLoaded(rootModuleConf)) { Message.debug(rootModuleConf + " is loaded and no conf to load. Skip loading"); } else { markRootModuleConfLoaded(rootModuleConf); if (md == null) { DependencyResolver resolver = data.getSettings().getResolver(getId()); if (resolver == null) { Message.error("no resolver found for " + getModuleId() + ": check your configuration"); problem = new RuntimeException("no resolver found for " + getModuleId() + ": check your configuration"); return false; } try { Message.debug("\tusing " + resolver + " to resolve " + getId()); DependencyDescriptor dependencyDescriptor = getDependencyDescriptor(parent); long start = System.currentTimeMillis(); ModuleRevisionId requestedRevisionId = dependencyDescriptor .getDependencyRevisionId(); data.getEventManager().fireIvyEvent( new StartResolveDependencyEvent(resolver, dependencyDescriptor, requestedRevisionId)); module = resolver.getDependency(dependencyDescriptor, data); data.getEventManager().fireIvyEvent( new EndResolveDependencyEvent(resolver, dependencyDescriptor, requestedRevisionId, module, System.currentTimeMillis() - start)); if (module != null) { module.getResolver() .getRepositoryCacheManager() .saveResolvers(module.getDescriptor(), module.getResolver().getName(), module.getArtifactResolver().getName()); if (settings.logModuleWhenFound() && LogOptions.LOG_DEFAULT.equals(getData().getOptions().getLog())) { Message.info("\tfound " + module.getId() + " in " + module.getResolver().getName()); } else { Message.verbose("\tfound " + module.getId() + " in " + module.getResolver().getName()); } // IVY-56: check if revision has actually been resolved if (settings.getVersionMatcher().isDynamic(getId()) && settings.getVersionMatcher().isDynamic(module.getId())) { Message.error("impossible to resolve dynamic revision for " + getId() + ": check your configuration and " + "make sure revision is part of your pattern"); problem = new RuntimeException("impossible to resolve dynamic revision"); return false; } if (!getId().equals(module.getId())) { IvyNode resolved = data.getNode(module.getId()); if (resolved != null) { // found revision has already been resolved // => update it and discard this node md = module.getDescriptor(); // needed for handleConfiguration if (!handleConfiguration(loaded, rootModuleConf, parent, parentConf, conf, shouldBePublic, usage)) { return false; } moveToRealNode(rootModuleConf, parent, parentConf, conf, shouldBePublic, resolved); return true; } String log = "\t[" + module.getId().getRevision() + "] " + getId(); if (!settings.getVersionMatcher().isDynamic(getId())) { log += " (forced)"; } if (settings.logResolvedRevision() && LogOptions.LOG_DEFAULT.equals(getData().getOptions() .getLog())) { Message.info(log); } else { Message.verbose(log); } } downloaded = module.getReport().isDownloaded(); searched = module.getReport().isSearched(); loaded = true; md = module.getDescriptor(); confsToFetch.remove("*"); updateConfsToFetch(Arrays .asList(resolveSpecialConfigurations(getRequiredConfigurations( parent, parentConf)))); } else { Message.warn("\tmodule not found: " + getId()); resolver.reportFailure(); problem = new RuntimeException("not found"); return false; } } catch (ResolveProcessException e) { throw e; } catch (Exception e) { problem = e; Message.debug("Unexpected error: " + problem.getMessage(), problem); return false; } } else { loaded = true; } } handleConfiguration(loaded, rootModuleConf, parent, parentConf, conf, shouldBePublic, usage); if (hasProblem()) { Message.debug("problem : " + problem.getMessage()); return false; } else { DependencyDescriptor dd = getDependencyDescriptor(parent); if (dd != null) { usage.addUsage(rootModuleConf, dd, parentConf); } return loaded; } } private void moveToRealNode(String rootModuleConf, IvyNode parent, String parentConf, String conf, boolean shouldBePublic, IvyNode resolved) { if (resolved.md == null) { resolved.md = md; } if (resolved.module == null) { resolved.module = module; } resolved.downloaded |= module.getReport().isDownloaded(); resolved.searched |= module.getReport().isSearched(); resolved.dds.putAll(dds); resolved.updateDataFrom(this, rootModuleConf, true); resolved.loadData(rootModuleConf, parent, parentConf, conf, shouldBePublic, usage); resolved.usage.updateDataFrom(getAllUsages(), rootModuleConf); usage = resolved.usage; data.replaceNode(getId(), resolved, rootModuleConf); // this actually discards the node if (settings.logResolvedRevision() && LogOptions.LOG_DEFAULT.equals(getData().getOptions().getLog())) { Message.info("\t[" + module.getId().getRevision() + "] " + getId()); } else { Message.verbose("\t[" + module.getId().getRevision() + "] " + getId()); } } public Collection getDependencies(String rootModuleConf, String[] confs, String requestedConf) { if (md == null) { throw new IllegalStateException( "impossible to get dependencies when data has not been loaded"); } if (Arrays.asList(confs).contains("*")) { if (isRoot()) { confs = md.getConfigurationsNames(); } else { confs = md.getPublicConfigurationsNames(); } } Collection deps = new HashSet(); for (int i = 0; i < confs.length; i++) { deps.addAll(getDependencies(rootModuleConf, confs[i], requestedConf)); } return deps; } /** * Load the dependencies of the current node *

* The resulting collection of nodes may have some configuration to load * * @param rootModuleConf * the requested configuration of the root module * @param conf * the configuration to load of this node * @param requestedConf * the actual node conf requested, possibly extending the conf one. * @return */ public Collection/* */getDependencies(String rootModuleConf, String conf, String requestedConf) { if (md == null) { throw new IllegalStateException( "impossible to get dependencies when data has not been loaded"); } DependencyDescriptor[] dds = md.getDependencies(); Map/* */dependencies = new LinkedHashMap(); // it's important to // respect order for (int i = 0; i < dds.length; i++) { DependencyDescriptor dd = data.mediate(dds[i]); String[] dependencyConfigurations = dd.getDependencyConfigurations(conf, requestedConf); if (dependencyConfigurations.length == 0) { // no configuration of the dependency is required for current confs : // it is exactly the same as if there was no dependency at all on it continue; } ModuleRevisionId requestedDependencyRevisionId = dd.getDependencyRevisionId(); if (isDependencyModuleExcluded(dd, rootModuleConf, requestedDependencyRevisionId, conf)) { // the whole module is excluded, it is considered as not being part of dependencies // at all Message.verbose("excluding " + dd + " in " + conf); continue; } // check if not already loaded here IvyNode depNode = (IvyNode) dependencies.get(requestedDependencyRevisionId); if (depNode == null) { // check if not already loaded during the resolve session depNode = data.getNode(requestedDependencyRevisionId); } if (depNode == null) { depNode = new IvyNode(data, this, dd); } else { depNode.addDependencyDescriptor(this, dd); if (depNode.hasProblem()) { // dependency already tried to be resolved, but unsuccessfully // nothing special to do } } String[] confsArray = depNode.resolveSpecialConfigurations(dependencyConfigurations); Collection confs = Arrays.asList(confsArray); depNode.updateConfsToFetch(confs); depNode.addRootModuleConfigurations(depNode.usage, rootModuleConf, confsArray); depNode.usage.setRequiredConfs(this, conf, confs); depNode.addCaller(rootModuleConf, this, conf, requestedConf, dependencyConfigurations, dd); dependencies.put(requestedDependencyRevisionId, depNode); } return dependencies.values(); } private void addDependencyDescriptor(IvyNode parent, DependencyDescriptor dd) { dds.put(parent, dd); } public DependencyDescriptor getDependencyDescriptor(IvyNode parent) { return (DependencyDescriptor) dds.get(parent); } private boolean isDependencyModuleExcluded(DependencyDescriptor dd, String rootModuleConf, ModuleRevisionId dependencyRevisionId, String conf) { Artifact a = DefaultArtifact.newIvyArtifact(dependencyRevisionId, null); if (isRoot()) { // no callers, but maybe some exclude Boolean exclude = doesExclude(md, rootModuleConf, new String[] {rootModuleConf}, dd, a, new Stack()); return exclude == null ? false : exclude.booleanValue(); } return callers.doesCallersExclude(rootModuleConf, a); } Boolean doesExclude(ModuleDescriptor md, String rootModuleConf, String[] moduleConfs, DependencyDescriptor dd, Artifact artifact, Stack callersStack) { // artifact is excluded if it match any of the exclude pattern for this dependency... if (dd != null) { if (dd.doesExclude(moduleConfs, artifact.getId().getArtifactId())) { return Boolean.TRUE; } } if (md.doesExclude(moduleConfs, artifact.getId().getArtifactId())) { return Boolean.TRUE; } // ... or if it is excluded by all its callers IvyNode c = getData().getNode(md.getModuleRevisionId()); if (c != null) { if (callersStack.contains(c.getId())) { // a circular dependency, we cannot be conclusive here return null; } return Boolean.valueOf(c.doesCallersExclude(rootModuleConf, artifact, callersStack)); } else { return Boolean.FALSE; } } public boolean hasConfigurationsToLoad() { return !confsToFetch.isEmpty(); } private boolean markRootModuleConfLoaded(String rootModuleConf) { return loadedRootModuleConfs.add(rootModuleConf); } private boolean isRootModuleConfLoaded(String rootModuleConf) { return loadedRootModuleConfs.contains(rootModuleConf); } private boolean handleConfiguration(boolean loaded, String rootModuleConf, IvyNode parent, String parentConf, String conf, boolean shouldBePublic, IvyNodeUsage usage) { if (md != null) { String[] confs = getRealConfs(conf); addRootModuleConfigurations(usage, rootModuleConf, confs); for (int i = 0; i < confs.length; i++) { Configuration c = md.getConfiguration(confs[i]); if (c == null) { confsToFetch.remove(conf); if (isConfRequiredByMergedUsageOnly(rootModuleConf, conf)) { Message.verbose("configuration required by evicted revision is not available in " + "selected revision. skipping " + conf + " in " + this); } else if (!conf.equals(confs[i])) { problem = new RuntimeException("configuration not found in " + this + ": '" + conf + "'. Missing configuration: '" + confs[i] + "'. It was required from " + parent + " " + parentConf); } else { problem = new RuntimeException("configuration not found in " + this + ": '" + confs[i] + "'. It was required from " + parent + " " + parentConf); } return false; } else if (shouldBePublic && !isRoot() && c.getVisibility() != Configuration.Visibility.PUBLIC) { confsToFetch.remove(conf); if (isConfRequiredByMergedUsageOnly(rootModuleConf, conf)) { Message.verbose("configuration required by evicted revision is not visible in " + "selected revision. skipping " + conf + " in " + this); } else { problem = new RuntimeException("configuration not public in " + this + ": '" + c + "'. It was required from " + parent + " " + parentConf); } return false; } } if (loaded) { fetchedConfigurations.add(conf); confsToFetch.removeAll(Arrays.asList(confs)); confsToFetch.remove(conf); } } return true; } private String getDefaultConf(String conf) { Matcher m = FALLBACK_CONF_PATTERN.matcher(conf); if (m.matches()) { return m.group(2); } else { return conf; } } private String getMainConf(String conf) { Matcher m = FALLBACK_CONF_PATTERN.matcher(conf); if (m.matches()) { return m.group(1); } else { return null; } } public void updateConfsToFetch(Collection confs) { confsToFetch.addAll(confs); confsToFetch.removeAll(fetchedConfigurations); } /** * resolve the '*' special configurations if necessary and possible */ private String[] resolveSpecialConfigurations(String[] dependencyConfigurations) { if (dependencyConfigurations.length == 1 && dependencyConfigurations[0].startsWith("*") && isLoaded()) { String conf = dependencyConfigurations[0]; if ("*".equals(conf)) { return getDescriptor().getPublicConfigurationsNames(); } // there are exclusions in the configuration List exclusions = Arrays.asList(conf.substring(2).split("\\!")); List ret = new ArrayList(Arrays.asList(getDescriptor().getPublicConfigurationsNames())); ret.removeAll(exclusions); return (String[]) ret.toArray(new String[ret.size()]); } return dependencyConfigurations; } /** * returns the required configurations from the given node * * @param in * @return */ public String[] getRequiredConfigurations(IvyNode in, String inConf) { Collection req = new LinkedHashSet(); addAllIfNotNull(req, usage.getRequiredConfigurations(in, inConf)); for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); addAllIfNotNull(req, usage.getRequiredConfigurations(in, inConf)); } return req == null ? new String[0] : (String[]) req.toArray(new String[req.size()]); } private void addAllIfNotNull(Collection into, Collection col) { if (col != null) { into.addAll(col); } } /** * returns all the current required configurations of the node * * @return */ public String[] getRequiredConfigurations() { Collection required = new ArrayList(confsToFetch.size() + fetchedConfigurations.size()); required.addAll(fetchedConfigurations); required.addAll(confsToFetch); return (String[]) required.toArray(new String[required.size()]); } public Configuration getConfiguration(String conf) { if (md == null) { throw new IllegalStateException( "impossible to get configuration when data has not been loaded"); } String defaultConf = getDefaultConf(conf); conf = getMainConf(conf); Configuration configuration = md.getConfiguration(conf); if (configuration == null) { configuration = md.getConfiguration(defaultConf); } return configuration; } /** * Returns the configurations of the dependency required in a given root module configuration. * * @param rootModuleConf * @return */ public String[] getConfigurations(String rootModuleConf) { Set depConfs = new LinkedHashSet(); addAllIfNotNull(depConfs, usage.getConfigurations(rootModuleConf)); for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); addAllIfNotNull(depConfs, usage.getConfigurations(rootModuleConf)); } return (String[]) depConfs.toArray(new String[depConfs.size()]); } protected boolean isConfRequiredByMergedUsageOnly(String rootModuleConf, String conf) { Set confs = usage.getConfigurations(rootModuleConf); return confs == null || !confs.contains(conf); } // This is never called. Could we remove it? public void discardConf(String rootModuleConf, String conf) { Set depConfs = usage.addAndGetConfigurations(rootModuleConf); if (md != null) { // remove all given dependency configurations to the set + extended ones Configuration c = md.getConfiguration(conf); if (conf != null) { String[] exts = c.getExtends(); for (int i = 0; i < exts.length; i++) { discardConf(rootModuleConf, exts[i]); // recursive remove of extended // configurations } depConfs.remove(c.getName()); } else { Message.warn("unknown configuration in " + getId() + ": " + conf); } } else { depConfs.remove(conf); } } private void addRootModuleConfigurations(IvyNodeUsage usage, String rootModuleConf, String[] dependencyConfs) { Set depConfs = usage.addAndGetConfigurations(rootModuleConf); if (md != null) { // add all given dependency configurations to the set + extended ones for (int i = 0; i < dependencyConfs.length; i++) { depConfs.add(dependencyConfs[i]); Configuration conf = md.getConfiguration(dependencyConfs[i]); if (conf != null) { String[] exts = conf.getExtends(); // recursive add of extended addRootModuleConfigurations(usage, rootModuleConf, exts); } } } else { for (int i = 0; i < dependencyConfs.length; i++) { depConfs.add(dependencyConfs[i]); } } } /** * Returns the root module configurations in which this dependency is required * * @return */ public String[] getRootModuleConfigurations() { Set confs = getRootModuleConfigurationsSet(); return (String[]) confs.toArray(new String[confs.size()]); } /** * Returns the root module configurations in which this dependency is required * * @return */ public Set getRootModuleConfigurationsSet() { Set confs = new LinkedHashSet(); addAllIfNotNull(confs, usage.getRootModuleConfigurations()); for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); addAllIfNotNull(confs, usage.getRootModuleConfigurations()); } return confs; } public String[] getConfsToFetch() { return (String[]) confsToFetch.toArray(new String[confsToFetch.size()]); } public String[] getRealConfs(String conf) { if (md == null) { return new String[] {conf}; } String defaultConf = getDefaultConf(conf); conf = getMainConf(conf); if ((md.getConfiguration(conf) == null) || Configuration.Visibility.PRIVATE.equals(md.getConfiguration(conf) .getVisibility())) { if ("".equals(defaultConf)) { return new String[0]; } conf = defaultConf; } if (conf.startsWith("*")) { return resolveSpecialConfigurations(new String[] {conf}); } else if (conf.indexOf(',') != -1) { String[] confs = conf.split(","); for (int i = 0; i < confs.length; i++) { confs[i] = confs[i].trim(); } } return new String[] {conf}; } /** * Finds and returns a path in callers from the given module id to the current node * * @param from * the module id to start the path from * @return a collection representing the path, starting with the from node, followed by the list * of nodes being one path to the current node, excluded */ private Collection findPath(ModuleId from) { return findPath(from, this, new LinkedList()); } private Collection findPath(ModuleId from, IvyNode node, List path) { IvyNode parent = node.getDirectCallerFor(from); if (parent == null) { throw new IllegalArgumentException("no path from " + from + " to " + getId() + " found"); } if (path.contains(parent)) { path.add(0, parent); Message.verbose("circular dependency found while looking for the path for another one: " + "was looking for " + from + " as a caller of " + path.get(path.size() - 1)); return path; } path.add(0, parent); if (parent.getId().getModuleId().equals(from)) { return path; } return findPath(from, parent, path); } /** * Update data in this node from data of the given node, for the given root module * configuration. * * @param node * the source node from which data should be copied * @param rootModuleConf * the root module configuration for which data should be updated * @param real * true if the node to update from actually corresponds to the same real node * (usually updated because of dynamic revision resolution), false if it's not the * same real node (usually updated because of node eviction) */ private void updateDataFrom(IvyNode node, String rootModuleConf, boolean real) { // update callers callers.updateFrom(node.callers, rootModuleConf, real); if (real) { usage.updateDataFrom(node.getAllUsages(), rootModuleConf); } else { // let's copy usage information for the given rootModuleConf, into a separate usage // object to keep detailed data about where usage comes from IvyNodeUsage mergedUsage = (IvyNodeUsage) mergedUsages.get(node.getId()); if (mergedUsage == null) { mergedUsage = new IvyNodeUsage(node); mergedUsages.put(node.getId(), mergedUsage); } mergedUsage.updateDataFrom(node.getAllUsages(), rootModuleConf); } // update confsToFetch updateConfsToFetch(node.fetchedConfigurations); updateConfsToFetch(node.confsToFetch); } private Collection/* */getAllUsages() { Collection usages = new ArrayList(); usages.add(usage); usages.addAll(mergedUsages.values()); return usages; } /** * Returns all the artifacts of this dependency required in all the root module configurations * * @return */ public Artifact[] getAllArtifacts() { Set ret = new HashSet(); for (Iterator it = getRootModuleConfigurationsSet().iterator(); it.hasNext();) { String rootModuleConf = (String) it.next(); ret.addAll(Arrays.asList(getArtifacts(rootModuleConf))); } return (Artifact[]) ret.toArray(new Artifact[ret.size()]); } /** * Returns all the artifacts of this dependency required in the root module configurations in * which the node is not evicted nor blacklisted * * @param artifactFilter * @return */ public Artifact[] getSelectedArtifacts(Filter artifactFilter) { Collection ret = new HashSet(); for (Iterator it = getRootModuleConfigurationsSet().iterator(); it.hasNext();) { String rootModuleConf = (String) it.next(); if (!isEvicted(rootModuleConf) && !isBlacklisted(rootModuleConf)) { ret.addAll(Arrays.asList(getArtifacts(rootModuleConf))); } } ret = FilterHelper.filter(ret, artifactFilter); return (Artifact[]) ret.toArray(new Artifact[ret.size()]); } /** * Returns the artifacts of this dependency required in the configurations themselves required * in the given root module configuration * * @param rootModuleConf * @return */ public Artifact[] getArtifacts(String rootModuleConf) { // first we look for the dependency configurations required // in the given root module configuration String[] confs = getConfigurations(rootModuleConf); if (confs == null || confs.length == 0) { // no configuration required => no artifact required return new Artifact[0]; } if (md == null) { throw new IllegalStateException( "impossible to get artifacts when data has not been loaded. IvyNode = " + this.toString()); } Set artifacts = new HashSet(); // the set we fill before returning // we check if we have dependencyArtifacts includes description for this rootModuleConf Set dependencyArtifacts = usage.getDependencyArtifactsSet(rootModuleConf); if (md.isDefault() && dependencyArtifacts != null && !dependencyArtifacts.isEmpty()) { addArtifactsFromOwnUsage(artifacts, dependencyArtifacts); addArtifactsFromMergedUsage(rootModuleConf, artifacts); } else { Set includes = new LinkedHashSet(); addAllIfNotNull(includes, usage.getDependencyIncludesSet(rootModuleConf)); for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); addAllIfNotNull(includes, usage.getDependencyIncludesSet(rootModuleConf)); } if ((dependencyArtifacts == null || dependencyArtifacts.isEmpty()) && (includes.isEmpty())) { // no artifacts / includes: we get all artifacts as defined by the descriptor for (int i = 0; i < confs.length; i++) { artifacts.addAll(Arrays.asList(md.getArtifacts(confs[i]))); } } else { // we have to get only artifacts listed as "includes" // first we get all artifacts as defined by the module descriptor // and classify them by artifact id Map allArtifacts = new HashMap(); for (int i = 0; i < confs.length; i++) { Artifact[] arts = md.getArtifacts(confs[i]); for (int j = 0; j < arts.length; j++) { allArtifacts.put(arts[j].getId().getArtifactId(), arts[j]); } } // now we add caller defined ones if (dependencyArtifacts != null) { addArtifactsFromOwnUsage(artifacts, dependencyArtifacts); } addArtifactsFromMergedUsage(rootModuleConf, artifacts); // and now we filter according to include rules for (Iterator it = includes.iterator(); it.hasNext();) { IncludeRule dad = (IncludeRule) it.next(); Collection arts = findArtifactsMatching(dad, allArtifacts); if (arts.isEmpty()) { Message.error("a required artifact is not listed by module descriptor: " + dad.getId()); // we remove it from required list to prevent message to be displayed more // than once it.remove(); } else { Message.debug(this + " in " + rootModuleConf + ": including " + arts); artifacts.addAll(arts); } } } } // now excludes artifacts that aren't accepted by any caller for (Iterator iter = artifacts.iterator(); iter.hasNext();) { Artifact artifact = (Artifact) iter.next(); boolean excluded = callers.doesCallersExclude(rootModuleConf, artifact); if (excluded) { Message.debug(this + " in " + rootModuleConf + ": excluding " + artifact); iter.remove(); } } return (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()]); } private void addArtifactsFromOwnUsage(Set artifacts, Set dependencyArtifacts) { for (Iterator it = dependencyArtifacts.iterator(); it.hasNext();) { DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor) it.next(); artifacts.add(new MDArtifact(md, dad.getName(), dad.getType(), dad.getExt(), dad .getUrl(), dad.getQualifiedExtraAttributes())); } } private void addArtifactsFromMergedUsage(String rootModuleConf, Set artifacts) { for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); Set mergedDependencyArtifacts = usage.getDependencyArtifactsSet(rootModuleConf); if (mergedDependencyArtifacts != null) { for (Iterator it = mergedDependencyArtifacts.iterator(); it.hasNext();) { DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor) it.next(); Map extraAttributes = new HashMap(dad.getQualifiedExtraAttributes()); MDArtifact artifact = new MDArtifact(md, dad.getName(), dad.getType(), dad.getExt(), dad.getUrl(), extraAttributes); if (!artifacts.contains(artifact)) { // this is later used to know that this is a merged artifact extraAttributes.put("ivy:merged", dad.getDependencyDescriptor() .getParentRevisionId() + " -> " + usage.getNode().getId()); artifacts.add(artifact); } } } } } private static Collection findArtifactsMatching(IncludeRule rule, Map allArtifacts) { Collection ret = new ArrayList(); for (Iterator iter = allArtifacts.keySet().iterator(); iter.hasNext();) { ArtifactId aid = (ArtifactId) iter.next(); if (MatcherHelper.matches(rule.getMatcher(), rule.getId(), aid)) { ret.add(allArtifacts.get(aid)); } } return ret; } public boolean hasProblem() { return problem != null; } public Exception getProblem() { return problem; } public String getProblemMessage() { return StringUtils.getErrorMessage(problem); } public boolean isDownloaded() { return downloaded; } public boolean isSearched() { return searched; } public boolean isLoaded() { return md != null; } public boolean isFetched(String conf) { return fetchedConfigurations.contains(conf); } public IvyNode findNode(ModuleRevisionId mrid) { return data.getNode(mrid); } boolean isRoot() { return root == this; } public IvyNode getRoot() { return root; } public ConflictManager getConflictManager(ModuleId mid) { if (md == null) { throw new IllegalStateException( "impossible to get conflict manager when data has not been loaded. IvyNode = " + this.toString()); } ConflictManager cm = md.getConflictManager(mid); return cm == null ? settings.getConflictManager(mid) : cm; } public IvyNode getRealNode() { IvyNode real = data.getNode(getId()); return real != null ? real : this; } public ModuleRevisionId getId() { return id; } public ModuleId getModuleId() { return id.getModuleId(); } public ModuleDescriptor getDescriptor() { return md; } public ResolveData getData() { return data; } public ResolvedModuleRevision getModuleRevision() { return module; } public long getPublication() { if (module != null) { return module.getPublicationDate().getTime(); } return 0; } /** * Returns the last modified timestamp of the module represented by this Node, or 0 if the last * modified timestamp is currently unkwown (module not loaded) * * @return the last modified timestamp of the module represented by this Node */ public long getLastModified() { if (md != null) { return md.getLastModified(); } return 0; } public ModuleRevisionId getResolvedId() { if (md != null && md.getResolvedModuleRevisionId().getRevision() != null) { return md.getResolvedModuleRevisionId(); } else if (module != null) { return module.getId(); } else { return getId(); } } /** * Clean data related to one root module configuration only */ public void clean() { confsToFetch.clear(); } // ///////////////////////////////////////////////////////////////////////////// // CALLERS MANAGEMENT // ///////////////////////////////////////////////////////////////////////////// boolean canExclude(String rootModuleConf) { Caller[] callers = getCallers(rootModuleConf); for (int i = 0; i < callers.length; i++) { if (callers[i].canExclude()) { return true; } } return false; } private IvyNode getDirectCallerFor(ModuleId from) { return callers.getDirectCallerFor(from); } public Caller[] getCallers(String rootModuleConf) { return callers.getCallers(rootModuleConf); } public Collection getAllCallersModuleIds() { return callers.getAllCallersModuleIds(); } public Caller[] getAllCallers() { return callers.getAllCallers(); } public Caller[] getAllRealCallers() { return callers.getAllRealCallers(); } public void addCaller(String rootModuleConf, IvyNode callerNode, String callerConf, String requestedConf, String[] dependencyConfs, DependencyDescriptor dd) { callers.addCaller(rootModuleConf, callerNode, callerConf, requestedConf, dependencyConfs, dd); boolean isCircular = callers.getAllCallersModuleIds().contains(getId().getModuleId()); if (isCircular) { IvyContext.getContext().getCircularDependencyStrategy() .handleCircularDependency(toMrids(findPath(getId().getModuleId()), this)); } } public boolean doesCallersExclude(String rootModuleConf, Artifact artifact, Stack callersStack) { return callers.doesCallersExclude(rootModuleConf, artifact, callersStack); } private ModuleRevisionId[] toMrids(Collection path, IvyNode depNode) { ModuleRevisionId[] ret = new ModuleRevisionId[path.size() + 1]; int i = 0; for (Iterator iter = path.iterator(); iter.hasNext(); i++) { IvyNode node = (IvyNode) iter.next(); ret[i] = node.getId(); } ret[ret.length - 1] = depNode.getId(); return ret; } // ///////////////////////////////////////////////////////////////////////////// // EVICTION MANAGEMENT // ///////////////////////////////////////////////////////////////////////////// /** A copy of the set of resolved nodes (real nodes) */ public Set getResolvedNodes(ModuleId moduleId, String rootModuleConf) { return eviction.getResolvedNodes(moduleId, rootModuleConf); } public Collection getResolvedRevisions(ModuleId moduleId, String rootModuleConf) { return eviction.getResolvedRevisions(moduleId, rootModuleConf); } public void markEvicted(EvictionData evictionData) { eviction.markEvicted(evictionData); String rootModuleConf = evictionData.getRootModuleConf(); // bug 105: update selected data with evicted one if (evictionData.getSelected() != null) { for (Iterator iter = evictionData.getSelected().iterator(); iter.hasNext();) { IvyNode selected = (IvyNode) iter.next(); selected.updateDataFrom(this, rootModuleConf, false); } } } public Collection getAllEvictingConflictManagers() { return eviction.getAllEvictingConflictManagers(); } public Collection getAllEvictingNodes() { return eviction.getAllEvictingNodes(); } public Collection/* */getAllEvictingNodesDetails() { return eviction.getAllEvictingNodesDetails(); } public String[] getEvictedConfs() { return eviction.getEvictedConfs(); } public EvictionData getEvictedData(String rootModuleConf) { return eviction.getEvictedData(rootModuleConf); } public Collection getEvictedNodes(ModuleId mid, String rootModuleConf) { return eviction.getEvictedNodes(mid, rootModuleConf); } public Collection getEvictedRevisions(ModuleId mid, String rootModuleConf) { return eviction.getEvictedRevisions(mid, rootModuleConf); } public EvictionData getEvictionDataInRoot(String rootModuleConf, IvyNode ancestor) { return eviction.getEvictionDataInRoot(rootModuleConf, ancestor); } public boolean isCompletelyEvicted() { return eviction.isCompletelyEvicted(); } public boolean isEvicted(String rootModuleConf) { return eviction.isEvicted(rootModuleConf); } public void markEvicted(String rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection resolved) { EvictionData evictionData = new EvictionData(rootModuleConf, node, conflictManager, resolved); markEvicted(evictionData); } public void setEvictedNodes(ModuleId moduleId, String rootModuleConf, Collection evicted) { eviction.setEvictedNodes(moduleId, rootModuleConf, evicted); } public void setResolvedNodes(ModuleId moduleId, String rootModuleConf, Collection resolved) { eviction.setResolvedNodes(moduleId, rootModuleConf, resolved); } public String toString() { return getResolvedId().toString(); } public boolean equals(Object obj) { if (!(obj instanceof IvyNode)) { return false; } IvyNode node = (IvyNode) obj; return node.getId().equals(getId()); } public int compareTo(Object obj) { IvyNode that = (IvyNode) obj; return this.getModuleId().compareTo(that.getModuleId()); } public int hashCode() { return getId().hashCode(); } /** * Returns a collection of Nodes in conflict for which conflict has been detected but conflict * resolution hasn't been done yet * * @param rootModuleConf * @param mid * the module id for which pending conflicts should be found * @return a Collection of IvyNode in pending conflict */ public Collection getPendingConflicts(String rootModuleConf, ModuleId mid) { return eviction.getPendingConflicts(rootModuleConf, mid); } public void setPendingConflicts(ModuleId moduleId, String rootModuleConf, Collection conflicts) { eviction.setPendingConflicts(moduleId, rootModuleConf, conflicts); } // ///////////////////////////////////////////////////////////////////////////// // BLACKLISTING MANAGEMENT // ///////////////////////////////////////////////////////////////////////////// /** * Blacklists the current node, so that a new resolve process won't ever consider this node as * available in the repository. *

* This is useful in combination with {@link RestartResolveProcess} for conflict manager * implementation which use a best effort strategy to find compatible dependency set, like * {@link LatestCompatibleConflictManager} *

* * @param rootModuleConf * the root module configuration in which the node should be blacklisted */ public void blacklist(IvyNodeBlacklist bdata) { if (data.getSettings().logResolvedRevision()) { Message.info("BLACKLISTING " + bdata); } else { Message.verbose("BLACKLISTING " + bdata); } Stack callerStack = new Stack(); callerStack.push(this); clearEvictionDataInAllCallers(bdata.getRootModuleConf(), callerStack); usage.blacklist(bdata); data.blacklist(this); } private void clearEvictionDataInAllCallers(String rootModuleConf, Stack/* */callerStack) { IvyNode node = (IvyNode) callerStack.peek(); Caller[] callers = node.getCallers(rootModuleConf); for (int i = 0; i < callers.length; i++) { IvyNode callerNode = findNode(callers[i].getModuleRevisionId()); if (callerNode != null) { callerNode.eviction = new IvyNodeEviction(callerNode); if (!callerStack.contains(callerNode)) { callerStack.push(callerNode); clearEvictionDataInAllCallers(rootModuleConf, callerStack); callerStack.pop(); } } } } /** * Indicates if this node has been blacklisted in the given root module conf. *

* A blacklisted node should be considered as if it doesn't even exist on the repository. *

* * @param rootModuleConf * the root module conf for which we'd like to know if the node is blacklisted * * @return true if this node is blacklisted int he given root module conf, false otherwise * @see #blacklist(String) */ public boolean isBlacklisted(String rootModuleConf) { return usage.isBlacklisted(rootModuleConf); } /** * Indicates if this node has been blacklisted in all root module configurations. * * @return true if this node is blacklisted in all root module configurations, false otherwise * @see #blacklist(String) */ public boolean isCompletelyBlacklisted() { if (isRoot()) { return false; } String[] rootModuleConfigurations = getRootModuleConfigurations(); for (int i = 0; i < rootModuleConfigurations.length; i++) { if (!isBlacklisted(rootModuleConfigurations[i])) { return false; } } return true; } /** * Returns the blacklist data of this node in the given root module conf, or null * if this node is not blacklisted in this root module conf. * * @param rootModuleConf * the root module configuration to consider * @return the blacklist data if any */ public IvyNodeBlacklist getBlacklistData(String rootModuleConf) { return usage.getBlacklistData(rootModuleConf); } public IvyNodeUsage getMainUsage() { return usage; } /** * Indicates if there is any of the merged usages of this node which has a depender with * transitive dependency descriptor. *

* If at there is at least one usage from the merged usages for which there is a depender in the * given root module conf which has a dependency descriptor with transitive == true, then it * returns true. Otherwise it returns false. *

* * @param rootModuleConf * the root module configuration to consider * @return true if there is any merged usage with transitive dd, false otherwise. */ public boolean hasAnyMergedUsageWithTransitiveDependency(String rootModuleConf) { if (mergedUsages == null) { return false; } for (Iterator iterator = mergedUsages.values().iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); if (usage.hasTransitiveDepender(rootModuleConf)) { return true; } } return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/IvyNodeBlacklist.java000066400000000000000000000042061226750426600260320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; /** * Information about a blacklisted module, providing context information in which it has been * blacklisted */ public class IvyNodeBlacklist { private IvyNode conflictParent; private IvyNode selectedNode; private IvyNode evictedNode; private IvyNode blacklistedNode; private String rootModuleConf; public IvyNodeBlacklist(IvyNode conflictParent, IvyNode selectedNode, IvyNode evictedNode, IvyNode blacklistedNode, String rootModuleConf) { this.conflictParent = conflictParent; this.selectedNode = selectedNode; this.evictedNode = evictedNode; this.blacklistedNode = blacklistedNode; this.rootModuleConf = rootModuleConf; } public IvyNode getConflictParent() { return conflictParent; } public IvyNode getSelectedNode() { return selectedNode; } public IvyNode getEvictedNode() { return evictedNode; } public IvyNode getBlacklistedNode() { return blacklistedNode; } public String getRootModuleConf() { return rootModuleConf; } public String toString() { return "[" + blacklistedNode + " blacklisted to evict " + evictedNode + " in favor of " + selectedNode + " in " + conflictParent + " for " + rootModuleConf + "]"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/IvyNodeCallers.java000066400000000000000000000247431226750426600255170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Stack; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; public class IvyNodeCallers { public static class Caller { private ModuleDescriptor md; private ModuleRevisionId mrid; private Map confs = new HashMap(); // Map (String callerConf -> String[] dependencyConfs) private DependencyDescriptor dd; private boolean callerCanExclude; private boolean real = true; public Caller(ModuleDescriptor md, ModuleRevisionId mrid, DependencyDescriptor dd, boolean callerCanExclude) { this.md = md; this.mrid = mrid; this.dd = dd; this.callerCanExclude = callerCanExclude; } public void addConfiguration(String callerConf, String[] dependencyConfs) { updateConfs(callerConf, dependencyConfs); Configuration conf = md.getConfiguration(callerConf); if (conf != null) { String[] confExtends = conf.getExtends(); if (confExtends != null) { for (int i = 0; i < confExtends.length; i++) { addConfiguration(confExtends[i], dependencyConfs); } } } } private void updateConfs(String callerConf, String[] dependencyConfs) { String[] prevDepConfs = (String[]) confs.get(callerConf); if (prevDepConfs != null) { Set newDepConfs = new HashSet(Arrays.asList(prevDepConfs)); newDepConfs.addAll(Arrays.asList(dependencyConfs)); confs.put(callerConf, newDepConfs.toArray(new String[newDepConfs.size()])); } else { confs.put(callerConf, dependencyConfs); } } public String[] getCallerConfigurations() { return (String[]) confs.keySet().toArray(new String[confs.keySet().size()]); } public ModuleRevisionId getModuleRevisionId() { return mrid; } public boolean equals(Object obj) { if (!(obj instanceof Caller)) { return false; } Caller other = (Caller) obj; return other.confs.equals(confs) && mrid.equals(other.mrid); } public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 31; hash = hash * 13 + confs.hashCode(); hash = hash * 13 + mrid.hashCode(); // CheckStyle:MagicNumber| ON return hash; } public String toString() { return mrid.toString(); } public ModuleRevisionId getAskedDependencyId(ResolveData resolveData) { return dd.getDependencyRevisionId(); } public ModuleDescriptor getModuleDescriptor() { return md; } public boolean canExclude() { return callerCanExclude || md.canExclude() || dd.canExclude(); } public DependencyDescriptor getDependencyDescriptor() { return dd; } public void setRealCaller(boolean b) { this.real = b; } public boolean isRealCaller() { return real; } } // Map (String rootModuleConf -> Map (ModuleRevisionId -> Caller)): key in second map is used to // easily get a caller by its mrid private Map callersByRootConf = new HashMap(); // this map contains all the module ids calling this one (including transitively) as keys. // the mapped nodes (values) correspond to a direct caller from which the transitive caller // comes private Map allCallers = new HashMap(); // Map (ModuleId -> IvyNode) private IvyNode node; public IvyNodeCallers(IvyNode node) { this.node = node; } /** * @param rootModuleConf * @param mrid * @param callerConf * @param dependencyConfs * '*' must have been resolved * @param dd * the dependency revision id asked by the caller */ public void addCaller(String rootModuleConf, IvyNode callerNode, String callerConf, String requestedConf, String[] dependencyConfs, DependencyDescriptor dd) { ModuleDescriptor md = callerNode.getDescriptor(); ModuleRevisionId mrid = callerNode.getResolvedId(); if (mrid.getModuleId().equals(node.getId().getModuleId())) { throw new IllegalArgumentException("a module is not authorized to depend on itself: " + node.getId()); } Map callers = (Map) callersByRootConf.get(rootModuleConf); if (callers == null) { callers = new HashMap(); callersByRootConf.put(rootModuleConf, callers); } Caller caller = (Caller) callers.get(mrid); if (caller == null) { caller = new Caller(md, mrid, dd, callerNode.canExclude(rootModuleConf)); callers.put(mrid, caller); } caller.addConfiguration(requestedConf, dependencyConfs); IvyNode parent = callerNode.getRealNode(); for (Iterator iter = parent.getAllCallersModuleIds().iterator(); iter.hasNext();) { ModuleId mid = (ModuleId) iter.next(); allCallers.put(mid, parent); } allCallers.put(mrid.getModuleId(), callerNode); } void removeCaller(String rootModuleConf, ModuleRevisionId callerMrid) { allCallers.remove(callerMrid.getModuleId()); Map callers = (Map) callersByRootConf.get(rootModuleConf); if (callers != null) { callers.remove(callerMrid); } } public Caller[] getCallers(String rootModuleConf) { Map callers = (Map) callersByRootConf.get(rootModuleConf); if (callers == null) { return new Caller[0]; } return (Caller[]) callers.values().toArray(new Caller[callers.values().size()]); } public Caller[] getAllCallers() { Set all = new HashSet(); for (Iterator iter = callersByRootConf.values().iterator(); iter.hasNext();) { Map callers = (Map) iter.next(); all.addAll(callers.values()); } return (Caller[]) all.toArray(new Caller[all.size()]); } public Caller[] getAllRealCallers() { Set all = new HashSet(); for (Iterator iter = callersByRootConf.values().iterator(); iter.hasNext();) { Map callers = (Map) iter.next(); for (Iterator iterator = callers.values().iterator(); iterator.hasNext();) { Caller c = (Caller) iterator.next(); if (c.isRealCaller()) { all.add(c); } } } return (Caller[]) all.toArray(new Caller[all.size()]); } public Collection getAllCallersModuleIds() { return allCallers.keySet(); } void updateFrom(IvyNodeCallers callers, String rootModuleConf, boolean real) { Map nodecallers = (Map) callers.callersByRootConf.get(rootModuleConf); if (nodecallers != null) { Map thiscallers = (Map) callersByRootConf.get(rootModuleConf); if (thiscallers == null) { thiscallers = new HashMap(); callersByRootConf.put(rootModuleConf, thiscallers); } for (Iterator iter = nodecallers.values().iterator(); iter.hasNext();) { Caller caller = (Caller) iter.next(); if (!thiscallers.containsKey(caller.getModuleRevisionId())) { if (!real) { caller.setRealCaller(false); } thiscallers.put(caller.getModuleRevisionId(), caller); } } } } public IvyNode getDirectCallerFor(ModuleId from) { return (IvyNode) allCallers.get(from); } /** * Returns true if ALL callers exclude the given artifact in the given root module conf * * @param rootModuleConf * @param artifact * @return */ boolean doesCallersExclude(String rootModuleConf, Artifact artifact) { return doesCallersExclude(rootModuleConf, artifact, new Stack()); } boolean doesCallersExclude(String rootModuleConf, Artifact artifact, Stack callersStack) { callersStack.push(node.getId()); try { Caller[] callers = getCallers(rootModuleConf); if (callers.length == 0) { return false; } boolean allUnconclusive = true; for (int i = 0; i < callers.length; i++) { if (!callers[i].canExclude()) { return false; } ModuleDescriptor md = callers[i].getModuleDescriptor(); Boolean doesExclude = node.doesExclude(md, rootModuleConf, callers[i].getCallerConfigurations(), callers[i].getDependencyDescriptor(), artifact, callersStack); if (doesExclude != null) { if (!doesExclude.booleanValue()) { return false; } allUnconclusive = false; } } return allUnconclusive ? false : true; } finally { callersStack.pop(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/IvyNodeEviction.java000066400000000000000000000377671226750426600257240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.conflict.ConflictManager; public class IvyNodeEviction { /** * This class contains data about the eviction of an {@link IvyNode}. */ public static class EvictionData { /** * Can be null in case of transitive eviction. */ private IvyNode parent; /** * Can be null in case of transitive eviction. */ private ConflictManager conflictManager; /** * Can be null in case of transitive eviction. */ private Collection selected; // Collection(IvyNode) private String rootModuleConf; private String detail; /** * Creates a new object containing the eviction data of an {@link IvyNode}. * * @param rootModuleConf * the root module configuration * @param parent * the parent node (or null in case of transitive eviction) * @param conflictManager * the conflict manager which evicted the node (or null in case of * transitive eviction) * @param selected * a collection of {@link IvyNode}s which evict the evicted node (or * null in case of transitive eviction) */ public EvictionData(String rootModuleConf, IvyNode parent, ConflictManager conflictManager, Collection selected) { this(rootModuleConf, parent, conflictManager, selected, null); } /** * Creates a new object containing the eviction data of an {@link IvyNode}. * * @param rootModuleConf * the root module configuration * @param parent * the parent node (or null in case of transitive eviction) * @param conflictManager * the conflict manager which evicted the node (or null in case of * transitive eviction) * @param selected * a collection of {@link IvyNode}s which evict the evicted node (or * null in case of transitive eviction) * @param detail * a String detailing the reason why the node was evicted */ public EvictionData(String rootModuleConf, IvyNode parent, ConflictManager conflictManager, Collection selected, String detail) { this.rootModuleConf = rootModuleConf; this.parent = parent; this.conflictManager = conflictManager; this.selected = selected; this.detail = detail; } public String toString() { if (selected != null) { return selected + " in " + parent + (detail == null ? "" : " " + detail) + " (" + conflictManager + ") [" + rootModuleConf + "]"; } else { return "transitively [" + rootModuleConf + "]"; } } public ConflictManager getConflictManager() { return conflictManager; } public IvyNode getParent() { return parent; } public Collection getSelected() { return selected; } public String getRootModuleConf() { return rootModuleConf; } public boolean isTransitivelyEvicted() { return parent == null; } public String getDetail() { return detail; } } private static final class ModuleIdConf { private ModuleId moduleId; private String conf; public ModuleIdConf(ModuleId mid, String conf) { if (mid == null) { throw new NullPointerException("mid cannot be null"); } if (conf == null) { throw new NullPointerException("conf cannot be null"); } moduleId = mid; this.conf = conf; } public final String getConf() { return conf; } public final ModuleId getModuleId() { return moduleId; } public boolean equals(Object obj) { if (!(obj instanceof ModuleIdConf)) { return false; } return getModuleId().equals(((ModuleIdConf) obj).getModuleId()) && getConf().equals(((ModuleIdConf) obj).getConf()); } public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 33; hash += getModuleId().hashCode() * 17; hash += getConf().hashCode() * 17; // CheckStyle:MagicNumber| ON return hash; } } private IvyNode node; private Map selectedDeps = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map indicating // for each dependency which node has been selected private Map pendingConflicts = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map // indicating for each dependency which nodes // are in pending conflict (conflict detected // but not yet resolved) private Map evictedDeps = new HashMap(); // Map (ModuleIdConf -> Set(Node)) // map indicating // for each dependency which node has been evicted private Map evictedRevs = new HashMap(); // Map (ModuleIdConf -> Set(ModuleRevisionId)) // // map indicating for each dependency which revision // has been evicted private Map evicted = new HashMap(); // Map (root module conf -> EvictionData) // indicates // if the node is evicted in each root module conf public IvyNodeEviction(IvyNode node) { if (node == null) { throw new NullPointerException("node must not be null"); } this.node = node; } /** * @return A copy of the set of resolved nodes (real nodes) */ public Set getResolvedNodes(ModuleId mid, String rootModuleConf) { Collection resolved = (Collection) selectedDeps.get(new ModuleIdConf(mid, rootModuleConf)); Set ret = new HashSet(); if (resolved != null) { for (Iterator iter = resolved.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); ret.add(node.getRealNode()); } } return ret; } public Collection getResolvedRevisions(ModuleId mid, String rootModuleConf) { Collection resolved = (Collection) selectedDeps.get(new ModuleIdConf(mid, rootModuleConf)); if (resolved == null) { return new HashSet(); } else { Collection resolvedRevs = new HashSet(); for (Iterator iter = resolved.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); ModuleRevisionId resolvedId = node.getResolvedId(); resolvedRevs.add(node.getId()); resolvedRevs.add(resolvedId); // in case there are extra attributes on the resolved module we also add the // the module without these extra attributes (cfr. IVY-1236) if (!resolvedId.getExtraAttributes().isEmpty()) { resolvedRevs.add(ModuleRevisionId.newInstance(resolvedId.getOrganisation(), resolvedId.getName(), resolvedId.getBranch(), resolvedId.getRevision())); } } return resolvedRevs; } } public void setResolvedNodes(ModuleId moduleId, String rootModuleConf, Collection resolved) { ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId, rootModuleConf); selectedDeps.put(moduleIdConf, new HashSet(resolved)); } public Collection getEvictedNodes(ModuleId mid, String rootModuleConf) { Collection resolved = (Collection) evictedDeps.get(new ModuleIdConf(mid, rootModuleConf)); Set ret = new HashSet(); if (resolved != null) { for (Iterator iter = resolved.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); ret.add(node.getRealNode()); } } return ret; } public Collection getEvictedRevisions(ModuleId mid, String rootModuleConf) { Collection evicted = (Collection) evictedRevs.get(new ModuleIdConf(mid, rootModuleConf)); if (evicted == null) { return new HashSet(); } else { return new HashSet(evicted); } } public void setEvictedNodes(ModuleId moduleId, String rootModuleConf, Collection evicted) { ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId, rootModuleConf); evictedDeps.put(moduleIdConf, new HashSet(evicted)); Collection evictedRevs = new HashSet(); for (Iterator iter = evicted.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); evictedRevs.add(node.getId()); evictedRevs.add(node.getResolvedId()); } this.evictedRevs.put(moduleIdConf, evictedRevs); } public boolean isEvicted(String rootModuleConf) { cleanEvicted(); if (node.isRoot()) { return false; } EvictionData evictedData = getEvictedData(rootModuleConf); if (evictedData == null) { return false; } IvyNode root = node.getRoot(); ModuleId moduleId = node.getId().getModuleId(); Collection resolvedRevisions = root.getResolvedRevisions(moduleId, rootModuleConf); return !resolvedRevisions.contains(node.getResolvedId()) || evictedData.isTransitivelyEvicted(); } public boolean isCompletelyEvicted() { cleanEvicted(); if (node.isRoot()) { return false; } String[] rootModuleConfigurations = node.getRootModuleConfigurations(); for (int i = 0; i < rootModuleConfigurations.length; i++) { if (!isEvicted(rootModuleConfigurations[i])) { return false; } } return true; } private void cleanEvicted() { // check if it was evicted by a node that we are now the real node for for (Iterator iter = evicted.keySet().iterator(); iter.hasNext();) { String rootModuleConf = (String) iter.next(); EvictionData ed = (EvictionData) evicted.get(rootModuleConf); Collection sel = ed.getSelected(); if (sel != null) { for (Iterator iterator = sel.iterator(); iterator.hasNext();) { IvyNode n = (IvyNode) iterator.next(); if (n.getRealNode().equals(node)) { // yes, we are the real node for a selected one ! // we are no more evicted in this conf ! iter.remove(); } } } } } public void markEvicted(EvictionData evictionData) { evicted.put(evictionData.getRootModuleConf(), evictionData); } public EvictionData getEvictedData(String rootModuleConf) { cleanEvicted(); return (EvictionData) evicted.get(rootModuleConf); } public String[] getEvictedConfs() { cleanEvicted(); return (String[]) evicted.keySet().toArray(new String[evicted.keySet().size()]); } /** * Returns null if this node has only be evicted transitively, or the the collection of selected * nodes if it has been evicted by other selected nodes * * @return */ public Collection getAllEvictingNodes() { Collection allEvictingNodes = null; for (Iterator iter = evicted.values().iterator(); iter.hasNext();) { EvictionData ed = (EvictionData) iter.next(); Collection selected = ed.getSelected(); if (selected != null) { if (allEvictingNodes == null) { allEvictingNodes = new HashSet(); } allEvictingNodes.addAll(selected); } } return allEvictingNodes; } public Collection/* */getAllEvictingNodesDetails() { Collection ret = null; for (Iterator iter = evicted.values().iterator(); iter.hasNext();) { EvictionData ed = (EvictionData) iter.next(); Collection selected = ed.getSelected(); if (selected != null) { if (ret == null) { ret = new HashSet(); } if (selected.size() == 1) { ret.add(selected.iterator().next() + (ed.getDetail() == null ? "" : " " + ed.getDetail())); } else if (selected.size() > 1) { ret.add(selected + (ed.getDetail() == null ? "" : " " + ed.getDetail())); } } } return ret; } public Collection getAllEvictingConflictManagers() { Collection ret = new HashSet(); for (Iterator iter = evicted.values().iterator(); iter.hasNext();) { EvictionData ed = (EvictionData) iter.next(); ret.add(ed.getConflictManager()); } return ret; } /** * Returns the eviction data for this node if it has been previously evicted in the root, null * otherwise (if it hasn't been evicted in root) for the given rootModuleConf. Note that this * method only works if conflict resolution has already be done in all the ancestors. * * @param rootModuleConf * @param ancestor * @return */ public EvictionData getEvictionDataInRoot(String rootModuleConf, IvyNode ancestor) { Collection selectedNodes = node.getRoot().getResolvedNodes(node.getModuleId(), rootModuleConf); for (Iterator iter = selectedNodes.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); if (node.getResolvedId().equals(this.node.getResolvedId())) { // the node is part of the selected ones for the root: no eviction data to return return null; } } // we didn't find this mrid in the selected ones for the root: it has been previously // evicted return new EvictionData(rootModuleConf, ancestor, node.getRoot().getConflictManager( node.getModuleId()), selectedNodes); } public Collection getPendingConflicts(String rootModuleConf, ModuleId mid) { Collection resolved = (Collection) pendingConflicts.get(new ModuleIdConf(mid, rootModuleConf)); Set ret = new HashSet(); if (resolved != null) { for (Iterator iter = resolved.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); ret.add(node.getRealNode()); } } return ret; } public void setPendingConflicts(ModuleId moduleId, String rootModuleConf, Collection conflicts) { ModuleIdConf moduleIdConf = new ModuleIdConf(moduleId, rootModuleConf); pendingConflicts.put(moduleIdConf, new HashSet(conflicts)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/IvyNodeUsage.java000066400000000000000000000261431226750426600251720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.IncludeRule; /** * Class collecting usage data for an IvyNode. *

* Usage data contains the configurations required by callers for each root module configuration, * the configurations required by caller node and caller configuration, dependency artifacts * descriptors declared by callers, include rules declared by callers, and blacklisted data by root * module conf. *

*/ public class IvyNodeUsage { private static final class NodeConf { private IvyNode node; private String conf; public NodeConf(IvyNode node, String conf) { if (node == null) { throw new NullPointerException("node must not null"); } if (conf == null) { throw new NullPointerException("conf must not null"); } this.node = node; this.conf = conf; } public final String getConf() { return conf; } public final IvyNode getNode() { return node; } public boolean equals(Object obj) { if (!(obj instanceof NodeConf)) { return false; } return getNode().equals(((NodeConf) obj).getNode()) && getConf().equals(((NodeConf) obj).getConf()); } public int hashCode() { // CheckStyle:MagicNumber| OFF int hash = 33; hash += getNode().hashCode() * 17; hash += getConf().hashCode() * 17; // CheckStyle:MagicNumber| OFF return hash; } public String toString() { return "NodeConf(" + conf + ")"; } } private static final class Depender { private DependencyDescriptor dd; private String dependerConf; public Depender(DependencyDescriptor dd, String dependerConf) { this.dd = dd; this.dependerConf = dependerConf; } public String toString() { return dd + " [" + dependerConf + "]"; } public boolean equals(Object obj) { if (!(obj instanceof Depender)) { return false; } Depender other = (Depender) obj; return other.dd == dd && other.dependerConf.equals(dependerConf); } public int hashCode() { int hash = 33; hash += dd.hashCode() * 13; hash += dependerConf.hashCode() * 13; return hash; } } private IvyNode node; // Map (String rootConfName -> Set(String confName)) // used to know which configurations of the dependency are required // for each root module configuration private Map rootModuleConfs = new HashMap(); // Map (NodeConf in -> Set(String conf)) private Map requiredConfs = new HashMap(); private Map /* > */dependers = new HashMap(); // Map (String rootModuleConf -> IvyNodeBlacklist) private Map blacklisted = new HashMap(); public IvyNodeUsage(IvyNode node) { this.node = node; } protected Collection getRequiredConfigurations(IvyNode in, String inConf) { return (Collection) requiredConfs.get(new NodeConf(in, inConf)); } protected void setRequiredConfs(IvyNode parent, String parentConf, Collection confs) { requiredConfs.put(new NodeConf(parent, parentConf), new HashSet(confs)); } /** * Returns the configurations of the dependency required in a given root module configuration. * * @param rootModuleConf * @return */ protected Set getConfigurations(String rootModuleConf) { return (Set) rootModuleConfs.get(rootModuleConf); } protected Set addAndGetConfigurations(String rootModuleConf) { Set depConfs = (Set) rootModuleConfs.get(rootModuleConf); if (depConfs == null) { depConfs = new HashSet(); rootModuleConfs.put(rootModuleConf, depConfs); } return depConfs; } protected Set /* */getRootModuleConfigurations() { return rootModuleConfs.keySet(); } public void updateDataFrom(Collection/* */usages, String rootModuleConf) { for (Iterator iterator = usages.iterator(); iterator.hasNext();) { IvyNodeUsage usage = (IvyNodeUsage) iterator.next(); updateDataFrom(usage, rootModuleConf); } } private void updateDataFrom(IvyNodeUsage usage, String rootModuleConf) { // update requiredConfs updateMapOfSet(usage.requiredConfs, requiredConfs); // update rootModuleConfs updateMapOfSetForKey(usage.rootModuleConfs, rootModuleConfs, rootModuleConf); // update dependencyArtifacts updateMapOfSetForKey(usage.dependers, dependers, rootModuleConf); } private void updateMapOfSet(Map from, Map to) { for (Iterator iter = from.keySet().iterator(); iter.hasNext();) { Object key = iter.next(); updateMapOfSetForKey(from, to, key); } } private void updateMapOfSetForKey(Map from, Map to, Object key) { Set set = (Set) from.get(key); if (set != null) { Set toupdate = (Set) to.get(key); if (toupdate != null) { toupdate.addAll(set); } else { to.put(key, new HashSet(set)); } } } // protected void addDependencyArtifacts(String rootModuleConf, // DependencyArtifactDescriptor[] dependencyArtifacts) { // addObjectsForConf(rootModuleConf, Arrays.asList(dependencyArtifacts), // this.dependencyArtifacts); // } // // protected void addDependencyIncludes(String rootModuleConf, IncludeRule[] rules) { // addObjectsForConf(rootModuleConf, Arrays.asList(rules), dependencyIncludes); // } // private void addObjectsForConf(String rootModuleConf, Object objectToAdd, Map map) { Set set = (Set) map.get(rootModuleConf); if (set == null) { set = new HashSet(); map.put(rootModuleConf, set); } set.add(objectToAdd); } public void addUsage(String rootModuleConf, DependencyDescriptor dd, String parentConf) { addObjectsForConf(rootModuleConf, new Depender(dd, parentConf), dependers); } protected Set getDependencyArtifactsSet(String rootModuleConf) { Collection dependersInConf = (Collection) dependers.get(rootModuleConf); if (dependersInConf == null) { return null; } Set dependencyArtifacts = new HashSet(); for (Iterator iterator = dependersInConf.iterator(); iterator.hasNext();) { Depender depender = (Depender) iterator.next(); DependencyArtifactDescriptor[] dads = depender.dd .getDependencyArtifacts(depender.dependerConf); dependencyArtifacts.addAll(Arrays.asList(dads)); } return dependencyArtifacts; } protected Set getDependencyIncludesSet(String rootModuleConf) { Collection dependersInConf = (Collection) dependers.get(rootModuleConf); if (dependersInConf == null) { return null; } Set dependencyIncludes = new HashSet(); for (Iterator iterator = dependersInConf.iterator(); iterator.hasNext();) { Depender depender = (Depender) iterator.next(); IncludeRule[] rules = depender.dd.getIncludeRules(depender.dependerConf); if (rules == null || rules.length == 0) { // no include rule in at least one depender -> we must include everything, // and so return no include rule at all return null; } dependencyIncludes.addAll(Arrays.asList(rules)); } return dependencyIncludes; } protected void removeRootModuleConf(String rootModuleConf) { rootModuleConfs.remove(rootModuleConf); } protected void blacklist(IvyNodeBlacklist bdata) { blacklisted.put(bdata.getRootModuleConf(), bdata); } /** * Indicates if this node has been blacklisted in the given root module conf. *

* A blacklisted node should be considered as if it doesn't even exist on the repository. *

* * @param rootModuleConf * the root module conf for which we'd like to know if the node is blacklisted * * @return true if this node is blacklisted int he given root module conf, false otherwise * @see #blacklist(String) */ protected boolean isBlacklisted(String rootModuleConf) { return blacklisted.containsKey(rootModuleConf); } /** * Returns the blacklist data of this node in the given root module conf, or null * if this node is not blacklisted in this root module conf. * * @param rootModuleConf * the root module configuration to consider * @return the blacklist data if any */ protected IvyNodeBlacklist getBlacklistData(String rootModuleConf) { return (IvyNodeBlacklist) blacklisted.get(rootModuleConf); } protected IvyNode getNode() { return node; } /** * Indicates if at least one depender has a transitive dependency descriptor for the given root * module conf. * * @param rootModuleConf * the root module conf to consider * @return true if at least one depender has a transitive dependency descriptor for * the given root module conf, false otherwise. */ public boolean hasTransitiveDepender(String rootModuleConf) { Set/* */dependersSet = (Set) dependers.get(rootModuleConf); if (dependersSet == null) { return false; } for (Iterator iterator = dependersSet.iterator(); iterator.hasNext();) { Depender depender = (Depender) iterator.next(); if (depender.dd.isTransitive()) { return true; } } return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolveData.java000066400000000000000000000276031226750426600250430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.util.Message; public class ResolveData { private ResolveEngine engine; private Map visitData; // shared map of all visit data: Map (ModuleRevisionId -> VisitData) private ConfigurationResolveReport report; private ResolveOptions options; private VisitNode currentVisitNode = null; private ResolvedModuleRevision currentResolvedModuleRevision; public ResolveData(ResolveData data, boolean validate) { this(data.engine, new ResolveOptions(data.options).setValidate(validate), data.report, data.visitData); setCurrentVisitNode(data.currentVisitNode); setCurrentResolvedModuleRevision(data.currentResolvedModuleRevision); } public ResolveData(ResolveEngine engine, ResolveOptions options) { this(engine, options, null, new LinkedHashMap()); } public ResolveData(ResolveEngine engine, ResolveOptions options, ConfigurationResolveReport report) { this(engine, options, report, new LinkedHashMap()); } public ResolveData(ResolveEngine engine, ResolveOptions options, ConfigurationResolveReport report, Map visitData) { this.engine = engine; this.report = report; this.visitData = visitData; this.options = options; } public ConfigurationResolveReport getReport() { return report; } public IvyNode getNode(ModuleRevisionId mrid) { VisitData visitData = getVisitData(mrid); return visitData == null ? null : visitData.getNode(); } public Collection getNodes() { Collection nodes = new ArrayList(); for (Iterator iter = visitData.values().iterator(); iter.hasNext();) { VisitData vdata = (VisitData) iter.next(); nodes.add(vdata.getNode()); } return nodes; } public Collection getNodeIds() { return visitData.keySet(); } public VisitData getVisitData(ModuleRevisionId mrid) { VisitData result = (VisitData) visitData.get(mrid); if (result == null) { // search again, now ignore the missing extra attributes for (Iterator it = visitData.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); ModuleRevisionId current = (ModuleRevisionId) entry.getKey(); if (isSubMap(mrid.getAttributes(), current.getAttributes())) { result = (VisitData) entry.getValue(); break; } } } return result; } /** * Checks whether one map is a sub-map of the other. */ private static boolean isSubMap(Map map1, Map map2) { int map1Size = map1.size(); int map2Size = map2.size(); if (map1Size == map2Size) { return map1.equals(map2); } Map smallest = map1Size < map2Size ? map1 : map2; Map largest = map1Size < map2Size ? map2 : map1; for (Iterator it = smallest.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); if (!largest.containsKey(entry.getKey())) { return false; } Object map1Value = smallest.get(entry.getKey()); Object map2Value = largest.get(entry.getKey()); if (!isEqual(map1Value, map2Value)) { return false; } } return true; } private static boolean isEqual(Object obj1, Object obj2) { if (obj1 == obj2) { return true; } if (obj1 == null) { return obj2 == null; } if (obj2 == null) { return obj1 == null; } return obj1.equals(obj2); } /** * Returns the VisitNode currently visited, or null if there is no node currently * visited in this context. * * @return the VisitNode currently visited */ public VisitNode getCurrentVisitNode() { return currentVisitNode; } /** * Sets the currently visited node. WARNING: This should only be called by Ivy core * ResolveEngine! * * @param currentVisitNode */ void setCurrentVisitNode(VisitNode currentVisitNode) { this.currentVisitNode = currentVisitNode; } public void register(VisitNode node) { register(node.getId(), node); } public void register(ModuleRevisionId mrid, VisitNode node) { VisitData visitData = getVisitData(mrid); if (visitData == null) { visitData = new VisitData(node.getNode()); visitData.addVisitNode(node); this.visitData.put(mrid, visitData); } else { visitData.setNode(node.getNode()); visitData.addVisitNode(node); } } /** * Updates the visit data currently associated with the given mrid with the given node and the * visit nodes of the old visitData for the given rootModuleConf * * @param mrid * the module revision id for which the update should be done * @param node * the IvyNode to associate with the visit data to update * @param rootModuleConf * the root module configuration in which the update is made */ void replaceNode(ModuleRevisionId mrid, IvyNode node, String rootModuleConf) { VisitData visitData = getVisitData(mrid); if (visitData == null) { throw new IllegalArgumentException("impossible to replace node for id " + mrid + ". No registered node found."); } VisitData keptVisitData = getVisitData(node.getId()); if (keptVisitData == null) { throw new IllegalArgumentException("impossible to replace node with " + node + ". No registered node found for " + node.getId() + "."); } // replace visit data in Map (discards old one) this.visitData.put(mrid, keptVisitData); // update visit data with discarde visit nodes keptVisitData.addVisitNodes(rootModuleConf, visitData.getVisitNodes(rootModuleConf)); report.updateDependency(mrid, node); } public void setReport(ConfigurationResolveReport report) { this.report = report; } public Date getDate() { return options.getDate(); } public boolean isValidate() { return options.isValidate(); } public boolean isTransitive() { return options.isTransitive(); } public ResolveOptions getOptions() { return options; } public ResolveEngineSettings getSettings() { return engine.getSettings(); } public EventManager getEventManager() { return engine.getEventManager(); } public ResolveEngine getEngine() { return engine; } void blacklist(IvyNode node) { for (Iterator iter = visitData.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry) iter.next(); VisitData vdata = (VisitData) entry.getValue(); if (vdata.getNode() == node && !node.getResolvedId().equals(entry.getKey())) { // this visit data was associated with the blacklisted node, // we discard this association iter.remove(); } } } public boolean isBlacklisted(String rootModuleConf, ModuleRevisionId mrid) { IvyNode node = getNode(mrid); // if (node == null) { // // search again, now ignore the extra attributes // // TODO: maybe we should search the node that has at least the // // same attributes as mrid // for (Iterator it = visitData.entrySet().iterator(); it.hasNext();) { // Map.Entry entry = (Entry) it.next(); // ModuleRevisionId current = (ModuleRevisionId) entry.getKey(); // if (current.getModuleId().equals(mrid.getModuleId()) // && current.getRevision().equals(mrid.getRevision())) { // VisitData data = (VisitData) entry.getValue(); // node = data.getNode(); // break; // } // } // } // return node != null && node.isBlacklisted(rootModuleConf); } public DependencyDescriptor mediate(DependencyDescriptor dd) { DependencyDescriptor originalDD = dd; dd = getEngine().mediate(dd, getOptions()); VisitNode current = getCurrentVisitNode(); if (current != null) { // mediating dd through dependers stack List dependers = new ArrayList(current.getPath()); // the returned path contains the currently visited node, we are only interested in // the dependers, so we remove the currently visted node from the end dependers.remove(dependers.size() - 1); // we want to apply mediation going up in the dependers stack, not the opposite Collections.reverse(dependers); for (Iterator iterator = dependers.iterator(); iterator.hasNext();) { VisitNode n = (VisitNode) iterator.next(); ModuleDescriptor md = n.getDescriptor(); if (md != null) { dd = md.mediate(dd); } } } if (originalDD != dd) { Message.verbose("dependency descriptor has been mediated: " + originalDD + " => " + dd); } return dd; } /** * Sets the last {@link ResolvedModuleRevision} which has been currently resolved. *

* This can be used especially in dependency resolvers, to know if another dependency resolver * has already resolved the requested dependency, to take a decision if the resolver should try * to resolve it by itself or not. Indeed, the dependency resolver is responsible for taking * this decision, even when included in a chain. The chain responsibility is only to set this * current resolved module revision to enable the resolver to take the decision. *

* * @param mr * the last {@link ResolvedModuleRevision} which has been currently resolved. */ public void setCurrentResolvedModuleRevision(ResolvedModuleRevision mr) { this.currentResolvedModuleRevision = mr; } /** * Returns the last {@link ResolvedModuleRevision} which has been currently resolved. *

* It can be null. *

* * @return the last {@link ResolvedModuleRevision} which has been currently resolved. */ public ResolvedModuleRevision getCurrentResolvedModuleRevision() { return currentResolvedModuleRevision; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolveEngine.java000066400000000000000000001575101226750426600254000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.event.download.PrepareDownloadEvent; import org.apache.ivy.core.event.resolve.EndResolveEvent; import org.apache.ivy.core.event.resolve.StartResolveEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.sort.SortEngine; import org.apache.ivy.core.sort.SortOptions; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; import org.apache.ivy.util.filter.Filter; /** * The resolve engine which is the core of the dependency resolution mechanism used in Ivy. It * features several resolve methods, some very simple, like {@link #resolve(File)} and * {@link #resolve(URL)} which allow to simply resolve dependencies of a single module descriptor, * or more complete one, like the {@link #resolve(ModuleDescriptor, ResolveOptions)} which allows to * provide options to the resolution engine. * * @see ResolveOptions */ public class ResolveEngine { private ResolveEngineSettings settings; private EventManager eventManager; private SortEngine sortEngine; private Set fetchedSet = new HashSet(); private DependencyResolver dictatorResolver; /** * Constructs a ResolveEngine. * * @param settings * the settings to use to configure the engine. Must not be null. * @param eventManager * the event manager to use to send events about the resolution process. Must not be * null. * @param sortEngine * the sort engine to use to sort modules before producing the dependency resolution * report. Must not be null. */ public ResolveEngine(ResolveEngineSettings settings, EventManager eventManager, SortEngine sortEngine) { this.settings = settings; this.eventManager = eventManager; this.sortEngine = sortEngine; } /** * Returns the currently configured dictator resolver, which when non null is used in place of * any specified resolver in the {@link IvySettings} * * @return the currently configured dictator resolver, may be null. */ public DependencyResolver getDictatorResolver() { return dictatorResolver; } /** * Sets a dictator resolver, which is used in place of regular dependency resolver for * subsequent dependency resolution by this engine. * * @param dictatorResolver * the dictator resolver to use in this engine, null if regular settings should used */ public void setDictatorResolver(DependencyResolver dictatorResolver) { this.dictatorResolver = dictatorResolver; settings.setDictatorResolver(dictatorResolver); } public ResolveReport resolve(File ivySource) throws ParseException, IOException { return resolve(ivySource.toURI().toURL()); } public ResolveReport resolve(URL ivySource) throws ParseException, IOException { return resolve(ivySource, new ResolveOptions()); } /** * Resolves the module identified by the given mrid with its dependencies if transitive is set * to true. */ public ResolveReport resolve(final ModuleRevisionId mrid, ResolveOptions options, boolean changing) throws ParseException, IOException { DefaultModuleDescriptor md; ResolveOptions optionsToUse = new ResolveOptions(options); if (options.useSpecialConfs()) { // create new resolve options because this is a different resolve than the real resolve // (which will be a resolve of a newCallerInstance module) ResolvedModuleRevision rmr = findModule(mrid, new ResolveOptions(options)); if (rmr == null) { Message.verbose("module not found " + mrid); // we will continue the resolve anyway to get a nice error message back // to the user, however reduce the amount of logging in this case optionsToUse.setLog(LogOptions.LOG_DOWNLOAD_ONLY); md = DefaultModuleDescriptor.newCallerInstance(mrid, new String[] {"default"}, options.isTransitive(), changing); } else { String[] confs = options.getConfs(rmr.getDescriptor()); md = DefaultModuleDescriptor.newCallerInstance( ModuleRevisionId.newInstance(mrid, rmr.getId().getRevision()), confs, options.isTransitive(), changing); } } else { md = DefaultModuleDescriptor.newCallerInstance(mrid, options.getConfs(), options.isTransitive(), changing); } return resolve(md, optionsToUse); } /** * Resolve dependencies of a module described by an ivy file. */ public ResolveReport resolve(URL ivySource, ResolveOptions options) throws ParseException, IOException { URLResource res = new URLResource(ivySource); ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser(res); Message.verbose("using " + parser + " to parse " + ivySource); ModuleDescriptor md = parser.parseDescriptor(settings, ivySource, options.isValidate()); String revision = options.getRevision(); if (revision == null && md.getResolvedModuleRevisionId().getRevision() == null) { revision = Ivy.getWorkingRevision(); } if (revision != null) { md.setResolvedModuleRevisionId(ModuleRevisionId.newInstance(md.getModuleRevisionId(), revision)); } return resolve(md, options); } /** * Resolve dependencies of a module described by a module descriptor. */ public ResolveReport resolve(ModuleDescriptor md, ResolveOptions options) throws ParseException, IOException { DependencyResolver oldDictator = getDictatorResolver(); IvyContext context = IvyContext.getContext(); try { String[] confs = options.getConfs(md); options.setConfs(confs); if (options.getResolveId() == null) { options.setResolveId(ResolveOptions.getDefaultResolveId(md)); } eventManager.fireIvyEvent(new StartResolveEvent(md, confs)); long start = System.currentTimeMillis(); if (ResolveOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info(":: resolving dependencies :: " + md.getResolvedModuleRevisionId() + (options.isTransitive() ? "" : " [not transitive]")); Message.info("\tconfs: " + Arrays.asList(confs)); } else { Message.verbose(":: resolving dependencies :: " + md.getResolvedModuleRevisionId() + (options.isTransitive() ? "" : " [not transitive]")); Message.verbose("\tconfs: " + Arrays.asList(confs)); } Message.verbose("\tvalidate = " + options.isValidate()); Message.verbose("\trefresh = " + options.isRefresh()); ResolveReport report = new ResolveReport(md, options.getResolveId()); ResolveData data = new ResolveData(this, options); context.setResolveData(data); // resolve dependencies IvyNode[] dependencies = getDependencies(md, options, report); report.setDependencies(Arrays.asList(dependencies), options.getArtifactFilter()); if (options.getCheckIfChanged()) { report.checkIfChanged(); } // produce resolved ivy file and ivy properties in cache ResolutionCacheManager cacheManager = settings.getResolutionCacheManager(); cacheManager.saveResolvedModuleDescriptor(md); // we store the resolved dependencies revisions and statuses per asked dependency // revision id, for direct dependencies only. // this is used by the deliver task to resolve dynamic revisions to static ones File ivyPropertiesInCache = cacheManager.getResolvedIvyPropertiesInCache(md .getResolvedModuleRevisionId()); Properties props = new Properties(); if (dependencies.length > 0) { Map forcedRevisions = new HashMap(); for (int i = 0; i < dependencies.length; i++) { if (dependencies[i].getModuleRevision() != null && dependencies[i].getModuleRevision().isForce()) { forcedRevisions.put(dependencies[i].getModuleId(), dependencies[i].getResolvedId()); } } IvyNode root = dependencies[0].getRoot(); // (); Map topLevelDeps = new HashMap(); // for (int i = 0; i < dependencies.length; i++) { if (!dependencies[i].hasProblem()) { DependencyDescriptor dd = dependencies[i].getDependencyDescriptor(root); if (dd != null) { ModuleId orgMod = dependencies[i].getModuleId(); topLevelDeps.put(orgMod, dependencies[i]); } } } for (int i = 0; i < dependencies.length; i++) { if (!dependencies[i].hasProblem() && !dependencies[i].isCompletelyEvicted()) { DependencyDescriptor dd = dependencies[i].getDependencyDescriptor(root); if (dd == null) { ModuleId mid = dependencies[i].getModuleId(); IvyNode tlDep = (IvyNode) topLevelDeps.get(mid); if (tlDep != null) { dd = tlDep.getDependencyDescriptor(root); } } if (dd != null) { ModuleRevisionId depResolvedId = dependencies[i].getResolvedId(); ModuleDescriptor depDescriptor = dependencies[i].getDescriptor(); ModuleRevisionId depRevisionId = dd.getDependencyRevisionId(); ModuleRevisionId forcedRevisionId = (ModuleRevisionId) forcedRevisions .get(dependencies[i].getModuleId()); if (dependencies[i].getModuleRevision() != null && dependencies[i].getModuleRevision().isForce() && !depResolvedId.equals(depRevisionId) && !settings.getVersionMatcher().isDynamic(depRevisionId)) { // if we were forced to this revision and we // are not a dynamic revision, reset to the // asked revision depResolvedId = depRevisionId; depDescriptor = null; } if (depResolvedId == null) { throw new NullPointerException("getResolvedId() is null for " + dependencies[i].toString()); } if (depRevisionId == null) { throw new NullPointerException("getDependencyRevisionId() " + "is null for " + dd.toString()); } String rev = depResolvedId.getRevision(); String forcedRev = forcedRevisionId == null ? rev : forcedRevisionId .getRevision(); // The evicted modules have no description, so we can't put the status String status = depDescriptor == null ? "?" : depDescriptor.getStatus(); Message.debug("storing dependency " + depResolvedId + " in props"); props.put(depRevisionId.encodeToString(), rev + " " + status + " " + forcedRev + " " + depResolvedId.getBranch()); } } } } FileOutputStream out = new FileOutputStream(ivyPropertiesInCache); props.store(out, md.getResolvedModuleRevisionId() + " resolved revisions"); out.close(); Message.verbose("\tresolved ivy file produced in cache"); report.setResolveTime(System.currentTimeMillis() - start); if (options.isDownload()) { Message.verbose(":: downloading artifacts ::"); DownloadOptions downloadOptions = new DownloadOptions(); downloadOptions.setLog(options.getLog()); downloadArtifacts(report, options.getArtifactFilter(), downloadOptions); } if (options.isOutputReport()) { outputReport(report, cacheManager, options); } Message.verbose("\tresolve done (" + report.getResolveTime() + "ms resolve - " + report.getDownloadTime() + "ms download)"); Message.sumupProblems(); eventManager.fireIvyEvent(new EndResolveEvent(md, confs, report)); return report; } catch (RuntimeException ex) { Message.debug(ex); Message.error(ex.getMessage()); Message.sumupProblems(); throw ex; } finally { context.setResolveData(null); setDictatorResolver(oldDictator); } } public void outputReport(ResolveReport report, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException { if (ResolveOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info(":: resolution report :: resolve " + report.getResolveTime() + "ms" + " :: artifacts dl " + report.getDownloadTime() + "ms"); } else { Message.verbose(":: resolution report :: resolve " + report.getResolveTime() + "ms" + " :: artifacts dl " + report.getDownloadTime() + "ms"); } report.setProblemMessages(Message.getProblems()); // output report report.output(settings.getReportOutputters(), cacheMgr, options); } public void downloadArtifacts(ResolveReport report, Filter artifactFilter, DownloadOptions options) { long start = System.currentTimeMillis(); IvyNode[] dependencies = (IvyNode[]) report.getDependencies().toArray( new IvyNode[report.getDependencies().size()]); eventManager.fireIvyEvent(new PrepareDownloadEvent((Artifact[]) report.getArtifacts() .toArray(new Artifact[report.getArtifacts().size()]))); long totalSize = 0; for (int i = 0; i < dependencies.length; i++) { checkInterrupted(); // download artifacts required in all asked configurations if (!dependencies[i].isCompletelyEvicted() && !dependencies[i].hasProblem() && dependencies[i].getModuleRevision() != null) { DependencyResolver resolver = dependencies[i].getModuleRevision() .getArtifactResolver(); Artifact[] selectedArtifacts = dependencies[i].getSelectedArtifacts(artifactFilter); DownloadReport dReport = resolver.download(selectedArtifacts, options); ArtifactDownloadReport[] adrs = dReport.getArtifactsReports(); for (int j = 0; j < adrs.length; j++) { if (adrs[j].getDownloadStatus() == DownloadStatus.FAILED) { if (adrs[j].getArtifact().getExtraAttribute("ivy:merged") != null) { Message.warn("\tmerged artifact not found: " + adrs[j].getArtifact() + ". It was required in " + adrs[j].getArtifact().getExtraAttribute("ivy:merged")); } else { Message.warn("\t" + adrs[j]); resolver.reportFailure(adrs[j].getArtifact()); } } else if (adrs[j].getDownloadStatus() == DownloadStatus.SUCCESSFUL) { totalSize += adrs[j].getSize(); } } // update concerned reports String[] dconfs = dependencies[i].getRootModuleConfigurations(); for (int j = 0; j < dconfs.length; j++) { // the report itself is responsible to take into account only // artifacts required in its corresponding configuration // (as described by the Dependency object) if (dependencies[i].isEvicted(dconfs[j]) || dependencies[i].isBlacklisted(dconfs[j])) { report.getConfigurationReport(dconfs[j]).addDependency(dependencies[i]); } else { report.getConfigurationReport(dconfs[j]).addDependency(dependencies[i], dReport); } } } } report.setDownloadTime(System.currentTimeMillis() - start); report.setDownloadSize(totalSize); } /** * Download an artifact to the cache. Not used internally, useful especially for IDE plugins * needing to download artifact one by one (for source or javadoc artifact, for instance). *

* Downloaded artifact file can be accessed using {@link ArtifactDownloadReport#getLocalFile()}. *

*

* It is possible to track the progression of the download using classical ivy progress * monitoring feature (see addTransferListener). *

* * @param artifact * the artifact to download * @return a report concerning the download * @see #download(ArtifactOrigin, DownloadOptions) */ public ArtifactDownloadReport download(Artifact artifact, DownloadOptions options) { DependencyResolver resolver = settings.getResolver(artifact.getModuleRevisionId()); DownloadReport r = resolver.download(new Artifact[] {artifact}, options); return r.getArtifactReport(artifact); } /** * Locates an artifact in dependency resolvers, and return its location if it can be located and * actually exists, or an unknown {@link ArtifactOrigin} in other cases. * * @param artifact * the artifact to locate. * @return the artifact location, should be tested with * {@link ArtifactOrigin#isUnknown(ArtifactOrigin)} to check if the artifact has * actually been located. */ public ArtifactOrigin locate(Artifact artifact) { DependencyResolver resolver = settings.getResolver(artifact.getModuleRevisionId()); return resolver.locate(artifact); } /** * Materialize an artifact already located. *

* Not used internally, useful especially for IDE plugins needing to download artifact one by * one (for source or javadoc artifact, for instance). *

*

* Materialized artifact file can be accessed using * {@link ArtifactDownloadReport#getLocalFile()}. *

*

* It is possible to track the progression of the download using classical ivy progress * monitoring feature (see addTransferListener). *

* * @param origin * the artifact origin to materialize * @return a report concerning the download * @see #download(Artifact, DownloadOptions) * @see #locate(Artifact) */ public ArtifactDownloadReport download(ArtifactOrigin origin, DownloadOptions options) { DependencyResolver resolver = settings.getResolver(origin.getArtifact() .getModuleRevisionId()); return resolver.download(origin, options); } /** * Resolve the dependencies of a module without downloading corresponding artifacts. The module * to resolve is given by its ivy file URL. This method requires appropriate configuration of * the ivy instance, especially resolvers. * * @param ivySource * url of the ivy file to use for dependency resolving * @param confs * an array of configuration names to resolve - must not be null nor empty * @param getCache * the cache to use - default cache is used if null * @param date * the date to which resolution must be done - may be null * @return an array of the resolved dependencies * @throws ParseException * if a parsing problem occurred in the ivy file * @throws IOException * if an IO problem was raised during ivy file parsing */ public IvyNode[] getDependencies(URL ivySource, ResolveOptions options) throws ParseException, IOException { return getDependencies( ModuleDescriptorParserRegistry.getInstance().parseDescriptor(settings, ivySource, options.isValidate()), options, null); } /** * Resolve the dependencies of a module without downloading corresponding artifacts. The module * to resolve is given by its module descriptor. This method requires appropriate configuration * of the ivy instance, especially resolvers. *

* The IvyNodes are ordered from the most dependent to the less dependent, so that * an IvyNode is always found in the list after all IvyNode depending directly on it. * * @param md * the descriptor of the module for which we want to get dependencies - must not be * null * @param options * the resolve options to use to resolve the dependencies * @param report * a resolve report to fill during resolution - may be null * @return an array of the resolved Dependencies */ public IvyNode[] getDependencies(ModuleDescriptor md, ResolveOptions options, ResolveReport report) { // check parameters if (md == null) { throw new NullPointerException("module descriptor must not be null"); } String[] confs = options.getConfs(md); Collection missingConfs = new ArrayList(); for (int i = 0; i < confs.length; i++) { if (confs[i] == null) { throw new NullPointerException("null conf not allowed: confs where: " + Arrays.asList(confs)); } if (md.getConfiguration(confs[i]) == null) { missingConfs.add(" '" + confs[i] + "' "); } } if (!missingConfs.isEmpty()) { throw new IllegalArgumentException("requested configuration" + (missingConfs.size() > 1 ? "s" : "") + " not found in " + md.getModuleRevisionId() + ": " + missingConfs); } IvyContext context = IvyContext.pushNewCopyContext(); try { options.setConfs(confs); Date reportDate = new Date(); ResolveData data = context.getResolveData(); if (data == null) { data = new ResolveData(this, options); context.setResolveData(data); } IvyNode rootNode = new IvyNode(data, md); for (int i = 0; i < confs.length; i++) { Message.verbose("resolving dependencies for configuration '" + confs[i] + "'"); // for each configuration we clear the cache of what's been fetched fetchedSet.clear(); ConfigurationResolveReport confReport = null; if (report != null) { confReport = report.getConfigurationReport(confs[i]); if (confReport == null) { confReport = new ConfigurationResolveReport(this, md, confs[i], reportDate, options); report.addReport(confs[i], confReport); } } // we reuse the same resolve data with a new report for each conf data.setReport(confReport); // update the root module conf we are about to fetch VisitNode root = new VisitNode(data, rootNode, null, confs[i], null); root.setRequestedConf(confs[i]); rootNode.updateConfsToFetch(Collections.singleton(confs[i])); // go fetch ! boolean fetched = false; while (!fetched) { try { fetchDependencies(root, confs[i], false); fetched = true; } catch (RestartResolveProcess restart) { Message.verbose("===================================================="); Message.verbose("= RESTARTING RESOLVE PROCESS"); Message.verbose("= " + restart.getMessage()); Message.verbose("===================================================="); fetchedSet.clear(); } } // clean data for (Iterator iter = data.getNodes().iterator(); iter.hasNext();) { IvyNode dep = (IvyNode) iter.next(); dep.clean(); } } // prune and reverse sort fectched dependencies Collection nodes = data.getNodes(); // use a Set to avoid duplicates, linked to preserve order Collection dependencies = new LinkedHashSet(nodes.size()); for (Iterator iter = nodes.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); if (node != null && !node.isRoot() && !node.isCompletelyBlacklisted()) { dependencies.add(node); } } List sortedDependencies = sortEngine.sortNodes(dependencies, SortOptions.SILENT); Collections.reverse(sortedDependencies); handleTransiviteEviction(md, confs, data, sortedDependencies); return (IvyNode[]) dependencies.toArray(new IvyNode[dependencies.size()]); } finally { IvyContext.popContext(); } } private void handleTransiviteEviction(ModuleDescriptor md, String[] confs, ResolveData data, List sortedDependencies) { // handle transitive eviction now: // if a module has been evicted then all its dependencies required only by it should be // evicted too. Since nodes are now sorted from the more dependent to the less one, we // can traverse the list and check only the direct parent and not all the ancestors for (ListIterator iter = sortedDependencies.listIterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); if (!node.isCompletelyEvicted()) { for (int i = 0; i < confs.length; i++) { IvyNodeCallers.Caller[] callers = node.getCallers(confs[i]); if (settings.debugConflictResolution()) { Message.debug("checking if " + node.getId() + " is transitively evicted in " + confs[i]); } boolean allEvicted = callers.length > 0; for (int j = 0; j < callers.length; j++) { if (callers[j].getModuleRevisionId().equals(md.getModuleRevisionId())) { // the caller is the root module itself, it can't be evicted allEvicted = false; break; } else { IvyNode callerNode = data.getNode(callers[j].getModuleRevisionId()); if (callerNode == null) { Message.warn("ivy internal error: no node found for " + callers[j].getModuleRevisionId() + ": looked in " + data.getNodeIds() + " and root module id was " + md.getModuleRevisionId()); } else if (!callerNode.isEvicted(confs[i])) { allEvicted = false; break; } else { if (settings.debugConflictResolution()) { Message.debug("caller " + callerNode.getId() + " of " + node.getId() + " is evicted"); } } } } if (allEvicted) { Message.verbose("all callers are evicted for " + node + ": evicting too"); node.markEvicted(confs[i], null, null, null); } else { if (settings.debugConflictResolution()) { Message.debug(node.getId() + " isn't transitively evicted, at least one caller was" + " not evicted"); } } } } } } private void fetchDependencies(VisitNode node, String conf, boolean shouldBePublic) { checkInterrupted(); long start = System.currentTimeMillis(); if (node.getParent() != null) { Message.verbose("== resolving dependencies " + node.getParent().getId() + "->" + node.getId() + " [" + node.getParentConf() + "->" + conf + "]"); } else { Message.verbose("== resolving dependencies for " + node.getId() + " [" + conf + "]"); } ResolveData data = node.getNode().getData(); VisitNode parentVisitNode = data.getCurrentVisitNode(); data.setCurrentVisitNode(node); DependencyDescriptor dd = node.getDependencyDescriptor(); VersionMatcher versionMatcher = node.getNode().getData().getSettings().getVersionMatcher(); if (dd != null && !(node.getRoot() == node.getParent() && versionMatcher.isDynamic(dd .getDependencyRevisionId()))) { /* * we don't resolve conflicts before loading data for direct dependencies on dynamic * revisions, so that direct dynamic revisions are always resolved, which is mandatory * for proper replacement of dynamic revisions during 'deliver' */ resolveConflict(node, conf); } if (node.loadData(conf, shouldBePublic)) { // we resolve conflict again now that we have all information loaded // indeed in some cases conflict manager need more information than just asked // dependency to take the decision resolveConflict(node, conf); if (!node.isEvicted() && !node.isCircular()) { String[] confs = node.getRealConfs(conf); for (int i = 0; i < confs.length; i++) { doFetchDependencies(node, confs[i]); } } } else if (!node.hasProblem()) { // the node has not been loaded but hasn't problem: it was already loaded // => we just have to update its dependencies data if (!node.isEvicted() && !node.isCircular()) { String[] confs = node.getRealConfs(conf); for (int i = 0; i < confs.length; i++) { doFetchDependencies(node, confs[i]); } } } if (node.isEvicted()) { // update selected nodes with confs asked in evicted one EvictionData ed = node.getEvictedData(); if (ed.getSelected() != null) { for (Iterator iter = ed.getSelected().iterator(); iter.hasNext();) { IvyNode selected = (IvyNode) iter.next(); if (!selected.isLoaded()) { // the node is not yet loaded, we can simply update its set of // configurations to fetch selected.updateConfsToFetch(Collections.singleton(conf)); } else { // the node has already been loaded, we must fetch its dependencies in the // required conf fetchDependencies(node.gotoNode(selected), conf, true); } } } } if (settings.debugConflictResolution()) { Message.debug(node.getId() + " => dependencies resolved in " + conf + " (" + (System.currentTimeMillis() - start) + "ms)"); } data.setCurrentVisitNode(parentVisitNode); } private void doFetchDependencies(VisitNode node, String conf) { Configuration c = node.getConfiguration(conf); if (c == null) { if (!node.isConfRequiredByMergedUsageOnly(conf)) { Message.warn("configuration not found '" + conf + "' in " + node.getResolvedId() + ": ignoring"); if (node.getParent() != null) { Message.warn("it was required from " + node.getParent().getResolvedId()); } } return; } // we handle the case where the asked configuration extends others: // we have to first fetch the extended configurations // first we check if this is the actual requested conf (not an extended one) boolean requestedConfSet = false; if (node.getRequestedConf() == null) { node.setRequestedConf(conf); requestedConfSet = true; } // now let's recurse in extended confs String[] extendedConfs = c.getExtends(); if (extendedConfs.length > 0) { node.updateConfsToFetch(Arrays.asList(extendedConfs)); } for (int i = 0; i < extendedConfs.length; i++) { fetchDependencies(node, extendedConfs[i], false); } // now we can actually resolve this configuration dependencies if (!isDependenciesFetched(node.getNode(), conf) && node.isTransitive()) { Collection/* */dependencies = node.getDependencies(conf); for (Iterator iter = dependencies.iterator(); iter.hasNext();) { VisitNode dep = (VisitNode) iter.next(); dep.useRealNode(); // the node may have been resolved to another real one while // resolving other deps String[] confs = dep.getRequiredConfigurations(node, conf); for (int i = 0; i < confs.length; i++) { fetchDependencies(dep, confs[i], true); } if (!dep.isEvicted() && !dep.hasProblem()) { // if there are still confs to fetch (usually because they have // been updated when evicting another module), we fetch them now confs = dep.getConfsToFetch(); for (int i = 0; i < confs.length; i++) { // shouldBeFixed=false to because some of those dependencies might // be private when they were actually extending public conf. // Should we keep two list of confs to fetch (private&public)? // I don't think, visibility is already checked, and a change in the // configuration between version might anyway have worse problems. fetchDependencies(dep, confs[i], false); } } } markDependenciesFetched(node.getNode(), conf); } // we have finiched with this configuration, if it was the original requested conf // we can clean it now if (requestedConfSet) { node.setRequestedConf(null); } } /** * Returns true if we've already fetched the dependencies for this node and configuration * * @param node * node to check * @param conf * configuration to check * @return true if we've already fetched this dependency */ private boolean isDependenciesFetched(IvyNode node, String conf) { String key = getDependenciesFetchedKey(node, conf); return fetchedSet.contains(key); } private void markDependenciesFetched(IvyNode node, String conf) { String key = getDependenciesFetchedKey(node, conf); fetchedSet.add(key); } private String getDependenciesFetchedKey(IvyNode node, String conf) { ModuleRevisionId moduleRevisionId = node.getResolvedId(); String key = moduleRevisionId.getOrganisation() + "|" + moduleRevisionId.getName() + "|" + moduleRevisionId.getRevision() + "|" + conf; return key; } private void resolveConflict(VisitNode node, String conf) { resolveConflict(node, node.getParent(), conf, Collections.EMPTY_SET); } /** * Resolves conflict for the given node in the given ancestor. This method do conflict * resolution in ancestor parents recursively, unless not necessary. * * @param node * the node for which conflict resolution should be done * @param ancestor * the ancestor in which the conflict resolution should be done * @param toevict * a collection of IvyNode to evict (as computed by conflict resolution in * descendants of ancestor) * @return true if conflict resolution has been done, false it can't be done yet */ private boolean resolveConflict(VisitNode node, VisitNode ancestor, String conf, Collection toevict) { if (ancestor == null || node == ancestor) { return true; } // check if job is not already done if (checkConflictSolvedEvicted(node, ancestor)) { // job is done and node is evicted, nothing to do return true; } boolean debugConflictResolution = settings.debugConflictResolution(); if (checkConflictSolvedSelected(node, ancestor)) { // job is done and node is selected, nothing to do for this ancestor, but we still have // to check higher levels, for which conflict resolution might have been impossible // before if (resolveConflict(node, ancestor.getParent(), conf, toevict)) { // now that conflict resolution is ok in ancestors // we just have to check if the node wasn't previously evicted in root ancestor EvictionData evictionData = node.getEvictionDataInRoot(node.getRootModuleConf(), ancestor); if (evictionData != null) { // node has been previously evicted in an ancestor: we mark it as evicted if (debugConflictResolution) { Message.debug(node + " was previously evicted in root module conf " + node.getRootModuleConf()); } node.markEvicted(evictionData); if (debugConflictResolution) { Message.debug("evicting " + node + " by " + evictionData); } } return true; } else { return false; } } // compute conflicts Set resolvedNodes = ancestor.getNode().getResolvedNodes(node.getModuleId(), node.getRootModuleConf()); resolvedNodes.addAll(ancestor.getNode().getPendingConflicts(node.getRootModuleConf(), node.getModuleId())); Collection conflicts = computeConflicts(node, ancestor, conf, toevict, resolvedNodes); ConflictManager conflictManager = ancestor.getNode().getConflictManager(node.getModuleId()); Collection resolved = resolveConflicts(node, ancestor, conflicts, conflictManager); if (resolved == null) { if (debugConflictResolution) { Message.debug("impossible to resolve conflicts for " + node + " in " + ancestor + " yet"); Message.debug("setting all nodes as pending conflicts for later conflict" + " resolution: " + conflicts); } ancestor.getNode().setPendingConflicts(node.getModuleId(), node.getRootModuleConf(), conflicts); return false; } if (debugConflictResolution) { Message.debug("selected revisions for " + node + " in " + ancestor + ": " + resolved); } if (resolved.contains(node.getNode())) { // node has been selected for the current parent // handle previously selected nodes that are now evicted by this new node toevict = resolvedNodes; toevict.removeAll(resolved); for (Iterator iter = toevict.iterator(); iter.hasNext();) { IvyNode te = (IvyNode) iter.next(); te.markEvicted(node.getRootModuleConf(), ancestor.getNode(), conflictManager, resolved); if (debugConflictResolution) { Message.debug("evicting " + te + " by " + te.getEvictedData(node.getRootModuleConf())); } } // it's very important to update resolved and evicted nodes BEFORE recompute parent call // to allow it to recompute its resolved collection with correct data // if necessary ancestor.getNode().setResolvedNodes(node.getModuleId(), node.getRootModuleConf(), resolved); Collection evicted = new HashSet(ancestor.getNode().getEvictedNodes(node.getModuleId(), node.getRootModuleConf())); evicted.removeAll(resolved); evicted.addAll(toevict); ancestor.getNode().setEvictedNodes(node.getModuleId(), node.getRootModuleConf(), evicted); ancestor.getNode().setPendingConflicts(node.getModuleId(), node.getRootModuleConf(), Collections.EMPTY_SET); return resolveConflict(node, ancestor.getParent(), conf, toevict); } else { // node has been evicted for the current parent if (resolved.isEmpty()) { if (debugConflictResolution) { Message.verbose("conflict manager '" + conflictManager + "' evicted all revisions among " + conflicts); } } // it's time to update parent resolved and evicted with what was found Collection evicted = new HashSet(ancestor.getNode().getEvictedNodes(node.getModuleId(), node.getRootModuleConf())); toevict.removeAll(resolved); evicted.removeAll(resolved); evicted.addAll(toevict); evicted.add(node.getNode()); ancestor.getNode().setEvictedNodes(node.getModuleId(), node.getRootModuleConf(), evicted); ancestor.getNode().setPendingConflicts(node.getModuleId(), node.getRootModuleConf(), Collections.EMPTY_SET); node.markEvicted(ancestor, conflictManager, resolved); if (debugConflictResolution) { Message.debug("evicting " + node + " by " + node.getEvictedData()); } // if resolved changed we have to go up in the graph Collection prevResolved = ancestor.getNode().getResolvedNodes(node.getModuleId(), node.getRootModuleConf()); boolean solved = true; if (!prevResolved.equals(resolved)) { ancestor.getNode().setResolvedNodes(node.getModuleId(), node.getRootModuleConf(), resolved); for (Iterator iter = resolved.iterator(); iter.hasNext();) { IvyNode sel = (IvyNode) iter.next(); if (!prevResolved.contains(sel)) { solved &= resolveConflict(node.gotoNode(sel), ancestor.getParent(), conf, toevict); } } } return solved; } } private Collection resolveConflicts(VisitNode node, VisitNode ancestor, Collection conflicts, ConflictManager conflictManager) { if (node.getParent() != ancestor // we are not handling the direct parent && conflictManager == settings.getConflictManager(node.getModuleId()) // the conflict manager is the default one && node.getParent().getNode() .getResolvedNodes(node.getModuleId(), node.getRootModuleConf()) .equals(conflicts) // there is no new conflict in this ancestor ) { // IVY-465 case if (settings.debugConflictResolution()) { Message.debug("no new conflicting revisions for " + node + " in " + ancestor + ": " + conflicts); } return conflicts; } else { if (settings.debugConflictResolution()) { Message.debug("found conflicting revisions for " + node + " in " + ancestor + ": " + conflicts); } return conflictManager.resolveConflicts(ancestor.getNode(), conflicts); } } /** * Compute possible conflicts for a node, in the context of an ancestor (a node which has a * dependency - direct or indirect - on the node for which conflicts should be computed. * * @param node * the node for which conflicts should be computed * @param ancestor * the ancestor in which conflicts should be computed * @param conf * the configuration of the node in which conflicts should be computed * @param toevict * a collection of nodes which have been evicted during conflict resolution at lower * level. It may be empty if no conflict resolution has occurred for this node yet, * or if no node has been evicted. * @param selectedNodes * a collection of nodes selected during previous conflict resolution for the given * node and ancestor. This collection is updated by this call, removing nodes which * should be evicted. * @return a collection of IvyNode which may be in conflict with the given node in the given * ancestor. This collection always contain at least the given node. */ private Collection computeConflicts(VisitNode node, VisitNode ancestor, String conf, Collection toevict, Collection selectedNodes) { Collection conflicts = new LinkedHashSet(); conflicts.add(node.getNode()); /* * We first try to remove all evicted nodes from the collection of selected nodes to update * this collection. If the collection changes, it means that it contained evicted nodes, and * thus is not up to date. */ boolean evictedInSelected = selectedNodes.removeAll(toevict); /* * Another case where we need to deeply compute selected nodes is when selectedNodes is * empty (not computed yet) and we aren't in the context of the direct parent of the node. */ if (evictedInSelected || (selectedNodes.isEmpty() && !node.getParent().getNode() .equals(ancestor.getNode()))) { IvyContext context = IvyContext.getContext(); ResolveData data = context.getResolveData(); VisitNode oldVisitNode = data.getCurrentVisitNode(); data.setCurrentVisitNode(ancestor); try { // In this case we need to compute selected nodes again. Collection deps = ancestor.getNode().getDependencies(node.getRootModuleConf(), ancestor.getNode().getConfigurations(node.getRootModuleConf()), ancestor.getRequestedConf()); for (Iterator iter = deps.iterator(); iter.hasNext();) { IvyNode dep = (IvyNode) iter.next(); if (dep.getModuleId().equals(node.getModuleId())) { conflicts.add(dep); } conflicts.addAll(dep.getResolvedNodes(node.getModuleId(), node.getRootModuleConf())); } } finally { data.setCurrentVisitNode(oldVisitNode); } } else if (selectedNodes.isEmpty()) { /* * No selected nodes at all yet, and we are in the context of the direct parent * (otherwise previous block would have been reached). We can compute conflicts based on * the parent direct dependencies in current root module conf. */ VisitNode parent = node.getParent(); Collection parentDepIvyNodes = parent.getNode().getDependencies( node.getRootModuleConf(), parent.getNode().getConfigurations(node.getRootModuleConf()), parent.getRequestedConf()); for (Iterator it = parentDepIvyNodes.iterator(); it.hasNext();) { IvyNode parentDep = (IvyNode) it.next(); if (parentDep.getModuleId().equals(node.getModuleId())) { conflicts.add(parentDep); } } } else { conflicts.addAll(selectedNodes); } return conflicts; } private boolean checkConflictSolvedSelected(VisitNode node, VisitNode ancestor) { if (ancestor.getResolvedRevisions(node.getModuleId()).contains(node.getResolvedId())) { // resolve conflict has already be done with node with the same id if (settings.debugConflictResolution()) { Message.debug("conflict resolution already done for " + node + " in " + ancestor); } return true; } return false; } private boolean checkConflictSolvedEvicted(VisitNode node, VisitNode ancestor) { if (ancestor.getEvictedRevisions(node.getModuleId()).contains(node.getResolvedId())) { // resolve conflict has already be done with node with the same id if (settings.debugConflictResolution()) { Message.debug("conflict resolution already done for " + node + " in " + ancestor); } return true; } return false; } public ResolvedModuleRevision findModule(ModuleRevisionId id, ResolveOptions options) { DependencyResolver r = settings.getResolver(id); if (r == null) { throw new IllegalStateException("no resolver found for " + id.getModuleId()); } DefaultModuleDescriptor md = DefaultModuleDescriptor.newCallerInstance(id, new String[] {"*"}, false, false); if (options.getResolveId() == null) { options.setResolveId(ResolveOptions.getDefaultResolveId(md)); } try { return r.getDependency(new DefaultDependencyDescriptor(id, true), new ResolveData(this, options, new ConfigurationResolveReport(this, md, "default", null, options))); } catch (ParseException e) { throw new RuntimeException("problem while parsing repository module descriptor for " + id + ": " + e, e); } } /** * Mediates the given dependency descriptor according to given options. *

* The mediated dependency descriptor must return the actually requested module revision id when * the method {@link DependencyDescriptor#getDependencyRevisionId()} is called. *

* * @param dd * the dependency descriptor for which the requested module revision id should be * returned * @param options * the resolve options to use * @return the mediated {@link DependencyDescriptor}. */ public DependencyDescriptor mediate(DependencyDescriptor dd, ResolveOptions options) { if (dd == null) { return null; } String resolveMode = options.getResolveMode() == null ? settings.getResolveMode(dd .getDependencyId()) : options.getResolveMode(); if (ResolveOptions.RESOLVEMODE_DYNAMIC.equals(resolveMode) && !dd.getDynamicConstraintDependencyRevisionId().equals( dd.getDependencyRevisionId())) { // the dynamicRevId can contain a null branch, so make sure this // has been replaced by the default branch (if any!) return dd.clone(ModuleRevisionId.newInstance(dd .getDynamicConstraintDependencyRevisionId(), dd .getDynamicConstraintDependencyRevisionId().getRevision())); } else { return dd; } } public EventManager getEventManager() { return eventManager; } public ResolveEngineSettings getSettings() { return settings; } public SortEngine getSortEngine() { return sortEngine; } private void checkInterrupted() { IvyContext.getContext().getIvy().checkInterrupted(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolveEngineSettings.java000066400000000000000000000031351226750426600271120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.report.ReportOutputter; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.ResolverSettings; public interface ResolveEngineSettings extends ResolverSettings { void setDictatorResolver(DependencyResolver dictatorResolver); boolean debugConflictResolution(); ReportOutputter[] getReportOutputters(); String getResolverName(ModuleRevisionId mid); boolean logNotConvertedExclusionRule(); ConflictManager getConflictManager(ModuleId mid); boolean logModuleWhenFound(); boolean logResolvedRevision(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolveOptions.java000066400000000000000000000215611226750426600256220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.Date; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.util.ConfigurationUtils; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; /** * A set of options used during resolve related tasks * * @see ResolveEngine */ public class ResolveOptions extends LogOptions { /** * Default resolve mode, using default revision constraints in dependency descriptors. */ public static final String RESOLVEMODE_DEFAULT = "default"; /** * Dynamic resolve mode, using dynamic revision constraints in dependency descriptors. */ public static final String RESOLVEMODE_DYNAMIC = "dynamic"; /** * Array of all available resolve modes. */ public static final String[] RESOLVEMODES = new String[] {RESOLVEMODE_DEFAULT, RESOLVEMODE_DYNAMIC}; /** * an array of configuration names to resolve - must not be null nor empty */ private String[] confs = new String[] {"*"}; /** * the revision of the module for which dependencies should be resolved. This revision is * considered as the resolved revision of the module, unless it is null. If it is null, then a * default revision is given if necessary (no revision found in ivy file) */ private String revision = null; /** * the date for which the dependencies should be resolved. All obtained artifacts should have a * publication date which is before or equal to the given date. The date can be null, in which * case all artifacts will be considered */ private Date date = null; /** * True if validation of module descriptors should done, false otherwise */ private boolean validate = true; /** * True if only the cache should be used for resolve, false if a real resolve with dependency * resolvers should be done */ private boolean useCacheOnly = false; /** * True if the dependencies should be resolved transitively, false if only direct dependencies * should be resolved */ private boolean transitive = true; /** * True if the resolve should also download artifacts, false if only dependency resolution with * module descriptors should be done */ private boolean download = true; /** * True if a report of the resolve process should be output at the end of the process, false * otherwise */ private boolean outputReport = true; /** * A filter to use to avoid downloading all artifacts. */ private Filter artifactFilter = FilterHelper.NO_FILTER; /** * The resolve mode to use. Should be one of {@link #RESOLVEMODES}, or null to use * settings configured resolve mode. */ private String resolveMode; /** * The id used to store the resolve information. */ private String resolveId; private boolean refresh; /** * True if the resolve should compare the new resolution against the previous report **/ private boolean checkIfChanged = false; public ResolveOptions() { } public ResolveOptions(ResolveOptions options) { super(options); confs = options.confs; revision = options.revision; date = options.date; validate = options.validate; refresh = options.refresh; useCacheOnly = options.useCacheOnly; transitive = options.transitive; download = options.download; outputReport = options.outputReport; resolveMode = options.resolveMode; artifactFilter = options.artifactFilter; resolveId = options.resolveId; checkIfChanged = options.checkIfChanged; } public Filter getArtifactFilter() { return artifactFilter; } public ResolveOptions setArtifactFilter(Filter artifactFilter) { this.artifactFilter = artifactFilter; return this; } /** * Returns the resolve mode to use, or null to use settings configured resolve * mode. * * @return the resolve mode to use. */ public String getResolveMode() { return resolveMode; } public ResolveOptions setResolveMode(String resolveMode) { this.resolveMode = resolveMode; return this; } /** * Indicates if the configurations use a special configuration * , *(private) or *(public). When * special configurations are used, you must have the module descriptor in order to get the list * of configurations. * * @see #getConfs() * @see #getConfs(ModuleDescriptor) */ public boolean useSpecialConfs() { for (int i = 0; confs != null && i < confs.length; i++) { if (confs[0].startsWith("*")) { return true; } } return false; } /** * @pre can only be called if useSpecialConfs()==false. When it is true, you have to provide a * module desciptor so that configurations can be resolved. * @see #getConfs(ModuleDescriptor) */ public String[] getConfs() { if (useSpecialConfs()) { throw new AssertionError("ResolveOptions.getConfs() " + "can not be used for options used special confs."); } return confs; } /** * Get the aksed confs. Special confs (like *) use the moduleDescriptor to find the values * * * @param md * Used to get the exact values for special confs. * */ public String[] getConfs(ModuleDescriptor md) { // TODO add isInline, in that case, replace * by *(public). return ConfigurationUtils.replaceWildcards(confs, md); } public ResolveOptions setConfs(String[] confs) { this.confs = confs; return this; } public Date getDate() { return date; } public ResolveOptions setDate(Date date) { this.date = date; return this; } public boolean isDownload() { return download; } public ResolveOptions setDownload(boolean download) { this.download = download; return this; } public boolean isOutputReport() { return outputReport; } public ResolveOptions setOutputReport(boolean outputReport) { this.outputReport = outputReport; return this; } public boolean isTransitive() { return transitive; } public ResolveOptions setTransitive(boolean transitive) { this.transitive = transitive; return this; } public boolean isUseCacheOnly() { return useCacheOnly; } public ResolveOptions setUseCacheOnly(boolean useCacheOnly) { this.useCacheOnly = useCacheOnly; return this; } public boolean isValidate() { return validate; } public ResolveOptions setValidate(boolean validate) { this.validate = validate; return this; } public String getRevision() { return revision; } public ResolveOptions setRevision(String revision) { this.revision = revision; return this; } public String getResolveId() { return resolveId; } public ResolveOptions setResolveId(String resolveId) { this.resolveId = resolveId; return this; } public ResolveOptions setRefresh(boolean refresh) { this.refresh = refresh; return this; } public boolean isRefresh() { return refresh; } public ResolveOptions setCheckIfChanged(boolean checkIfChanged) { this.checkIfChanged = checkIfChanged; return this; } public boolean getCheckIfChanged() { return checkIfChanged; } public static String getDefaultResolveId(ModuleDescriptor md) { ModuleId module = md.getModuleRevisionId().getModuleId(); return getDefaultResolveId(module); } public static String getDefaultResolveId(ModuleId moduleId) { return moduleId.getOrganisation() + "-" + moduleId.getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolveProcessException.java000066400000000000000000000034271226750426600274650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; /** * ResolveProcessException is an exception which is used to control the resolve process. *

* All {@link ResolveProcessException} subclasses have the ability to interrupt the resolve process * when thrown while resolving dependencies, instead of only marking the module with a problem and * continuing the resolve process as part of the best effort strategy during resolve process. *

* Some subclasses have even a stronger power over the resolve process, like * {@link RestartResolveProcess} which orders to restart the resolve process at the start. */ public class ResolveProcessException extends RuntimeException { public ResolveProcessException() { } public ResolveProcessException(String message, Throwable cause) { super(message, cause); } public ResolveProcessException(String message) { super(message); } public ResolveProcessException(Throwable cause) { super(cause); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java000066400000000000000000000106241226750426600272750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.Date; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.plugins.resolver.DependencyResolver; /** * Represents a module revision provisioned on the local filesystem. */ public class ResolvedModuleRevision { private DependencyResolver resolver; private DependencyResolver artifactResolver; private ModuleDescriptor descriptor; private MetadataArtifactDownloadReport report; private boolean force = false; public ResolvedModuleRevision(DependencyResolver resolver, DependencyResolver artifactResolver, ModuleDescriptor descriptor, MetadataArtifactDownloadReport report) { this.resolver = resolver; this.artifactResolver = artifactResolver; this.descriptor = descriptor; this.report = report; } public ResolvedModuleRevision(DependencyResolver resolver, DependencyResolver artifactResolver, ModuleDescriptor descriptor, MetadataArtifactDownloadReport report, boolean force) { this.resolver = resolver; this.artifactResolver = artifactResolver; this.descriptor = descriptor; this.report = report; this.force = force; } /** * Returns the identifier of the resolved module. * * @return the identifier of the resolved module. */ public ModuleRevisionId getId() { return descriptor.getResolvedModuleRevisionId(); } /** * Returns the date of publication of the resolved module. * * @return the date of publication of the resolved module. */ public Date getPublicationDate() { return descriptor.getResolvedPublicationDate(); } /** * Returns the descriptor of the resolved module. * * @return the descriptor of the resolved module. */ public ModuleDescriptor getDescriptor() { return descriptor; } /** * The resolver which resolved this ResolvedModuleRevision * * @return The resolver which resolved this ResolvedModuleRevision */ public DependencyResolver getResolver() { return resolver; } /** * The resolver to use to download artifacts * * @return The resolver to use to download artifacts */ public DependencyResolver getArtifactResolver() { return artifactResolver; } /** * Returns a report of the resolved module metadata artifact provisioning. * * @return a report of the resolved module metadata artifact provisioning. */ public MetadataArtifactDownloadReport getReport() { return report; } /** * Returns true if this resolved module revision should be forced as the one being * returned. *

* This is used as an indication for CompositeResolver, to know if they should continue to look * for a better ResolvedModuleRevision if possible, or stop with this instance. *

* * @return true if this resolved module revision should be forced as the one being * returned. */ public boolean isForce() { return force; } public boolean equals(Object obj) { if (!(obj instanceof ResolvedModuleRevision)) { return false; } return ((ResolvedModuleRevision) obj).getId().equals(getId()); } public int hashCode() { return getId().hashCode(); } public String toString() { return getId().toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/RestartResolveProcess.java000066400000000000000000000024661226750426600271550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; /** * This RuntimeException is used during the resolve process to ask the engine to restart the resolve * process. *

* Users of this feature should be very careful to make sure they handle a termination condition, * since the resolve engine itself won't check the same exception is not thrown ad libitum *

*/ public class RestartResolveProcess extends ResolveProcessException { public RestartResolveProcess(String message) { super(message); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/VisitData.java000066400000000000000000000046271226750426600245230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class is used to store data related to one node of the dependency graph visit. It stores * both an {@link IvyNode} and related {@link VisitNode} objects. Indeed, during the visit of the * graph, the algorithm can visit the same node from several parents, thus requiring several * VisitNode. */ public class VisitData { /** * A node in the graph of module dependencies resolution */ private IvyNode node; /** * The associated visit nodes, per rootModuleConf Note that the value is a List, because a node * can be visited from several parents during the resolution process */ private Map visitNodes = new HashMap(); // Map (String rootModuleConf -> List(VisitNode)) public VisitData(IvyNode node) { this.node = node; } public void addVisitNode(VisitNode node) { String rootModuleConf = node.getRootModuleConf(); getVisitNodes(rootModuleConf).add(node); } public List getVisitNodes(String rootModuleConf) { List visits = (List) visitNodes.get(rootModuleConf); if (visits == null) { visits = new ArrayList(); visitNodes.put(rootModuleConf, visits); } return visits; } public IvyNode getNode() { return node; } public void setNode(IvyNode node) { this.node = node; } public void addVisitNodes(String rootModuleConf, List visitNodes) { getVisitNodes(rootModuleConf).addAll(visitNodes); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/resolve/VisitNode.java000066400000000000000000000424471226750426600245410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.resolve; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.util.Checks; /** * A visit node is an object used to represent one visit from one parent on an {@link IvyNode} of * the dependency graph. During dependency resolution, the {@link ResolveEngine} visits nodes of the * depency graph following the dependencies, thus the same node can be visited several times, if it * is requested from several module. In this case you will have one VisitNode per parent and per * root module configuration. Thus VisitNode stores data specific to the visit: *
    *
  • parent
  • * the node from which the visit is occuring *
  • parentConf
  • * the configuration of the parent in which this node is visited *
  • rootModuleConf
  • * the configuration of the root module which is currently resolved *
*/ public class VisitNode { /** * The node which is currently visited */ private IvyNode node; /** * Represents the current parent of the node during ivy visit of dependency graph. */ private VisitNode parent = null; /** * The root node of the current visit It is null until it is required, see getRoot */ private VisitNode root = null; /** * Direct path from root to this node. Note that the colleciton is ordered but is not a list * implementation This collection is null until it is required, see getPath */ private Collection path = null; // Collection(VisitNode) /** * The configuration of the parent module in the current visit */ private String parentConf = null; /** * The configuration requested by the parent Note that this is the actual conf requested by the * parent, not a configuration extended by the requested conf which actually trigger the node * visit */ private String requestedConf; /** * The root configuration which is currently visited */ private String rootModuleConf; /** * Shared ResolveData instance, which can be used to get info on the current resolve process */ private ResolveData data; /** * Boolean.TRUE if a node with a same module id as the one visited has already been visited in * the current path. null if not computed yet Boolean.FALSE otherwise */ private Boolean isCircular; /** * IvyNode usage information to update when visiting the underlying IvyNode. This is usually the * main IvyNodeUsage of the underlying node, except when we are visiting it coming from an * evicted node replaced by the other one. */ private IvyNodeUsage usage; public VisitNode(ResolveData data, IvyNode node, VisitNode parent, String rootModuleConf, String parentConf) { this(data, node, parent, rootModuleConf, parentConf, null); } public VisitNode(ResolveData data, IvyNode node, VisitNode parent, String rootModuleConf, String parentConf, IvyNodeUsage usage) { Checks.checkNotNull(data, "data"); Checks.checkNotNull(node, "node"); Checks.checkNotNull(rootModuleConf, "rootModuleConf"); this.data = data; this.node = node; this.parent = parent; this.rootModuleConf = rootModuleConf; this.parentConf = parentConf; this.usage = usage; this.data.register(this); } public IvyNode getNode() { return node; } /** * @return Returns the configuration requested by the parent */ public String getRequestedConf() { return requestedConf; } public void setRequestedConf(String requestedConf) { this.requestedConf = requestedConf; } public VisitNode getParent() { return parent; } public VisitNode getRoot() { if (root == null) { root = computeRoot(); } return root; } /** * Get an ordered collection with the nodes from the root to this node * * @return */ public Collection/* */getPath() { if (path == null) { path = computePath(); } return path; } private Collection/* */computePath() { if (parent != null) { Collection p = new LinkedHashSet(parent.getPath()); p.add(this); return p; } else { return Collections.singletonList(this); } } private VisitNode computeRoot() { if (node.isRoot()) { return this; } else if (parent != null) { return parent.getRoot(); } else { return null; } } public String getParentConf() { return parentConf; } public void setParentConf(String parentConf) { this.parentConf = parentConf; } public String getRootModuleConf() { return rootModuleConf; } public static VisitNode getRoot(VisitNode parent) { VisitNode root = parent; Collection path = new HashSet(); path.add(root); while (root.getParent() != null && !root.getNode().isRoot()) { if (path.contains(root.getParent())) { return root; } root = root.getParent(); path.add(root); } return root; } /** * Returns true if the current dependency descriptor is transitive and the parent configuration * is transitive. Otherwise returns false. * * @return true if current node is transitive and the parent configuration is transitive. */ public boolean isTransitive() { if (node.isRoot()) { // the root node is always considered transitive! return true; } if (!data.isTransitive()) { return false; } if (!isParentConfTransitive()) { return false; } DependencyDescriptor dd = node.getDependencyDescriptor(getParentNode()); if ((dd != null) && dd.isTransitive()) { return true; } return node.hasAnyMergedUsageWithTransitiveDependency(rootModuleConf); } /** * Checks if the current node's parent configuration is transitive. * * @param node * current node * @return true if the node's parent configuration is transitive */ protected boolean isParentConfTransitive() { String conf = getParent().getRequestedConf(); if (conf == null) { return true; } Configuration parentConf = getParentNode().getConfiguration(conf); return parentConf.isTransitive(); } /** * Returns the 'real' node currently visited. 'Real' means that if we are visiting a node * created originally with only a version constraint, and if this version constraint has been * resolved to an existing node in the graph, we will return the existing node, and not the one * originally used which is about to be discarded, since it's not possible to have in the graph * two nodes for the same ModuleRevisionId * * @return the 'real' node currently visited. */ public IvyNode getRealNode() { IvyNode node = this.node.getRealNode(); if (node != null) { return node; } else { return this.node; } } /** * Ask to the current visited node to use a real node only, if one exist. See getRealNode for * details about what a 'real' node is. */ public void useRealNode() { if (parent != null) { // use real node make sense only for non root module IvyNode node = data.getNode(this.node.getId()); if (node != null && node != this.node) { this.node = node; } } } public boolean loadData(String conf, boolean shouldBePublic) { boolean loaded = node.loadData(rootModuleConf, getParentNode(), parentConf, conf, shouldBePublic, getUsage()); if (loaded) { useRealNode(); // if the loaded revision is different from original one // we now register this node on the new resolved id // this includes two cases: // - the id refers to a dynamic revision, which has been resolved by loadData // - the loaded module descriptor has extra attributes in his info tag which are not // used when declaring the dependency if (data.getNode(node.getResolvedId()) == null || !data.getNode(node.getResolvedId()).getId().equals(node.getResolvedId())) { data.register(node.getResolvedId(), this); } } return loaded; } public Collection/* */getDependencies(String conf) { Collection/* */deps = node.getDependencies(rootModuleConf, conf, requestedConf); Collection/* */ret = new ArrayList(deps.size()); for (Iterator iter = deps.iterator(); iter.hasNext();) { IvyNode depNode = (IvyNode) iter.next(); ret.add(traverseChild(conf, depNode)); } return ret; } /** * Returns a VisitNode for the given node. The given node must be a representation of the same * module (usually in another revision) as the one visited by this node. * * @param node * the node to visit * @return a VisitNode for the given node */ VisitNode gotoNode(IvyNode node) { if (!getModuleId().equals(node.getModuleId())) { throw new IllegalArgumentException( "You can't use gotoNode for a node which does not represent the same Module " + "as the one represented by this node.\nCurrent node module id=" + getModuleId() + " Given node module id=" + node.getModuleId()); } VisitData visitData = data.getVisitData(node.getId()); if (visitData != null) { List visitNodes = visitData.getVisitNodes(rootModuleConf); for (Iterator iter = visitNodes.iterator(); iter.hasNext();) { VisitNode vnode = (VisitNode) iter.next(); if ((parent == null && vnode.getParent() == null) || (parent != null && parent.getId().equals(vnode.getParent().getId()))) { vnode.parentConf = parentConf; vnode.usage = getUsage(); return vnode; } } } // the node has not yet been visited from the current parent, we create a new visit node return traverse(parent, parentConf, node, getUsage()); } private IvyNodeUsage getUsage() { return usage == null ? node.getMainUsage() : usage; } private VisitNode traverseChild(String parentConf, IvyNode child) { VisitNode parent = this; return traverse(parent, parentConf, child, null); } private VisitNode traverse(VisitNode parent, String parentConf, IvyNode node, IvyNodeUsage usage) { if (getPath().contains(node)) { IvyContext.getContext().getCircularDependencyStrategy() .handleCircularDependency(toMrids(getPath(), node.getId())); // we do not use the new parent, but the first one, to always be able to go up to the // root // parent = getVisitNode(depNode).getParent(); } return new VisitNode(data, node, parent, rootModuleConf, parentConf, usage); } private ModuleRevisionId[] toMrids(Collection path, ModuleRevisionId last) { ModuleRevisionId[] ret = new ModuleRevisionId[path.size() + 1]; int i = 0; for (Iterator iter = path.iterator(); iter.hasNext(); i++) { VisitNode node = (VisitNode) iter.next(); ret[i] = node.getNode().getId(); } ret[ret.length - 1] = last; return ret; } public ModuleRevisionId getResolvedId() { return node.getResolvedId(); } public void updateConfsToFetch(Collection confs) { node.updateConfsToFetch(confs); } public ModuleRevisionId getId() { return node.getId(); } public boolean isEvicted() { return node.isEvicted(rootModuleConf); } public String[] getRealConfs(String conf) { return node.getRealConfs(conf); } public boolean hasProblem() { return node.hasProblem(); } public Configuration getConfiguration(String conf) { return node.getConfiguration(conf); } public EvictionData getEvictedData() { return node.getEvictedData(rootModuleConf); } public DependencyDescriptor getDependencyDescriptor() { return node.getDependencyDescriptor(getParentNode()); } private IvyNode getParentNode() { return parent == null ? null : parent.getNode(); } /** * Returns true if this node can already be found in the path * * @return */ public boolean isCircular() { if (isCircular == null) { if (parent != null) { isCircular = Boolean.FALSE; // asumme it's false, and see if it isn't by checking // the parent path for (Iterator iter = parent.getPath().iterator(); iter.hasNext();) { VisitNode ancestor = (VisitNode) iter.next(); if (getId().getModuleId().equals(ancestor.getId().getModuleId())) { isCircular = Boolean.TRUE; break; } } } else { isCircular = Boolean.FALSE; } } return isCircular.booleanValue(); } public String[] getConfsToFetch() { return node.getConfsToFetch(); } public String[] getRequiredConfigurations(VisitNode in, String inConf) { return node.getRequiredConfigurations(in.getNode(), inConf); } public ModuleId getModuleId() { return node.getModuleId(); } public Collection getResolvedRevisions(ModuleId mid) { return node.getResolvedRevisions(mid, rootModuleConf); } public void markEvicted(EvictionData evictionData) { node.markEvicted(evictionData); } public String[] getRequiredConfigurations() { return node.getRequiredConfigurations(); } /** * Marks the current node as evicted by the the given selected IvyNodes, in the given parent and * root module configuration, with the given {@link ConflictManager} * * @param parent * the VisitNode in which eviction has been made * @param conflictMgr * the conflict manager responsible for the eviction * @param selected * a Collection of {@link IvyNode} which have been selected */ public void markEvicted(VisitNode parent, ConflictManager conflictMgr, Collection selected) { node.markEvicted(rootModuleConf, parent.getNode(), conflictMgr, selected); } public ModuleDescriptor getDescriptor() { return node.getDescriptor(); } public EvictionData getEvictionDataInRoot(String rootModuleConf, VisitNode ancestor) { return node.getEvictionDataInRoot(rootModuleConf, ancestor.getNode()); } public Collection getEvictedRevisions(ModuleId moduleId) { return node.getEvictedRevisions(moduleId, rootModuleConf); } // public void setRootModuleConf(String rootModuleConf) { // if (rootModuleConf != null && !rootModuleConf.equals(rootModuleConf)) { // _confsToFetch.clear(); // we change of root module conf => we discard all confs to fetch // } // if (rootModuleConf != null && rootModuleConf.equals(rootModuleConf)) { // _selectedDeps.put(new ModuleIdConf(_id.getModuleId(), rootModuleConf), // Collections.singleton(this)); // } // rootModuleConf = rootModuleConf; // } public String toString() { return node.toString(); } public boolean isConfRequiredByMergedUsageOnly(String conf) { return node.isConfRequiredByMergedUsageOnly(rootModuleConf, conf); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/000077500000000000000000000000001226750426600221255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/FileNameMapper.java000066400000000000000000000017011226750426600256140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.retrieve; public interface FileNameMapper { String[] mapFileName(String fileName); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java000066400000000000000000000547541226750426600257220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.retrieve; import java.io.File; import java.io.IOException; import java.text.ParseException; 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.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.event.retrieve.EndRetrieveArtifactEvent; import org.apache.ivy.core.event.retrieve.EndRetrieveEvent; import org.apache.ivy.core.event.retrieve.StartRetrieveArtifactEvent; import org.apache.ivy.core.event.retrieve.StartRetrieveEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.plugins.report.XmlReportParser; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; public class RetrieveEngine { private static final int KILO = 1024; private RetrieveEngineSettings settings; private EventManager eventManager; public RetrieveEngine(RetrieveEngineSettings settings, EventManager eventManager) { this.settings = settings; this.eventManager = eventManager; } /** * example of destFilePattern : - lib/[organisation]/[module]/[artifact]-[revision].[type] - * lib/[artifact].[type] : flatten with no revision moduleId is used with confs and * localCacheDirectory to determine an ivy report file, used as input for the copy If such a * file does not exist for any conf (resolve has not been called before ?) then an * IllegalStateException is thrown and nothing is copied. * * @deprecated Use * {@link #retrieve(org.apache.ivy.core.module.id.ModuleRevisionId, RetrieveOptions)} * instead */ @Deprecated public int retrieve(ModuleRevisionId mrid, String destFilePattern, RetrieveOptions options) throws IOException { RetrieveOptions retieveOptions = new RetrieveOptions(options); retieveOptions.setDestArtifactPattern(destFilePattern); RetrieveReport result = retrieve(mrid, retieveOptions); return result.getNbrArtifactsCopied(); } public RetrieveReport retrieve(ModuleRevisionId mrid, RetrieveOptions options) throws IOException { RetrieveReport report = new RetrieveReport(); ModuleId moduleId = mrid.getModuleId(); if (LogOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info(":: retrieving :: " + moduleId + (options.isSync() ? " [sync]" : "")); } else { Message.verbose(":: retrieving :: " + moduleId + (options.isSync() ? " [sync]" : "")); } Message.verbose("\tcheckUpToDate=" + settings.isCheckUpToDate()); long start = System.currentTimeMillis(); String destFilePattern = IvyPatternHelper.substituteVariables( options.getDestArtifactPattern(), settings.getVariables()); String destIvyPattern = IvyPatternHelper.substituteVariables(options.getDestIvyPattern(), settings.getVariables()); String[] confs = getConfs(mrid, options); if (LogOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info("\tconfs: " + Arrays.asList(confs)); } else { Message.verbose("\tconfs: " + Arrays.asList(confs)); } if (this.eventManager != null) { this.eventManager.fireIvyEvent(new StartRetrieveEvent(mrid, confs, options)); } try { Map/* */destToSrcMap = null; // Map> Map artifactsToCopy = determineArtifactsToCopy(mrid, destFilePattern, options); File fileRetrieveRoot = settings.resolveFile(IvyPatternHelper .getTokenRoot(destFilePattern)); report.setRetrieveRoot(fileRetrieveRoot); File ivyRetrieveRoot = destIvyPattern == null ? null : settings .resolveFile(IvyPatternHelper.getTokenRoot(destIvyPattern)); Collection targetArtifactsStructure = new HashSet(); // Set(File) set of all paths // which should be present at // then end of retrieve (useful // for sync) Collection targetIvysStructure = new HashSet(); // same for ivy files if (options.isMakeSymlinksInMass()) { // The HashMap is of "destToSrc" because src could go two places, but dest can only // come from one destToSrcMap = new HashMap(); } // do retrieve long totalCopiedSize = 0; for (Iterator iter = artifactsToCopy.keySet().iterator(); iter.hasNext();) { ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter.next(); File archive = artifact.getLocalFile(); if (artifact.getUnpackedLocalFile() != null) { archive = artifact.getUnpackedLocalFile(); } if (archive == null) { Message.verbose("\tno local file available for " + artifact + ": skipping"); continue; } Set dest = (Set) artifactsToCopy.get(artifact); Message.verbose("\tretrieving " + archive); for (Iterator it2 = dest.iterator(); it2.hasNext();) { IvyContext.getContext().checkInterrupted(); File destFile = settings.resolveFile((String) it2.next()); if (!settings.isCheckUpToDate() || !upToDate(archive, destFile, options)) { Message.verbose("\t\tto " + destFile); if (this.eventManager != null) { // There is no unitary event for the mass sym linking. // skip the event declaration. if (!options.isMakeSymlinksInMass()) { this.eventManager.fireIvyEvent(new StartRetrieveArtifactEvent( artifact, destFile)); } } if (options.isMakeSymlinksInMass()) { if (FileUtil.prepareCopy(archive, destFile, true)) { destToSrcMap.put(destFile, archive); } } else if (options.isMakeSymlinks()) { FileUtil.symlink(archive, destFile, null, true); } else { FileUtil.copy(archive, destFile, null, true); } if (this.eventManager != null) { // There is no unitary event for the mass sym linking. // skip the event declaration. if (!options.isMakeSymlinksInMass()) { this.eventManager.fireIvyEvent(new EndRetrieveArtifactEvent( artifact, destFile)); } } totalCopiedSize += FileUtil.getFileLength(destFile); report.addCopiedFile(destFile, artifact); } else { Message.verbose("\t\tto " + destFile + " [NOT REQUIRED]"); report.addUpToDateFile(destFile, artifact); } if ("ivy".equals(artifact.getType())) { targetIvysStructure .addAll(FileUtil.getPathFiles(ivyRetrieveRoot, destFile)); } else { Iterator destFiles = FileUtil.listAll(destFile, Collections.EMPTY_LIST) .iterator(); while (destFiles.hasNext()) { targetArtifactsStructure.addAll(FileUtil.getPathFiles(fileRetrieveRoot, (File) destFiles.next())); } } } } if (options.isMakeSymlinksInMass()) { Message.verbose("\tMass symlinking " + destToSrcMap.size() + " files"); FileUtil.symlinkInMass(destToSrcMap, true); } if (options.isSync()) { Message.verbose("\tsyncing..."); String[] ignorableFilenames = settings.getIgnorableFilenames(); Collection ignoreList = Arrays.asList(ignorableFilenames); Collection existingArtifacts = FileUtil.listAll(fileRetrieveRoot, ignoreList); Collection existingIvys = ivyRetrieveRoot == null ? null : FileUtil.listAll( ivyRetrieveRoot, ignoreList); if (fileRetrieveRoot.equals(ivyRetrieveRoot)) { Collection target = targetArtifactsStructure; target.addAll(targetIvysStructure); Collection existing = existingArtifacts; existing.addAll(existingIvys); sync(target, existing); } else { sync(targetArtifactsStructure, existingArtifacts); if (existingIvys != null) { sync(targetIvysStructure, existingIvys); } } } long elapsedTime = System.currentTimeMillis() - start; String msg = "\t" + report.getNbrArtifactsCopied() + " artifacts copied" + (settings.isCheckUpToDate() ? (", " + report.getNbrArtifactsUpToDate() + " already retrieved") : "") + " (" + (totalCopiedSize / KILO) + "kB/" + elapsedTime + "ms)"; if (LogOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info(msg); } else { Message.verbose(msg); } Message.verbose("\tretrieve done (" + (elapsedTime) + "ms)"); if (this.eventManager != null) { this.eventManager.fireIvyEvent(new EndRetrieveEvent(mrid, confs, elapsedTime, report.getNbrArtifactsCopied(), report.getNbrArtifactsUpToDate(), totalCopiedSize, options)); } return report; } catch (Exception ex) { throw new RuntimeException("problem during retrieve of " + moduleId + ": " + ex, ex); } } private String[] getConfs(ModuleRevisionId mrid, RetrieveOptions options) throws IOException { String[] confs = options.getConfs(); if (confs == null || (confs.length == 1 && "*".equals(confs[0]))) { try { ModuleDescriptor md = getCache().getResolvedModuleDescriptor(mrid); Message.verbose("no explicit confs given for retrieve, using ivy file: " + md.getResource().getName()); confs = md.getConfigurationsNames(); options.setConfs(confs); } catch (IOException e) { throw e; } catch (Exception e) { IOException ioex = new IOException(e.getMessage()); ioex.initCause(e); throw ioex; } } return confs; } private ResolutionCacheManager getCache() { return settings.getResolutionCacheManager(); } private void sync(Collection target, Collection existing) { Collection toRemove = new HashSet(); for (Iterator iter = existing.iterator(); iter.hasNext();) { File file = (File) iter.next(); toRemove.add(file.getAbsoluteFile()); } for (Iterator iter = target.iterator(); iter.hasNext();) { File file = (File) iter.next(); toRemove.remove(file.getAbsoluteFile()); } for (Iterator iter = toRemove.iterator(); iter.hasNext();) { File file = (File) iter.next(); if (file.exists()) { Message.verbose("\t\tdeleting " + file); FileUtil.forceDelete(file); } } } /** * @return Map> */ public Map determineArtifactsToCopy(ModuleRevisionId mrid, String destFilePattern, RetrieveOptions options) throws ParseException, IOException { ModuleId moduleId = mrid.getModuleId(); if (options.getResolveId() == null) { options.setResolveId(ResolveOptions.getDefaultResolveId(moduleId)); } ResolutionCacheManager cacheManager = getCache(); String[] confs = getConfs(mrid, options); String destIvyPattern = IvyPatternHelper.substituteVariables(options.getDestIvyPattern(), settings.getVariables()); // find what we must retrieve where // ArtifactDownloadReport source -> Set (String copyDestAbsolutePath) final Map artifactsToCopy = new HashMap(); // String copyDestAbsolutePath -> Set (ArtifactRevisionId source) final Map conflictsMap = new HashMap(); // String copyDestAbsolutePath -> Set (ArtifactDownloadReport source) final Map conflictsReportsMap = new HashMap(); // String copyDestAbsolutePath -> Set (String conf) final Map conflictsConfMap = new HashMap(); XmlReportParser parser = new XmlReportParser(); for (int i = 0; i < confs.length; i++) { final String conf = confs[i]; File report = cacheManager.getConfigurationResolveReportInCache(options.getResolveId(), conf); parser.parse(report); Collection artifacts = new ArrayList(Arrays.asList(parser.getArtifactReports())); if (destIvyPattern != null) { ModuleRevisionId[] mrids = parser.getRealDependencyRevisionIds(); for (int j = 0; j < mrids.length; j++) { artifacts.add(parser.getMetadataArtifactReport(mrids[j])); } } for (Iterator iter = artifacts.iterator(); iter.hasNext();) { ArtifactDownloadReport adr = (ArtifactDownloadReport) iter.next(); Artifact artifact = adr.getArtifact(); String ext = artifact.getExt(); if (adr.getUnpackedLocalFile() != null) { ext = ""; } String destPattern = "ivy".equals(adr.getType()) ? destIvyPattern : destFilePattern; if (!"ivy".equals(adr.getType()) && !options.getArtifactFilter().accept(adr.getArtifact())) { continue; // skip this artifact, the filter didn't accept it! } ModuleRevisionId aMrid = artifact.getModuleRevisionId(); String destFileName = IvyPatternHelper.substitute(destPattern, aMrid.getOrganisation(), aMrid.getName(), aMrid.getBranch(), aMrid.getRevision(), artifact.getName(), artifact.getType(), ext, conf, adr.getArtifactOrigin(), aMrid.getQualifiedExtraAttributes(), artifact.getQualifiedExtraAttributes()); Set dest = (Set) artifactsToCopy.get(adr); if (dest == null) { dest = new HashSet(); artifactsToCopy.put(adr, dest); } String copyDest = settings.resolveFile(destFileName).getAbsolutePath(); String[] destinations = new String[] {copyDest}; if (options.getMapper() != null) { destinations = options.getMapper().mapFileName(copyDest); } for (int j = 0; j < destinations.length; j++) { dest.add(destinations[j]); Set conflicts = (Set) conflictsMap.get(destinations[j]); Set conflictsReports = (Set) conflictsReportsMap.get(destinations[j]); Set conflictsConf = (Set) conflictsConfMap.get(destinations[j]); if (conflicts == null) { conflicts = new HashSet(); conflictsMap.put(destinations[j], conflicts); } if (conflictsReports == null) { conflictsReports = new HashSet(); conflictsReportsMap.put(destinations[j], conflictsReports); } if (conflictsConf == null) { conflictsConf = new HashSet(); conflictsConfMap.put(destinations[j], conflictsConf); } if (conflicts.add(artifact.getId())) { conflictsReports.add(adr); conflictsConf.add(conf); } } } } // resolve conflicts if any for (Iterator iter = conflictsMap.keySet().iterator(); iter.hasNext();) { String copyDest = (String) iter.next(); Set artifacts = (Set) conflictsMap.get(copyDest); Set conflictsConfs = (Set) conflictsConfMap.get(copyDest); if (artifacts.size() > 1) { List artifactsList = new ArrayList((Collection) conflictsReportsMap.get(copyDest)); // conflicts battle is resolved by a sort using a conflict resolving policy // comparator which consider as greater a winning artifact Collections.sort(artifactsList, getConflictResolvingPolicy()); // after the sort, the winning artifact is the greatest one, i.e. the last one // we fail if different artifacts of the same module are mapped to the same file ArtifactDownloadReport winner = (ArtifactDownloadReport) artifactsList .get(artifactsList.size() - 1); ModuleRevisionId winnerMD = winner.getArtifact().getModuleRevisionId(); for (int i = artifactsList.size() - 2; i >= 0; i--) { ArtifactDownloadReport current = (ArtifactDownloadReport) artifactsList.get(i); if (winnerMD.equals(current.getArtifact().getModuleRevisionId())) { throw new RuntimeException("Multiple artifacts of the module " + winnerMD + " are retrieved to the same file! Update the retrieve pattern " + " to fix this error."); } } Message.info("\tconflict on " + copyDest + " in " + conflictsConfs + ": " + winnerMD.getRevision() + " won"); // we now iterate over the list beginning with the artifact preceding the winner, // and going backward to the least artifact for (int i = artifactsList.size() - 2; i >= 0; i--) { ArtifactDownloadReport looser = (ArtifactDownloadReport) artifactsList.get(i); Message.verbose("\t\tremoving conflict looser artifact: " + looser.getArtifact()); // for each loser, we remove the pair (loser - copyDest) in the artifactsToCopy // map Set dest = (Set) artifactsToCopy.get(looser); dest.remove(copyDest); if (dest.isEmpty()) { artifactsToCopy.remove(looser); } } } } return artifactsToCopy; } private boolean upToDate(File source, File target, RetrieveOptions options) { if (!target.exists()) { return false; } String overwriteMode = options.getOverwriteMode(); if (RetrieveOptions.OVERWRITEMODE_ALWAYS.equals(overwriteMode)) { return false; } if (RetrieveOptions.OVERWRITEMODE_NEVER.equals(overwriteMode)) { return true; } if (RetrieveOptions.OVERWRITEMODE_NEWER.equals(overwriteMode)) { return source.lastModified() <= target.lastModified(); } if (RetrieveOptions.OVERWRITEMODE_DIFFERENT.equals(overwriteMode)) { return source.lastModified() == target.lastModified(); } // unknown, so just to be sure return false; } /** * The returned comparator should consider greater the artifact which gains the conflict battle. * This is used only during retrieve... prefer resolve conflict manager to resolve conflicts. * * @return */ private Comparator getConflictResolvingPolicy() { return new Comparator() { // younger conflict resolving policy public int compare(Object o1, Object o2) { Artifact a1 = ((ArtifactDownloadReport) o1).getArtifact(); Artifact a2 = ((ArtifactDownloadReport) o2).getArtifact(); if (a1.getPublicationDate().after(a2.getPublicationDate())) { // a1 is after a2 <=> a1 is younger than a2 <=> a1 wins the conflict battle return +1; } else if (a1.getPublicationDate().before(a2.getPublicationDate())) { // a1 is before a2 <=> a2 is younger than a1 <=> a2 wins the conflict battle return -1; } else { return 0; } } }; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/RetrieveEngineSettings.java000066400000000000000000000021751226750426600274310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.retrieve; import org.apache.ivy.core.settings.IvyVariableContainer; import org.apache.ivy.plugins.parser.ParserSettings; public interface RetrieveEngineSettings extends ParserSettings { boolean isCheckUpToDate(); IvyVariableContainer getVariables(); String[] getIgnorableFilenames(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java000066400000000000000000000137501226750426600261370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.retrieve; import org.apache.ivy.core.LogOptions; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.filter.FilterHelper; /** * A set of options used during retrieve related tasks * * @see RetrieveEngine */ public class RetrieveOptions extends LogOptions { public static final String OVERWRITEMODE_NEVER = "never"; public static final String OVERWRITEMODE_ALWAYS = "always"; public static final String OVERWRITEMODE_NEWER = "newer"; public static final String OVERWRITEMODE_DIFFERENT = "different"; /** * The names of configurations to retrieve. If the array consists only of '*', then all * configurations of the module will be retrieved. */ private String[] confs = new String[] {"*"}; /** * The pattern to which ivy files should be retrieved. If destIvyPattern is null no ivy files * will be copied. */ private String destIvyPattern = null; /** * The pattern to which artifacts should be retrieved. */ private String destArtifactPattern = null; /** * The filter to apply before retrieving artifacts. */ private Filter artifactFilter = FilterHelper.NO_FILTER; /** * True if a synchronisation of the destination directory should be done, false if a simple copy * is enough. Synchronisation means that after the retrieve only files which have been retrieved * will be present in the destination directory, which means that some files may be deleted. */ private boolean sync = false; private String overwriteMode = OVERWRITEMODE_NEWER; /** * True if the original files should be used insteaad of their cache copy. */ private boolean useOrigin = false; /** * True if symbolic links should be created instead of plain copy. Works only on OS supporting * symbolic links. */ private boolean makeSymlinks = false; /** * True if symbolic links should be created all at once, instead of one at a time. Works only on * OS supporting with both "sh" (a shell) and "ln" (the link command). */ private boolean makeSymlinksInMass = false; /** * The id used to store the resolve information. */ private String resolveId; private FileNameMapper mapper; public RetrieveOptions() { } public RetrieveOptions(RetrieveOptions options) { super(options); this.confs = options.confs; this.destIvyPattern = options.destIvyPattern; this.destArtifactPattern = options.destArtifactPattern; this.artifactFilter = options.artifactFilter; this.sync = options.sync; this.overwriteMode = options.overwriteMode; this.useOrigin = options.useOrigin; this.makeSymlinks = options.makeSymlinks; this.makeSymlinksInMass = options.makeSymlinksInMass; this.resolveId = options.resolveId; this.mapper = options.mapper; } public String getDestArtifactPattern() { return destArtifactPattern; } public RetrieveOptions setDestArtifactPattern(String destArtifactPattern) { this.destArtifactPattern = destArtifactPattern; return this; } public Filter getArtifactFilter() { return artifactFilter; } public RetrieveOptions setArtifactFilter(Filter artifactFilter) { this.artifactFilter = artifactFilter; return this; } public String[] getConfs() { return confs; } public RetrieveOptions setConfs(String[] confs) { this.confs = confs; return this; } public String getOverwriteMode() { return overwriteMode == null ? OVERWRITEMODE_NEWER : overwriteMode; } public RetrieveOptions setOverwriteMode(String overwriteMode) { this.overwriteMode = overwriteMode; return this; } public String getDestIvyPattern() { return destIvyPattern; } public RetrieveOptions setDestIvyPattern(String destIvyPattern) { this.destIvyPattern = destIvyPattern; return this; } public boolean isMakeSymlinks() { return makeSymlinks; } public boolean isMakeSymlinksInMass() { return makeSymlinksInMass; } public RetrieveOptions setMakeSymlinks(boolean makeSymlinks) { this.makeSymlinks = makeSymlinks; return this; } public RetrieveOptions setMakeSymlinksInMass(boolean makeSymlinksInMass) { this.makeSymlinksInMass = makeSymlinksInMass; return this; } public boolean isSync() { return sync; } public RetrieveOptions setSync(boolean sync) { this.sync = sync; return this; } public boolean isUseOrigin() { return useOrigin; } public RetrieveOptions setUseOrigin(boolean useOrigin) { this.useOrigin = useOrigin; return this; } public String getResolveId() { return resolveId; } public RetrieveOptions setResolveId(String resolveId) { this.resolveId = resolveId; return this; } public FileNameMapper getMapper() { return mapper; } public RetrieveOptions setMapper(FileNameMapper mapper) { this.mapper = mapper; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/retrieve/RetrieveReport.java000066400000000000000000000061211226750426600257510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.retrieve; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import org.apache.ivy.core.report.ArtifactDownloadReport; public class RetrieveReport { private Collection/* */upToDateFiles = new HashSet(); private Collection/* */copiedFiles = new HashSet(); private Map/* */downloadReport = new HashMap(); private File retrieveRoot; /** * Returns the root directory to where the artifacts are retrieved. */ public File getRetrieveRoot() { return retrieveRoot; } public void setRetrieveRoot(File retrieveRoot) { this.retrieveRoot = retrieveRoot; } public int getNbrArtifactsCopied() { return copiedFiles.size(); } public int getNbrArtifactsUpToDate() { return upToDateFiles.size(); } public void addCopiedFile(File file, ArtifactDownloadReport report) { copiedFiles.add(file); downloadReport.put(file, report); } public void addUpToDateFile(File file, ArtifactDownloadReport report) { upToDateFiles.add(file); downloadReport.put(file, report); } /** * Returns a collection of File objects who were actually copied during the retrieve * process. */ public Collection getCopiedFiles() { return new ArrayList(copiedFiles); } /** * Returns a collection of File objects who were actually copied during the retrieve * process. */ public Collection getUpToDateFiles() { return new ArrayList(upToDateFiles); } /** * Returns a collection of File objects who were retrieved during the retrieve process. * This is the union of the files being copied and the files that were up-to-date. */ public Collection getRetrievedFiles() { Collection result = new ArrayList(upToDateFiles.size() + copiedFiles.size()); result.addAll(upToDateFiles); result.addAll(copiedFiles); return result; } /** * Get the mapping between the copied files and their corresponding download report */ public Map getDownloadReport() { return downloadReport; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/search/000077500000000000000000000000001226750426600215455ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/search/ModuleEntry.java000066400000000000000000000030621226750426600246600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.search; import org.apache.ivy.plugins.resolver.DependencyResolver; public class ModuleEntry { private OrganisationEntry organisationEntry; private String module; public ModuleEntry(OrganisationEntry org, String name) { organisationEntry = org; module = name; } public String getOrganisation() { return organisationEntry.getOrganisation(); } public DependencyResolver getResolver() { return organisationEntry.getResolver(); } public String getModule() { return module; } public OrganisationEntry getOrganisationEntry() { return organisationEntry; } public String toString() { return organisationEntry + "#" + module; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/search/OrganisationEntry.java000066400000000000000000000025771226750426600261020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.search; import org.apache.ivy.plugins.resolver.DependencyResolver; public class OrganisationEntry { private DependencyResolver resolver; private String organisation; public OrganisationEntry(DependencyResolver resolver, String organisation) { this.resolver = resolver; this.organisation = organisation; } public String getOrganisation() { return organisation; } public DependencyResolver getResolver() { return resolver; } public String toString() { return organisation; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/search/RevisionEntry.java000066400000000000000000000033031226750426600252270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.search; import org.apache.ivy.plugins.resolver.DependencyResolver; public class RevisionEntry { private ModuleEntry moduleEntry; private String revision; public RevisionEntry(ModuleEntry mod, String name) { moduleEntry = mod; revision = name; } public ModuleEntry getModuleEntry() { return moduleEntry; } public String getRevision() { return revision; } public String getModule() { return moduleEntry.getModule(); } public String getOrganisation() { return moduleEntry.getOrganisation(); } public OrganisationEntry getOrganisationEntry() { return moduleEntry.getOrganisationEntry(); } public DependencyResolver getResolver() { return moduleEntry.getResolver(); } public String toString() { return moduleEntry + ";" + revision; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/search/SearchEngine.java000066400000000000000000000450541226750426600247530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.search; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.resolver.AbstractResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; public class SearchEngine { private IvySettings settings; public SearchEngine(IvySettings settings) { this.settings = settings; } /** * Returns an empty array when no token values are found. * * @param token * @param otherTokenValues * @return */ public String[] listTokenValues(String token, Map otherTokenValues) { Set entries = new LinkedHashSet(); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] values = resolver.listTokenValues(new String[] {token}, otherTokenValues); for (int i = 0; i < values.length; i++) { entries.add(values[i].get(token)); } } return (String[]) entries.toArray(new String[entries.size()]); } public OrganisationEntry[] listOrganisationEntries() { Set entries = new HashSet(); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] orgs = resolver.listTokenValues(new String[] {IvyPatternHelper.ORGANISATION_KEY}, new HashMap()); for (int i = 0; i < orgs.length; i++) { String org = (String) orgs[i].get(IvyPatternHelper.ORGANISATION_KEY); entries.add(new OrganisationEntry(resolver, org)); } } return (OrganisationEntry[]) entries.toArray(new OrganisationEntry[entries.size()]); } public String[] listOrganisations() { Set entries = new HashSet(); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] orgs = resolver.listTokenValues(new String[] {IvyPatternHelper.ORGANISATION_KEY}, new HashMap()); for (int i = 0; i < orgs.length; i++) { entries.add(orgs[i].get(IvyPatternHelper.ORGANISATION_KEY)); } } return (String[]) entries.toArray(new String[entries.size()]); } public ModuleEntry[] listModuleEntries(OrganisationEntry org) { Set entries = new HashSet(); Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] modules = resolver.listTokenValues(new String[] {IvyPatternHelper.MODULE_KEY}, tokenValues); for (int i = 0; i < modules.length; i++) { String module = (String) modules[i].get(IvyPatternHelper.MODULE_KEY); entries.add(new ModuleEntry(org, module)); } } return (ModuleEntry[]) entries.toArray(new ModuleEntry[entries.size()]); } public String[] listModules(String org) { Set entries = new HashSet(); Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] modules = resolver.listTokenValues(new String[] {IvyPatternHelper.MODULE_KEY}, tokenValues); for (int i = 0; i < modules.length; i++) { entries.add(modules[i].get(IvyPatternHelper.MODULE_KEY)); } } return (String[]) entries.toArray(new String[entries.size()]); } public RevisionEntry[] listRevisionEntries(ModuleEntry module) { Set entries = new HashSet(); Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, module.getOrganisation()); tokenValues.put(IvyPatternHelper.MODULE_KEY, module.getModule()); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] revisions = resolver.listTokenValues( new String[] {IvyPatternHelper.REVISION_KEY}, tokenValues); for (int i = 0; i < revisions.length; i++) { String revision = (String) revisions[i].get(IvyPatternHelper.REVISION_KEY); entries.add(new RevisionEntry(module, revision)); } } return (RevisionEntry[]) entries.toArray(new RevisionEntry[entries.size()]); } public String[] listRevisions(String org, String module) { Set entries = new HashSet(); Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org); tokenValues.put(IvyPatternHelper.MODULE_KEY, module); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] revisions = resolver.listTokenValues( new String[] {IvyPatternHelper.REVISION_KEY}, tokenValues); for (int i = 0; i < revisions.length; i++) { entries.add(revisions[i].get(IvyPatternHelper.REVISION_KEY)); } } return (String[]) entries.toArray(new String[entries.size()]); } /** * List module ids of the module accessible through the current resolvers matching the given mid * criteria according to the given matcher. *

* ModuleId are returned in the system namespace. *

* * @param criteria * @param matcher * @return */ public ModuleId[] listModules(ModuleId moduleCrit, PatternMatcher matcher) { List ret = new ArrayList(); Map criteria = new HashMap(); addMatcher(matcher, moduleCrit.getOrganisation(), criteria, IvyPatternHelper.ORGANISATION_KEY); addMatcher(matcher, moduleCrit.getName(), criteria, IvyPatternHelper.MODULE_KEY); String[] tokensToList = new String[] {IvyPatternHelper.ORGANISATION_KEY, IvyPatternHelper.MODULE_KEY}; for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] moduleIdAsMap = resolver.listTokenValues(tokensToList, criteria); for (int i = 0; i < moduleIdAsMap.length; i++) { String org = (String) moduleIdAsMap[i].get(IvyPatternHelper.ORGANISATION_KEY); String name = (String) moduleIdAsMap[i].get(IvyPatternHelper.MODULE_KEY); ModuleId modId = ModuleId.newInstance(org, name); ret.add(NameSpaceHelper.transform(modId, resolver.getNamespace() .getToSystemTransformer())); } } return (ModuleId[]) ret.toArray(new ModuleId[ret.size()]); } /** * List module revision ids of the module accessible through the current resolvers matching the * given mrid criteria according to the given matcher. *

* ModuleRevisionId are returned in the system namespace. *

* * @param criteria * @param matcher * @return */ public ModuleRevisionId[] listModules(ModuleRevisionId moduleCrit, PatternMatcher matcher) { List ret = new ArrayList(); Map criteria = new HashMap(); for (Iterator it = moduleCrit.getAttributes().entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); addMatcher(matcher, (String) entry.getValue(), criteria, (String) entry.getKey()); } String[] tokensToList = (String[]) moduleCrit.getAttributes().keySet() .toArray(new String[moduleCrit.getAttributes().size()]); for (Iterator iter = settings.getResolvers().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] moduleIdAsMap = resolver.listTokenValues(tokensToList, criteria); for (int i = 0; i < moduleIdAsMap.length; i++) { String org = (String) moduleIdAsMap[i].get(IvyPatternHelper.ORGANISATION_KEY); String name = (String) moduleIdAsMap[i].get(IvyPatternHelper.MODULE_KEY); String branch = (String) moduleIdAsMap[i].get(IvyPatternHelper.BRANCH_KEY); String rev = (String) moduleIdAsMap[i].get(IvyPatternHelper.REVISION_KEY); Map foundExtraAtts = new HashMap(); Set qualAttributes = moduleCrit.getQualifiedExtraAttributes().keySet(); for (Iterator iter2 = qualAttributes.iterator(); iter2.hasNext();) { String qualifiedKey = (String) iter2.next(); String value = null; int colonIndex = qualifiedKey.indexOf(':'); if (colonIndex == -1) { value = (String) moduleIdAsMap[i].get(qualifiedKey); } else { value = (String) moduleIdAsMap[i].get(qualifiedKey .substring(colonIndex + 1)); } if (value != null) { foundExtraAtts.put(qualifiedKey, value); } } ModuleRevisionId modRevId = ModuleRevisionId.newInstance(org, name, branch, rev, foundExtraAtts); ret.add(resolver.getNamespace().getToSystemTransformer().transform(modRevId)); } } return (ModuleRevisionId[]) ret.toArray(new ModuleRevisionId[ret.size()]); } /** * List modules matching a given criteria, available in the given dependency resolver. *

* ModuleRevisionId are returned in the system namespace. *

* * @param resolver * the resolver in which modules should looked up * @param moduleCrit * the criteria to match * @param matcher * the matcher to use to match criteria * @return an array of matching module revision ids */ public ModuleRevisionId[] listModules(DependencyResolver resolver, ModuleRevisionId moduleCrit, PatternMatcher matcher) { Map criteria = new HashMap(); for (Iterator it = moduleCrit.getAttributes().entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); addMatcher(matcher, (String) entry.getValue(), criteria, (String) entry.getKey()); } String[] tokensToList = (String[]) moduleCrit.getAttributes().keySet() .toArray(new String[moduleCrit.getAttributes().size()]); Map[] moduleIdAsMap = resolver.listTokenValues(tokensToList, criteria); Set result = new LinkedHashSet(); // we use a Set to remove duplicates for (int i = 0; i < moduleIdAsMap.length; i++) { String org = (String) moduleIdAsMap[i].get(IvyPatternHelper.ORGANISATION_KEY); String name = (String) moduleIdAsMap[i].get(IvyPatternHelper.MODULE_KEY); String branch = (String) moduleIdAsMap[i].get(IvyPatternHelper.BRANCH_KEY); String rev = (String) moduleIdAsMap[i].get(IvyPatternHelper.REVISION_KEY); Map foundExtraAtts = new HashMap(); Set qualExtraAttributes = moduleCrit.getQualifiedExtraAttributes().keySet(); for (Iterator iter2 = qualExtraAttributes.iterator(); iter2.hasNext();) { String qualifiedKey = (String) iter2.next(); String value = null; int colonIndex = qualifiedKey.indexOf(':'); if (colonIndex == -1) { value = (String) moduleIdAsMap[i].get(qualifiedKey); } else { value = (String) moduleIdAsMap[i].get(qualifiedKey.substring(colonIndex + 1)); } if (value != null) { foundExtraAtts.put(qualifiedKey, value); } } ModuleRevisionId modRevId = ModuleRevisionId.newInstance(org, name, branch, rev, foundExtraAtts); result.add(resolver.getNamespace().getToSystemTransformer().transform(modRevId)); } return (ModuleRevisionId[]) result.toArray(new ModuleRevisionId[result.size()]); } private void addMatcher(PatternMatcher patternMatcher, String expression, Map criteria, String key) { if (expression == null) { return; } Matcher matcher = patternMatcher.getMatcher(expression); if (matcher.isExact()) { criteria.put(key, expression); } else { criteria.put(key, matcher); } } public Collection findModuleRevisionIds(DependencyResolver resolver, ModuleRevisionId pattern, PatternMatcher matcher) { Collection mrids = new ArrayList(); String resolverName = resolver.getName(); Message.verbose("looking for modules matching " + pattern + " using " + matcher.getName()); Namespace fromNamespace = null; if (resolver instanceof AbstractResolver) { fromNamespace = ((AbstractResolver) resolver).getNamespace(); } Collection modules = new ArrayList(); OrganisationEntry[] orgs = resolver.listOrganisations(); if (orgs == null || orgs.length == 0) { // hack for resolvers which are not able to list organisation, we try to see if the // asked organisation is not an exact one: String org = pattern.getOrganisation(); if (fromNamespace != null) { org = NameSpaceHelper.transform(pattern.getModuleId(), fromNamespace.getFromSystemTransformer()).getOrganisation(); } modules.addAll(Arrays.asList(resolver.listModules(new OrganisationEntry(resolver, org)))); } else { Matcher orgMatcher = matcher.getMatcher(pattern.getOrganisation()); for (int i = 0; i < orgs.length; i++) { String org = orgs[i].getOrganisation(); String systemOrg = org; if (fromNamespace != null) { systemOrg = NameSpaceHelper.transformOrganisation(org, fromNamespace.getToSystemTransformer()); } if (orgMatcher.matches(systemOrg)) { modules.addAll(Arrays.asList(resolver.listModules(new OrganisationEntry( resolver, org)))); } } } Message.debug("found " + modules.size() + " modules for " + pattern.getOrganisation() + " on " + resolverName); boolean foundModule = false; for (Iterator iter = modules.iterator(); iter.hasNext();) { ModuleEntry mEntry = (ModuleEntry) iter.next(); ModuleId foundMid = new ModuleId(mEntry.getOrganisation(), mEntry.getModule()); ModuleId systemMid = foundMid; if (fromNamespace != null) { systemMid = NameSpaceHelper.transform(foundMid, fromNamespace.getToSystemTransformer()); } if (MatcherHelper.matches(matcher, pattern.getModuleId(), systemMid)) { // The module corresponds to the searched module pattern foundModule = true; RevisionEntry[] rEntries = resolver.listRevisions(mEntry); Message.debug("found " + rEntries.length + " revisions for [" + mEntry.getOrganisation() + ", " + mEntry.getModule() + "] on " + resolverName); boolean foundRevision = false; for (int j = 0; j < rEntries.length; j++) { RevisionEntry rEntry = rEntries[j]; ModuleRevisionId foundMrid = ModuleRevisionId.newInstance( mEntry.getOrganisation(), mEntry.getModule(), rEntry.getRevision()); ModuleRevisionId systemMrid = foundMrid; if (fromNamespace != null) { systemMrid = fromNamespace.getToSystemTransformer().transform(foundMrid); } if (MatcherHelper.matches(matcher, pattern, systemMrid)) { // We have a matching module revision foundRevision = true; mrids.add(systemMrid); } } if (!foundRevision) { Message.debug("no revision found matching " + pattern + " in [" + mEntry.getOrganisation() + "," + mEntry.getModule() + "] using " + resolverName); } } } if (!foundModule) { Message.debug("no module found matching " + pattern + " using " + resolverName); } return mrids; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/000077500000000000000000000000001226750426600221405ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/IvyPattern.java000066400000000000000000000020571226750426600251140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; /** * */ public class IvyPattern { private String pattern; public String getPattern() { return pattern; } public void setPattern(String pattern) { this.pattern = pattern; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/IvySettings.java000066400000000000000000001574541226750426600253130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.AccessControlException; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.NormalRelativeUrlResolver; import org.apache.ivy.core.RelativeUrlResolver; import org.apache.ivy.core.cache.CacheUtil; import org.apache.ivy.core.cache.DefaultRepositoryCacheManager; import org.apache.ivy.core.cache.DefaultResolutionCacheManager; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.check.CheckEngineSettings; import org.apache.ivy.core.deliver.DeliverEngineSettings; import org.apache.ivy.core.install.InstallEngineSettings; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.core.pack.ArchivePacking; import org.apache.ivy.core.pack.PackingRegistry; import org.apache.ivy.core.publish.PublishEngineSettings; import org.apache.ivy.core.repository.RepositoryManagementEngineSettings; import org.apache.ivy.core.resolve.ResolveEngineSettings; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.retrieve.RetrieveEngineSettings; import org.apache.ivy.core.sort.SortEngineSettings; import org.apache.ivy.osgi.core.OsgiLatestStrategy; import org.apache.ivy.plugins.IvySettingsAware; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.circular.ErrorCircularDependencyStrategy; import org.apache.ivy.plugins.circular.IgnoreCircularDependencyStrategy; import org.apache.ivy.plugins.circular.WarnCircularDependencyStrategy; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.conflict.LatestCompatibleConflictManager; import org.apache.ivy.plugins.conflict.LatestConflictManager; import org.apache.ivy.plugins.conflict.NoConflictManager; import org.apache.ivy.plugins.conflict.StrictConflictManager; import org.apache.ivy.plugins.latest.LatestLexicographicStrategy; import org.apache.ivy.plugins.latest.LatestRevisionStrategy; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.latest.LatestTimeStrategy; import org.apache.ivy.plugins.lock.CreateFileLockStrategy; import org.apache.ivy.plugins.lock.LockStrategy; import org.apache.ivy.plugins.lock.NIOFileLockStrategy; import org.apache.ivy.plugins.lock.NoLockStrategy; import org.apache.ivy.plugins.matcher.ExactOrRegexpPatternMatcher; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.matcher.RegexpPatternMatcher; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.report.LogReportOutputter; import org.apache.ivy.plugins.report.ReportOutputter; import org.apache.ivy.plugins.report.XmlReportOutputter; import org.apache.ivy.plugins.resolver.ChainResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.DualResolver; import org.apache.ivy.plugins.resolver.ResolverSettings; import org.apache.ivy.plugins.signer.SignatureGenerator; import org.apache.ivy.plugins.trigger.Trigger; import org.apache.ivy.plugins.version.ChainVersionMatcher; import org.apache.ivy.plugins.version.ExactVersionMatcher; import org.apache.ivy.plugins.version.LatestVersionMatcher; import org.apache.ivy.plugins.version.SubVersionMatcher; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.plugins.version.VersionRangeMatcher; import org.apache.ivy.util.Checks; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.filter.Filter; import org.apache.ivy.util.url.URLHandlerRegistry; public class IvySettings implements SortEngineSettings, PublishEngineSettings, ParserSettings, DeliverEngineSettings, CheckEngineSettings, InstallEngineSettings, ResolverSettings, ResolveEngineSettings, RetrieveEngineSettings, RepositoryManagementEngineSettings { private static final long INTERUPT_TIMEOUT = 2000; private Map typeDefs = new HashMap(); private Map resolversMap = new HashMap(); private DependencyResolver defaultResolver; private DependencyResolver dictatorResolver = null; private String defaultResolverName; private File defaultCache; private String defaultBranch = null; private boolean checkUpToDate = true; private ModuleRules moduleSettings = new ModuleRules(); // Map (String conflictManagerName -> ConflictManager) private Map conflictsManager = new HashMap(); // Map (String latestStrategyName -> LatestStrategy) private Map latestStrategies = new HashMap(); // Map (String name -> LockStrategy) private Map lockStrategies = new HashMap(); // Map (String namespaceName -> Namespace) private Map namespaces = new HashMap(); // Map (String matcherName -> Matcher) private Map matchers = new HashMap(); // Map (String outputterName -> ReportOutputter) private Map reportOutputters = new HashMap(); // Map (String matcherName -> VersionMatcher) private Map versionMatchers = new HashMap(); // Map (String name -> CircularDependencyStrategy) private Map circularDependencyStrategies = new HashMap(); // Map (String name -> RepositoryCacheManager) private Map repositoryCacheManagers = new HashMap(); // Map (String name -> SignatureGenerator) private Map signatureGenerators = new HashMap(); // List (Trigger) private List triggers = new ArrayList(); private IvyVariableContainer variableContainer = new IvyVariableContainerImpl(); private boolean validate = true; private LatestStrategy defaultLatestStrategy = null; private LockStrategy defaultLockStrategy = null; private ConflictManager defaultConflictManager = null; private CircularDependencyStrategy circularDependencyStrategy = null; private RepositoryCacheManager defaultRepositoryCacheManager = null; private ResolutionCacheManager resolutionCacheManager = null; private List listingIgnore = new ArrayList(); private boolean repositoriesConfigured; private boolean useRemoteConfig = false; private File defaultUserDir; private File baseDir = new File(".").getAbsoluteFile(); private List classpathURLs = new ArrayList(); private ClassLoader classloader; private Boolean debugConflictResolution; private boolean logNotConvertedExclusionRule; private VersionMatcher versionMatcher; private StatusManager statusManager; private Boolean debugLocking; private Boolean dumpMemoryUsage; private String defaultCacheIvyPattern; private String defaultCacheArtifactPattern; private boolean defaultUseOrigin; private String defaultResolveMode = ResolveOptions.RESOLVEMODE_DEFAULT; private PackingRegistry packingRegistry = new PackingRegistry(); public IvySettings() { this(new IvyVariableContainerImpl()); } public IvySettings(IvyVariableContainer variableContainer) { setVariableContainer(variableContainer); setVariable("ivy.default.settings.dir", getDefaultSettingsDir(), true); setVariable("ivy.basedir", getBaseDir().getAbsolutePath()); setDeprecatedVariable("ivy.default.conf.dir", "ivy.default.settings.dir"); String ivyTypeDefs = System.getProperty("ivy.typedef.files"); if (ivyTypeDefs != null) { String[] files = ivyTypeDefs.split("\\,"); for (int i = 0; i < files.length; i++) { try { typeDefs( new FileInputStream(Checks.checkAbsolute(files[i].trim(), "ivy.typedef.files")), true); } catch (FileNotFoundException e) { Message.warn("typedefs file not found: " + files[i].trim()); } catch (IOException e) { Message.warn("problem with typedef file: " + files[i].trim(), e); } } } else { try { typeDefs(getSettingsURL("typedef.properties").openStream(), true); } catch (IOException e) { Message.warn("impossible to load default type defs", e); } } LatestLexicographicStrategy latestLexicographicStrategy = new LatestLexicographicStrategy(); LatestRevisionStrategy latestRevisionStrategy = new LatestRevisionStrategy(); LatestTimeStrategy latestTimeStrategy = new LatestTimeStrategy(); OsgiLatestStrategy osgiLatestStrategy = new OsgiLatestStrategy(); addLatestStrategy("latest-revision", latestRevisionStrategy); addLatestStrategy("latest-lexico", latestLexicographicStrategy); addLatestStrategy("latest-time", latestTimeStrategy); addLatestStrategy("latest-osgi", osgiLatestStrategy); addLockStrategy("no-lock", new NoLockStrategy()); addLockStrategy("artifact-lock", new CreateFileLockStrategy(debugLocking())); addLockStrategy("artifact-lock-nio", new NIOFileLockStrategy(debugLocking())); addConflictManager("latest-revision", new LatestConflictManager("latest-revision", latestRevisionStrategy)); addConflictManager("latest-compatible", new LatestCompatibleConflictManager( "latest-compatible", latestRevisionStrategy)); addConflictManager("latest-time", new LatestConflictManager("latest-time", latestTimeStrategy)); addConflictManager("all", new NoConflictManager()); addConflictManager("strict", new StrictConflictManager()); addMatcher(ExactPatternMatcher.INSTANCE); addMatcher(RegexpPatternMatcher.INSTANCE); addMatcher(ExactOrRegexpPatternMatcher.INSTANCE); try { // GlobPatternMatcher is optional. Only add it when available. Class globClazz = IvySettings.class.getClassLoader().loadClass( "org.apache.ivy.plugins.matcher.GlobPatternMatcher"); Field instanceField = globClazz.getField("INSTANCE"); addMatcher((PatternMatcher) instanceField.get(null)); } catch (Exception e) { // ignore: the matcher isn't on the classpath Message.info("impossible to define glob matcher: " + "org.apache.ivy.plugins.matcher.GlobPatternMatcher was not found", e); } addReportOutputter(new LogReportOutputter()); addReportOutputter(new XmlReportOutputter()); configureDefaultCircularDependencyStrategies(); listingIgnore.add(".cvsignore"); listingIgnore.add("CVS"); listingIgnore.add(".svn"); listingIgnore.add("maven-metadata.xml"); listingIgnore.add("maven-metadata.xml.md5"); listingIgnore.add("maven-metadata.xml.sha1"); addSystemProperties(); } private synchronized void addSystemProperties() { try { addAllVariables((Map) System.getProperties().clone()); } catch (AccessControlException ex) { Message.verbose("access denied to getting all system properties: they won't be available as Ivy variables." + "\nset " + ex.getPermission() + " permission if you want to access them"); } } /** * Call this method to ask ivy to configure some variables using either a remote or a local * properties file */ public synchronized void configureRepositories(boolean remote) { if (!repositoriesConfigured) { Properties props = new Properties(); boolean configured = false; if (useRemoteConfig && remote) { try { URL url = new URL("http://ant.apache.org/ivy/repository.properties"); Message.verbose("configuring repositories with " + url); props.load(URLHandlerRegistry.getDefault().openStream(url)); configured = true; } catch (Exception ex) { Message.verbose("unable to use remote repository configuration", ex); props = new Properties(); } } if (!configured) { InputStream repositoryPropsStream = null; try { repositoryPropsStream = getSettingsURL("repository.properties").openStream(); props.load(repositoryPropsStream); } catch (IOException e) { Message.error("unable to use internal repository configuration", e); if (repositoryPropsStream != null) { try { repositoryPropsStream.close(); } catch (Exception ex) { // nothing to do } } } } addAllVariables(props, false); repositoriesConfigured = true; } } public synchronized void typeDefs(InputStream stream) throws IOException { typeDefs(stream, false); } public synchronized void typeDefs(InputStream stream, boolean silentFail) throws IOException { try { Properties p = new Properties(); p.load(stream); typeDefs(p, silentFail); } finally { stream.close(); } } public synchronized void typeDefs(Properties p) { typeDefs(p, false); } public synchronized void typeDefs(Properties p, boolean silentFail) { for (Iterator iter = p.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); typeDef(name, p.getProperty(name), silentFail); } } public synchronized void load(File settingsFile) throws ParseException, IOException { Message.info(":: loading settings :: file = " + settingsFile); long start = System.currentTimeMillis(); setSettingsVariables(settingsFile); if (getVariable("ivy.default.ivy.user.dir") != null) { setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"), "ivy.default.ivy.user.dir")); } else { getDefaultIvyUserDir(); } loadDefaultProperties(); try { new XmlSettingsParser(this).parse(settingsFile.toURI().toURL()); } catch (MalformedURLException e) { IllegalArgumentException iae = new IllegalArgumentException( "given file cannot be transformed to url: " + settingsFile); iae.initCause(e); throw iae; } setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false); Message.verbose("settings loaded (" + (System.currentTimeMillis() - start) + "ms)"); dumpSettings(); } public synchronized void load(URL settingsURL) throws ParseException, IOException { Message.info(":: loading settings :: url = " + settingsURL); long start = System.currentTimeMillis(); setSettingsVariables(settingsURL); if (getVariable("ivy.default.ivy.user.dir") != null) { setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"), "ivy.default.ivy.user.dir")); } else { getDefaultIvyUserDir(); } loadDefaultProperties(); new XmlSettingsParser(this).parse(settingsURL); setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false); Message.verbose("settings loaded (" + (System.currentTimeMillis() - start) + "ms)"); dumpSettings(); } /** * Default initialization of settings, useful when you don't want to load your settings from a * settings file or URL, but prefer to set them manually. By calling this method you will still * have the basic initialization done when loading settings. * * @throws IOException */ public synchronized void defaultInit() throws IOException { if (getVariable("ivy.default.ivy.user.dir") != null) { setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"), "ivy.default.ivy.user.dir")); } else { getDefaultIvyUserDir(); } getDefaultCache(); loadDefaultProperties(); setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false); dumpSettings(); } public synchronized void loadDefault() throws ParseException, IOException { load(getDefaultSettingsURL()); } public synchronized void loadDefault14() throws ParseException, IOException { load(getDefault14SettingsURL()); } private void loadDefaultProperties() throws IOException { loadProperties(getDefaultPropertiesURL(), false); } public static URL getDefaultPropertiesURL() { return getSettingsURL("ivy.properties"); } public static URL getDefaultSettingsURL() { return getSettingsURL("ivysettings.xml"); } public static URL getDefault14SettingsURL() { return getSettingsURL("ivysettings-1.4.xml"); } private String getDefaultSettingsDir() { String ivysettingsLocation = getDefaultSettingsURL().toExternalForm(); return ivysettingsLocation.substring(0, ivysettingsLocation.length() - "ivysettings.xml".length() - 1); } private static URL getSettingsURL(String file) { return XmlSettingsParser.class.getResource(file); } public synchronized void setSettingsVariables(File settingsFile) { try { setVariable("ivy.settings.dir", new File(settingsFile.getAbsolutePath()).getParent()); setDeprecatedVariable("ivy.conf.dir", "ivy.settings.dir"); setVariable("ivy.settings.file", settingsFile.getAbsolutePath()); setDeprecatedVariable("ivy.conf.file", "ivy.settings.file"); setVariable("ivy.settings.url", settingsFile.toURI().toURL().toExternalForm()); setDeprecatedVariable("ivy.conf.url", "ivy.settings.url"); setVariable("ivy.settings.dir.url", new File(settingsFile.getAbsolutePath()) .getParentFile().toURI().toURL().toExternalForm()); } catch (MalformedURLException e) { IllegalArgumentException iae = new IllegalArgumentException( "given file cannot be transformed to url: " + settingsFile); iae.initCause(e); throw iae; } } /** * Sets a deprecated variable with the value of the new variable * * @param deprecatedKey * the deprecated variable name * @param newKey * the new variable name */ private void setDeprecatedVariable(String deprecatedKey, String newKey) { setVariable(deprecatedKey, getVariable(newKey)); } public synchronized void setSettingsVariables(URL settingsURL) { String settingsURLStr = settingsURL.toExternalForm(); setVariable("ivy.settings.url", settingsURLStr); setDeprecatedVariable("ivy.conf.url", "ivy.settings.url"); int slashIndex = settingsURLStr.lastIndexOf('/'); if (slashIndex != -1) { String dirUrl = settingsURLStr.substring(0, slashIndex); setVariable("ivy.settings.dir", dirUrl); setVariable("ivy.settings.dir.url", dirUrl); setDeprecatedVariable("ivy.conf.dir", "ivy.settings.dir"); } else { Message.warn("settings url does not contain any slash (/): " + "ivy.settings.dir variable not set"); } } private void dumpSettings() { Message.verbose("\tdefault cache: " + getDefaultCache()); Message.verbose("\tdefault resolver: " + getDefaultResolver()); Message.debug("\tdefault latest strategy: " + getDefaultLatestStrategy()); Message.debug("\tdefault conflict manager: " + getDefaultConflictManager()); Message.debug("\tcircular dependency strategy: " + getCircularDependencyStrategy()); Message.debug("\tvalidate: " + doValidate()); Message.debug("\tcheck up2date: " + isCheckUpToDate()); if (!classpathURLs.isEmpty()) { Message.verbose("\t-- " + classpathURLs.size() + " custom classpath urls:"); for (Iterator iter = classpathURLs.iterator(); iter.hasNext();) { Message.debug("\t\t" + iter.next()); } } Message.verbose("\t-- " + resolversMap.size() + " resolvers:"); for (Iterator iter = resolversMap.values().iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); resolver.dumpSettings(); } Message.debug("\tmodule settings:"); moduleSettings.dump("\t\t"); } public synchronized void loadProperties(URL url) throws IOException { loadProperties(url, true); } public synchronized void loadProperties(URL url, boolean overwrite) throws IOException { loadProperties(url.openStream(), overwrite); } public synchronized void loadProperties(File file) throws IOException { loadProperties(file, true); } public synchronized void loadProperties(File file, boolean overwrite) throws IOException { loadProperties(new FileInputStream(file), overwrite); } private void loadProperties(InputStream stream, boolean overwrite) throws IOException { try { Properties properties = new Properties(); properties.load(stream); addAllVariables(properties, overwrite); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // nothing } } } } public synchronized void setVariable(String varName, String value) { setVariable(varName, value, true); } public synchronized void setVariable(String varName, String value, boolean overwrite) { setVariable(varName, value, overwrite, null, null); } public synchronized void setVariable(String varName, String value, boolean overwrite, String ifSetVar, String unlessSetVar) { if (ifSetVar != null && variableContainer.getVariable(ifSetVar) == null) { Message.verbose("Not setting '" + varName + "' to '" + value + "' since '" + ifSetVar + "' is not set."); return; } if (unlessSetVar != null && variableContainer.getVariable(unlessSetVar) != null) { Message.verbose("Not setting '" + varName + "' to '" + value + "' since '" + unlessSetVar + "' is set."); return; } variableContainer.setVariable(varName, value, overwrite); } public synchronized void addAllVariables(Map variables) { addAllVariables(variables, true); } public synchronized void addAllVariables(Map variables, boolean overwrite) { for (Iterator iter = variables.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); String val = (String) variables.get(key); setVariable(key, val, overwrite); } } /** * Substitute variables in the given string by their value found in the current set of variables * * @param str * the string in which substitution should be made * @return the string where all current ivy variables have been substituted by their value If * the input str doesn't use any variable, the same object is returned */ public synchronized String substitute(String str) { return IvyPatternHelper.substituteVariables(str, variableContainer); } /** * Substitute variables in the given map values by their value found in the current set of * variables * * @param strings * the map of strings in which substitution should be made * @return a new map of strings in which all current ivy variables in values have been * substituted by their value */ public synchronized Map/* */substitute(Map/* */strings) { Map substituted = new LinkedHashMap(); for (Iterator it = strings.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); substituted.put(entry.getKey(), substitute((String) entry.getValue())); } return substituted; } /** * Returns the variables loaded in configuration file. Those variables may better be seen as ant * properties * * @return */ public synchronized IvyVariableContainer getVariables() { return variableContainer; } public synchronized Class typeDef(String name, String className) { return typeDef(name, className, false); } public synchronized Class typeDef(String name, String className, boolean silentFail) { Class clazz = classForName(className, silentFail); if (clazz != null) { typeDefs.put(name, clazz); } return clazz; } private Class classForName(String className, boolean silentFail) { try { return getClassLoader().loadClass(className); } catch (ClassNotFoundException e) { if (silentFail) { Message.info("impossible to define new type: class not found: " + className + " in " + classpathURLs + " nor Ivy classloader"); return null; } else { throw new RuntimeException("impossible to define new type: class not found: " + className + " in " + classpathURLs + " nor Ivy classloader"); } } } private ClassLoader getClassLoader() { if (classloader == null) { if (classpathURLs.isEmpty()) { classloader = Ivy.class.getClassLoader(); } else { classloader = new URLClassLoader( (URL[]) classpathURLs.toArray(new URL[classpathURLs.size()]), Ivy.class.getClassLoader()); } } return classloader; } public synchronized void addClasspathURL(URL url) { classpathURLs.add(url); classloader = null; } public synchronized Map getTypeDefs() { return typeDefs; } public synchronized Class getTypeDef(String name) { return (Class) typeDefs.get(name); } // methods which match ivy conf method signature specs public synchronized void addConfigured(DependencyResolver resolver) { addResolver(resolver); } public synchronized void addConfigured(ModuleDescriptorParser parser) { ModuleDescriptorParserRegistry.getInstance().addParser(parser); } public synchronized void addConfigured(SignatureGenerator generator) { addSignatureGenerator(generator); } public synchronized void addSignatureGenerator(SignatureGenerator generator) { init(generator); signatureGenerators.put(generator.getName(), generator); } public synchronized SignatureGenerator getSignatureGenerator(String name) { return (SignatureGenerator) signatureGenerators.get(name); } public synchronized void addResolver(DependencyResolver resolver) { if (resolver == null) { throw new NullPointerException("null resolver"); } init(resolver); resolversMap.put(resolver.getName(), resolver); if (resolver instanceof ChainResolver) { List subresolvers = ((ChainResolver) resolver).getResolvers(); for (Iterator iter = subresolvers.iterator(); iter.hasNext();) { DependencyResolver dr = (DependencyResolver) iter.next(); addResolver(dr); } } else if (resolver instanceof DualResolver) { DependencyResolver ivyResolver = ((DualResolver) resolver).getIvyResolver(); if (ivyResolver != null) { addResolver(ivyResolver); } DependencyResolver artifactResolver = ((DualResolver) resolver).getArtifactResolver(); if (artifactResolver != null) { addResolver(artifactResolver); } } } public synchronized void setDefaultCache(File cacheDirectory) { setVariable("ivy.cache.dir", cacheDirectory.getAbsolutePath(), false); defaultCache = cacheDirectory; if (defaultRepositoryCacheManager != null) { if ("default-cache".equals(defaultRepositoryCacheManager.getName()) && defaultRepositoryCacheManager instanceof DefaultRepositoryCacheManager) { ((DefaultRepositoryCacheManager) defaultRepositoryCacheManager) .setBasedir(defaultCache); } } } public synchronized void setDefaultResolver(String resolverName) { checkResolverName(resolverName); if (resolverName != null && !resolverName.equals(defaultResolverName)) { defaultResolver = null; } defaultResolverName = resolverName; } private void checkResolverName(String resolverName) { if (resolverName != null && !resolversMap.containsKey(resolverName)) { throw new IllegalArgumentException("no resolver found called " + resolverName + ": check your settings"); } } /** * regular expressions as explained in Pattern class may be used in attributes */ public synchronized void addModuleConfiguration(Map attributes, PatternMatcher matcher, String resolverName, String branch, String conflictManager, String resolveMode) { checkResolverName(resolverName); moduleSettings.defineRule(new MapMatcher(attributes, matcher), new ModuleSettings( resolverName, branch, conflictManager, resolveMode)); } /** * Return the canonical form of a filename. *

* If the specified file name is relative it is resolved with respect to the settings's base * directory. * * @param fileName * The name of the file to resolve. Must not be null. * * @return the resolved File. * */ public synchronized File resolveFile(String fileName) { return FileUtil.resolveFile(baseDir, fileName); } public synchronized void setBaseDir(File baseDir) { this.baseDir = baseDir.getAbsoluteFile(); setVariable("ivy.basedir", this.baseDir.getAbsolutePath()); setVariable("basedir", this.baseDir.getAbsolutePath(), false); } public synchronized File getBaseDir() { return baseDir; } public synchronized File getDefaultIvyUserDir() { if (defaultUserDir == null) { if (getVariable("ivy.home") != null) { setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.home"), "ivy.home")); Message.verbose("using ivy.default.ivy.user.dir variable for default ivy user dir: " + defaultUserDir); } else { setDefaultIvyUserDir(new File(System.getProperty("user.home"), ".ivy2")); Message.verbose("no default ivy user dir defined: set to " + defaultUserDir); } } return defaultUserDir; } public synchronized void setDefaultIvyUserDir(File defaultUserDir) { this.defaultUserDir = defaultUserDir; setVariable("ivy.default.ivy.user.dir", this.defaultUserDir.getAbsolutePath()); setVariable("ivy.home", this.defaultUserDir.getAbsolutePath()); } public synchronized File getDefaultCache() { if (defaultCache == null) { String cache = getVariable("ivy.cache.dir"); if (cache != null) { defaultCache = Checks.checkAbsolute(cache, "ivy.cache.dir"); } else { setDefaultCache(new File(getDefaultIvyUserDir(), "cache")); Message.verbose("no default cache defined: set to " + defaultCache); } } return defaultCache; } public synchronized void setDefaultRepositoryCacheBasedir(String repositoryCacheRoot) { setVariable("ivy.cache.repository", repositoryCacheRoot, true); if (defaultRepositoryCacheManager != null && "default-cache".equals(defaultRepositoryCacheManager.getName()) && defaultRepositoryCacheManager instanceof DefaultRepositoryCacheManager) { ((DefaultRepositoryCacheManager) defaultRepositoryCacheManager) .setBasedir(getDefaultRepositoryCacheBasedir()); } } public synchronized void setDefaultResolutionCacheBasedir(String resolutionCacheRoot) { setVariable("ivy.cache.resolution", resolutionCacheRoot, true); if (resolutionCacheManager != null && resolutionCacheManager instanceof DefaultResolutionCacheManager) { ((DefaultResolutionCacheManager) resolutionCacheManager) .setBasedir(getDefaultResolutionCacheBasedir()); } } public synchronized File getDefaultRepositoryCacheBasedir() { String repositoryCacheRoot = getVariable("ivy.cache.repository"); if (repositoryCacheRoot != null) { return Checks.checkAbsolute(repositoryCacheRoot, "ivy.cache.repository"); } else { return getDefaultCache(); } } public synchronized File getDefaultResolutionCacheBasedir() { String resolutionCacheRoot = getVariable("ivy.cache.resolution"); if (resolutionCacheRoot != null) { return Checks.checkAbsolute(resolutionCacheRoot, "ivy.cache.resolution"); } else { return getDefaultCache(); } } public synchronized void setDictatorResolver(DependencyResolver resolver) { dictatorResolver = resolver; } public synchronized DependencyResolver getResolver(ModuleRevisionId mrid) { if (dictatorResolver != null) { return dictatorResolver; } String resolverName = getResolverName(mrid); return getResolver(resolverName); } public synchronized boolean hasResolver(String resolverName) { return resolversMap.containsKey(resolverName); } public synchronized DependencyResolver getResolver(String resolverName) { if (dictatorResolver != null) { return dictatorResolver; } DependencyResolver resolver = (DependencyResolver) resolversMap.get(resolverName); if (resolver == null) { Message.error("unknown resolver " + resolverName); } return resolver; } public synchronized DependencyResolver getDefaultResolver() { if (dictatorResolver != null) { return dictatorResolver; } if (defaultResolver == null) { defaultResolver = (DependencyResolver) resolversMap.get(defaultResolverName); } return defaultResolver; } public synchronized String getResolverName(ModuleRevisionId mrid) { ModuleSettings ms = (ModuleSettings) moduleSettings.getRule(mrid, new Filter() { public boolean accept(Object o) { return ((ModuleSettings) o).getResolverName() != null; } }); return ms == null ? defaultResolverName : ms.getResolverName(); } public synchronized String getDefaultBranch(ModuleId moduleId) { ModuleSettings ms = (ModuleSettings) moduleSettings.getRule(moduleId, new Filter() { public boolean accept(Object o) { return ((ModuleSettings) o).getBranch() != null; } }); return ms == null ? getDefaultBranch() : ms.getBranch(); } public synchronized String getDefaultBranch() { return defaultBranch; } public synchronized void setDefaultBranch(String defaultBranch) { this.defaultBranch = defaultBranch; } public synchronized ConflictManager getConflictManager(ModuleId moduleId) { ModuleSettings ms = (ModuleSettings) moduleSettings.getRule(moduleId, new Filter() { public boolean accept(Object o) { return ((ModuleSettings) o).getConflictManager() != null; } }); if (ms == null) { return getDefaultConflictManager(); } else { ConflictManager cm = getConflictManager(ms.getConflictManager()); if (cm == null) { throw new IllegalStateException("ivy badly configured: unknown conflict manager " + ms.getConflictManager()); } return cm; } } public synchronized String getResolveMode(ModuleId moduleId) { ModuleSettings ms = (ModuleSettings) moduleSettings.getRule(moduleId, new Filter() { public boolean accept(Object o) { return ((ModuleSettings) o).getResolveMode() != null; } }); return ms == null ? getDefaultResolveMode() : ms.getResolveMode(); } public synchronized String getDefaultResolveMode() { return defaultResolveMode; } public synchronized void setDefaultResolveMode(String defaultResolveMode) { this.defaultResolveMode = defaultResolveMode; } public synchronized void addConfigured(ConflictManager cm) { addConflictManager(cm.getName(), cm); } public synchronized ConflictManager getConflictManager(String name) { if ("default".equals(name)) { return getDefaultConflictManager(); } return (ConflictManager) conflictsManager.get(name); } public synchronized void addConflictManager(String name, ConflictManager cm) { init(cm); conflictsManager.put(name, cm); } public synchronized void addConfigured(LatestStrategy latest) { addLatestStrategy(latest.getName(), latest); } public synchronized LatestStrategy getLatestStrategy(String name) { if ("default".equals(name)) { return getDefaultLatestStrategy(); } return (LatestStrategy) latestStrategies.get(name); } public synchronized void addLatestStrategy(String name, LatestStrategy latest) { init(latest); latestStrategies.put(name, latest); } public synchronized void addConfigured(LockStrategy lockStrategy) { addLockStrategy(lockStrategy.getName(), lockStrategy); } public synchronized LockStrategy getLockStrategy(String name) { if ("default".equals(name)) { return getDefaultLockStrategy(); } return (LockStrategy) lockStrategies.get(name); } public synchronized void addLockStrategy(String name, LockStrategy lockStrategy) { init(lockStrategy); lockStrategies.put(name, lockStrategy); } public synchronized void addConfigured(Namespace ns) { addNamespace(ns); } public synchronized Namespace getNamespace(String name) { if ("system".equals(name)) { return getSystemNamespace(); } return (Namespace) namespaces.get(name); } public final Namespace getSystemNamespace() { return Namespace.SYSTEM_NAMESPACE; } public synchronized void addNamespace(Namespace ns) { init(ns); namespaces.put(ns.getName(), ns); } public synchronized void addConfigured(PatternMatcher m) { addMatcher(m); } public synchronized PatternMatcher getMatcher(String name) { return (PatternMatcher) matchers.get(name); } public synchronized void addMatcher(PatternMatcher m) { init(m); matchers.put(m.getName(), m); } public synchronized void addConfigured(RepositoryCacheManager c) { addRepositoryCacheManager(c); } public synchronized RepositoryCacheManager getRepositoryCacheManager(String name) { return (RepositoryCacheManager) repositoryCacheManagers.get(name); } public synchronized void addRepositoryCacheManager(RepositoryCacheManager c) { init(c); repositoryCacheManagers.put(c.getName(), c); } public synchronized RepositoryCacheManager[] getRepositoryCacheManagers() { return (RepositoryCacheManager[]) repositoryCacheManagers.values().toArray( new RepositoryCacheManager[repositoryCacheManagers.size()]); } public synchronized void addConfigured(ReportOutputter outputter) { addReportOutputter(outputter); } public synchronized ReportOutputter getReportOutputter(String name) { return (ReportOutputter) reportOutputters.get(name); } public synchronized void addReportOutputter(ReportOutputter outputter) { init(outputter); reportOutputters.put(outputter.getName(), outputter); } public synchronized ReportOutputter[] getReportOutputters() { return (ReportOutputter[]) reportOutputters.values().toArray( new ReportOutputter[reportOutputters.size()]); } public synchronized void addConfigured(VersionMatcher vmatcher) { addVersionMatcher(vmatcher); } public synchronized VersionMatcher getVersionMatcher(String name) { return (VersionMatcher) versionMatchers.get(name); } public synchronized void addVersionMatcher(VersionMatcher vmatcher) { init(vmatcher); versionMatchers.put(vmatcher.getName(), vmatcher); if (versionMatcher == null) { versionMatcher = new ChainVersionMatcher(); addVersionMatcher(new ExactVersionMatcher()); } if (versionMatcher instanceof ChainVersionMatcher) { ChainVersionMatcher chain = (ChainVersionMatcher) versionMatcher; chain.add(vmatcher); } } public synchronized VersionMatcher[] getVersionMatchers() { return (VersionMatcher[]) versionMatchers.values().toArray( new VersionMatcher[versionMatchers.size()]); } public synchronized VersionMatcher getVersionMatcher() { if (versionMatcher == null) { configureDefaultVersionMatcher(); } return versionMatcher; } public synchronized void configureDefaultVersionMatcher() { addVersionMatcher(new LatestVersionMatcher()); addVersionMatcher(new SubVersionMatcher()); addVersionMatcher(new VersionRangeMatcher()); } public synchronized CircularDependencyStrategy getCircularDependencyStrategy() { if (circularDependencyStrategy == null) { circularDependencyStrategy = getCircularDependencyStrategy("default"); } return circularDependencyStrategy; } public synchronized CircularDependencyStrategy getCircularDependencyStrategy(String name) { if ("default".equals(name)) { name = "warn"; } return (CircularDependencyStrategy) circularDependencyStrategies.get(name); } public synchronized void setCircularDependencyStrategy(CircularDependencyStrategy strategy) { circularDependencyStrategy = strategy; } public synchronized void addConfigured(CircularDependencyStrategy strategy) { addCircularDependencyStrategy(strategy); } private void addCircularDependencyStrategy(CircularDependencyStrategy strategy) { circularDependencyStrategies.put(strategy.getName(), strategy); } private void configureDefaultCircularDependencyStrategies() { addCircularDependencyStrategy(WarnCircularDependencyStrategy.getInstance()); addCircularDependencyStrategy(ErrorCircularDependencyStrategy.getInstance()); addCircularDependencyStrategy(IgnoreCircularDependencyStrategy.getInstance()); } public synchronized StatusManager getStatusManager() { if (statusManager == null) { statusManager = StatusManager.newDefaultInstance(); } return statusManager; } public void setStatusManager(StatusManager statusManager) { this.statusManager = statusManager; } /** * Returns the file names of the files that should be ignored when creating a file listing. */ public synchronized String[] getIgnorableFilenames() { return (String[]) listingIgnore.toArray(new String[listingIgnore.size()]); } /** * Filters the names list by removing all names that should be ignored as defined by the listing * ignore list * * @param names */ public synchronized void filterIgnore(Collection names) { names.removeAll(listingIgnore); } public synchronized boolean isCheckUpToDate() { return checkUpToDate; } public synchronized void setCheckUpToDate(boolean checkUpToDate) { this.checkUpToDate = checkUpToDate; } public synchronized boolean doValidate() { return validate; } public synchronized void setValidate(boolean validate) { this.validate = validate; } public synchronized String getVariable(String name) { return variableContainer.getVariable(name); } public synchronized ConflictManager getDefaultConflictManager() { if (defaultConflictManager == null) { defaultConflictManager = new LatestConflictManager(getDefaultLatestStrategy()); ((LatestConflictManager) defaultConflictManager).setSettings(this); } return defaultConflictManager; } public synchronized void setDefaultConflictManager(ConflictManager defaultConflictManager) { this.defaultConflictManager = defaultConflictManager; } public synchronized LatestStrategy getDefaultLatestStrategy() { if (defaultLatestStrategy == null) { defaultLatestStrategy = new LatestRevisionStrategy(); } return defaultLatestStrategy; } public synchronized void setDefaultLatestStrategy(LatestStrategy defaultLatestStrategy) { this.defaultLatestStrategy = defaultLatestStrategy; } public synchronized LockStrategy getDefaultLockStrategy() { if (defaultLockStrategy == null) { defaultLockStrategy = new NoLockStrategy(); } return defaultLockStrategy; } public synchronized void setDefaultLockStrategy(LockStrategy defaultLockStrategy) { this.defaultLockStrategy = defaultLockStrategy; } public synchronized RepositoryCacheManager getDefaultRepositoryCacheManager() { if (defaultRepositoryCacheManager == null) { defaultRepositoryCacheManager = new DefaultRepositoryCacheManager("default-cache", this, getDefaultRepositoryCacheBasedir()); addRepositoryCacheManager(defaultRepositoryCacheManager); } return defaultRepositoryCacheManager; } public synchronized void setDefaultRepositoryCacheManager(RepositoryCacheManager cache) { this.defaultRepositoryCacheManager = cache; } public synchronized ResolutionCacheManager getResolutionCacheManager() { if (resolutionCacheManager == null) { resolutionCacheManager = new DefaultResolutionCacheManager( getDefaultResolutionCacheBasedir()); init(resolutionCacheManager); } return resolutionCacheManager; } public synchronized void setResolutionCacheManager(ResolutionCacheManager resolutionCacheManager) { this.resolutionCacheManager = resolutionCacheManager; } public synchronized void addTrigger(Trigger trigger) { init(trigger); triggers.add(trigger); } public synchronized List getTriggers() { return triggers; } public synchronized void addConfigured(Trigger trigger) { addTrigger(trigger); } public synchronized boolean isUseRemoteConfig() { return useRemoteConfig; } public synchronized void setUseRemoteConfig(boolean useRemoteConfig) { this.useRemoteConfig = useRemoteConfig; } public synchronized boolean logModulesInUse() { String var = getVariable("ivy.log.modules.in.use"); return var == null || Boolean.valueOf(var).booleanValue(); } public synchronized boolean logModuleWhenFound() { String var = getVariable("ivy.log.module.when.found"); return var == null || Boolean.valueOf(var).booleanValue(); } public synchronized boolean logResolvedRevision() { String var = getVariable("ivy.log.resolved.revision"); return var == null || Boolean.valueOf(var).booleanValue(); } public synchronized boolean debugConflictResolution() { if (debugConflictResolution == null) { String var = getVariable("ivy.log.conflict.resolution"); debugConflictResolution = Boolean.valueOf(var != null && Boolean.valueOf(var).booleanValue()); } return debugConflictResolution.booleanValue(); } public synchronized boolean debugLocking() { if (debugLocking == null) { String var = getVariable("ivy.log.locking"); debugLocking = Boolean.valueOf(var != null && Boolean.valueOf(var).booleanValue()); } return debugLocking.booleanValue(); } public synchronized boolean dumpMemoryUsage() { if (dumpMemoryUsage == null) { String var = getVariable("ivy.log.memory"); dumpMemoryUsage = Boolean.valueOf(var != null && Boolean.valueOf(var).booleanValue()); } return dumpMemoryUsage.booleanValue(); } public synchronized boolean logNotConvertedExclusionRule() { return logNotConvertedExclusionRule; } public synchronized void setLogNotConvertedExclusionRule(boolean logNotConvertedExclusionRule) { this.logNotConvertedExclusionRule = logNotConvertedExclusionRule; } private void init(Object obj) { if (obj instanceof IvySettingsAware) { ((IvySettingsAware) obj).setSettings(this); } else if (obj instanceof DependencyResolver) { ((DependencyResolver) obj).setSettings(this); } } private static class ModuleSettings { private String resolverName; private String branch; private String conflictManager; private String resolveMode; public ModuleSettings(String resolver, String branchName, String conflictMgr, String resolveMode) { this.resolverName = resolver; this.branch = branchName; this.conflictManager = conflictMgr; this.resolveMode = resolveMode; } public String toString() { return (resolverName != null ? "resolver: " + resolverName : "") + (branch != null ? "branch: " + branch : "") + (conflictManager != null ? "conflictManager: " + conflictManager : "") + (resolveMode != null ? "resolveMode: " + resolveMode : ""); } public String getBranch() { return branch; } public String getResolverName() { return resolverName; } public String getConflictManager() { return conflictManager; } public String getResolveMode() { return resolveMode; } } public final long getInterruptTimeout() { return INTERUPT_TIMEOUT; } public synchronized Collection getResolvers() { return resolversMap.values(); } public synchronized Collection getResolverNames() { return resolversMap.keySet(); } public synchronized Collection getMatcherNames() { return matchers.keySet(); } public synchronized IvyVariableContainer getVariableContainer() { return variableContainer; } /** * Use a different variable container. * * @param variables */ public synchronized void setVariableContainer(IvyVariableContainer variables) { variableContainer = variables; } public synchronized RelativeUrlResolver getRelativeUrlResolver() { return new NormalRelativeUrlResolver(); } public synchronized void setDefaultCacheIvyPattern(String defaultCacheIvyPattern) { CacheUtil.checkCachePattern(defaultCacheIvyPattern); this.defaultCacheIvyPattern = defaultCacheIvyPattern; } public synchronized String getDefaultCacheIvyPattern() { return defaultCacheIvyPattern; } public synchronized void setDefaultCacheArtifactPattern(String defaultCacheArtifactPattern) { CacheUtil.checkCachePattern(defaultCacheArtifactPattern); this.defaultCacheArtifactPattern = defaultCacheArtifactPattern; } public synchronized String getDefaultCacheArtifactPattern() { return defaultCacheArtifactPattern; } public synchronized void setDefaultUseOrigin(boolean useOrigin) { defaultUseOrigin = useOrigin; } public synchronized boolean isDefaultUseOrigin() { return defaultUseOrigin; } public synchronized void useDeprecatedUseOrigin() { Message.deprecated("useOrigin option is deprecated when calling resolve, use useOrigin" + " setting on the cache implementation instead"); setDefaultUseOrigin(true); } /** * Validates the settings, throwing an {@link IllegalStateException} if the current state is not * valid. * * @throws IllegalStateException * if the settings is not valid. */ public synchronized void validate() { validateAll(resolversMap.values()); validateAll(conflictsManager.values()); validateAll(latestStrategies.values()); validateAll(lockStrategies.values()); validateAll(repositoryCacheManagers.values()); validateAll(reportOutputters.values()); validateAll(circularDependencyStrategies.values()); validateAll(versionMatchers.values()); validateAll(namespaces.values()); } /** * Validates all {@link Validatable} objects in the collection. * * @param objects * the collection of objects to validate. * @throws IllegalStateException * if any of the objects is not valid. */ private void validateAll(Collection values) { for (Iterator iterator = values.iterator(); iterator.hasNext();) { Object object = iterator.next(); if (object instanceof Validatable) { ((Validatable) object).validate(); } } } public Namespace getContextNamespace() { return Namespace.SYSTEM_NAMESPACE; } public synchronized void addConfigured(ArchivePacking packing) { init(packing); packingRegistry.register(packing); } public PackingRegistry getPackingRegistry() { return packingRegistry; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/IvyVariableContainer.java000066400000000000000000000026541226750426600270720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; /** * Store and provide access to the ivy variables. */ public interface IvyVariableContainer extends Cloneable { public void setVariable(String varName, String value, boolean overwrite); public String getVariable(String name); /** * Specifies the prefix used to indicate a variable is an environment variable. If the prefix * doesn't end with a '.', it will be added automatically. * * @param prefix * the prefix to use for the environment variables */ public void setEnvironmentPrefix(String prefix); public Object clone(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/IvyVariableContainerImpl.java000066400000000000000000000061411226750426600277070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; import java.util.HashMap; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.util.Message; public class IvyVariableContainerImpl implements IvyVariableContainer { private Map variables; private String envPrefix; public IvyVariableContainerImpl() { this.variables = new HashMap(); } public IvyVariableContainerImpl(Map variables) { this.variables = variables; } /* * (non-Javadoc) * * @see org.apache.ivy.core.settings.IvyVariableContainer#setVariable(java.lang.String, * java.lang.String, boolean) */ public void setVariable(String varName, String value, boolean overwrite) { if (overwrite || !variables.containsKey(varName)) { Message.debug("setting '" + varName + "' to '" + value + "'"); variables.put(varName, substitute(value)); } else { Message.debug("'" + varName + "' already set: discarding '" + value + "'"); } } public void setEnvironmentPrefix(String prefix) { if ((prefix != null) && !prefix.endsWith(".")) { this.envPrefix = prefix + "."; } else { this.envPrefix = prefix; } } protected String substitute(String value) { return IvyPatternHelper.substituteVariables(value, this); } protected Map getVariables() { return variables; } protected String getEnvironmentPrefix() { return envPrefix; } /* * (non-Javadoc) * * @see org.apache.ivy.core.settings.IvyVariableContainer#getVariable(java.lang.String) */ public String getVariable(String name) { String val = null; if ((envPrefix != null) && name.startsWith(envPrefix)) { val = System.getenv(name.substring(envPrefix.length())); } else { val = (String) variables.get(name); } return val; } public Object clone() { IvyVariableContainerImpl clone; try { clone = (IvyVariableContainerImpl) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("unable to clone a " + this.getClass()); } clone.variables = new HashMap(this.variables); return clone; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/Validatable.java000066400000000000000000000023671226750426600252230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; /** * Implemented by settings element which need to perform validation when settings are loaded. */ public interface Validatable { /** * Validates the Validatable, throwing an {@link IllegalStateException} if the current state is * not valid. * * @throws IllegalStateException * if the state of the {@link Validatable} is not valid. */ public void validate(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java000066400000000000000000000670341226750426600264530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.settings; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.SAXParserFactory; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.lock.LockStrategy; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Configurator; import org.apache.ivy.util.FileResolver; import org.apache.ivy.util.Message; import org.apache.ivy.util.url.CredentialsStore; import org.apache.ivy.util.url.URLHandler; import org.apache.ivy.util.url.URLHandlerRegistry; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** */ public class XmlSettingsParser extends DefaultHandler { /** * Wraps an {@link IvyVariableContainer} delegating most method calls to the wrapped instance, * except for a set of variables which are only stored locally in the wrapper, and not * propagated to the wrapped instance. */ private static final class IvyVariableContainerWrapper implements IvyVariableContainer { private static final Collection SETTINGS_VARIABLES = Arrays.asList(new String[] { "ivy.settings.dir", "ivy.settings.url", "ivy.settings.file", "ivy.conf.dir", "ivy.conf.url", "ivy.conf.file"}); private final IvyVariableContainer variables; private Map localVariables = new HashMap(); private IvyVariableContainerWrapper(IvyVariableContainer variables) { this.variables = variables; } public void setVariable(String varName, String value, boolean overwrite) { if (SETTINGS_VARIABLES.contains(varName)) { if (!localVariables.containsKey(varName) || overwrite) { localVariables.put(varName, value); } } else { variables.setVariable(varName, value, overwrite); } } public void setEnvironmentPrefix(String prefix) { variables.setEnvironmentPrefix(prefix); } public String getVariable(String name) { if (localVariables.containsKey(name)) { return (String) localVariables.get(name); } return variables.getVariable(name); } public Object clone() { throw new UnsupportedOperationException(); } } private Configurator configurator; private List configuratorTags = Arrays.asList(new String[] {"resolvers", "namespaces", "parsers", "latest-strategies", "conflict-managers", "outputters", "version-matchers", "statuses", "circular-dependency-strategies", "triggers", "lock-strategies", "caches", "signers"}); private IvySettings ivy; private String defaultResolver; private String defaultCM; private String defaultLatest; private String defaultCacheManager; private String defaultCircular; private String defaultLock; private String currentConfiguratorTag; private URL settings; private boolean deprecatedMessagePrinted = false; public XmlSettingsParser(IvySettings ivy) { this.ivy = ivy; } public void parse(URL settings) throws ParseException, IOException { configurator = new Configurator(); configurator.setFileResolver(new FileResolver() { public File resolveFile(String path, String filename) { return Checks.checkAbsolute(path, filename); } }); // put every type definition from ivy to configurator Map typeDefs = ivy.getTypeDefs(); for (Iterator iter = typeDefs.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); configurator.typeDef(name, (Class) typeDefs.get(name)); } doParse(settings); } private void doParse(URL settingsUrl) throws IOException, ParseException { this.settings = settingsUrl; InputStream stream = null; try { stream = URLHandlerRegistry.getDefault().openStream(settingsUrl); InputSource inSrc = new InputSource(stream); inSrc.setSystemId(settingsUrl.toExternalForm()); SAXParserFactory.newInstance().newSAXParser().parse(settingsUrl.toExternalForm(), this); ivy.validate(); } catch (IOException e) { throw e; } catch (Exception e) { ParseException pe = new ParseException("failed to load settings from " + settingsUrl + ": " + e.getMessage(), 0); pe.initCause(e); throw pe; } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignored } } } } private void parse(Configurator configurator, URL configuration) throws IOException, ParseException { this.configurator = configurator; doParse(configuration); } public void startElement(String uri, String localName, String qName, Attributes att) throws SAXException { // we first copy attributes in a Map to be able to modify them Map attributes = new HashMap(); for (int i = 0; i < att.getLength(); i++) { attributes.put(att.getQName(i), ivy.substitute(att.getValue(i))); } try { if ("ivyconf".equals(qName)) { deprecatedMessagePrinted = true; Message.deprecated("'ivyconf' element is deprecated, use 'ivysettings' instead (" + settings + ")"); } if (configurator.getCurrent() != null) { inConfiguratorStarted(qName, attributes); } else if ("classpath".equals(qName)) { classpathStarted(attributes); } else if ("typedef".equals(qName)) { typedefStarted(attributes); } else if ("property".equals(qName)) { propertyStarted(attributes); } else if ("properties".equals(qName)) { propertiesStarted(attributes); } else if ("include".equals(qName)) { includeStarted(attributes); } else if ("settings".equals(qName) || "conf".equals(qName)) { settingsStarted(qName, attributes); } else if ("caches".equals(qName)) { cachesStarted(qName, attributes); } else if ("version-matchers".equals(qName)) { versionMatchersStarted(qName, attributes); } else if ("statuses".equals(qName)) { statusesStarted(qName, attributes); } else if (configuratorTags.contains(qName)) { anyConfiguratorStarted(qName); } else if ("macrodef".equals(qName)) { macrodefStarted(qName, attributes); } else if ("module".equals(qName)) { moduleStarted(attributes); } else if ("credentials".equals(qName)) { credentialsStarted(attributes); } } catch (ParseException ex) { SAXException sax = new SAXException("problem in config file: " + ex.getMessage(), ex); sax.initCause(ex); throw sax; } catch (IOException ex) { SAXException sax = new SAXException("io problem while parsing config file: " + ex.getMessage(), ex); sax.initCause(ex); throw sax; } } private void credentialsStarted(Map attributes) { String realm = (String) attributes.remove("realm"); String host = (String) attributes.remove("host"); String userName = (String) attributes.remove("username"); String passwd = (String) attributes.remove("passwd"); CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd); } private void moduleStarted(Map attributes) { attributes.put(IvyPatternHelper.MODULE_KEY, attributes.remove("name")); String resolver = (String) attributes.remove("resolver"); String branch = (String) attributes.remove("branch"); String cm = (String) attributes.remove("conflict-manager"); String resolveMode = (String) attributes.remove("resolveMode"); String matcher = (String) attributes.remove("matcher"); matcher = matcher == null ? PatternMatcher.EXACT_OR_REGEXP : matcher; ivy.addModuleConfiguration(attributes, ivy.getMatcher(matcher), resolver, branch, cm, resolveMode); } private void macrodefStarted(String qName, Map attributes) { currentConfiguratorTag = qName; Configurator.MacroDef macrodef = configurator .startMacroDef((String) attributes.get("name")); macrodef.addAttribute("name", null); } private void anyConfiguratorStarted(String qName) { currentConfiguratorTag = qName; configurator.setRoot(ivy); } private void statusesStarted(String qName, Map attributes) { currentConfiguratorTag = qName; StatusManager m = new StatusManager(); String defaultStatus = (String) attributes.get("default"); if (defaultStatus != null) { m.setDefaultStatus(defaultStatus); } ivy.setStatusManager(m); configurator.setRoot(m); } private void versionMatchersStarted(String qName, Map attributes) { anyConfiguratorStarted(qName); if ("true".equals(attributes.get("usedefaults"))) { ivy.configureDefaultVersionMatcher(); } } private void cachesStarted(String qName, Map attributes) { anyConfiguratorStarted(qName); defaultLock = (String) attributes.get("lockStrategy"); defaultCacheManager = (String) attributes.get("default"); String cache = (String) attributes.get("defaultCacheDir"); if (cache != null) { ivy.setDefaultCache(Checks.checkAbsolute(cache, "defaultCacheDir")); } String up2d = (String) attributes.get("checkUpToDate"); if (up2d != null) { Message.deprecated("'checkUpToDate' is deprecated, " + "use the 'overwriteMode' on the 'ivy:retrieve' task instead (" + settings + ")"); ivy.setCheckUpToDate(Boolean.valueOf(up2d).booleanValue()); } String resolutionDir = (String) attributes.get("resolutionCacheDir"); if (resolutionDir != null) { ivy.setDefaultResolutionCacheBasedir(resolutionDir); } String useOrigin = (String) attributes.get("useOrigin"); if (useOrigin != null) { ivy.setDefaultUseOrigin(Boolean.valueOf(useOrigin).booleanValue()); } String cacheIvyPattern = (String) attributes.get("ivyPattern"); if (cacheIvyPattern != null) { ivy.setDefaultCacheIvyPattern(cacheIvyPattern); } String cacheArtPattern = (String) attributes.get("artifactPattern"); if (cacheArtPattern != null) { ivy.setDefaultCacheArtifactPattern(cacheArtPattern); } String repositoryDir = (String) attributes.get("repositoryCacheDir"); if (repositoryDir != null) { ivy.setDefaultRepositoryCacheBasedir(repositoryDir); } } private void settingsStarted(String qName, Map attributes) { if ("conf".equals(qName) && !deprecatedMessagePrinted) { Message.deprecated("'conf' is deprecated, use 'settings' instead (" + settings + ")"); } String cache = (String) attributes.get("defaultCache"); if (cache != null) { Message.deprecated("'defaultCache' is deprecated, " + "use 'caches[@defaultCacheDir]' instead (" + settings + ")"); ivy.setDefaultCache(Checks.checkAbsolute(cache, "defaultCache")); } String defaultBranch = (String) attributes.get("defaultBranch"); if (defaultBranch != null) { ivy.setDefaultBranch(defaultBranch); } String defaultResolveMode = (String) attributes.get("defaultResolveMode"); if (defaultResolveMode != null) { ivy.setDefaultResolveMode(defaultResolveMode); } String validate = (String) attributes.get("validate"); if (validate != null) { ivy.setValidate(Boolean.valueOf(validate).booleanValue()); } String up2d = (String) attributes.get("checkUpToDate"); if (up2d != null) { Message.deprecated("'checkUpToDate' is deprecated, " + "use the 'overwriteMode' on the 'ivy:retrieve' task instead (" + settings + ")"); ivy.setCheckUpToDate(Boolean.valueOf(up2d).booleanValue()); } String useRemoteConfig = (String) attributes.get("useRemoteConfig"); if (useRemoteConfig != null) { ivy.setUseRemoteConfig(Boolean.valueOf(useRemoteConfig).booleanValue()); } String cacheIvyPattern = (String) attributes.get("cacheIvyPattern"); if (cacheIvyPattern != null) { Message.deprecated("'cacheIvyPattern' is deprecated, use 'caches[@ivyPattern]' instead" + " (" + settings + ")"); ivy.setDefaultCacheIvyPattern(cacheIvyPattern); } String cacheArtPattern = (String) attributes.get("cacheArtifactPattern"); if (cacheArtPattern != null) { Message.deprecated("'cacheArtifactPattern' is deprecated, " + "use 'caches[@artifactPattern]' instead (" + settings + ")"); ivy.setDefaultCacheArtifactPattern(cacheArtPattern); } // we do not set following defaults here since no instances has been registered yet defaultResolver = (String) attributes.get("defaultResolver"); defaultCM = (String) attributes.get("defaultConflictManager"); defaultLatest = (String) attributes.get("defaultLatestStrategy"); defaultCircular = (String) attributes.get("circularDependencyStrategy"); String requestMethod = (String) attributes.get("httpRequestMethod"); if ("head".equalsIgnoreCase(requestMethod)) { URLHandlerRegistry.getHttp().setRequestMethod(URLHandler.REQUEST_METHOD_HEAD); } else if ("get".equalsIgnoreCase(requestMethod)) { URLHandlerRegistry.getHttp().setRequestMethod(URLHandler.REQUEST_METHOD_GET); } else if ((requestMethod != null) && (requestMethod.trim().length() > 0)) { throw new IllegalArgumentException("Invalid httpRequestMethod specified, must be " + "one of {'HEAD', 'GET'}"); } } private void includeStarted(Map attributes) throws IOException, ParseException { final IvyVariableContainer variables = ivy.getVariableContainer(); ivy.setVariableContainer(new IvyVariableContainerWrapper(variables)); try { String propFilePath = (String) attributes.get("file"); URL settingsURL = null; if (propFilePath == null) { propFilePath = (String) attributes.get("url"); if (propFilePath == null) { throw new IllegalArgumentException( "bad include tag: specify file or url to include"); } else { try { // First asume that it is an absolute URL settingsURL = new URL(propFilePath); } catch (MalformedURLException e) { // If that fail, it may be because it is a relative one. settingsURL = new URL(this.settings, propFilePath); } Message.verbose("including url: " + settingsURL.toString()); ivy.setSettingsVariables(settingsURL); } } else { settingsURL = urlFromFileAttribute(propFilePath); Message.verbose("including file: " + settingsURL); if ("file".equals(settingsURL.getProtocol())) { try { File settingsFile = new File(new URI(settingsURL.toExternalForm())); String optional = (String) attributes.get("optional"); if ("true".equals(optional) && !settingsFile.exists()) { return; } ivy.setSettingsVariables(Checks.checkAbsolute(settingsFile, "settings include path")); } catch (URISyntaxException e) { // try to make the best of it... ivy.setSettingsVariables(Checks.checkAbsolute(settingsURL.getPath(), "settings include path")); } } else { ivy.setSettingsVariables(settingsURL); } } new XmlSettingsParser(ivy).parse(configurator, settingsURL); } finally { ivy.setVariableContainer(variables); } } /** * Provide an URL referencing the given filepath. If filePath is an absolute path, then the * resulting URL point to a local file, otherwise, the filepath is evaluated relatively to the * URL of the current settings file (can be local file or remote URL). */ private URL urlFromFileAttribute(String filePath) throws IOException { try { return new URL(filePath); } catch (MalformedURLException e) { // ignore, we'll try to create a correct URL below } File incFile = new File(filePath); if (incFile.isAbsolute()) { if (!incFile.exists()) { throw new FileNotFoundException(incFile.getAbsolutePath()); } return incFile.toURI().toURL(); } else if ("file".equals(this.settings.getProtocol())) { try { File settingsFile = new File(new URI(this.settings.toExternalForm())); if (!settingsFile.exists()) { throw new FileNotFoundException(settingsFile.getAbsolutePath()); } return new File(settingsFile.getParentFile(), filePath).toURI().toURL(); } catch (URISyntaxException e) { return new URL(this.settings, filePath); } } else { return new URL(this.settings, filePath); } } private void propertiesStarted(Map attributes) throws IOException { String propFilePath = (String) attributes.get("file"); String environmentPrefix = (String) attributes.get("environment"); if (propFilePath != null) { String overrideStr = (String) attributes.get("override"); boolean override = overrideStr == null ? true : Boolean.valueOf(overrideStr) .booleanValue(); Message.verbose("loading properties: " + propFilePath); try { URL fileUrl = urlFromFileAttribute(propFilePath); ivy.loadProperties(fileUrl, override); } catch (FileNotFoundException e) { Message.verbose("Unable to find property file: " + propFilePath); } } else if (environmentPrefix != null) { ivy.getVariableContainer().setEnvironmentPrefix(environmentPrefix); } else { throw new IllegalArgumentException("Didn't find a 'file' or 'environment' attribute " + "on the 'properties' element"); } } private void propertyStarted(Map attributes) { String name = (String) attributes.get("name"); String value = (String) attributes.get("value"); String override = (String) attributes.get("override"); String isSetVar = (String) attributes.get("ifset"); String unlessSetVar = (String) attributes.get("unlessset"); if (name == null) { throw new IllegalArgumentException("missing attribute name on property tag"); } if (value == null) { throw new IllegalArgumentException("missing attribute value on property tag"); } ivy.setVariable(name, value, override == null ? true : Boolean.valueOf(override) .booleanValue(), isSetVar, unlessSetVar); } private void typedefStarted(Map attributes) { String name = (String) attributes.get("name"); String className = (String) attributes.get("classname"); Class clazz = ivy.typeDef(name, className); configurator.typeDef(name, clazz); } private void classpathStarted(Map attributes) throws IOException { String urlStr = (String) attributes.get("url"); URL url = null; if (urlStr == null) { String file = (String) attributes.get("file"); if (file == null) { throw new IllegalArgumentException( "either url or file should be given for classpath element"); } else { url = urlFromFileAttribute(file); } } else { url = new URL(urlStr); } ivy.addClasspathURL(url); } private void inConfiguratorStarted(String qName, Map attributes) { if ("macrodef".equals(currentConfiguratorTag) && configurator.getTypeDef(qName) != null) { String name = (String) attributes.get("name"); if (name == null) { attributes.put("name", "@{name}"); } else if (name.indexOf("@{name}") != -1) { attributes.put("name", name); } else { attributes.put("name", "@{name}-" + name); } } if (attributes.get("ref") != null) { if (attributes.size() != 1) { throw new IllegalArgumentException("ref attribute should be the only one ! found " + attributes.size() + " in " + qName); } String name = (String) attributes.get("ref"); Object child = null; if ("resolvers".equals(currentConfiguratorTag) || "resolver".equals(qName)) { child = ivy.getResolver(name); if (child == null) { throw new IllegalArgumentException("unknown resolver " + name + ": resolver should be defined before being referenced"); } } else if ("latest-strategies".equals(currentConfiguratorTag)) { child = ivy.getLatestStrategy(name); if (child == null) { throw new IllegalArgumentException("unknown latest strategy " + name + ": latest strategy should be defined before being referenced"); } } else if ("conflict-managers".equals(currentConfiguratorTag)) { child = ivy.getConflictManager(name); if (child == null) { throw new IllegalArgumentException("unknown conflict manager " + name + ": conflict manager should be defined before being referenced"); } } if (child == null) { throw new IllegalArgumentException("bad reference " + name); } configurator.addChild(qName, child); } else { configurator.startCreateChild(qName); for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { String attName = (String) iter.next(); configurator.setAttribute(attName, (String) attributes.get(attName)); } } } public void endElement(String uri, String localName, String qName) throws SAXException { if (configurator.getCurrent() != null) { if (configuratorTags.contains(qName) && configurator.getDepth() == 1) { configurator.clear(); currentConfiguratorTag = null; } else if ("macrodef".equals(qName) && configurator.getDepth() == 1) { configurator.endMacroDef(); currentConfiguratorTag = null; } else { configurator.endCreateChild(); } } } public void endDocument() throws SAXException { if (defaultResolver != null) { ivy.setDefaultResolver(ivy.substitute(defaultResolver)); } if (defaultCM != null) { ConflictManager conflictManager = ivy.getConflictManager(ivy.substitute(defaultCM)); if (conflictManager == null) { throw new IllegalArgumentException("unknown conflict manager " + ivy.substitute(defaultCM)); } ivy.setDefaultConflictManager(conflictManager); } if (defaultLatest != null) { LatestStrategy latestStrategy = ivy.getLatestStrategy(ivy.substitute(defaultLatest)); if (latestStrategy == null) { throw new IllegalArgumentException("unknown latest strategy " + ivy.substitute(defaultLatest)); } ivy.setDefaultLatestStrategy(latestStrategy); } if (defaultCacheManager != null) { RepositoryCacheManager cache = ivy.getRepositoryCacheManager(ivy .substitute(defaultCacheManager)); if (cache == null) { throw new IllegalArgumentException("unknown cache manager " + ivy.substitute(defaultCacheManager)); } ivy.setDefaultRepositoryCacheManager(cache); } if (defaultCircular != null) { CircularDependencyStrategy strategy = ivy.getCircularDependencyStrategy(ivy .substitute(defaultCircular)); if (strategy == null) { throw new IllegalArgumentException("unknown circular dependency strategy " + ivy.substitute(defaultCircular)); } ivy.setCircularDependencyStrategy(strategy); } if (defaultLock != null) { LockStrategy strategy = ivy.getLockStrategy(ivy.substitute(defaultLock)); if (strategy == null) { throw new IllegalArgumentException("unknown lock strategy " + ivy.substitute(defaultLock)); } ivy.setDefaultLockStrategy(strategy); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivy.properties000066400000000000000000000034671226750426600250770ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** ivy.project.dir = ${basedir} ivy.lib.dir = ${ivy.project.dir}/lib ivy.build.artifacts.dir = ${ivy.project.dir}/build/artifacts ivy.distrib.dir = ${ivy.project.dir}/distrib ivy.resolver.default.check.modified = false ivy.default.always.check.exact.revision = false ivy.configurations = * ivy.resolve.default.type.filter = * ivy.status = integration ivy.dep.file = ivy.xml ivy.settings.file = ivysettings.xml ivy.retrieve.pattern = ${ivy.lib.dir}/[artifact]-[revision](-[classifier]).[ext] ivy.deliver.ivy.pattern = ${ivy.distrib.dir}/[type]s/[artifact]-[revision](-[classifier]).[ext] ivy.publish.src.artifacts.pattern = ${ivy.distrib.dir}/[type]s/[artifact]-[revision](-[classifier]).[ext] ivy.cache.ttl.default = 10s ivy.report.output.pattern = [organisation]-[module]-[conf].[ext] ivy.buildlist.ivyfilepath = ivy.xml ivy.checksums=sha1,md5 ivy.log.modules.in.use=false ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-1.4.xml000066400000000000000000000023501226750426600255520ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-default-chain.xml000066400000000000000000000017431226750426600277610ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-local.xml000066400000000000000000000027021226750426600263430ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-main-chain.xml000066400000000000000000000017071226750426600272610ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-public.xml000066400000000000000000000016211226750426600265260ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings-shared.xml000066400000000000000000000027131226750426600265210ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/ivysettings.xml000066400000000000000000000023211226750426600252500ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/repository.properties000066400000000000000000000025021226750426600264740ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** ivy.ibiblio.default.artifact.root = http://www.ibiblio.org/maven/ ivy.ibiblio.default.artifact.pattern = [module]/[type]s/[artifact]-[revision].[ext] ivy.ivyrep.default.ivy.pattern = [organisation]/[module]/ivy-[revision].xml ivy.ivyrep.default.artifact.root = ${ivy.ibiblio.default.artifact.root} ivy.ivyrep.default.artifact.pattern = ${ivy.ibiblio.default.artifact.pattern} ivy-2.4.0-rc1/src/java/org/apache/ivy/core/settings/typedef.properties000066400000000000000000000065401226750426600257230ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** filesystem = org.apache.ivy.plugins.resolver.FileSystemResolver chain = org.apache.ivy.plugins.resolver.ChainResolver ibiblio = org.apache.ivy.plugins.resolver.IBiblioResolver url = org.apache.ivy.plugins.resolver.URLResolver dual = org.apache.ivy.plugins.resolver.DualResolver ivyrep = org.apache.ivy.plugins.resolver.IvyRepResolver ssh = org.apache.ivy.plugins.resolver.SshResolver sftp = org.apache.ivy.plugins.resolver.SFTPResolver vsftp = org.apache.ivy.plugins.resolver.VsftpResolver vfs = org.apache.ivy.plugins.resolver.VfsResolver jar = org.apache.ivy.plugins.resolver.JarResolver cache = org.apache.ivy.plugins.resolver.CacheResolver packager = org.apache.ivy.plugins.resolver.packager.PackagerResolver obr = org.apache.ivy.osgi.obr.OBRResolver mirroredurl = org.apache.ivy.plugins.resolver.MirroredURLResolver updatesite = org.apache.ivy.osgi.updatesite.UpdateSiteResolver osgi-agg = org.apache.ivy.osgi.repo.AggregatedOSGiResolver latest-revision = org.apache.ivy.plugins.latest.LatestRevisionStrategy latest-lexico = org.apache.ivy.plugins.latest.LatestLexicographicStrategy latest-time = org.apache.ivy.plugins.latest.LatestTimeStrategy fixed-cm = org.apache.ivy.plugins.conflict.FixedConflictManager latest-cm = org.apache.ivy.plugins.conflict.LatestConflictManager compatible-cm = org.apache.ivy.plugins.conflict.LatestCompatibleConflictManager no-cm = org.apache.ivy.plugins.conflict.NoConflictManager strict-cm = org.apache.ivy.plugins.conflict.StrictConflictManager regexp-cm = org.apache.ivy.plugins.conflict.RegexpConflictManager namespace = org.apache.ivy.plugins.namespace.Namespace exact-vm = org.apache.ivy.plugins.version.ExactVersionMatcher chain-vm = org.apache.ivy.plugins.version.ChainVersionMatcher latest-vm = org.apache.ivy.plugins.version.LatestVersionMatcher sub-vm = org.apache.ivy.plugins.version.SubVersionMatcher range-vm = org.apache.ivy.plugins.version.VersionRangeMatcher pattern-vm = org.apache.ivy.plugins.version.PatternVersionMatcher ant-build = org.apache.ivy.ant.AntBuildTrigger ant-call = org.apache.ivy.ant.AntCallTrigger log = org.apache.ivy.plugins.trigger.LogTrigger cache = org.apache.ivy.core.cache.DefaultRepositoryCacheManager pgp = org.apache.ivy.plugins.signer.bouncycastle.OpenPGPSignatureGenerator osgi-manifest-parser = org.apache.ivy.osgi.core.OSGiManifestParser ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/000077500000000000000000000000001226750426600212675ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/CollectionOfModulesToSort.java000066400000000000000000000104201226750426600272130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.plugins.version.VersionMatcher; /** * Wrap a collection of descriptores wrapped themself in ModuleInSort elements. It contains some * dedicated function to retrieve module descriptors based on dependencies descriptors.
* This class is designed to be used internally by the ModuleDescriptorSorter. */ class CollectionOfModulesToSort implements Iterable { private final List moduleDescriptors; private final VersionMatcher versionMatcher; private final Map> modulesByModuleId; private final NonMatchingVersionReporter nonMatchingVersionReporter; /** * @param modulesToSort * The collection of ModuleDescriptor to sort * @param matcher * The matcher to used to check if dependencyDescriptor match a module in this * collection * @param nonMatchingVersionReporter */ public CollectionOfModulesToSort(Collection modulesToSort, VersionMatcher matcher, NonMatchingVersionReporter nonMatchingVersionReporter) { this.versionMatcher = matcher; this.nonMatchingVersionReporter = nonMatchingVersionReporter; this.modulesByModuleId = new HashMap>(); moduleDescriptors = new ArrayList(modulesToSort.size()); for (ModuleDescriptor md : modulesToSort) { ModuleInSort mdInSort = new ModuleInSort(md); moduleDescriptors.add(mdInSort); addToModulesByModuleId(md, mdInSort); } } private void addToModulesByModuleId(ModuleDescriptor md, ModuleInSort mdInSort) { ModuleId mdId = md.getModuleRevisionId().getModuleId(); List mdInSortAsList = new LinkedList(); mdInSortAsList.add(mdInSort); Collection previousList = modulesByModuleId.put(mdId, mdInSortAsList); if (previousList != null) { mdInSortAsList.addAll(previousList); } } public Iterator iterator() { return moduleDescriptors.iterator(); } public int size() { return moduleDescriptors.size(); } /** * Find a matching module descriptor in the list of module to sort. * * @param descriptor * @return a ModuleDescriptor from the collection of module descriptors to sort. If none exists * returns null. */ public ModuleInSort getModuleDescriptorDependency(DependencyDescriptor descriptor) { Collection modulesOfSameId = modulesByModuleId.get(descriptor .getDependencyId()); if (modulesOfSameId == null) { return null; } for (ModuleInSort mdInSort : modulesOfSameId) { if (mdInSort.match(descriptor, versionMatcher)) { return mdInSort; } else { nonMatchingVersionReporter.reportNonMatchingVersion(descriptor, mdInSort.getSortedModuleDescriptor()); } } return null; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/MessageBasedNonMatchingVersionReporter.java000066400000000000000000000043001226750426600316710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; abstract class MessageBasedNonMatchingVersionReporter implements NonMatchingVersionReporter { public void reportNonMatchingVersion(DependencyDescriptor descriptor, ModuleDescriptor md) { ModuleRevisionId dependencyRevisionId = descriptor.getDependencyRevisionId(); ModuleRevisionId parentRevisionId = descriptor.getParentRevisionId(); if (parentRevisionId == null) { // There are some rare case where DependencyDescriptor have no parent. // This is should not be used in the SortEngine, but if it is, we // show a decent trace. reportMessage("Non matching revision detected when sorting. Dependency " + dependencyRevisionId + " doesn't match " + md.getModuleRevisionId()); } else { ModuleId parentModuleId = parentRevisionId.getModuleId(); reportMessage("Non matching revision detected when sorting. " + parentModuleId + " depends on " + dependencyRevisionId + ", doesn't match " + md.getModuleRevisionId()); } } protected abstract void reportMessage(String msg); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/ModuleDescriptorSorter.java000066400000000000000000000105031226750426600266140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.circular.CircularDependencyException; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; /** * Inner helper class for sorting ModuleDescriptors.
* ModuleDescriptorSorter use CollectionOfModulesToSort to find the dependencies of the modules, and * use ModuleInSort to store some temporary values attached to the modules to sort. * * @see ModuleInSort * @see CollectionOfModulesToSort */ public class ModuleDescriptorSorter { private final CollectionOfModulesToSort moduleDescriptors; private final List sorted = new LinkedList(); private final CircularDependencyStrategy circularDepStrategy; public ModuleDescriptorSorter(Collection modulesDescriptorsToSort, VersionMatcher matcher, NonMatchingVersionReporter nonMatchingVersionReporter, CircularDependencyStrategy circularDepStrategy) { this.circularDepStrategy = circularDepStrategy; moduleDescriptors = new CollectionOfModulesToSort(modulesDescriptorsToSort, matcher, nonMatchingVersionReporter); } /** * Iterates over all modules calling sortModuleDescriptorsHelp. * * @return sorted module * @throws CircularDependencyException */ public List sortModuleDescriptors() throws CircularDependencyException { Message.debug("Nbr of module to sort : " + moduleDescriptors.size()); for (ModuleInSort m : moduleDescriptors) { sortModuleDescriptorsHelp(m, m); } return sorted; } /** * If current module has already been added to list, returns, Otherwise invokes * sortModuleDescriptorsHelp for all dependencies contained within set of moduleDescriptors. * Then finally adds self to list of sorted.
* When a loop is detected by a recursive call, the moduleDescriptors are not added immediately * added to the sorted list. They are added as loop dependencies of the root, and will be added * to the sorted list only when the root itself will be added. * * @param current * Current module to add to sorted list. * @throws CircularDependencyException */ private void sortModuleDescriptorsHelp(ModuleInSort current, ModuleInSort caller) throws CircularDependencyException { // if already sorted return if (current.isProcessed()) { return; } if (current.checkLoop(caller, circularDepStrategy)) { return; } DependencyDescriptor[] descriptors = current.getDependencies(); Message.debug("Sort dependencies of : " + current.toString() + " / Number of dependencies = " + descriptors.length); current.setCaller(caller); for (int i = 0; i < descriptors.length; i++) { ModuleInSort child = moduleDescriptors.getModuleDescriptorDependency(descriptors[i]); if (child != null) { sortModuleDescriptorsHelp(child, current); } } current.endOfCall(); Message.debug("Sort done for : " + current.toString()); current.addToSortedListIfRequired(sorted); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/ModuleInSort.java000066400000000000000000000162231226750426600245220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import java.util.LinkedList; import java.util.List; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.circular.CircularDependencyHelper; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; /** * Decorates a ModuleDescriptor with some attributes used during the sort. Thus every instance of a * ModuleInSort can be used in only one ModuleDescriptorSorter at a time.
* The added fields are :
*

    *
  • isSorted : is true iff this module has already been added to the sorted list.
  • *
  • loopElements : When the module is the root of a loop (=the first element of a * loop met during the sort), loopElements contains all ModuleInSort of the loop * (excluding the root itself.
  • *
  • isLoopIntermediateElement : When a loop is detected, all modules included in the * loop (except the root) have isLoopIntermediateElement set to true.
  • *
  • caller : During the sort, we traverse recursively the graph. When doing that, * caller point to the parent element. */ class ModuleInSort { private final ModuleDescriptor module; private boolean isSorted = false; private List loopElements = new LinkedList(); private boolean isLoopIntermediateElement = false; private ModuleInSort caller; public ModuleInSort(ModuleDescriptor moduleToSort) { module = moduleToSort; } public boolean isInLoop() { return isLoopIntermediateElement; } /** This ModuleInSort has been placed on the sorted list */ public boolean isSorted() { if (isSorted) { Message.debug("Module descriptor already sorted : " + module.getModuleRevisionId().toString()); return true; } else { return false; } } /** * This ModuleInSort has already been analyzed. It is either already added to the sorted list, * either it is included in a loop and will be added when the root of the loop will be added to * the list. */ public boolean isProcessed() { if (isSorted || isLoopIntermediateElement) { Message.debug("Module descriptor is processed : " + module.getModuleRevisionId().toString()); return true; } else { return false; } } public void setCaller(ModuleInSort caller) { this.caller = caller; } public void endOfCall() { caller = null; } /** * Check if a adding this element as a dependency of caller will introduce a circular * dependency. If it is, all the elements of the loop are flaged as 'loopIntermediateElement', * and the loopElements of this module (which is the root of the loop) is updated. The * depStrategy is invoked on order to report a correct circular loop message. * * @param futurCaller * @param depStrategy * @return true if a loop is detected. */ public boolean checkLoop(ModuleInSort futurCaller, CircularDependencyStrategy depStrategy) { if (caller != null) { LinkedList elemOfLoop = new LinkedList(); elemOfLoop.add(this.module.getModuleRevisionId()); for (ModuleInSort stackEl = futurCaller; stackEl != this; stackEl = stackEl.caller) { elemOfLoop.add(stackEl.module.getModuleRevisionId()); stackEl.isLoopIntermediateElement = true; loopElements.add(stackEl); } elemOfLoop.add(this.module.getModuleRevisionId()); ModuleRevisionId[] mrids = elemOfLoop.toArray(new ModuleRevisionId[elemOfLoop.size()]); depStrategy.handleCircularDependency(mrids); return true; } else { return false; } } /** * Add this module to the sorted list except if this module is an intermediary element of a * loop. If this module is the 'root' of a loop, then all elements of that loops are added * before. * * @param sorted * The list of sorted elements on which this module will be added */ public void addToSortedListIfRequired(List sorted) { if (!isLoopIntermediateElement) { addToSortList(sorted); } } /** * Add this module to the sorted list. If current is the 'root' of a loop, then all elements of * that loops are added before. */ private void addToSortList(List sortedList) { for (ModuleInSort moduleInLoop : loopElements) { moduleInLoop.addToSortList(sortedList); } if (!this.isSorted()) { sortedList.add(module); this.isSorted = true; } } public String toString() { return module.getModuleRevisionId().toString(); } public DependencyDescriptor[] getDependencies() { return module.getDependencies(); } /** Log a warning saying that a loop is detected */ public static void logLoopWarning(List loopElement) { Message.warn("circular dependency detected during sort: " + CircularDependencyHelper.formatMessageFromDescriptors(loopElement)); } /** * Return true if this module match the DependencyDescriptor with the given versionMatcher. If * this module has no version defined, then true is always returned. */ public boolean match(DependencyDescriptor descriptor, VersionMatcher versionMatcher) { ModuleDescriptor md = module; return md.getResolvedModuleRevisionId().getRevision() == null || md.getResolvedModuleRevisionId().getRevision().equals(Ivy.getWorkingRevision()) || versionMatcher.accept(descriptor.getDependencyRevisionId(), md); // Checking md.getResolvedModuleRevisionId().getRevision().equals(Ivy.getWorkingRevision() // allow to consider any local non resolved ivy.xml // as a valid module. } public ModuleDescriptor getSortedModuleDescriptor() { return module; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/NonMatchingVersionReporter.java000066400000000000000000000027341226750426600274360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; public interface NonMatchingVersionReporter { /** * Report to the user that ivy has detected that a module to sort has a dependency on an other * module to sort, but the revisions doesn't match. * * @param descriptor * The non matching dependency descriptor. * @param md * The module to sort having the corect moduleID but a non matching revision */ public void reportNonMatchingVersion(DependencyDescriptor descriptor, ModuleDescriptor md); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/SilentNonMatchingVersionReporter.java000066400000000000000000000022421226750426600306070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.util.Message; /** * A NonMatchingVersionReporter that only print debug message. */ public class SilentNonMatchingVersionReporter extends MessageBasedNonMatchingVersionReporter implements NonMatchingVersionReporter { protected void reportMessage(String msg) { Message.debug(msg); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/SimpleSortEngineSettings.java000066400000000000000000000030511226750426600271010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.version.VersionMatcher; public class SimpleSortEngineSettings implements SortEngineSettings { private CircularDependencyStrategy circularStrategy; private VersionMatcher versionMatcher; public CircularDependencyStrategy getCircularDependencyStrategy() { return circularStrategy; } public VersionMatcher getVersionMatcher() { return versionMatcher; } public void setCircularDependencyStrategy(CircularDependencyStrategy strategy) { circularStrategy = strategy; } public void setVersionMatcher(VersionMatcher matcher) { versionMatcher = matcher; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/SortEngine.java000066400000000000000000000122431226750426600242110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.plugins.circular.CircularDependencyException; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.circular.IgnoreCircularDependencyStrategy; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Checks; public class SortEngine { private SortEngineSettings settings; public SortEngine(SortEngineSettings settings) { if (settings == null) { throw new NullPointerException("SortEngine.settings can not be null"); } this.settings = settings; } /** * Same as {@link #sortModuleDescriptors(Collection, SortOptions)} but for IvyNode * s. * * @param nodes * a Collection of nodes to sort * @param options * Options to use to sort the nodes. * @return a List of sorted IvyNode * @throws CircularDependencyException * if a circular dependency exists and circular dependency strategy decide to throw * an exception */ public List sortNodes(Collection nodes, SortOptions options) { /* * here we want to use the sort algorithm which work on module descriptors : so we first put * dependencies on a map from descriptors to dependency, then we sort the keySet (i.e. a * collection of descriptors), then we replace in the sorted list each descriptor by the * corresponding dependency */ Map> dependenciesMap = new LinkedHashMap>(); List nulls = new ArrayList(); for (IvyNode node : nodes) { if (node.getDescriptor() == null) { nulls.add(node); } else { List n = dependenciesMap.get(node.getDescriptor()); if (n == null) { n = new ArrayList(); dependenciesMap.put(node.getDescriptor(), n); } n.add(node); } } List list = sortModuleDescriptors(dependenciesMap.keySet(), options); final double adjustFactor = 1.3; List ret = new ArrayList( (int) (list.size() * adjustFactor + nulls.size())); // attempt to adjust the size to avoid too much list resizing for (int i = 0; i < list.size(); i++) { ModuleDescriptor md = list.get(i); List n = dependenciesMap.get(md); ret.addAll(n); } ret.addAll(0, nulls); return ret; } /** * Sorts the given ModuleDescriptors from the less dependent to the more dependent. This sort * ensures that a ModuleDescriptor is always found in the list before all ModuleDescriptors * depending directly on it. * * @param moduleDescriptors * a Collection of ModuleDescriptor to sort * @param options * Options to use to sort the descriptors. * @return a List of sorted ModuleDescriptors * @throws CircularDependencyException * if a circular dependency exists and circular dependency strategy decide to throw * an exception */ public List sortModuleDescriptors( Collection moduleDescriptors, SortOptions options) throws CircularDependencyException { Checks.checkNotNull(options, "options"); ModuleDescriptorSorter sorter = new ModuleDescriptorSorter(moduleDescriptors, getVersionMatcher(), options.getNonMatchingVersionReporter(), options.isUseCircularDependencyStrategy() ? getCircularStrategy() : IgnoreCircularDependencyStrategy.getInstance()); return sorter.sortModuleDescriptors(); } protected CircularDependencyStrategy getCircularStrategy() { return settings.getCircularDependencyStrategy(); } protected VersionMatcher getVersionMatcher() { return settings.getVersionMatcher(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/SortEngineSettings.java000066400000000000000000000022541226750426600257330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.plugins.circular.CircularDependencyStrategy; import org.apache.ivy.plugins.version.VersionMatcher; /** * The settings/collaborators used by the SortEngine. */ public interface SortEngineSettings { public CircularDependencyStrategy getCircularDependencyStrategy(); public VersionMatcher getVersionMatcher(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/SortOptions.java000066400000000000000000000044151226750426600244410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; public class SortOptions { public static final SortOptions DEFAULT = new SortOptions(); public static final SortOptions SILENT = new SortOptions().setNonMatchingVersionReporter( new SilentNonMatchingVersionReporter()).setUseCircularDependencyStrategy(false); /** * Used to report some non matching version (when a modules depends on a specific revision of an * other modules present in the of modules to sort with a different revision. */ private NonMatchingVersionReporter nonMatchingVersionReporter = new WarningNonMatchingVersionReporter(); /** * Should the default circular dependency strategy be used when a circular dependency is found, * or should circular dependencies be ignored? */ private boolean useCircularDependencyStrategy = true; public NonMatchingVersionReporter getNonMatchingVersionReporter() { return nonMatchingVersionReporter; } public SortOptions setNonMatchingVersionReporter( NonMatchingVersionReporter nonMatchingVersionReporter) { this.nonMatchingVersionReporter = nonMatchingVersionReporter; return this; } public boolean isUseCircularDependencyStrategy() { return useCircularDependencyStrategy; } public SortOptions setUseCircularDependencyStrategy(boolean useCircularDependencyStrategy) { this.useCircularDependencyStrategy = useCircularDependencyStrategy; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/core/sort/WarningNonMatchingVersionReporter.java000066400000000000000000000022301226750426600307530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.core.sort; import org.apache.ivy.util.Message; /** * A NonMatchingVersionReporter that raise warnings. */ public class WarningNonMatchingVersionReporter extends MessageBasedNonMatchingVersionReporter implements NonMatchingVersionReporter { protected void reportMessage(String msg) { Message.warn(msg); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/logo.png000066400000000000000000000215751226750426600210300ustar00rootroot00000000000000‰PNG  IHDRd»³ïbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÕ&„h´ IDATxÚíyœe¹ï¿OUu÷ôl™ÌL& ÙC @dßÔ¯^ëé‘&´Tà4"Å¿ÆêôŠøÇàø‡'‚`*»&ÌLjŒwUÕZÍmŽò_?[Ÿžƒ4mÀÑÀ…Àñ SQàEàaà`3pʲPqT NPØ©†*¿³Sô“uÐÜ ù&ð>E­ $x™_'ïínº|K¨83,Ô òÏñNsÒΞ—‡óY„E(Â3õ©9˜A£lGZ&ä‹)³Ÿ(XÆZ.‚‚œGÊÎÉC!ÑÌv_GºåÌÀõ^@Ùü’>u]ŸÚGÐßÎ@x}ùà (,Râ¿©drCÐxoËÞ.ÈYª*%:ÐÀX}j~Ns;Êë¬ 0(1‰håÕZl9Ðò¿Aï^«ª§ -ˆQtw{0¯€×9ÌÁËi\àŸæ—›Ï>g‘ë(LD&ISEߊòFDþĉTˆb ¬ááú´Ü”=íî _!¢(èf)Kie‡Nè7‰HÿLá;÷;êÓrƒ&½þ06ñaJ¯ÎYBãQ¥:°†r&õ›ªOË+ƒÓ¬¹­¢¸‰Fð| y?,ÌP~U¾_¨N¯ Ð8ßú¼á$û^(€V ²[õ)y€FU kPþsb.¥XQu±¬— §åœDªa',ñÊûÒAnŸlT½†êÀsš<®¸·œ(¦™H%­}®:ë'€õK‰Ã¸“úŒ+YðC`Ûþ|°z¢úË€aàSÀÓ§Øv޶æ®çO^zþyS;î±\ùÄHQ¥óÀ£À÷÷¶î»^twp€ày”K@póoŽ´w¶ÍÛ³ìÄþKKcûFÇÉUÒQ*ë>êÔ‡Cõ©x…ƒF=¿ÊFàJ…(†ÉðXÿü­ÝÏ\¼`ÖkŸ;dÚ’ß«ºÑÜ&ÄlŸÐ4 ŸÝü²bÒy‘$5u:Pœf>ðcÿ˜x A”õÛ}ÇöžumÍÓø(ªµYSêéZð?†rUÍ–Y5h àQ.™p f5ÐÓ¿ù˜õ[Wþó´Ž…Ï7$šŠ8Rýµq™î½6åëtÀÈŠ˜”Ye³­ b`ŠÁ¶Ýk.pÜÜJÛ±Ç%ßa¢R6_©Èòþn¯â  N¶S£Ÿ,ŒÓ¸Àsá+^±¬©±ÅƒÛ犠ˆPs6Ÿhz½xî  s€Ÿáµ»ÛFù3ÊÖ(Ë(çd›ºÚ´5Äš]WÝòtˆÊ&v@­u]ö€ÓBà_‡=˜ƒ—I9hŠOá“ú$"7‚^=,-X@Ž›3-«ÁŠÇ’†@/ȘïØÄ+úl<šQŸ³Fíx9ágsýù=a¥ÿ¹:ê‹«¯÷ƒ&œ\¯©W‚ûI”Žàä[¦åôìÈerc7¬6øàGxʈŸ›£„w’TŽ@˜l)âduNóÒi.ñ~àë±À >‡ ÎÅ °¾œÓD“ \ò'àà ¡Ðg±U¹ÌÈ®coUǵ1 Uý>Âj”ÿœtI¿hÎG19„,Ê© ©ƒååO^>x,ÒJº;€¯†Y¸µË=äâé@Š«®Ãhz˜œ“%f%hN¶3ž"Iaªú˜ — ŽðÙaPA²ŠŽ£"²)èéÓKNg§ãÅù~,Cip¢À-Àoþ2Y“»8 YZº†aàº.#=¨*-MS™5í0vô¬cd|ˌẈ bl6E̬:P^VZ‚ð^”ŸˆÈŠ>„ø ñ(…p U‚ǵ–å´úæ8â×uÊ9Ùõ¶“=Õ™®:®«®cŠŒ‚‘ÛOÒX€4°–ý“t>¯8/û2LVÜ÷ì(¾,Â+p´küŽëßðjê·!ÌSt0ÄBZŒr?¿7GµUÓ ß=n‚çø>Ã0$•KÆ›¿µpÖkÝM;Ÿ|MkcçCé\êu#cýçäìtÜ0bn¸Ý­%òT¼^ûàQýD 1|gÙ ìãÀOÃ+<-cCõª` ,` –yÁ+e3 Â_P>†—‹½¯&ò]ÀEÝ2^TA¸ /ä7Õ×%ß|Ï·ŠõõÎ_m"Ò®ªq”Ex}…FÖp­œ¦ hÖkȶ³lÚ±ês‡Î9áý ñæŸÄ­†ñ¬“¾gÞŒ×ܺgpËWGzδÌXEQä=°—f˜f®¹±ãEËŒ=ÖoÜ®ª›Ò™Ñõ*"çÛGà1(oEHYuZ‰ÕIyõ„ †v®ïÙS™¥VµÎP´¶†¡`–$h+^½ü€€|bøœÉ»ôzù1¨4Ù°u›dCKßÜKÿiñÜ“JÆ[tãŽU8Ž1þzHç—ŽeFÏdRm†aøƒRìAVu1ì˜ßÞ1eÎ݇tþ;sí“ë~gŽìÖY‹ñXr¹«Î©†˜ç ò¼œŸ½!X†,ã.=ña€Dq›Âµ€åÀ_*Á³ŠŽ—dEU§U¤ÃxaƒÓñêõ¯d-`~®/V7ì‹NC^—щº%ËŒoèš2÷Ê|¦Ÿªâ89Zš:inì n%·.žsÒ·7l{ô͆avd³ã3\µ›%ï/TH&ZžjmêüucCëScé¡®]½/žŸJ^¡è!†aº{†¶u9N®ÅAN#˜Y89šås™üBJÒ˜š–‰×Š~€"r-г— ™¡è™¥’=R¼†>›ºÀ—QnDè.‚‰Lƒ}ÑýOÀd90¸O )æ29fM_ü«D,y«!&†˜Äb $Z˜Ýu ‰\uÔv3϶·ÎjN¶ív]7™³3óm'Ûì8¹1+Ö03›FÓý‡îêÛøå±ôðRÇÉ!b`YžSÙ¶ĘÈÄ1P.Bö4Ç [V:ðZ»ž&ê¼óŽÃëÎqe?’–ƒvV¿§ Ϧ¬E¸Ý×UFÿ@Y¥¢g ²ø"ðÉÀÂø<ÊÿÌG  ÑšXŒw UA]Á`jËÌ ÉD‹ˆÚ7´ U‡®Ž…¤³#Œg†Pu6ï|æs£»–47L]ÕÚܵ>K®ÉæRk ʉêâî¾ ŸOgG– ‚iZ˜F¬¨½¬R:øoôý>ý‘ƒN1„·yázÿÚêsN)™¸`QŸTá&¥œ%º¡¡èyþŠv&«Ó(ú¶·ËW‰„í9¥ÑÜFøµo=9çÀˆÂ%Àù%Üê2ŸÓÜ 0³³¨º˜¦ÅÐX/ŠÒÜ8×uQu²"ÄDLLÓÜú=U.5D«z– !VíSð{œ šHz=0³<&!æ-:Oíc¸þ<ÿ>n›$àÏöMæêãTÞê%O ò¸¢Ó}1ô.”N„„Gý×QY‹!œÜeìMýØNfj{ËÌyÓ;æ3£c­M8NŽlvœ\nœ¶ÖØNîÃéÌè!¦ÇyÚPyHDþ0á › cóeƒy"Ê¡¡¹8áé&ÂÛkžp¥dK¾  (íÍS]Ü_¸\X墴U€!”Ÿ{­ì¸ åãþý¶ËŽ.zöpZ‹ò £¦rÒÜqÃ"c[Ý}ëß±£ç¹ØŽÞíñãNžÏ)“M-Û¸cÕÕªŽé?T Á@¹iBÙûü™YgMÊ…¯›”£œžX­dî %ba~E° PŽ«ùÞô¸Ïoß{R¹öã:a­_òŸü å<`ei…eèQ`ã¹o;9TÝaumMõá¸9ÓuÓŒ™Žëýìú¾•Íe’b˜ÁJ¹$Â*ß_Í‘«Õ‹Cey¨õž x -áŠm¥Ú­‰Ïl¿Ôæª ŸU˜¢,µÌ&ížnÂùä®rÝIÂ5”7ZpPn2þ»özéE¹üY<Àüø`>bù¢£²g/—i¶Ì˜g9©ƒª²èãþ{ɼ3¾%í‘ñ~LÃ2;wvïÐÖÃ;Þ8–]8q킜ÍK¤ï ¼HTå4aÁˆœ Êk}²Ê(çk©, îz«UÙýßòÈ”´{«®ÿfâmªv‡1Bĵ(zRHî'_cŸUÁ׎eü< ÜPrÝõxÝÆ*ä;åoÊ•~ngZfœ*‡3½}þ_svÁ¶³$-»O<âܯµ6uógÇ¡³OÎÍž~”1šêÿèÐXïBÇÍMˆ«ôÿ áÁ¢•¡!¦ke4ÍFüÉ .V‘¢8 ápÂ[ö‡ô ,wI¡ü¥ß÷mü™Xµ•-©¨Ï”c@_[59ZY„rtyý{ é·”4 *¯“!, ×aSR-%"cÁ12Ͻøx±ÆŠGWûÜ'âñæcû‡¶/´Ì†a<×?¼ý–m»ŸÚ¾ç9l'KOÿFr¹´§z— §z»¦Oÿû®©ónJgS'8v®AD2?GØè³¼^¼9$ÔçQ=]T€Œ ÷’‰,ú> œæ/¾ðß)’ãR:Ñ>†0îOÈ o©èŒOxGƒovÿ©ÊÊ8xŸÏ"D¨”_¿øþ§ç",V"ŒŸŽ«Gó?i«Ÿ@#k¤Ò‹%ijhß}ØÜ“¯ˆY #"`ÛiÙÞó¼±y×3ìèY‡!B<Ö€í¤»†S½ f´/üKgÛìMi™ùÓ°²~ŒFJVÌÃ(÷ïS‚—ùwT©ï%ðo^â‘s‰ŽÙhQë~~ôÎ~„×µ´vû[Êb`ËAš+dÔ Â2ŸSTà†;ó2n²(— Ü€rø–gÌ÷c%€³P¦åçÊpœ•×±³¹ô±£cý«Ï9éûcé­öôö…v×Ôœ~ì»IÄiH4ÅGwÿc,ß2wÆÒ÷‰}[»ŸþÁxzd*ØNÎimž&s¦IÌL ª)„ëb<B—¢gT(ü_Ì/Úõ®L&Uðâ*›ùá+LÚ- ÏEÞg©Ä ¯B]zz…"ŒÃQŽŸ„Y]zžW—¢œàGÙW Üè;:GýNª×"|ØT¦P{ÿOE˜’¿Qkëîg«.çî¾õÿ±xîÉ?ÂÕïtN™}FcrjnÞÌ¥®§ß4c™ zú7Ÿµµûé‡Í>áœx¬1µ¹{õÏGv­°¬D¦¹aê½S[gÞÖÔ0åIǵ™7ó5lÜñ$®:ûnõ7ÔÛ ¸³üÖo}%^^8 h*- /\«J§Rᆈã0p#ðÝšDT8uøÏ}_Äç¯õt± ½[*ÍCÀc¾ò¾ ¯@`á_}Åø:?ŠÜ‚àwÀ¿ù¾¤Dà9rh!ôau¶Í­Üôhz°íÅíß2{Ú’/Ï™qÔe–?<—w]מ€eS²mô©ó/ÏŽunÛóüm}ƒ;NjJ¶mžÑ±àk-ÍÓnÈåÒK Ój4L+°’µo%Ÿ©¢fíÖ": 8Œòä¬Ã€SËŵڼþIdÙ1z+Â'€Ã"MWJÍe[-Sՙ䓷%'ƒ3Q̲XR˜˜ ‹CÝ2¡– ióMàA† ë ¿x/ÊåWá …ÎV[sW5~çÆ¬Äó=[NØÜ½úÊö)sNéœ:ïºÆDcƲLRcƒXV×µ»>ñÜ–G¾”³ÓñC:ûmKSÇ•³§-yb[Ϻ÷ìîßøÕTzð³¦ßê[6轊®á´rM,búa+4úbh¥gÂJÀ‰¦ ËnefªF• _CåZó~ïùNh,(¤ât£[ðRDN!ßYU‹òYάèrP)îó\Û‚ò‹²Ù(+Üú `qñ$ÄÒ j}=^e@.ðþÑà‹& Éé i76ñŽ‚ˆþL½I_\r€¢ÿ‰pŸo@4~ïX¼TÒ_¤ePîÆ«c»Q`½|J–F5©`ŒgG§{“íýŠiĺÛZéë˜2Ln”=ý›q\»wá!Ç&^×Ö<}eKÓ´vã ÏÅcÉñìè,GCÝÜ«nmìÄkËfݑΤ.ÍæÆO$ì~"ô-|v¬¢GLØ#AϬè¡ÕhóXï!åû3„(Úݾ~ð $0³ZðÅÜo9ÊòU‘7xíÿ54ý"ÌÀÓn{@”o#œøþMÀ×€cx{ªÞmtø–áZà³Àjà(ïÖ’¦S†ë:T;ÔUÓqll;Cƒ•ìëš:ÿzÇI¯éf$ÕGÎΠêö45¶ý¨9Ù¾r,3̶]Ï\°eçÓ×8¸mDZbÙÌŽE¿´íl³ª‹ªâªK:;J:›"5>Ôk;™ÛE ·¦ØŠ–™²&øûjzt¦ïŸ¨=Ë­ðz=ð«Rom…;º›‰† Z¼¬Î)—'þž¦ªgOpµouÄÞ¢ù·þ¨è£x›Í_rÊ”/úe+oFù-ʇ|.3Å÷=½ID.ÀËÉ^Wšd¢…*‡4&ÛÖMmyßáóOÿÌŒöEït\{(›K/q]T™Þ1ŸæÆ6wd´‡tfA·ì|úœéܰuå7s¹ñYÉDófw-ùksc;­M´4µLû,ªzÂsÕô‚ȸ‘òO,Ñáç‰ÔÞ’¿X©¼Caí$šYlÀkg[9x}á-¢BX\ƒevÍÊxå-)Ä/›)¾—Fßj»á°°¤èÛÁ ’JH¤ß:æÐåÕV“=–ùÈPªgJÂjø‡mÃÛ¯8¼«}þ¥ O:®M2ÑŒˆˆª=«»wýwS{VÄb Æ2Ã3V¯ÿÃMó¦/}¯•lXi;9 ÃÄU‡ñôHðw¶ù±/E*•u‘E('ù êi5šëÅ1(ODܶîÆ_¢¼Ï›ìÒH…ý± íM³|žu¿e8 ¼á‹¬§Àw˜B‚q­®Šþ)èPôÛ‚¼ è+µÎ¬ñÌHUoÑÀH÷eƒ£»/ÙØýÔ êºˆ˜ô mw³¹qD`öô£p]·#•º¤·Ûûdz#Çâé †˜d²c‹v lúጎCßÖ’l_ïÅ¥lút{’¹IUß?Ñ< d› `r{ÉC ÂÅx»à%*)¾… ¸¼ïÍ׎D~ãËòˆIŽDíDï>W>Z¾‚i›^,i&pºˆìRÕÅ1Þ XŠæ:ê¥þa/—úËž¯§›+ ŸsîÓUôFA>ŒWæRÍãÏÿ®Ú*2M1> r¤!†kÅ/¶µÎØØÑ:{CÌŠÅÉ9®­¦a58¶}ÊðXßq¦à €!O’Zô–¿žÏåÄKó,ºOÝŠpÈ¿Lk ¸ÿóyÊÞä—Õ\Œeå©F˜¾%þ¥ÕïUL¼ªL?Þ…07|bÂ8NQ†Ý `°È[w€–úx¤Œ~ôc 2‘Íø„Ë1 㥕³UÃbúÑðOC)VÜj¨î™RU{N×׆uM&;:š³ÇÏ™3㨞ÆDëzaxt׎®ö—ŽgFë½ÚqrSò¹ÂªŠ!FÚˆ5dªÆ ”ý âwÊ’nÀ“«Á%èMHg¹ì!ÂÔ(F+"¿EõÙÈÆ“Õ½¼kP~ƒpy¸Í]Á÷žo™¢3‹ê¬Ï^äã¡´“<Šp°Ýóýðu YYéõ´¶TVO¿¹DDb ÏûuŒÒT‚°ÃqœXC¼yÏQ‹–}«99uî–]Ïþ,‘hš9{úQÝÓ;kkó4\uÉÚé1¾sHÇaŸ7ÍØ˜–¢·–^iÂà–b]&Ê äQh´?EJ-‘`î‰÷;½ß­65Ä}nv|Z]§*uÁ½0CD O l7äßþDVˆZj1Ë  ñ¹jHŒb±uì—ÍVWûzE9H'¡Zk¾\¨ÚÄ¢Ñô-Ï/o‰ØJ ]”ÒtŠ¢ë¹Ñ{|C%5–°¨‚‘3×±³] ñæÞÍ;Wné~U—D¼‰9Óôô+ à¶O™uçÎÞΦ´yNÙµ5loD¹E…OåŸH&Óš$_Ÿf¶–?ïðÝýØöäzàbÖRq>¡§ø¾BËMŠÓÈD1OäzEçúÞåA¸²¾8y~"=®EdN‚³À=À:¯*Aã^`VÖüE=&禖BBWX,‘mJNyÁ0Œ~DZ›æÏ:61¥© DZà 5>ÀŽ=ë0ÍXže>‹%²ŽmÇ*‹™ÐG°¹ø° ÍJTÉj˜ráΉãø@¼xšýG«¼X’~ ܃­Qå-%Ñ꺔wÎ~°vÄ÷¿t⥸fú(öæžúÅPþ%ü7p95´0©©îIµlÌUéLÄ›Ü=ƒÛ“cãCó-#þ”íx-^âM,YpnAÜÜýtζ³ˆ”¥'T×0× Ü¢ðÏÑÝ*äoú,/š‚œ*ÿZÑ”Ÿ"°I¹ásp©ƒ*ç8•“Åu[?$¿# —²1\á¾~ÈGé%fëv„멱çQËvŠZ1+1Ò”œÒ£"³²ö½ƒ[^g¦ÕhÆ4-Gºëgxt#©=Œ¤ö˜®«Rfv†?;üõ£«2h¥ºRq5_Áâ¼RÈð¿së~æ2ùù¸½ØÁ(UbiZvÿ{•)°y%^v¢zÏ„þSý¾Ö¢ºa"ZÐkþŸ OÕºGVMаˆád³ã»úÖ'Du“eÆéî~kgû‚Ž…sN`îÌcÝÆm²»ÿE¶÷<Ç®Þ Ó³N:žjO°Ó#Ÿsr<ŠÈÝ‘%#eE¨–X¬ëhÐà9µ"¡æ?¼ã:$à$ým‰§MhòZÆ}$½ñk³k›ï~„M%«3 òpaÙÉþá4bçœLÛpª÷x…¡x¬‘ÁÑîÃ7ïxâík6<ÈêçïÃ4c¤ÆiH´0wÆR0ŒÓ'¯f=U ì¤}·~¤2¤5ˆº°Â|‘;Až˜ÔÎ.“óû­äÎÚ·s”r3ð`¥Ÿz:(ȯq*î¦W>ÖëK>ë}l2{eµ‰hpU"F2f5ôŠ‚iX<½þþ«{¶ž74² Ó´°,¨Ò˜hMìéß|¾¨ŸWªý×\'âµæøs¤¯¡¬<$¢Ž©x<@oµkÜ3¨˜KÔvd½ !]C ±,Q"8hq"÷U yDÓ äw$öB;5“¹€QÛiŠˆb–ƬxÎUÓˆ1–i~ÛßnVÕsœÜÂx¬±iÛîµñ-»žyÇèøàÒ}pÉ)盌C‘«= ”Zb±ï»ù[௼ôô^šEíú¿TÁà8 ¿T+‡·„_¯p |áEߨ˜Õå&¡NÊuì•"²V¼=NÕ|XL„ Ê‹WvågM#|/\ïDôÌ-©¢ÔBJ—ºá÷/‰ö"Tjõq¯ßïî´J¹Éõ´Âû÷‹È ûáŽTóz(çZ@ãà•2€ÆÌ„m1SUó=gkRØ÷nãø–ÔÞŠ &UJ»_é¼EV]Ÿ‘ŠVV?’Zú2S­íÓœü„ûn8‡ýÓn~oÈÞËï¨ûmDùÁ†aÜ$,ÄP:yx¸}K^Âmm êôR’\ŽpQUóZ«ZƒY”›'ÁÝ8§yµO|£ï›ŒXl.®¦P»/–ä:àîÚ:­-q¬š—„š€Ïàå­öcC¾C,ã»l_ÑnÄKM8xÁ´Õ&;ªUáïë'ë„«sšG  zžúPR¾ÉšE‰ámo4avyj©–GêËt›ðö´‚¬~~°ì¾WMuÇK=ÏŸÐ)¨ß«%²8Ÿè2–R·Zî½.ù¾ª~’2’š=/ˆª+µY];CB¸öUò[ú·FD´‹çù~ò]%¨sš/tj§íÕ½µU ÒÂþ®^9:‚ò()À?,ƒW'ɤŽ=xuÒÕ¨“gåP‘¢|Ï¡I4¯<ú*†J´ŠU4îçýÿK‚íÙê yÅÑ(^Élu$!\¤Z¡\¹Ùý;à_ˆÊX¬ƒæé3“;FQ¿•Úd8ŠÒé³âe¾çÜr°ß«Sž¼šzªzt£€SR°!³À+}½‹X­ƒf?R¶|åG(3a5ÒÑ6¢<üÊ/{éy% F4µÓõÀC(ÓE¤ ¯ÍÙt ¡˜âu §U+!d Ñaº¯ÝÚ3(ëÑÉ'BHúÿ”%ÁÇGŠIEND®B`‚ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/000077500000000000000000000000001226750426600203115ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/000077500000000000000000000000001226750426600212415ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/BundleArtifact.java000066400000000000000000000024621226750426600247770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.net.URI; public class BundleArtifact { private boolean source = false; private URI uri; private String format; public BundleArtifact(boolean source, URI uri, String format) { this.source = source; this.uri = uri; this.format = format; } public boolean isSource() { return source; } public URI getUri() { return uri; } public String getFormat() { return format; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/BundleCapability.java000066400000000000000000000047551226750426600253320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import org.apache.ivy.osgi.util.Version; public class BundleCapability { private final String name; private final Version version; private final String type; public BundleCapability(String type, String name, Version version) { this.type = type; this.name = name; this.version = version; } public String getType() { return type; } public String getName() { return name; } public Version getVersion() { return version; } public Version getRawVersion() { return version; } public String toString() { return name + (version == null ? "" : ";" + version); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BundleCapability)) { return false; } BundleCapability other = (BundleCapability) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (version == null) { if (other.version != null) { return false; } } else if (!version.equals(other.version)) { return false; } return true; } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/BundleInfo.java000066400000000000000000000254351226750426600241420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.ivy.osgi.util.Version; /** * Bundle info extracted from the bundle manifest. * */ public class BundleInfo { public static final Version DEFAULT_VERSION = new Version(1, 0, 0, null); public static final String PACKAGE_TYPE = "package"; public static final String BUNDLE_TYPE = "bundle"; public static final String EXECUTION_ENVIRONMENT_TYPE = "ee"; public static final String SERVICE_TYPE = "service"; private String symbolicName; private String presentationName; private String id; private Version version; private Set requirements = new LinkedHashSet(); private Set capabilities = new LinkedHashSet(); private List executionEnvironments = new ArrayList(); private String description; private String documentation; private String license; private Integer size; private boolean isSource = false; /** the symbolic name of the bundle it is source of */ private String symbolicNameTarget; /** the version of the bundle it is source of */ private Version versionTarget; private boolean hasInnerClasspath; private List classpath; private List artifacts = new ArrayList(); public BundleInfo(String name, Version version) { this.symbolicName = name; this.version = version; } public String toString() { StringBuffer builder = new StringBuffer(); builder.append("BundleInfo [executionEnvironments="); builder.append(executionEnvironments); builder.append(", capabilities="); builder.append(capabilities); builder.append(", requirements="); builder.append(requirements); builder.append(", symbolicName="); builder.append(symbolicName); builder.append(", version="); builder.append(version); builder.append("]"); if (symbolicNameTarget != null) { builder.append(" source of "); builder.append(symbolicNameTarget); builder.append("@"); builder.append(versionTarget); } return builder.toString(); } public String getSymbolicName() { return symbolicName; } public Version getVersion() { return version == null ? DEFAULT_VERSION : version; } public Version getRawVersion() { return version; } public void setId(String id) { this.id = id; } public String getId() { return id; } public void setPresentationName(String presentationName) { this.presentationName = presentationName; } public String getPresentationName() { return presentationName; } public void setDescription(String description) { this.description = description; } public String getDescription() { return description; } public void setDocumentation(String documentation) { this.documentation = documentation; } public String getDocumentation() { return documentation; } public void setLicense(String license) { this.license = license; } public String getLicense() { return license; } public void setSize(Integer size) { this.size = size; } public Integer getSize() { return size; } public void addRequirement(BundleRequirement requirement) { requirements.add(requirement); } public Set getRequirements() { return requirements; } public void addCapability(BundleCapability capability) { capabilities.add(capability); } public Set getCapabilities() { return capabilities; } public List getExecutionEnvironments() { return executionEnvironments; } public void setExecutionEnvironments(List executionEnvironments) { this.executionEnvironments = executionEnvironments; for (String executionEnvironment : executionEnvironments) { addRequirement(new BundleRequirement(EXECUTION_ENVIRONMENT_TYPE, executionEnvironment, null, null)); } } public void addExecutionEnvironment(String name) { executionEnvironments.add(name); } public void setSource(boolean isSource) { this.isSource = isSource; } public boolean isSource() { return isSource; } public void setSymbolicNameTarget(String symbolicNameTarget) { this.symbolicNameTarget = symbolicNameTarget; } public String getSymbolicNameTarget() { return symbolicNameTarget; } public void setVersionTarget(Version versionTarget) { this.versionTarget = versionTarget; } public Version getVersionTarget() { return versionTarget; } public void setHasInnerClasspath(boolean hasInnerClasspath) { this.hasInnerClasspath = hasInnerClasspath; } public boolean hasInnerClasspath() { return hasInnerClasspath; } public void setClasspath(List classpath) { this.classpath = classpath; } public List getClasspath() { return classpath; } public void addArtifact(BundleArtifact artifact) { artifacts.add(artifact); } public void removeArtifact(BundleArtifact same) { artifacts.remove(same); } public List getArtifacts() { return artifacts; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((capabilities == null) ? 0 : capabilities.hashCode()); result = prime * result + ((requirements == null) ? 0 : requirements.hashCode()); result = prime * result + ((symbolicName == null) ? 0 : symbolicName.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); result = prime * result + ((executionEnvironments == null) ? 0 : executionEnvironments.hashCode()); result = prime * result + ((symbolicNameTarget == null) ? 0 : symbolicNameTarget.hashCode()); result = prime * result + ((versionTarget == null) ? 0 : versionTarget.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BundleInfo)) { return false; } BundleInfo other = (BundleInfo) obj; if (capabilities == null) { if (other.capabilities != null) { return false; } } else if (!capabilities.equals(other.capabilities)) { return false; } if (requirements == null) { if (other.requirements != null) { return false; } } else if (!requirements.equals(other.requirements)) { return false; } if (symbolicName == null) { if (other.symbolicName != null) { return false; } } else if (!symbolicName.equals(other.symbolicName)) { return false; } if (version == null) { if (other.version != null) { return false; } } else if (!version.equals(other.version)) { return false; } if (executionEnvironments == null) { if (other.executionEnvironments != null) { return false; } } else if (!executionEnvironments.equals(other.executionEnvironments)) { return false; } if (isSource != other.isSource) { return false; } if (symbolicNameTarget == null) { if (other.symbolicNameTarget != null) { return false; } } else if (!symbolicNameTarget.equals(other.symbolicNameTarget)) { return false; } if (versionTarget == null) { if (other.versionTarget != null) { return false; } } else if (!versionTarget.equals(other.versionTarget)) { return false; } if (hasInnerClasspath != other.hasInnerClasspath) { return false; } if (classpath == null) { if (other.classpath != null) { return false; } } else if (!classpath.equals(other.classpath)) { return false; } return true; } public Set getRequires() { Set set = new LinkedHashSet(); for (BundleRequirement requirement : requirements) { if (requirement.getType().equals(BUNDLE_TYPE)) { set.add(requirement); } } return set; } public Set getImports() { Set set = new LinkedHashSet(); for (BundleRequirement requirement : requirements) { if (requirement.getType().equals(PACKAGE_TYPE)) { set.add(requirement); } } return set; } public Set getExports() { Set set = new LinkedHashSet(); for (BundleCapability capability : capabilities) { if (PACKAGE_TYPE.equals(capability.getType())) { set.add((ExportPackage) capability); } } return set; } public Set getServices() { Set set = new LinkedHashSet(); for (BundleCapability capability : capabilities) { if (SERVICE_TYPE.equals(capability.getType())) { set.add(capability); } } return set; } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/BundleInfoAdapter.java000066400000000000000000000341241226750426600254360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.Ivy; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.osgi.util.VersionRange; import org.apache.ivy.plugins.matcher.ExactOrRegexpPatternMatcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; public class BundleInfoAdapter { public static final String CONF_NAME_DEFAULT = "default"; public static final Configuration CONF_DEFAULT = new Configuration(CONF_NAME_DEFAULT); public static final String CONF_NAME_OPTIONAL = "optional"; public static final Configuration CONF_OPTIONAL = new Configuration(CONF_NAME_OPTIONAL, Visibility.PUBLIC, "Optional dependencies", new String[] {CONF_NAME_DEFAULT}, true, null); public static final String CONF_NAME_TRANSITIVE_OPTIONAL = "transitive-optional"; public static final Configuration CONF_TRANSITIVE_OPTIONAL = new Configuration( CONF_NAME_TRANSITIVE_OPTIONAL, Visibility.PUBLIC, "Optional dependencies", new String[] {CONF_NAME_OPTIONAL}, true, null); public static final String CONF_USE_PREFIX = "use_"; public static final String EXTRA_INFO_EXPORT_PREFIX = "_osgi_export_"; /** * * @param baseUri * uri to help build the absolute url if the bundle info has a relative uri. * @param bundle * @param profileProvider * @param parser * @return * @throws ProfileNotFoundException */ public static DefaultModuleDescriptor toModuleDescriptor(ModuleDescriptorParser parser, URI baseUri, BundleInfo bundle, ExecutionEnvironmentProfileProvider profileProvider) throws ProfileNotFoundException { DefaultModuleDescriptor md = new DefaultModuleDescriptor(parser, null); md.addExtraAttributeNamespace("o", Ivy.getIvyHomeURL() + "osgi"); ModuleRevisionId mrid = asMrid(BundleInfo.BUNDLE_TYPE, bundle.getSymbolicName(), bundle.getVersion()); md.setResolvedPublicationDate(new Date()); md.setModuleRevisionId(mrid); md.addConfiguration(CONF_DEFAULT); md.addConfiguration(CONF_OPTIONAL); md.addConfiguration(CONF_TRANSITIVE_OPTIONAL); Set exportedPkgNames = new HashSet(bundle.getExports().size()); for (ExportPackage exportPackage : bundle.getExports()) { md.getExtraInfo().put(EXTRA_INFO_EXPORT_PREFIX + exportPackage.getName(), exportPackage.getVersion().toString()); exportedPkgNames.add(exportPackage.getName()); String[] confDependencies = new String[exportPackage.getUses().size() + 1]; int i = 0; for (String use : exportPackage.getUses()) { confDependencies[i++] = CONF_USE_PREFIX + use; } confDependencies[i] = CONF_NAME_DEFAULT; md.addConfiguration(new Configuration(CONF_USE_PREFIX + exportPackage.getName(), Visibility.PUBLIC, "Exported package " + exportPackage.getName(), confDependencies, true, null)); } requirementAsDependency(md, bundle, exportedPkgNames); if (baseUri != null) { for (BundleArtifact bundleArtifact : bundle.getArtifacts()) { String type = "jar"; String ext = "jar"; String packaging = null; if (bundle.hasInnerClasspath()) { packaging = "zip"; } if ("packed".equals(bundleArtifact.getFormat())) { ext = "jar.pack.gz"; if (packaging != null) { packaging += ",pack200"; } else { packaging = "pack200"; } } if (bundleArtifact.isSource()) { type = "source"; } URI uri = bundleArtifact.getUri(); if (uri != null) { DefaultArtifact artifact = buildArtifact(mrid, baseUri, uri, type, ext, packaging); md.addArtifact(CONF_NAME_DEFAULT, artifact); } } } if (profileProvider != null) { for (String env : bundle.getExecutionEnvironments()) { ExecutionEnvironmentProfile profile = profileProvider.getProfile(env); if (profile == null) { throw new ProfileNotFoundException("Execution environment profile " + env + " not found"); } for (String pkg : profile.getPkgNames()) { ArtifactId id = new ArtifactId(ModuleId.newInstance(BundleInfo.PACKAGE_TYPE, pkg), PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION); DefaultExcludeRule rule = new DefaultExcludeRule(id, ExactOrRegexpPatternMatcher.INSTANCE, null); String[] confs = md.getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { rule.addConfiguration(confs[i]); } md.addExcludeRule(rule); } } } return md; } public static DefaultArtifact buildArtifact(ModuleRevisionId mrid, URI baseUri, URI uri, String type, String ext, String packaging) { DefaultArtifact artifact; if ("ivy".equals(uri.getScheme())) { artifact = decodeIvyURI(uri); } else { if (!uri.isAbsolute()) { uri = baseUri.resolve(uri); } Map extraAtt = new HashMap(); if (packaging != null) { extraAtt.put("packaging", packaging); } try { artifact = new DefaultArtifact(mrid, null, mrid.getName(), type, ext, new URL( uri.toString()), extraAtt); } catch (MalformedURLException e) { throw new RuntimeException("Unable to make the uri into the url", e); } } return artifact; } public static List getConfigurations(BundleInfo bundle) { List confs = new ArrayList(); confs.add(CONF_NAME_DEFAULT); confs.add(CONF_NAME_OPTIONAL); confs.add(CONF_NAME_TRANSITIVE_OPTIONAL); for (ExportPackage exportPackage : bundle.getExports()) { confs.add(CONF_USE_PREFIX + exportPackage.getName()); } return confs; } public static URI buildIvyURI(Artifact artifact) { ModuleRevisionId mrid = artifact.getModuleRevisionId(); return asIvyURI(mrid.getOrganisation(), mrid.getName(), mrid.getBranch(), mrid.getRevision(), artifact.getType(), artifact.getName(), artifact.getExt()); } private static URI asIvyURI(String org, String name, String branch, String rev, String type, String art, String ext) { StringBuffer builder = new StringBuffer(); builder.append("ivy:///"); builder.append(org); builder.append('/'); builder.append(name); builder.append('?'); if (branch != null) { builder.append("branch="); builder.append(branch); } if (rev != null) { builder.append("&rev="); builder.append(rev); } if (type != null) { builder.append("&type="); builder.append(type); } if (art != null) { builder.append("&art="); builder.append(art); } if (ext != null) { builder.append("&ext="); builder.append(ext); } try { return new URI(builder.toString()); } catch (URISyntaxException e) { throw new RuntimeException("illformed ivy url", e); } } private static DefaultArtifact decodeIvyURI(final URI uri) { String org = null; String name = null; String branch = null; String rev = null; String art = null; String type = null; String ext = null; String path = uri.getPath(); if (!path.startsWith("/")) { throw new IllegalArgumentException( "An ivy url should be of the form ivy:///org/module but was : " + uri); } int i = path.indexOf('/', 1); if (i < 0) { throw new IllegalArgumentException("Expecting an organisation in the ivy url: " + uri); } org = path.substring(1, i); name = path.substring(i + 1); String query = uri.getQuery(); String[] parameters = query.split("&"); for (int j = 0; j < parameters.length; j++) { String parameter = parameters[j]; if (parameter.length() == 0) { continue; } String[] nameAndValue = parameter.split("="); if (nameAndValue.length != 2) { throw new IllegalArgumentException("Malformed query string in the ivy url: " + uri); } else if (nameAndValue[0].equals("branch")) { branch = nameAndValue[1]; } else if (nameAndValue[0].equals("rev")) { rev = nameAndValue[1]; } else if (nameAndValue[0].equals("art")) { art = nameAndValue[1]; } else if (nameAndValue[0].equals("type")) { type = nameAndValue[1]; } else if (nameAndValue[0].equals("ext")) { ext = nameAndValue[1]; } else { throw new IllegalArgumentException("Unrecognized parameter '" + nameAndValue[0] + " in the query string of the ivy url: " + uri); } } ModuleRevisionId amrid = ModuleRevisionId.newInstance(org, name, branch, rev); DefaultArtifact artifact = new DefaultArtifact(amrid, null, art, type, ext); return artifact; } private static void requirementAsDependency(DefaultModuleDescriptor md, BundleInfo bundleInfo, Set exportedPkgNames) { for (BundleRequirement requirement : bundleInfo.getRequirements()) { String type = requirement.getType(); String name = requirement.getName(); if (BundleInfo.PACKAGE_TYPE.equals(type) && exportedPkgNames.contains(name)) { // don't declare package exported by the current bundle continue; } if (BundleInfo.EXECUTION_ENVIRONMENT_TYPE.equals(type)) { // execution environment are handled elsewhere continue; } ModuleRevisionId ddmrid = asMrid(type, name, requirement.getVersion()); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ddmrid, false); String conf = CONF_NAME_DEFAULT; if (BundleInfo.PACKAGE_TYPE.equals(type)) { // declare the configuration for the package conf = CONF_USE_PREFIX + name; md.addConfiguration(new Configuration(CONF_USE_PREFIX + name, Visibility.PUBLIC, "Exported package " + name, new String[] {CONF_NAME_DEFAULT}, true, null)); dd.addDependencyConfiguration(conf, conf); } if ("optional".equals(requirement.getResolution())) { dd.addDependencyConfiguration(CONF_NAME_OPTIONAL, conf); dd.addDependencyConfiguration(CONF_NAME_TRANSITIVE_OPTIONAL, CONF_NAME_TRANSITIVE_OPTIONAL); } else { dd.addDependencyConfiguration(CONF_NAME_DEFAULT, conf); } md.addDependency(dd); } } public static ModuleRevisionId asMrid(String type, String name, Version v) { return ModuleRevisionId.newInstance(type, name, v == null ? null : v.toString()); } public static ModuleRevisionId asMrid(String type, String name, VersionRange v) { String revision; if (v == null) { revision = "[0,)"; } else { revision = v.toIvyRevision(); } return ModuleRevisionId.newInstance(type, name, revision); } public static class ProfileNotFoundException extends RuntimeException { public ProfileNotFoundException(String msg) { super(msg); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/BundleRequirement.java000066400000000000000000000063461226750426600255470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import org.apache.ivy.osgi.util.VersionRange; public class BundleRequirement { private final String name; private final String resolution; private final VersionRange version; private final String type; public BundleRequirement(String type, String name, VersionRange version, String resolution) { this.type = type; this.name = name; this.version = version; this.resolution = resolution; } public String getType() { return type; } public String getName() { return name; } public VersionRange getVersion() { return version; } public String getResolution() { return resolution; } public String toString() { return name + (version == null ? "" : ";" + version) + (resolution == null ? "" : " (" + resolution + ")"); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((resolution == null) ? 0 : resolution.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BundleRequirement)) { return false; } BundleRequirement other = (BundleRequirement) obj; if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (resolution == null) { if (other.resolution != null) { return false; } } else if (!resolution.equals(other.resolution)) { return false; } if (version == null) { if (other.version != null) { return false; } } else if (!version.equals(other.version)) { return false; } return true; } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ExecutionEnvironmentProfile.java000066400000000000000000000044701226750426600276220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.util.Set; import java.util.TreeSet; public class ExecutionEnvironmentProfile { Set pkgNames = new TreeSet(); private final String name; public ExecutionEnvironmentProfile(String name) { this.name = name; } public String getName() { return name; } public Set getPkgNames() { return pkgNames; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((pkgNames == null) ? 0 : pkgNames.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof ExecutionEnvironmentProfile)) { return false; } ExecutionEnvironmentProfile other = (ExecutionEnvironmentProfile) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (pkgNames == null) { if (other.pkgNames != null) { return false; } } else if (!pkgNames.equals(other.pkgNames)) { return false; } return true; } public String toString() { return name + ":" + pkgNames; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ExecutionEnvironmentProfileProvider.java000066400000000000000000000117501226750426600313340ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.apache.ivy.util.Message; public class ExecutionEnvironmentProfileProvider { private static final String DEFAULT_PROFILES_FILE = "jvm-packages.properties"; private static final String PACKAGE_PREFIX = "org/apache/ivy/osgi/core/"; private Map profileList; private static final ExecutionEnvironmentProfileProvider INSTANCE; static { try { INSTANCE = new ExecutionEnvironmentProfileProvider(); } catch (IOException e) { throw new RuntimeException(e); } } public static ExecutionEnvironmentProfileProvider getInstance() { return INSTANCE; } public ExecutionEnvironmentProfileProvider() throws IOException { profileList = loadDefaultProfileList(); } public ExecutionEnvironmentProfile getProfile(String profile) { return profileList.get(profile); } public static Map loadDefaultProfileList() throws IOException { ClassLoader loader = ExecutionEnvironmentProfileProvider.class.getClassLoader(); InputStream defaultProfilesFile = loader.getResourceAsStream(PACKAGE_PREFIX + DEFAULT_PROFILES_FILE); if (defaultProfilesFile == null) { throw new FileNotFoundException(PACKAGE_PREFIX + DEFAULT_PROFILES_FILE + " not found in the classpath"); } Properties props = new Properties(); try { props.load(defaultProfilesFile); } finally { defaultProfilesFile.close(); } Map profiles = new HashMap(); for (Entry prop : props.entrySet()) { String propName = (String) prop.getKey(); if (propName.endsWith(".pkglist")) { String profileName = propName.substring(0, propName.length() - 8); if (!profiles.containsKey(profileName)) { loadProfile(props, profiles, profileName); } } } return profiles; } private static ExecutionEnvironmentProfile loadProfile(Properties props, Map profiles, String name) { ExecutionEnvironmentProfile profile = new ExecutionEnvironmentProfile(name); // load the package for the extended profile String extendedProfileName = props.getProperty(name + ".extends"); if (extendedProfileName != null) { ExecutionEnvironmentProfile extendedProfile = profiles.get(extendedProfileName); if (extendedProfile == null) { // not loaded yet, so load it now extendedProfile = loadProfile(props, profiles, extendedProfileName); } profile.pkgNames.addAll(extendedProfile.pkgNames); } // load the actual list String pkgList = props.getProperty(name + ".pkglist"); String[] packages = pkgList.split(","); for (int i = 0; i < packages.length; i++) { String pkg = packages[i].trim(); if (pkg.length() != 0) { profile.pkgNames.add(pkg); } } profiles.put(name, profile); String aliasList = props.getProperty(name + ".aliases"); if (aliasList != null) { String[] aliases = aliasList.split(","); for (int i = 0; i < aliases.length; i++) { String alias = aliases[i].trim(); if (alias.length() != 0) { ExecutionEnvironmentProfile profileAlias = new ExecutionEnvironmentProfile( alias); profileAlias.pkgNames = profile.pkgNames; profiles.put(alias, profileAlias); } } } Message.verbose("Execution environment profile " + profile.getName() + " loaded"); return profile; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ExportPackage.java000066400000000000000000000040501226750426600246400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.util.HashSet; import java.util.Set; import org.apache.ivy.osgi.util.Version; public class ExportPackage extends BundleCapability { private final Set uses = new HashSet(); public ExportPackage(String name, Version version) { super(BundleInfo.PACKAGE_TYPE, name, version); } public void addUse(String pkg) { uses.add(pkg); } public Version getVersion() { return super.getVersion() == null ? BundleInfo.DEFAULT_VERSION : super.getVersion(); } public Set getUses() { return uses; } public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((uses == null) ? 0 : uses.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } ExportPackage other = (ExportPackage) obj; if (uses == null) { if (other.uses != null) { return false; } } else if (!uses.equals(other.uses)) { return false; } return true; } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ManifestHeaderElement.java000066400000000000000000000072451226750426600263050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class ManifestHeaderElement { private List values = new ArrayList(); private Map attributes = new HashMap(); private Map directives = new HashMap(); public List getValues() { return values; } public void addValue(String value) { values.add(value); } public Map getAttributes() { return attributes; } public void addAttribute(String name, String value) { attributes.put(name, value); } public Map getDirectives() { return directives; } public void addDirective(String name, String value) { directives.put(name, value); } public boolean equals(Object obj) { if (!(obj instanceof ManifestHeaderElement)) { return false; } ManifestHeaderElement other = (ManifestHeaderElement) obj; if (other.values.size() != values.size()) { return false; } for (String value : values) { if (!other.values.contains(value)) { return false; } } if (other.directives.size() != directives.size()) { return false; } for (Entry directive : directives.entrySet()) { if (!directive.getValue().equals(other.directives.get(directive.getKey()))) { return false; } } if (other.attributes.size() != attributes.size()) { return false; } for (Entry attribute : attributes.entrySet()) { if (!attribute.getValue().equals(other.attributes.get(attribute.getKey()))) { return false; } } return true; } public String toString() { String string = ""; Iterator itValues = values.iterator(); while (itValues.hasNext()) { string = string.concat(itValues.next()); if (itValues.hasNext()) { string = string.concat(";"); } } for (Entry directive : directives.entrySet()) { string = string.concat(";"); string = string.concat(directive.getKey()); string = string.concat(":="); string = string.concat(directive.getValue()); } for (Entry attribute : attributes.entrySet()) { string = string.concat(";"); string = string.concat(attribute.getKey()); string = string.concat("="); string = string.concat(attribute.getValue()); } return string; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ManifestHeaderValue.java000066400000000000000000000316231226750426600257650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.io.PrintStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Parse a header of a manifest. The manifest header is composed with the following rules: * *
     * header ::= header-element (',' header-element)*
     * header-element ::= values (';' (attribute | directive) )*
     * values ::= value (';' value)*
     * value ::= <any string value that does not have ';' or ','>
     * attribute ::= key '=' value
     * directive ::= key '=' value
     * key ::= token
     * value ::= token | quoted-string | double-quoted-string
     * 
    */ public class ManifestHeaderValue { private List elements = new ArrayList(); ManifestHeaderValue() { // just for unit testing } public ManifestHeaderValue(String header) throws ParseException { if (header != null) { new ManifestHeaderParser(header).parse(); } } public List getElements() { return elements; } public String getSingleValue() { if (elements.isEmpty()) { return null; } List values = getElements().iterator().next().getValues(); if (values.isEmpty()) { return null; } return values.iterator().next(); } public List getValues() { if (elements.isEmpty()) { return Collections.emptyList(); } List list = new ArrayList(); for (ManifestHeaderElement element : getElements()) { list.addAll(element.getValues()); } return list; } void addElement(ManifestHeaderElement element) { this.elements.add(element); } class ManifestHeaderParser { /** * header to parse */ private final String header; /** * the length of the source */ private int length; /** * buffer */ private StringBuffer buffer = new StringBuffer(); /** * position in the source */ private int pos = 0; /** * last read character */ private char c; /** * the header element being build */ private ManifestHeaderElement elem = new ManifestHeaderElement(); /** * Once at true (at the first attribute parsed), only parameters are allowed */ private boolean valuesParsed; /** * the last parsed parameter name */ private String paramName; /** * true if the last parsed parameter is a directive (assigned via :=) */ private boolean isDirective; /** * Default constructor * * @param header * the header to parse */ ManifestHeaderParser(String header) { this.header = header; this.length = header.length(); } /** * Do the parsing * * @throws ParseException */ void parse() throws ParseException { do { elem = new ManifestHeaderElement(); int posElement = pos; parseElement(); if (elem.getValues().isEmpty()) { error("No defined value", posElement); // try to recover: ignore that element continue; } addElement(elem); } while (pos < length); } private char readNext() { if (pos == length) { c = '\0'; } else { c = header.charAt(pos++); } return c; } private void error(String message) throws ParseException { error(message, pos - 1); } private void error(String message, int p) throws ParseException { throw new ParseException(message, p); } private void parseElement() throws ParseException { valuesParsed = false; do { parseValueOrParameter(); } while (c == ';' && pos < length); } private void parseValueOrParameter() throws ParseException { // true if the value/parameter parsing has started, white spaces skipped boolean start = false; do { switch (readNext()) { case '\0': break; case ';': case ',': endValue(); return; case ':': case '=': endParameterName(); parseSeparator(); parseParameterValue(); return; case ' ': case '\t': case '\n': case '\r': if (start) { buffer.append(c); } break; default: start = true; buffer.append(c); } } while (pos < length); endValue(); } private void endValue() throws ParseException { if (valuesParsed) { error("Early end of a parameter"); // try to recover: ignore it buffer.setLength(0); return; } if (buffer.length() == 0) { error("Empty value"); // try to recover: just ignore the error } elem.addValue(buffer.toString()); buffer.setLength(0); } private void endParameterName() throws ParseException { if (buffer.length() == 0) { error("Empty parameter name"); // try to recover: won't store the value paramName = null; } paramName = buffer.toString(); buffer.setLength(0); } private void parseSeparator() throws ParseException { if (c == '=') { isDirective = false; return; } if (readNext() != '=') { error("Expecting '='"); // try to recover: will ignore this parameter pos--; paramName = null; } isDirective = true; } private void parseParameterValue() throws ParseException { // true if the value parsing has started, white spaces skipped boolean start = false; // true if the value parsing is ended, then only white spaces are allowed boolean end = false; boolean doubleQuoted = false; do { switch (readNext()) { case '\0': break; case ',': case ';': endParameterValue(); return; case '=': case ':': error("Illegal character '" + c + "' in parameter value of " + paramName); // try to recover: ignore that parameter paramName = null; break; case '\"': doubleQuoted = true; case '\'': if (end && paramName != null) { error("Expecting the end of a parameter value"); // try to recover: ignore that parameter paramName = null; } if (start) { // quote in the middle of the value, just add it as a quote buffer.append(c); } else { start = true; appendQuoted(doubleQuoted); end = true; } break; case '\\': if (end && paramName != null) { error("Expecting the end of a parameter value"); // try to recover: ignore that parameter paramName = null; } start = true; appendEscaped(); break; case ' ': case '\t': case '\n': case '\r': if (start) { end = true; } break; default: if (end && paramName != null) { error("Expecting the end of a parameter value"); // try to recover: ignore that parameter paramName = null; } start = true; buffer.append(c); } } while (pos < length); endParameterValue(); } private void endParameterValue() throws ParseException { if (paramName == null) { // recovering from an incorrect parameter: skip the value return; } if (buffer.length() == 0) { error("Empty parameter value"); // try to recover: do not store the parameter return; } String value = buffer.toString(); if (isDirective) { elem.addDirective(paramName, value); } else { elem.addAttribute(paramName, value); } valuesParsed = true; buffer.setLength(0); } private void appendQuoted(boolean doubleQuoted) { do { switch (readNext()) { case '\0': break; case '\"': if (doubleQuoted) { return; } buffer.append(c); break; case '\'': if (!doubleQuoted) { return; } buffer.append(c); break; case '\\': break; default: buffer.append(c); } } while (pos < length); } private void appendEscaped() { if (pos < length) { buffer.append(readNext()); } else { buffer.append(c); } } } public boolean equals(Object obj) { if (!(obj instanceof ManifestHeaderValue)) { return false; } ManifestHeaderValue other = (ManifestHeaderValue) obj; if (other.elements.size() != elements.size()) { return false; } for (ManifestHeaderElement element : elements) { if (!other.elements.contains(element)) { return false; } } return true; } public String toString() { String string = ""; Iterator it = elements.iterator(); while (it.hasNext()) { string = string.concat(it.next().toString()); if (it.hasNext()) { string = string.concat(","); } } return string; } public static void writeParseException(PrintStream out, String source, ParseException e) { out.println(e.getMessage()); out.print(" " + source + "\n "); for (int i = 0; i < e.getErrorOffset(); i++) { out.print(' '); } out.println('^'); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/ManifestParser.java000066400000000000000000000273751226750426600250450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.List; import java.util.jar.Attributes; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.osgi.util.VersionRange; /** * Provides an OSGi manifest parser. * */ public class ManifestParser { private static final String EXPORT_PACKAGE = "Export-Package"; private static final String IMPORT_PACKAGE = "Import-Package"; private static final String EXPORT_SERVICE = "Export-Service"; private static final String IMPORT_SERVICE = "Import-Service"; private static final String REQUIRE_BUNDLE = "Require-Bundle"; private static final String BUNDLE_VERSION = "Bundle-Version"; private static final String BUNDLE_NAME = "Bundle-Name"; private static final String BUNDLE_DESCRIPTION = "Bundle-Description"; private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName"; private static final String BUNDLE_MANIFEST_VERSION = "Bundle-ManifestVersion"; private static final String BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT = "Bundle-RequiredExecutionEnvironment"; private static final String BUNDLE_CLASSPATH = "Bundle-ClassPath"; private static final String ECLIPSE_SOURCE_BUNDLE = "Eclipse-SourceBundle"; private static final String ATTR_RESOLUTION = "resolution"; private static final String ATTR_VERSION = "version"; private static final String ATTR_BUNDLE_VERSION = "bundle-version"; private static final String ATTR_USE = "use"; public static BundleInfo parseJarManifest(InputStream jarStream) throws IOException, ParseException { JarInputStream jis = new JarInputStream(jarStream); Manifest manifest = jis.getManifest(); if (manifest == null) { return null; } BundleInfo bundleInfo = parseManifest(manifest); return bundleInfo; } public static BundleInfo parseManifest(File manifestFile) throws IOException, ParseException { FileInputStream fis = new FileInputStream(manifestFile); try { BundleInfo parseManifest = parseManifest(fis); return parseManifest; } finally { try { fis.close(); } catch (IOException e) { // ignore } } } public static BundleInfo parseManifest(String manifest) throws IOException, ParseException { ByteArrayInputStream bais = new ByteArrayInputStream(manifest.getBytes("UTF-8")); BundleInfo parseManifest = parseManifest(bais); bais.close(); return parseManifest; } public static BundleInfo parseManifest(InputStream manifestStream) throws IOException, ParseException { BundleInfo parseManifest = parseManifest(new Manifest(manifestStream)); return parseManifest; } public static BundleInfo parseManifest(Manifest manifest) throws ParseException { Attributes mainAttributes = manifest.getMainAttributes(); // Eclipse source bundle doesn't have it. Disable it until proven actually useful // String manifestVersion = mainAttributes.getValue(BUNDLE_MANIFEST_VERSION); // if (manifestVersion == null) { // // non OSGi manifest // throw new ParseException("No " + BUNDLE_MANIFEST_VERSION + " in the manifest", 0); // } String symbolicName = new ManifestHeaderValue(mainAttributes.getValue(BUNDLE_SYMBOLIC_NAME)) .getSingleValue(); if (symbolicName == null) { throw new ParseException("No " + BUNDLE_SYMBOLIC_NAME + " in the manifest", 0); } String description = new ManifestHeaderValue(mainAttributes.getValue(BUNDLE_DESCRIPTION)) .getSingleValue(); if (description == null) { description = new ManifestHeaderValue(mainAttributes.getValue(BUNDLE_DESCRIPTION)) .getSingleValue(); } String vBundle = new ManifestHeaderValue(mainAttributes.getValue(BUNDLE_VERSION)) .getSingleValue(); Version version; try { version = versionOf(vBundle); } catch (NumberFormatException e) { throw new ParseException("The " + BUNDLE_VERSION + " has an incorrect version: " + vBundle + " (" + e.getMessage() + ")", 0); } BundleInfo bundleInfo = new BundleInfo(symbolicName, version); bundleInfo.setDescription(description); List environments = new ManifestHeaderValue( mainAttributes.getValue(BUNDLE_REQUIRED_EXECUTION_ENVIRONMENT)).getValues(); bundleInfo.setExecutionEnvironments(environments); parseRequirement(bundleInfo, mainAttributes, REQUIRE_BUNDLE, BundleInfo.BUNDLE_TYPE, ATTR_BUNDLE_VERSION); parseRequirement(bundleInfo, mainAttributes, IMPORT_PACKAGE, BundleInfo.PACKAGE_TYPE, ATTR_VERSION); parseRequirement(bundleInfo, mainAttributes, IMPORT_SERVICE, BundleInfo.SERVICE_TYPE, ATTR_VERSION); ManifestHeaderValue exportElements = new ManifestHeaderValue( mainAttributes.getValue(EXPORT_PACKAGE)); for (ManifestHeaderElement exportElement : exportElements.getElements()) { String vExport = exportElement.getAttributes().get(ATTR_VERSION); Version v = null; try { v = versionOf(vExport); } catch (NumberFormatException e) { throw new ParseException("The " + EXPORT_PACKAGE + " has an incorrect version: " + vExport + " (" + e.getMessage() + ")", 0); } for (String name : exportElement.getValues()) { ExportPackage export = new ExportPackage(name, v); String uses = exportElement.getDirectives().get(ATTR_USE); if (uses != null) { String[] split = uses.trim().split(","); for (int i = 0; i < split.length; i++) { export.addUse(split[i].trim()); } } bundleInfo.addCapability(export); } } parseCapability(bundleInfo, mainAttributes, EXPORT_SERVICE, BundleInfo.SERVICE_TYPE); // handle Eclipse specific source attachement String eclipseSourceBundle = mainAttributes.getValue(ECLIPSE_SOURCE_BUNDLE); if (eclipseSourceBundle != null) { bundleInfo.setSource(true); ManifestHeaderValue eclipseSourceBundleValue = new ManifestHeaderValue( eclipseSourceBundle); ManifestHeaderElement element = eclipseSourceBundleValue.getElements().iterator() .next(); String symbolicNameTarget = element.getValues().iterator().next(); bundleInfo.setSymbolicNameTarget(symbolicNameTarget); String v = element.getAttributes().get(ATTR_VERSION); if (v != null) { bundleInfo.setVersionTarget(new Version(v)); } } String bundleClasspath = mainAttributes.getValue(BUNDLE_CLASSPATH); if (bundleClasspath != null) { ManifestHeaderValue bundleClasspathValue = new ManifestHeaderValue(bundleClasspath); bundleInfo.setClasspath(bundleClasspathValue.getValues()); } return bundleInfo; } private static void parseRequirement(BundleInfo bundleInfo, Attributes mainAttributes, String headerName, String type, String versionAttr) throws ParseException { ManifestHeaderValue elements = new ManifestHeaderValue(mainAttributes.getValue(headerName)); for (ManifestHeaderElement element : elements.getElements()) { String resolution = element.getDirectives().get(ATTR_RESOLUTION); String attVersion = element.getAttributes().get(versionAttr); VersionRange version = null; try { version = versionRangeOf(attVersion); } catch (ParseException e) { throw new ParseException("The " + headerName + " has an incorrect version: " + attVersion + " (" + e.getMessage() + ")", 0); } for (String name : element.getValues()) { bundleInfo.addRequirement(new BundleRequirement(type, name, version, resolution)); } } } private static void parseCapability(BundleInfo bundleInfo, Attributes mainAttributes, String headerName, String type) throws ParseException { ManifestHeaderValue elements = new ManifestHeaderValue(mainAttributes.getValue(headerName)); for (ManifestHeaderElement element : elements.getElements()) { String attVersion = element.getAttributes().get(ATTR_VERSION); Version version = null; try { version = versionOf(attVersion); } catch (NumberFormatException e) { throw new ParseException("The " + headerName + " has an incorrect version: " + attVersion + " (" + e.getMessage() + ")", 0); } for (String name : element.getValues()) { BundleCapability export = new BundleCapability(type, name, version); bundleInfo.addCapability(export); } } } private static VersionRange versionRangeOf(String v) throws ParseException { if (v == null) { return null; } return new VersionRange(v); } private static Version versionOf(String v) throws ParseException { if (v == null) { return null; } return new Version(v); } /** * Ensure that the lines are not longer than 72 characters, so it can be parsed by the * {@link Manifest} class * * @param manifest * @return */ public static String formatLines(String manifest) { StringBuffer buffer = new StringBuffer(manifest.length()); String[] lines = manifest.split("\n"); for (int i = 0; i < lines.length; i++) { if (lines[i].length() <= 72) { buffer.append(lines[i]); buffer.append('\n'); } else { buffer.append(lines[i].substring(0, 72)); buffer.append("\n "); int n = 72; while (n <= lines[i].length() - 1) { int end = n + 71; if (end > lines[i].length()) { end = lines[i].length(); } buffer.append(lines[i].substring(n, end)); buffer.append('\n'); if (end != lines[i].length()) { buffer.append(' '); } n = end; } } } return buffer.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/OSGiManifestParser.java000066400000000000000000000075631226750426600255640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.Date; import java.util.Locale; import java.util.jar.Manifest; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLResource; public class OSGiManifestParser implements ModuleDescriptorParser { private static final OSGiManifestParser INSTANCE = new OSGiManifestParser(); public static OSGiManifestParser getInstance() { return INSTANCE; } private ExecutionEnvironmentProfileProvider profileProvider = ExecutionEnvironmentProfileProvider .getInstance(); public void add(ExecutionEnvironmentProfileProvider pp) { this.profileProvider = pp; } public boolean accept(Resource res) { if (res == null || res.getName() == null || res.getName().trim().equals("")) { return false; } return res.getName().toUpperCase(Locale.US).endsWith("MANIFEST.MF"); } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, Resource res, boolean validate) throws ParseException, IOException { Manifest m = new Manifest(res.openStream()); BundleInfo bundleInfo = ManifestParser.parseManifest(m); try { bundleInfo.addArtifact(new BundleArtifact(false, new URI(res.getName()), null)); } catch (URISyntaxException e) { throw new RuntimeException("Unsupported repository, resources names are not uris", e); } return BundleInfoAdapter.toModuleDescriptor(this, null, bundleInfo, profileProvider); } public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws ParseException, IOException { try { XmlModuleDescriptorWriter.write(md, destFile); } finally { if (is != null) { is.close(); } } } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, boolean validate) throws ParseException, IOException { URLResource resource = new URLResource(descriptorURL); return parseDescriptor(ivySettings, descriptorURL, resource, validate); } public String getType() { return "manifest"; } public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) { return DefaultArtifact.newIvyArtifact(mrid, new Date(res.getLastModified())); } public String toString() { return "manifest parser"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/OsgiLatestStrategy.java000066400000000000000000000077171226750426600257210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.core; import java.text.ParseException; import java.util.Comparator; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.ComparatorLatestStrategy; import org.apache.ivy.plugins.version.VersionMatcher; public class OsgiLatestStrategy extends ComparatorLatestStrategy { final class MridComparator implements Comparator { public int compare(ModuleRevisionId o1, ModuleRevisionId o2) { Version v1; Version v2; try { v1 = new Version(o1.getRevision()); v2 = new Version(o2.getRevision()); } catch (ParseException e) { throw new RuntimeException("Uncomparable versions:" + o1.getRevision() + " and " + o2.getRevision() + " (" + e.getMessage() + ")"); } try { return v1.compareTo(v2); } catch (RuntimeException e) { if (e.getCause() instanceof ParseException) { throw new RuntimeException("Uncomparable versions:" + o1.getRevision() + " and " + o2.getRevision() + " (" + e.getMessage() + ")"); } throw e; } } } final class ArtifactInfoComparator implements Comparator { public int compare(ArtifactInfo o1, ArtifactInfo o2) { String rev1 = o1.getRevision(); String rev2 = o2.getRevision(); /* * The revisions can still be not resolved, so we use the current version matcher to * know if one revision is dynamic, and in this case if it should be considered greater * or lower than the other one. Note that if the version matcher compare method returns * 0, it's because it's not possible to know which revision is greater. In this case we * consider the dynamic one to be greater, because most of the time it will then be * actually resolved and a real comparison will occur. */ VersionMatcher vmatcher = IvyContext.getContext().getSettings().getVersionMatcher(); ModuleRevisionId mrid1 = ModuleRevisionId.newInstance("", "", rev1); ModuleRevisionId mrid2 = ModuleRevisionId.newInstance("", "", rev2); if (vmatcher.isDynamic(mrid1)) { int c = vmatcher.compare(mrid1, mrid2, mridComparator); return c >= 0 ? 1 : -1; } else if (vmatcher.isDynamic(mrid2)) { int c = vmatcher.compare(mrid2, mrid1, mridComparator); return c >= 0 ? -1 : 1; } return mridComparator.compare(mrid1, mrid2); } } private final Comparator mridComparator = new MridComparator(); private final Comparator artifactInfoComparator = new ArtifactInfoComparator(); public OsgiLatestStrategy() { setComparator(artifactInfoComparator); setName("latest-osgi"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/core/jvm-packages.properties000066400000000000000000000134041226750426600257310ustar00rootroot00000000000000# *************************************************************** # * Licensed to the Apache Software Foundation (ASF) under one # * or more contributor license agreements. See the NOTICE file # * distributed with this work for additional information # * regarding copyright ownership. The ASF licenses this file # * to you under the Apache License, Version 2.0 (the # * "License"); you may not use this file except in compliance # * with the License. You may obtain a copy of the License at # * # * http://www.apache.org/licenses/LICENSE-2.0 # * # * Unless required by applicable law or agreed to in writing, # * software distributed under the License is distributed on an # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # * KIND, either express or implied. See the License for the # * specific language governing permissions and limitations # * under the License. # *************************************************************** OSGi/Minimum-1.0.aliases = OSGI_MINIMUM-1.0 OSGi/Minimum-1.0.pkglist = OSGi/Minimum-1.1.aliases = OSGI_MINIMUM-1.1 OSGi/Minimum-1.1.pkglist = OSGi/Minimum-1.2.aliases = OSGI_MINIMUM-1.2 OSGi/Minimum-1.2.pkglist = CDC-1.0/Foundation-1.0.aliases = CDC-1.0_Foundation-1.0 CDC-1.0/Foundation-1.0.pkglist = \ javax.microedition.io CDC-1.1/Foundation-1.1.aliases = CDC-1.1_Foundation-1.1 CDC-1.1/Foundation-1.1.extends = CDC-1.0/Foundation-1.0 CDC-1.1/Foundation-1.1.pkglist = \ javax.microedition.pki,\ javax.security.auth.x500 JavaSE-1.2.aliases = J2SE-1.2 JavaSE-1.2.pkglist = \ javax.accessibility,\ javax.swing,\ javax.swing.border,\ javax.swing.colorchooser,\ javax.swing.event,\ javax.swing.filechooser,\ javax.swing.plaf,\ javax.swing.plaf.basic,\ javax.swing.plaf.metal,\ javax.swing.plaf.multi,\ javax.swing.table,\ javax.swing.text,\ javax.swing.text.html,\ javax.swing.text.html.parser,\ javax.swing.text.rtf,\ javax.swing.tree,\ javax.swing.undo,\ org.omg.CORBA,\ org.omg.CORBA.DynAnyPackage,\ org.omg.CORBA.ORBPackage,\ org.omg.CORBA.portable,\ org.omg.CORBA.TypeCodePackage,\ org.omg.CosNaming,\ org.omg.CosNaming.NamingContextPackage JavaSE-1.3.aliases = J2SE-1.3 JavaSE-1.3.extends = JavaSE-1.2 JavaSE-1.3.pkglist = \ javax.naming,\ javax.naming.directory,\ javax.naming.event,\ javax.naming.ldap,\ javax.naming.spi,\ javax.rmi,\ javax.rmi.CORBA,\ javax.sound.midi,\ javax.sound.midi.spi,\ javax.sound.sampled,\ javax.sound.sampled.spi,\ javax.transaction,\ org.omg.CORBA_2_3,\ org.omg.CORBA_2_3.portable,\ org.omg.SendingContext,\ org.omg.stub.java.rmi JavaSE-1.4.aliases = J2SE-1.4 JavaSE-1.4.extends = JavaSE-1.3 JavaSE-1.4.pkglist = \ javax.crypto,\ javax.crypto.interfaces,\ javax.crypto.spec,\ javax.imageio,\ javax.imageio.event,\ javax.imageio.metadata,\ javax.imageio.plugins.jpeg,\ javax.imageio.spi,\ javax.imageio.stream,\ javax.net,\ javax.net.ssl,\ javax.print,\ javax.print.attribute,\ javax.print.attribute.standard,\ javax.print.event,\ javax.security.auth,\ javax.security.auth.callback,\ javax.security.auth.kerberos,\ javax.security.auth.login,\ javax.security.auth.spi,\ javax.security.auth.x500,\ javax.security.cert,\ javax.sql,\ javax.transaction.xa,\ javax.xml.parsers,\ javax.xml.transform,\ javax.xml.transform.dom,\ javax.xml.transform.sax,\ javax.xml.transform.stream,\ org.ietf.jgss,\ org.omg.CosNaming.NamingContextExtPackage,\ org.omg.Dynamic,\ org.omg.DynamicAny,\ org.omg.DynamicAny.DynAnyFactoryPackage,\ org.omg.DynamicAny.DynAnyPackage,\ org.omg.IOP,\ org.omg.IOP.CodecFactoryPackage,\ org.omg.IOP.CodecPackage,\ org.omg.Messaging,\ org.omg.PortableInterceptor,\ org.omg.PortableInterceptor.ORBInitInfoPackage,\ org.omg.PortableServer,\ org.omg.PortableServer.CurrentPackage,\ org.omg.PortableServer.POAManagerPackage,\ org.omg.PortableServer.POAPackage,\ org.omg.PortableServer.portable,\ org.omg.PortableServer.ServantLocatorPackage,\ org.w3c.dom,\ org.w3c.dom.css,\ org.w3c.dom.events,\ org.w3c.dom.html,\ org.w3c.dom.stylesheets,\ org.w3c.dom.views,\ org.xml.sax,\ org.xml.sax.ext,\ org.xml.sax.helpers JavaSE-1.5.aliases = J2SE-1.5 JavaSE-1.5.extends = JavaSE-1.4 JavaSE-1.5.pkglist = \ javax.activity,\ javax.imageio.plugins.bmp,\ javax.management,\ javax.management.loading,\ javax.management.modelmbean,\ javax.management.monitor,\ javax.management.openmbean,\ javax.management.relation,\ javax.management.remote,\ javax.management.remote.rmi,\ javax.management.timer,\ javax.rmi.ssl,\ javax.security.sasl,\ javax.sql.rowset,\ javax.sql.rowset.serial,\ javax.sql.rowset.spi,\ javax.swing.plaf.synth,\ javax.xml,\ javax.xml.datatype,\ javax.xml.namespace,\ javax.xml.validation,\ javax.xml.xpath,\ org.w3c.dom.bootstrap,\ org.w3c.dom.ls,\ org.w3c.dom.ranges,\ org.w3c.dom.traversal JavaSE-1.6.extends = JavaSE-1.5 JavaSE-1.6.pkglist = \ javax.activation,\ javax.annotation,\ javax.annotation.processing,\ javax.jws,\ javax.jws.soap,\ javax.lang.model,\ javax.lang.model.element,\ javax.lang.model.type,\ javax.lang.model.util,\ javax.script,\ javax.tools,\ javax.xml.bind,\ javax.xml.bind.annotation,\ javax.xml.bind.annotation.adapters,\ javax.xml.bind.attachment,\ javax.xml.bind.helpers,\ javax.xml.bind.util,\ javax.xml.crypto,\ javax.xml.crypto.dom,\ javax.xml.crypto.dsig,\ javax.xml.crypto.dsig.dom,\ javax.xml.crypto.dsig.keyinfo,\ javax.xml.crypto.dsig.spec,\ javax.xml.soap,\ javax.xml.stream,\ javax.xml.stream.events,\ javax.xml.stream.util,\ javax.xml.transform.stax,\ javax.xml.ws,\ javax.xml.ws.handler,\ javax.xml.ws.handler.soap,\ javax.xml.ws.http,\ javax.xml.ws.soap,\ javax.xml.ws.spi,\ javax.xml.ws.spi.http,\ javax.xml.ws.wsaddressing JavaSE-1.7.extends = JavaSE-1.6 JavaSE-1.7.pkglist = \ javax.swing.plaf.nimbus JavaSE-1.8.extends = JavaSE-1.7 JavaSE-1.8.pkglist = ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/000077500000000000000000000000001226750426600215765ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/AndFilter.java000066400000000000000000000025261226750426600243160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.Map; public class AndFilter extends MultiOperatorFilter { public AndFilter() { super(); } public AndFilter(OSGiFilter[] filters) { super(filters); } protected char operator() { return '&'; } @Override public boolean eval(Map properties) { for (OSGiFilter filter : getSubFilters()) { if (!filter.eval(properties)) { return false; } } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/CompareFilter.java000066400000000000000000000076651226750426600252130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.Map; public class CompareFilter extends OSGiFilter { public static enum Operator { EQUALS("="), LOWER_THAN("<"), LOWER_OR_EQUAL("<="), GREATER_THAN(">"), GREATER_OR_EQUAL( ">="); private String op; private Operator(String op) { this.op = op; } public String toString() { return op; } } private Operator operator; private final String rightValue; private final String leftValue; public CompareFilter(String leftValue, Operator operator, String rightValue) { this.leftValue = leftValue; this.rightValue = rightValue; this.operator = operator; } public String getLeftValue() { return leftValue; } public Operator getOperator() { return operator; } public String getRightValue() { return rightValue; } public void append(StringBuffer builder) { builder.append("("); builder.append(leftValue); builder.append(operator.toString()); builder.append(rightValue); builder.append(")"); } @Override public boolean eval(Map properties) { String actualValue = properties.get(leftValue); if (actualValue == null) { return false; } int diff = rightValue.compareTo(actualValue); switch (operator) { case EQUALS: return diff == 0; case GREATER_THAN: return diff > 0; case GREATER_OR_EQUAL: return diff >= 0; case LOWER_OR_EQUAL: return diff <= 0; case LOWER_THAN: return diff < 0; default: throw new IllegalStateException(); } } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((leftValue == null) ? 0 : leftValue.hashCode()); result = prime * result + ((operator == null) ? 0 : operator.hashCode()); result = prime * result + ((rightValue == null) ? 0 : rightValue.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof CompareFilter)) { return false; } CompareFilter other = (CompareFilter) obj; if (leftValue == null) { if (other.leftValue != null) { return false; } } else if (!leftValue.equals(other.leftValue)) { return false; } if (operator == null) { if (other.operator != null) { return false; } } else if (!operator.equals(other.operator)) { return false; } if (rightValue == null) { if (other.rightValue != null) { return false; } } else if (!rightValue.equals(other.rightValue)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/MultiOperatorFilter.java000066400000000000000000000052771226750426600264300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.ArrayList; import java.util.List; public abstract class MultiOperatorFilter extends OSGiFilter { private List subFilters = new ArrayList(); public MultiOperatorFilter() { // default constructor } public MultiOperatorFilter(OSGiFilter[] filters) { for (int i = 0; i < filters.length; i++) { OSGiFilter filter = filters[i]; add(filter); } } abstract protected char operator(); public void append(StringBuffer builder) { builder.append('('); builder.append(operator()); for (OSGiFilter filter : subFilters) { filter.append(builder); } builder.append(')'); } public void add(OSGiFilter subFilter2) { subFilters.add(subFilter2); } public List getSubFilters() { return subFilters; } public int hashCode() { final int prime = 31; int result = 1; for (OSGiFilter subFilter : subFilters) { result = prime * result + ((subFilter == null) ? 0 : subFilter.hashCode()); } return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof MultiOperatorFilter)) { return false; } MultiOperatorFilter other = (MultiOperatorFilter) obj; if (subFilters == null) { if (other.subFilters != null) { return false; } } else if (other.subFilters == null) { return false; } else if (subFilters.size() != other.subFilters.size()) { return false; } else if (!subFilters.containsAll(other.subFilters)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/NotFilter.java000066400000000000000000000022531226750426600243510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.Map; public class NotFilter extends UniOperatorFilter { public NotFilter(OSGiFilter subFilter) { super(subFilter); } protected char operator() { return '!'; } @Override public boolean eval(Map properties) { return !getSubFilter().eval(properties); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/OSGiFilter.java000066400000000000000000000022431226750426600244110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.Map; public abstract class OSGiFilter { public String toString() { StringBuffer builder = new StringBuffer(); append(builder); return builder.toString(); } public abstract void append(StringBuffer builder); public abstract boolean eval(Map properties); } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/OSGiFilterParser.java000066400000000000000000000144071226750426600255730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.text.ParseException; import org.apache.ivy.osgi.filter.CompareFilter.Operator; public class OSGiFilterParser { public static OSGiFilter parse(String text) throws ParseException { return new Parser(text).parse(); } static class Parser { /** * text to parse */ private final String text; /** * the length of the source */ private int length; /** * position in the source */ private int pos = 0; /** * last read character */ private char c; /** * Default constructor * * @param header * the header to parse */ Parser(String text) { this.text = text; this.length = text.length(); } /** * Do the parsing * * @return * * @throws ParseException */ OSGiFilter parse() throws ParseException { return parseFilter(); } private char readNext() { if (pos == length) { c = '\0'; } else { c = text.charAt(pos++); } return c; } private void unread() { if (pos > 0) { pos--; } } private OSGiFilter parseFilter() throws ParseException { skipWhiteSpace(); readNext(); if (c != '(') { throw new ParseException("Expecting '(' as the start of the filter", pos); } OSGiFilter filter; switch (readNext()) { case '&': filter = parseAnd(); break; case '|': filter = parseOr(); break; case '!': filter = parseNot(); break; default: unread(); filter = parseCompare(); break; } readNext(); if (c != ')') { throw new ParseException("Expecting ')' as the end of the filter", pos); } return filter; } private OSGiFilter parseCompare() throws ParseException { String leftValue = parseCompareValue(); Operator operator = parseCompareOperator(); String rightValue = parseCompareValue(); return new CompareFilter(leftValue, operator, rightValue); } private String parseCompareValue() { StringBuffer builder = new StringBuffer(); do { readNext(); if (!isOperator(c) && c != ')' && c != '(') { builder.append(c); } else { unread(); break; } } while (pos < length); return builder.toString(); } private boolean isOperator(char ch) { return ch == '=' || ch == '<' || ch == '>'; } private Operator parseCompareOperator() throws ParseException { switch (readNext()) { case '=': return Operator.EQUALS; case '>': if (readNext() == '=') { return Operator.GREATER_OR_EQUAL; } unread(); return Operator.GREATER_THAN; case '<': if (readNext() == '=') { return Operator.LOWER_OR_EQUAL; } unread(); return Operator.LOWER_THAN; default: break; } throw new ParseException("Expecting an operator: =, <, <=, > or >=", pos); } private OSGiFilter parseAnd() throws ParseException { AndFilter filter = new AndFilter(); parseMultiOperator(filter); return filter; } private OSGiFilter parseOr() throws ParseException { OrFilter filter = new OrFilter(); parseMultiOperator(filter); return filter; } private void parseMultiOperator(MultiOperatorFilter filter) throws ParseException { do { skipWhiteSpace(); readNext(); if (c == '(') { unread(); filter.add(parseFilter()); } else { unread(); break; } } while (pos < length); if (filter.getSubFilters().size() == 0) { throw new ParseException("Expecting at least one sub filter", pos); } } private OSGiFilter parseNot() throws ParseException { readNext(); if (c != '(') { throw new ParseException("The ! operator is expecting a filter", pos); } unread(); return new NotFilter(parseFilter()); } private void skipWhiteSpace() { do { switch (readNext()) { case ' ': continue; default: unread(); return; } } while (pos < length); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/OrFilter.java000066400000000000000000000025221226750426600241700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; import java.util.Map; public class OrFilter extends MultiOperatorFilter { public OrFilter() { super(); } public OrFilter(OSGiFilter[] filters) { super(filters); } protected char operator() { return '|'; } @Override public boolean eval(Map properties) { for (OSGiFilter filter : getSubFilters()) { if (filter.eval(properties)) { return true; } } return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/filter/UniOperatorFilter.java000066400000000000000000000040751226750426600260640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.filter; public abstract class UniOperatorFilter extends OSGiFilter { private final OSGiFilter subFilter; public UniOperatorFilter(OSGiFilter subFilter) { this.subFilter = subFilter; } abstract protected char operator(); public void append(StringBuffer builder) { builder.append("("); builder.append(operator()); builder.append(subFilter.toString()); builder.append(")"); } public OSGiFilter getSubFilter() { return subFilter; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((subFilter == null) ? 0 : subFilter.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof UniOperatorFilter)) { return false; } UniOperatorFilter other = (UniOperatorFilter) obj; if (subFilter == null) { if (other.subFilter != null) { return false; } } else if (!subFilter.equals(other.subFilter)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/000077500000000000000000000000001226750426600210735ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/OBRResolver.java000066400000000000000000000133601226750426600241050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import org.apache.ivy.core.cache.CacheResourceOptions; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.osgi.obr.xml.OBRXMLParser; import org.apache.ivy.osgi.repo.AbstractOSGiResolver; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLResource; import org.xml.sax.SAXException; public class OBRResolver extends AbstractOSGiResolver { private String repoXmlURL; private String repoXmlFile; private Long metadataTtl; private Boolean forceMetadataUpdate; public void setRepoXmlFile(String repositoryXmlFile) { this.repoXmlFile = repositoryXmlFile; } public void setRepoXmlURL(String repositoryXmlURL) { this.repoXmlURL = repositoryXmlURL; } public void setMetadataTtl(Long metadataTtl) { this.metadataTtl = metadataTtl; } public void setForceMetadataUpdate(Boolean forceMetadataUpdate) { this.forceMetadataUpdate = forceMetadataUpdate; } protected void init() { if (repoXmlFile != null && repoXmlURL != null) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: repoXmlFile and repoXmlUrl cannot be set both"); } if (repoXmlFile != null) { File f = new File(repoXmlFile); loadRepoFromFile(f.getParentFile().toURI(), f, repoXmlFile); } else if (repoXmlURL != null) { final URL url; try { url = new URL(repoXmlURL); } catch (MalformedURLException e) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: repoXmlURL '" + repoXmlURL + "' is not an URL"); } ArtifactDownloadReport report; EventManager eventManager = getEventManager(); try { if (eventManager != null) { getRepository().addTransferListener(eventManager); } Resource obrResource = new URLResource(url); CacheResourceOptions options = new CacheResourceOptions(); if (metadataTtl != null) { options.setTtl(metadataTtl.longValue()); } if (forceMetadataUpdate != null) { options.setForce(forceMetadataUpdate.booleanValue()); } report = getRepositoryCacheManager().downloadRepositoryResource(obrResource, "obr", "obr", "xml", options, getRepository()); } finally { if (eventManager != null) { getRepository().removeTransferListener(eventManager); } } URI baseURI; try { baseURI = new URI(repoXmlURL); } catch (URISyntaxException e) { throw new RuntimeException("illegal uri"); } loadRepoFromFile(baseURI, report.getLocalFile(), repoXmlURL); } else { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: repoXmlFile or repoXmlUrl is missing"); } } private void loadRepoFromFile(URI baseUri, File repoFile, String sourceLocation) { FileInputStream in; try { in = new FileInputStream(repoFile); } catch (FileNotFoundException e) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: the file " + sourceLocation + " was not found"); } try { setRepoDescriptor(OBRXMLParser.parse(baseUri, in)); } catch (ParseException e) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: the file " + sourceLocation + " is incorrectly formed (" + e.getMessage() + ")", e); } catch (IOException e) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: the file " + sourceLocation + " could not be read (" + e.getMessage() + ")", e); } catch (SAXException e) { throw new RuntimeException("The OBR repository resolver " + getName() + " couldn't be configured: the file " + sourceLocation + " has incorrect XML (" + e.getMessage() + ")", e); } try { in.close(); } catch (IOException e) { // don't care } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/000077500000000000000000000000001226750426600216735ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/Capability.java000066400000000000000000000032341226750426600246210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import java.util.ArrayList; import java.util.List; public class Capability { private List properties = new ArrayList(); private String name; public Capability(String name) { this.name = name; } public String getName() { return name; } public void addProperty(String n, String value, String type) { properties.add(new CapabilityProperty(n, value, type)); } public List getProperties() { return properties; } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append(name); for (CapabilityProperty p : properties) { buffer.append(" "); buffer.append(p); } return buffer.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/CapabilityAdapter.java000066400000000000000000000103711226750426600261220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import java.text.ParseException; import org.apache.ivy.osgi.core.BundleCapability; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ExportPackage; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.Message; public class CapabilityAdapter { public static void adapt(BundleInfo bundleInfo, Capability capability) throws ParseException { String name = capability.getName(); if (BundleInfo.PACKAGE_TYPE.equals(name)) { ExportPackage exportPackage = getExportPackage(bundleInfo, capability); bundleInfo.addCapability(exportPackage); } else if (BundleInfo.BUNDLE_TYPE.equals(name)) { // nothing to do, already handled at the resource tag level } else if (BundleInfo.SERVICE_TYPE.equals(name)) { BundleCapability service = getOSGiService(bundleInfo, capability); bundleInfo.addCapability(service); } else { Message.warn("Unsupported capability '" + name + "' on the bundle '" + bundleInfo.getSymbolicName() + "'"); } } private static ExportPackage getExportPackage(BundleInfo bundleInfo, Capability capability) throws ParseException { String pkgName = null; Version version = null; String uses = null; for (CapabilityProperty property : capability.getProperties()) { String propName = property.getName(); if ("package".equals(propName)) { pkgName = property.getValue(); } else if ("version".equals(propName)) { version = new Version(property.getValue()); } else if ("uses".equals(propName)) { uses = property.getValue(); } else { Message.warn("Unsupported property '" + propName + "' on the 'package' capability of the bundle '" + bundleInfo.getSymbolicName() + "'"); } } if (pkgName == null) { throw new ParseException("No package name for the capability", 0); } ExportPackage exportPackage = new ExportPackage(pkgName, version); if (uses != null) { String[] split = uses.trim().split(","); for (int i = 0; i < split.length; i++) { String u = split[i]; exportPackage.addUse(u.trim()); } } return exportPackage; } private static BundleCapability getOSGiService(BundleInfo bundleInfo, Capability capability) throws ParseException { String name = null; Version version = null; for (CapabilityProperty property : capability.getProperties()) { String propName = property.getName(); if ("service".equals(propName)) { name = property.getValue(); } else if ("version".equals(propName)) { version = new Version(property.getValue()); } else { Message.warn("Unsupported property '" + propName + "' on the 'package' capability of the bundle '" + bundleInfo.getSymbolicName() + "'"); } } if (name == null) { throw new ParseException("No service name for the capability", 0); } BundleCapability service = new BundleCapability(BundleInfo.SERVICE_TYPE, name, version); return service; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/CapabilityProperty.java000066400000000000000000000026321226750426600263670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; public class CapabilityProperty { private String name; private String value; private String type; public CapabilityProperty(String name, String value, String type) { this.name = name; this.value = value; this.type = type; } public String getName() { return name; } public String getValue() { return value; } public String getType() { return type; } @Override public String toString() { return (type == null ? "" : "[" + type + "]") + name + "=" + value; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLParser.java000066400000000000000000000341371226750426600247260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.core.BundleArtifact; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.filter.OSGiFilter; import org.apache.ivy.osgi.filter.OSGiFilterParser; import org.apache.ivy.osgi.repo.BundleRepoDescriptor; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class OBRXMLParser { public static BundleRepoDescriptor parse(URI baseUri, InputStream in) throws ParseException, IOException, SAXException { RepositoryHandler handler = new RepositoryHandler(baseUri); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } return handler.repo; } static class RepositoryHandler extends DelegatingHandler { static final String REPOSITORY = "repository"; static final String LASTMODIFIED = "lastmodified"; static final String NAME = "name"; BundleRepoDescriptor repo; private final URI baseUri; public RepositoryHandler(URI baseUri) { super(REPOSITORY); this.baseUri = baseUri; addChild(new ResourceHandler(), new ChildElementHandler() { public void childHanlded(ResourceHandler child) { repo.addBundle(child.bundleInfo); } }); } protected void handleAttributes(Attributes atts) { repo = new BundleRepoDescriptor(baseUri, ExecutionEnvironmentProfileProvider.getInstance()); repo.setName(atts.getValue(NAME)); repo.setLastModified(atts.getValue(LASTMODIFIED)); } } static class ResourceHandler extends DelegatingHandler { private static final String DEFAULT_VERSION = "1.0.0"; static final String RESOURCE = "resource"; static final String ID = "id"; static final String PRESENTATION_NAME = "presentationname"; static final String SYMBOLIC_NAME = "symbolicname"; static final String URI = "uri"; static final String VERSION = "version"; BundleInfo bundleInfo; public ResourceHandler() { super(RESOURCE); setSkipOnError(true); // if anything bad happen in any children, just ignore the // resource addChild(new ResourceSourceHandler(), new ChildElementHandler() { public void childHanlded(ResourceSourceHandler child) { String uri = child.getBufferedChars().trim(); if (!uri.endsWith(".jar")) { // the maven plugin is putting some useless source url sometimes... log(Message.MSG_WARN, "A source uri is suspect, it is not ending with .jar, it is probably" + " a pointer to a download page. Ignoring it."); return; } try { bundleInfo.addArtifact(new BundleArtifact(true, new URI(uri), null)); } catch (URISyntaxException e) { log(Message.MSG_WARN, "Incorrect uri " + uri + ". The source of " + bundleInfo.getSymbolicName() + " is then ignored."); return; } } }); addChild(new ResourceDescriptionHandler(), new ChildElementHandler() { public void childHanlded(ResourceDescriptionHandler child) { bundleInfo.setDescription(child.getBufferedChars().trim()); } }); addChild(new ResourceDocumentationHandler(), new ChildElementHandler() { public void childHanlded(ResourceDocumentationHandler child) { bundleInfo.setDocumentation(child.getBufferedChars().trim()); } }); addChild(new ResourceLicenseHandler(), new ChildElementHandler() { public void childHanlded(ResourceLicenseHandler child) { bundleInfo.setLicense(child.getBufferedChars().trim()); } }); addChild(new ResourceSizeHandler(), new ChildElementHandler() { public void childHanlded(ResourceSizeHandler child) { String size = child.getBufferedChars().trim(); try { bundleInfo.setSize(Integer.valueOf(size)); } catch (NumberFormatException e) { log(Message.MSG_WARN, "Invalid size for the bundle " + bundleInfo.getSymbolicName() + ": " + size + ". This size is then ignored."); } } }); addChild(new CapabilityHandler(), new ChildElementHandler() { public void childHanlded(CapabilityHandler child) throws SAXParseException { try { CapabilityAdapter.adapt(bundleInfo, child.capability); } catch (ParseException e) { throw new SAXParseException("Invalid capability: " + e.getMessage(), child .getLocator()); } } }); addChild(new RequireHandler(), new ChildElementHandler() { public void childHanlded(RequireHandler child) throws SAXParseException { try { RequirementAdapter.adapt(bundleInfo, child.requirement); } catch (UnsupportedFilterException e) { throw new SAXParseException("Unsupported requirement filter: " + child.filter + " (" + e.getMessage() + ")", getLocator()); } catch (ParseException e) { throw new SAXParseException( "Error in the requirement filter on the bundle: " + e.getMessage(), getLocator()); } } }); addChild(new ExtendHandler(), new ChildElementHandler() { public void childHanlded(ExtendHandler child) throws SAXParseException { // TODO handle fragment host } }); } protected void handleAttributes(Attributes atts) throws SAXException { String symbolicname = atts.getValue(SYMBOLIC_NAME); if (symbolicname == null) { log(Message.MSG_ERR, "Resource with no symobilc name, skipping it."); skip(); return; } String v = getOptionalAttribute(atts, VERSION, DEFAULT_VERSION); Version version; try { version = new Version(v); } catch (ParseException e) { log(Message.MSG_ERR, "Incorrect resource version: " + v + ". The resource " + symbolicname + " is then ignored."); skip(); return; } bundleInfo = new BundleInfo(symbolicname, version); bundleInfo.setPresentationName(atts.getValue(PRESENTATION_NAME)); String uri = atts.getValue(URI); if (uri != null) { try { bundleInfo.addArtifact(new BundleArtifact(false, new URI(uri), null)); } catch (URISyntaxException e) { log(Message.MSG_ERR, "Incorrect uri " + uri + ". The resource " + symbolicname + " is then ignored."); skip(); return; } } bundleInfo.setId(atts.getValue(ID)); } protected String getCurrentElementIdentifier() { return bundleInfo.getSymbolicName() + "/" + bundleInfo.getVersion(); } } static class ResourceSourceHandler extends DelegatingHandler { static final String SOURCE = "source"; public ResourceSourceHandler() { super(SOURCE); setBufferingChar(true); } } static class ResourceDescriptionHandler extends DelegatingHandler { static final String DESCRIPTION = "description"; public ResourceDescriptionHandler() { super(DESCRIPTION); setBufferingChar(true); } } static class ResourceDocumentationHandler extends DelegatingHandler { static final String DOCUMENTATION = "documentation"; public ResourceDocumentationHandler() { super(DOCUMENTATION); setBufferingChar(true); } } static class ResourceLicenseHandler extends DelegatingHandler { static final String LICENSE = "license"; public ResourceLicenseHandler() { super(LICENSE); setBufferingChar(true); } } static class ResourceSizeHandler extends DelegatingHandler { static final String SIZE = "size"; public ResourceSizeHandler() { super(SIZE); setBufferingChar(true); } } static class CapabilityHandler extends DelegatingHandler { static final String CAPABILITY = "capability"; static final String NAME = "name"; Capability capability; public CapabilityHandler() { super(CAPABILITY); addChild(new CapabilityPropertyHandler(), new ChildElementHandler() { public void childHanlded(CapabilityPropertyHandler child) { String name = child.name; String value = child.value; String type = child.type; capability.addProperty(name, value, type); } }); } protected void handleAttributes(Attributes atts) throws SAXException { String name = getRequiredAttribute(atts, NAME); capability = new Capability(name); } } static class CapabilityPropertyHandler extends DelegatingHandler { static final String CAPABILITY_PROPERTY = "p"; static final String NAME = "n"; static final String VALUE = "v"; static final String TYPE = "t"; String name; String value; String type; public CapabilityPropertyHandler() { super(CAPABILITY_PROPERTY); } protected void handleAttributes(Attributes atts) throws SAXException { name = getRequiredAttribute(atts, NAME); value = getRequiredAttribute(atts, VALUE); type = atts.getValue(TYPE); } } static class AbstractRequirementHandler extends DelegatingHandler { static final String NAME = "name"; static final String OPTIONAL = "optional"; static final String MULTIPLE = "multiple"; static final String FILTER = "filter"; Requirement requirement; OSGiFilter filter; public AbstractRequirementHandler(String name) { super(name); } protected void handleAttributes(Attributes atts) throws SAXException { String name = getRequiredAttribute(atts, NAME); String filterText = atts.getValue(FILTER); filter = null; if (filterText != null) { try { filter = OSGiFilterParser.parse(filterText); } catch (ParseException e) { throw new SAXParseException("Requirement with illformed filter: " + filterText, getLocator()); } } Boolean optional = getOptionalBooleanAttribute(atts, OPTIONAL, null); Boolean multiple = getOptionalBooleanAttribute(atts, MULTIPLE, null); requirement = new Requirement(name, filter); if (optional != null) { requirement.setOptional(optional.booleanValue()); } if (multiple != null) { requirement.setMultiple(multiple.booleanValue()); } } } static class RequireHandler extends AbstractRequirementHandler { static final String REQUIRE = "require"; public RequireHandler() { super(REQUIRE); } } static class ExtendHandler extends AbstractRequirementHandler { static final String EXTEND = "extend"; public ExtendHandler() { super(EXTEND); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLWriter.java000066400000000000000000000304441226750426600247430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import java.io.OutputStream; import java.text.ParseException; import java.util.Set; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.apache.ivy.core.IvyContext; import org.apache.ivy.osgi.core.BundleArtifact; import org.apache.ivy.osgi.core.BundleCapability; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleRequirement; import org.apache.ivy.osgi.core.ExportPackage; import org.apache.ivy.osgi.core.ManifestParser; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.CapabilityHandler; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.CapabilityPropertyHandler; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.RepositoryHandler; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.RequireHandler; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.ResourceHandler; import org.apache.ivy.osgi.obr.xml.OBRXMLParser.ResourceSourceHandler; import org.apache.ivy.osgi.repo.ManifestAndLocation; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.osgi.util.VersionRange; import org.apache.ivy.util.Message; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; public class OBRXMLWriter { public static ContentHandler newHandler(OutputStream out, String encoding, boolean indent) throws TransformerConfigurationException { SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler hd = tf.newTransformerHandler(); Transformer serializer = tf.newTransformer(); StreamResult stream = new StreamResult(out); serializer.setOutputProperty(OutputKeys.ENCODING, encoding); serializer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); hd.setResult(stream); return hd; } public static void writeManifests(Iterable manifestAndLocations, ContentHandler handler, boolean quiet) throws SAXException { int level = quiet ? Message.MSG_DEBUG : Message.MSG_WARN; handler.startDocument(); AttributesImpl atts = new AttributesImpl(); handler.startElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY, atts); int nbOk = 0; int nbRejected = 0; for (ManifestAndLocation manifestAndLocation : manifestAndLocations) { BundleInfo bundleInfo; try { bundleInfo = ManifestParser.parseManifest(manifestAndLocation.getManifest()); bundleInfo .addArtifact(new BundleArtifact(false, manifestAndLocation.getUri(), null)); if (manifestAndLocation.getSourceURI() != null) { bundleInfo.addArtifact(new BundleArtifact(true, manifestAndLocation .getSourceURI(), null)); } nbOk++; } catch (ParseException e) { nbRejected++; IvyContext .getContext() .getMessageLogger() .log("Rejected " + manifestAndLocation.getUri() + ": " + e.getMessage(), level); continue; } saxBundleInfo(bundleInfo, handler); } handler.endElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY); handler.endDocument(); Message.info(nbOk + " bundle" + (nbOk > 1 ? "s" : "") + " added, " + nbRejected + " bundle" + (nbRejected > 1 ? "s" : "") + " rejected."); } public static void writeBundles(Iterable bundleInfos, ContentHandler handler) throws SAXException { handler.startDocument(); AttributesImpl atts = new AttributesImpl(); handler.startElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY, atts); for (BundleInfo bundleInfo : bundleInfos) { saxBundleInfo(bundleInfo, handler); } handler.endElement("", RepositoryHandler.REPOSITORY, RepositoryHandler.REPOSITORY); handler.endDocument(); } private static void saxBundleInfo(BundleInfo bundleInfo, ContentHandler handler) throws SAXException { AttributesImpl atts = new AttributesImpl(); addAttr(atts, ResourceHandler.SYMBOLIC_NAME, bundleInfo.getSymbolicName()); addAttr(atts, ResourceHandler.VERSION, bundleInfo.getRawVersion()); for (BundleArtifact artifact : bundleInfo.getArtifacts()) { if (!artifact.isSource()) { addAttr(atts, ResourceHandler.URI, bundleInfo.getArtifacts().get(0).getUri() .toString()); break; } } handler.startElement("", ResourceHandler.RESOURCE, ResourceHandler.RESOURCE, atts); for (BundleArtifact artifact : bundleInfo.getArtifacts()) { if (artifact.isSource()) { startElement(handler, ResourceSourceHandler.SOURCE); characters(handler, artifact.getUri().toString()); endElement(handler, ResourceSourceHandler.SOURCE); break; } } for (BundleCapability capability : bundleInfo.getCapabilities()) { saxCapability(capability, handler); } for (BundleRequirement requirement : bundleInfo.getRequirements()) { saxRequirement(requirement, handler); } handler.endElement("", ResourceHandler.RESOURCE, ResourceHandler.RESOURCE); handler.characters("\n".toCharArray(), 0, 1); } private static void saxCapability(BundleCapability capability, ContentHandler handler) throws SAXException { AttributesImpl atts = new AttributesImpl(); String type = capability.getType(); addAttr(atts, CapabilityHandler.NAME, type); handler.startElement("", CapabilityHandler.CAPABILITY, CapabilityHandler.CAPABILITY, atts); if (type.equals(BundleInfo.BUNDLE_TYPE)) { // nothing to do, already handled with the resource tag } else if (type.equals(BundleInfo.PACKAGE_TYPE)) { saxCapabilityProperty("package", capability.getName(), handler); Version v = capability.getRawVersion(); if (v != null) { saxCapabilityProperty("version", v.toString(), handler); } Set uses = ((ExportPackage) capability).getUses(); if (uses != null && !uses.isEmpty()) { StringBuffer builder = new StringBuffer(); for (String use : uses) { if (builder.length() != 0) { builder.append(','); } builder.append(use); } saxCapabilityProperty("uses", builder.toString(), handler); } } else if (type.equals(BundleInfo.SERVICE_TYPE)) { saxCapabilityProperty("service", capability.getName(), handler); Version v = capability.getRawVersion(); if (v != null) { saxCapabilityProperty("version", v.toString(), handler); } } else { // oups } handler.endElement("", CapabilityHandler.CAPABILITY, CapabilityHandler.CAPABILITY); handler.characters("\n".toCharArray(), 0, 1); } private static void saxCapabilityProperty(String n, String v, ContentHandler handler) throws SAXException { saxCapabilityProperty(n, null, v, handler); } private static void saxCapabilityProperty(String n, String t, String v, ContentHandler handler) throws SAXException { AttributesImpl atts = new AttributesImpl(); addAttr(atts, CapabilityPropertyHandler.NAME, n); if (t != null) { addAttr(atts, CapabilityPropertyHandler.TYPE, t); } addAttr(atts, CapabilityPropertyHandler.VALUE, v); handler.startElement("", CapabilityPropertyHandler.CAPABILITY_PROPERTY, CapabilityPropertyHandler.CAPABILITY_PROPERTY, atts); handler.endElement("", CapabilityPropertyHandler.CAPABILITY_PROPERTY, CapabilityPropertyHandler.CAPABILITY_PROPERTY); handler.characters("\n".toCharArray(), 0, 1); } private static void saxRequirement(BundleRequirement requirement, ContentHandler handler) throws SAXException { AttributesImpl atts = new AttributesImpl(); addAttr(atts, RequireHandler.NAME, requirement.getType()); if ("optional".equals(requirement.getResolution())) { addAttr(atts, RequireHandler.OPTIONAL, Boolean.TRUE.toString()); } addAttr(atts, RequireHandler.FILTER, buildFilter(requirement)); handler.startElement("", RequireHandler.REQUIRE, RequireHandler.REQUIRE, atts); handler.endElement("", RequireHandler.REQUIRE, RequireHandler.REQUIRE); handler.characters("\n".toCharArray(), 0, 1); } private static String buildFilter(BundleRequirement requirement) { StringBuffer filter = new StringBuffer(); VersionRange v = requirement.getVersion(); if (v != null) { appendVersion(filter, v); } filter.append('('); filter.append(requirement.getType()); filter.append("="); filter.append(requirement.getName()); filter.append(')'); if (v != null) { filter.append(')'); } return filter.toString(); } private static void appendVersion(StringBuffer filter, VersionRange v) { filter.append("(&"); Version start = v.getStartVersion(); if (start != null) { if (!v.isStartExclusive()) { filter.append("(version>="); filter.append(start.toString()); filter.append(')'); } else { filter.append("(!"); filter.append("(version<="); filter.append(start.toString()); filter.append("))"); } } Version end = v.getEndVersion(); if (end != null) { if (!v.isEndExclusive()) { filter.append("(version<="); filter.append(end.toString()); filter.append(')'); } else { filter.append("(!"); filter.append("(version>="); filter.append(end.toString()); filter.append("))"); } } } private static void addAttr(AttributesImpl atts, String name, String value) { if (value != null) { atts.addAttribute("", name, name, "CDATA", value); } } private static void addAttr(AttributesImpl atts, String name, Object value) { if (value != null) { atts.addAttribute("", name, name, "CDATA", value.toString()); } } private static void startElement(ContentHandler handler, String name) throws SAXException { handler.startElement("", name, name, new AttributesImpl()); } private static void endElement(ContentHandler handler, String name) throws SAXException { handler.endElement("", name, name); } private static void characters(ContentHandler handler, String value) throws SAXException { char[] chars = value.toCharArray(); handler.characters(chars, 0, chars.length); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/Requirement.java000066400000000000000000000031321226750426600250350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import org.apache.ivy.osgi.filter.OSGiFilter; public class Requirement { private final String name; private boolean optional; private final OSGiFilter filter; private boolean multiple = false; public Requirement(String name, OSGiFilter filter) { this.name = name; this.filter = filter; } public String getName() { return name; } public OSGiFilter getFilter() { return filter; } public void setOptional(boolean optional) { this.optional = optional; } public boolean isOptional() { return optional; } public void setMultiple(boolean multiple) { this.multiple = multiple; } public boolean isMultiple() { return multiple; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/RequirementAdapter.java000066400000000000000000000173321226750426600263450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; import java.text.ParseException; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleRequirement; import org.apache.ivy.osgi.filter.AndFilter; import org.apache.ivy.osgi.filter.CompareFilter; import org.apache.ivy.osgi.filter.CompareFilter.Operator; import org.apache.ivy.osgi.filter.NotFilter; import org.apache.ivy.osgi.filter.OSGiFilter; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.osgi.util.VersionRange; public class RequirementAdapter { private Version startVersion = null; private boolean startExclusive = false; private Version endVersion = null; private boolean endExclusive = false; private String type = null; private String name = null; public static void adapt(BundleInfo info, Requirement requirement) throws UnsupportedFilterException, ParseException { RequirementAdapter adapter = new RequirementAdapter(); adapter.extractFilter(requirement.getFilter()); adapter.adapt(info, requirement.isOptional()); } private void extractFilter(OSGiFilter filter) throws UnsupportedFilterException, ParseException { if (filter instanceof AndFilter) { AndFilter andFilter = (AndFilter) filter; for (OSGiFilter subFilter : andFilter.getSubFilters()) { extractFilter(subFilter); } } else if (filter instanceof CompareFilter) { CompareFilter compareFilter = ((CompareFilter) filter); parseCompareFilter(compareFilter, false); } else if (filter instanceof NotFilter) { NotFilter notFilter = ((NotFilter) filter); if (notFilter.getSubFilter() instanceof CompareFilter) { CompareFilter compareFilter = ((CompareFilter) notFilter.getSubFilter()); parseCompareFilter(compareFilter, true); } } else { throw new UnsupportedFilterException("Unsupported filter: " + filter.getClass().getName()); } } private void adapt(BundleInfo info, boolean optional) throws ParseException { VersionRange range = getVersionRange(); String resolution = optional ? "optional" : null; if (type == null) { throw new ParseException("No requirement actually specified", 0); } BundleRequirement requirement = new BundleRequirement(type, name, range, resolution); info.addRequirement(requirement); if (BundleInfo.EXECUTION_ENVIRONMENT_TYPE.equals(type)) { info.addExecutionEnvironment(name); } } private VersionRange getVersionRange() { VersionRange range = null; if (startVersion != null || endVersion != null) { range = new VersionRange(startExclusive, startVersion, endExclusive, endVersion); } return range; } private void parseCompareFilter(CompareFilter compareFilter, boolean not) throws UnsupportedFilterException, ParseException { String att = compareFilter.getLeftValue(); if (BundleInfo.PACKAGE_TYPE.equals(att) || BundleInfo.BUNDLE_TYPE.equals(att) || BundleInfo.EXECUTION_ENVIRONMENT_TYPE.equals(att) || "symbolicname".equals(att) || BundleInfo.SERVICE_TYPE.equals(att)) { if (not) { throw new UnsupportedFilterException( "Not filter on requirement comparaison is not supported"); } if (type != null) { throw new UnsupportedFilterException("Multiple requirement type are not supported"); } if ("symbolicname".equals(att)) { type = BundleInfo.BUNDLE_TYPE; } else { type = att; } if (compareFilter.getOperator() != Operator.EQUALS) { throw new UnsupportedFilterException( "Filtering is only supported with the operator '='"); } name = compareFilter.getRightValue(); } else if ("version".equals(att)) { String v = compareFilter.getRightValue(); Version version; try { version = new Version(v); } catch (ParseException e) { throw new ParseException("Ill formed version: " + v, 0); } Operator operator = compareFilter.getOperator(); if (not) { if (operator == Operator.EQUALS) { throw new UnsupportedFilterException( "Not filter on equals comparaison is not supported"); } else if (operator == Operator.GREATER_OR_EQUAL) { operator = Operator.LOWER_THAN; } else if (operator == Operator.GREATER_THAN) { operator = Operator.LOWER_OR_EQUAL; } else if (operator == Operator.LOWER_OR_EQUAL) { operator = Operator.GREATER_THAN; } else if (operator == Operator.LOWER_THAN) { operator = Operator.GREATER_OR_EQUAL; } } if (operator == Operator.EQUALS) { if (startVersion != null || endVersion != null) { throw new UnsupportedFilterException( "Multiple version matching is not supported"); } startVersion = version; startExclusive = false; endVersion = version; endExclusive = false; } else if (operator == Operator.GREATER_OR_EQUAL) { if (startVersion != null) { throw new UnsupportedFilterException( "Multiple version matching is not supported"); } startVersion = version; startExclusive = false; } else if (operator == Operator.GREATER_THAN) { if (startVersion != null) { throw new UnsupportedFilterException( "Multiple version matching is not supported"); } startVersion = version; startExclusive = true; } else if (operator == Operator.LOWER_OR_EQUAL) { if (endVersion != null) { throw new UnsupportedFilterException( "Multiple version matching is not supported"); } endVersion = version; endExclusive = false; } else if (operator == Operator.LOWER_THAN) { if (endVersion != null) { throw new UnsupportedFilterException( "Multiple version matching is not supported"); } endVersion = version; endExclusive = true; } } else { throw new UnsupportedFilterException("Unsupported attribute: " + att); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/obr/xml/UnsupportedFilterException.java000066400000000000000000000017541226750426600301220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.obr.xml; public class UnsupportedFilterException extends Exception { public UnsupportedFilterException(String message) { super(message); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/000077500000000000000000000000001226750426600206325ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/P2Artifact.java000066400000000000000000000027071226750426600234420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import org.apache.ivy.osgi.util.Version; public class P2Artifact { private String id; private Version version; private String classifier; public P2Artifact(String id, Version version, String classifier) { this.id = id; this.version = version; this.classifier = classifier; } public String getClassifier() { return classifier; } public String getId() { return id; } public Version getVersion() { return version; } @Override public String toString() { return id + "@" + version + " (" + classifier + ")"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/P2ArtifactParser.java000066400000000000000000000223511226750426600246140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.filter.OSGiFilter; import org.apache.ivy.osgi.filter.OSGiFilterParser; import org.apache.ivy.osgi.p2.PropertiesParser.PropertiesHandler; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class P2ArtifactParser implements XMLInputParser { private final P2Descriptor p2Descriptor; private final String repoUrl; public P2ArtifactParser(P2Descriptor p2Descriptor, String repoUrl) { this.p2Descriptor = p2Descriptor; this.repoUrl = repoUrl; } public void parse(InputStream in) throws ParseException, IOException, SAXException { RepositoryHandler handler = new RepositoryHandler(p2Descriptor, repoUrl); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } } private static class RepositoryHandler extends DelegatingHandler { private static final String REPOSITORY = "repository"; // private static final String NAME = "name"; // // private static final String TYPE = "type"; // // private static final String VERSION = "version"; private Map artifactPatterns = new LinkedHashMap(); public RepositoryHandler(final P2Descriptor p2Descriptor, String repoUrl) { super(REPOSITORY); // addChild(new PropertiesHandler(), new ChildElementHandler() { // public void childHanlded(PropertiesHandler child) { // } // }); addChild(new MappingsHandler(), new ChildElementHandler() { public void childHanlded(MappingsHandler child) { for (Entry entry : child.outputByFilter.entrySet()) { OSGiFilter filter; try { filter = OSGiFilterParser.parse(entry.getKey()); } catch (ParseException e) { throw new IllegalStateException(); } artifactPatterns.put(filter, entry.getValue()); } } }); addChild(new ArtifactsHandler(p2Descriptor, artifactPatterns, repoUrl), new ChildElementHandler() { public void childHanlded(ArtifactsHandler child) { // nothing to do } }); } // protected void handleAttributes(Attributes atts) { // String name = atts.getValue(NAME); // String type = atts.getValue(TYPE); // String version = atts.getValue(VERSION); // } } private static class MappingsHandler extends DelegatingHandler { private static final String MAPPINGS = "mappings"; private static final String SIZE = "size"; Map outputByFilter; public MappingsHandler() { super(MAPPINGS); addChild(new RuleHandler(), new ChildElementHandler() { public void childHanlded(RuleHandler child) { outputByFilter.put(child.filter, child.output); } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); outputByFilter = new LinkedHashMap(size); } } private static class RuleHandler extends DelegatingHandler { private static final String RULE = "rule"; private static final String FILTER = "filter"; private static final String OUTPUT = "output"; private String filter; private String output; public RuleHandler() { super(RULE); } protected void handleAttributes(Attributes atts) { filter = atts.getValue(FILTER); output = atts.getValue(OUTPUT); } } private static class ArtifactsHandler extends DelegatingHandler { private static final String ARTIFACTS = "artifacts"; // private static final String SIZE = "size"; public ArtifactsHandler(final P2Descriptor p2Descriptor, final Map artifactPatterns, final String repoUrl) { super(ARTIFACTS); addChild(new ArtifactHandler(), new ChildElementHandler() { public void childHanlded(ArtifactHandler child) throws SAXParseException { String url = getPattern(child.p2Artifact, child.properties); if (url != null) { url = url.replaceAll("\\$\\{repoUrl\\}", repoUrl); url = url.replaceAll("\\$\\{id\\}", child.p2Artifact.getId()); url = url.replaceAll("\\$\\{version\\}", child.p2Artifact.getVersion() .toString()); URI uri; try { uri = new URL(url).toURI(); } catch (MalformedURLException e) { throw new SAXParseException("Incorrect artifact url '" + url + "' (" + e.getMessage() + ")", getLocator(), e); } catch (URISyntaxException e) { throw new SAXParseException("Incorrect artifact url '" + url + "' (" + e.getMessage() + ")", getLocator(), e); } p2Descriptor.addArtifactUrl(child.p2Artifact.getClassifier(), child.p2Artifact.getId(), child.p2Artifact.getVersion(), uri, child.properties.get("format")); } } private String getPattern(P2Artifact p2Artifact, Map properties) { Map props = new HashMap(properties); props.put("classifier", p2Artifact.getClassifier()); for (Entry pattern : artifactPatterns.entrySet()) { if (pattern.getKey().eval(props)) { return pattern.getValue(); } } return null; } }); } // protected void handleAttributes(Attributes atts) { // int size = Integer.parseInt(atts.getValue(SIZE)); // artifacts = new ArrayList(size); // } } private static class ArtifactHandler extends DelegatingHandler { private static final String ARTIFACT = "artifact"; private static final String CLASSIFIER = "classifier"; private static final String ID = "id"; private static final String VERSION = "version"; private P2Artifact p2Artifact; private Map properties; public ArtifactHandler() { super(ARTIFACT); addChild(new PropertiesHandler(), new ChildElementHandler() { public void childHanlded(PropertiesHandler child) { properties = child.properties; } }); } protected void handleAttributes(Attributes atts) throws SAXException { String id = atts.getValue(ID); Version version; try { version = new Version(atts.getValue(VERSION)); } catch (ParseException e) { throw new SAXException("Incorrect version attribute on artifact '" + id + "': " + atts.getValue(VERSION) + " (" + e.getMessage() + ")"); } String classifier = atts.getValue(CLASSIFIER); p2Artifact = new P2Artifact(id, version, classifier); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/P2CompositeParser.java000066400000000000000000000075611226750426600250270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; public class P2CompositeParser implements XMLInputParser { private Set childLocations = new LinkedHashSet(); public Set getChildLocations() { return childLocations; } public void parse(InputStream in) throws ParseException, IOException, SAXException { RepositoryHandler handler = new RepositoryHandler(); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } childLocations.addAll(handler.childLocations); } private static class RepositoryHandler extends DelegatingHandler { private static final String REPOSITORY = "repository"; // private static final String NAME = "name"; // // private static final String TYPE = "type"; // // private static final String VERSION = "version"; List childLocations = Collections.emptyList(); public RepositoryHandler() { super(REPOSITORY); addChild(new ChildrenHandler(), new ChildElementHandler() { public void childHanlded(ChildrenHandler child) { childLocations = child.childLocations; } }); } // protected void handleAttributes(Attributes atts) { // String name = atts.getValue(NAME); // String type = atts.getValue(TYPE); // String version = atts.getValue(VERSION); // } } private static class ChildrenHandler extends DelegatingHandler { private static final String CHILDREN = "children"; private static final String SIZE = "size"; List childLocations; public ChildrenHandler() { super(CHILDREN); addChild(new ChildHandler(), new ChildElementHandler() { public void childHanlded(ChildHandler child) { childLocations.add(child.location); } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); childLocations = new ArrayList(size); } } private static class ChildHandler extends DelegatingHandler { private static final String CHILD = "child"; private static final String LOCATION = "location"; String location; public ChildHandler() { super(CHILD); } protected void handleAttributes(Attributes atts) { location = atts.getValue(LOCATION); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/P2Descriptor.java000066400000000000000000000140711226750426600240200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.ivy.osgi.core.BundleArtifact; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.repo.EditableRepoDescriptor; import org.apache.ivy.osgi.repo.ModuleDescriptorWrapper; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.Message; public class P2Descriptor extends EditableRepoDescriptor { private Map> sourceTargetBundles = new HashMap>(); private Map> sourceBundles = new HashMap>(); public P2Descriptor(URI repoUri, ExecutionEnvironmentProfileProvider profileProvider) { super(repoUri, profileProvider); } public void addBundle(BundleInfo bundleInfo) { if (bundleInfo.isSource()) { if (bundleInfo.getSymbolicNameTarget() == null || bundleInfo.getVersionTarget() == null) { if (getLogLevel() <= Message.MSG_VERBOSE) { Message.verbose("The source bundle " + bundleInfo.getSymbolicName() + " did not declare its target. Ignoring it"); } return; } Map byVersion = sourceBundles.get(bundleInfo.getSymbolicName()); if (byVersion == null) { byVersion = new HashMap(); sourceBundles.put(bundleInfo.getSymbolicName(), byVersion); } byVersion.put(bundleInfo.getVersion(), bundleInfo); Map byTargetVersion = sourceTargetBundles.get(bundleInfo .getSymbolicNameTarget()); if (byTargetVersion == null) { byTargetVersion = new HashMap(); sourceTargetBundles.put(bundleInfo.getSymbolicNameTarget(), byTargetVersion); } BundleInfo old = byTargetVersion.put(bundleInfo.getVersionTarget(), bundleInfo); if (old != null && !old.equals(bundleInfo)) { if (getLogLevel() <= Message.MSG_VERBOSE) { Message.verbose("Duplicate source for the bundle " + bundleInfo.getSymbolicNameTarget() + "@" + bundleInfo.getVersionTarget() + " : " + bundleInfo + " is replacing " + old); } } return; } super.addBundle(bundleInfo); } public void finish() { sourceBundles = null; Set bundleIds = getCapabilityValues(BundleInfo.BUNDLE_TYPE); if (bundleIds == null) { return; } for (String bundleId : bundleIds) { Set modules = findModules(BundleInfo.BUNDLE_TYPE, bundleId); for (ModuleDescriptorWrapper mdw : modules) { String symbolicName = mdw.getBundleInfo().getSymbolicName(); Map byVersion = sourceTargetBundles.get(symbolicName); if (byVersion == null) { continue; } BundleInfo source = byVersion.get(mdw.getBundleInfo().getVersion()); if (source == null) { continue; } for (BundleArtifact artifact : source.getArtifacts()) { mdw.getBundleInfo().addArtifact(artifact); } } } sourceTargetBundles = null; } public void addArtifactUrl(String classifier, String id, Version version, URI uri, String format) { if (!classifier.equals("osgi.bundle")) { // we only support OSGi bundle, no Eclipse feature or anything else return; } ModuleDescriptorWrapper module = findModule(id, version); if (module != null) { addArtifact(module.getBundleInfo(), new BundleArtifact(false, uri, format)); return; } // not found in the regular bundle. Let's look up in the source ones Map byVersion = sourceBundles.get(id); if (byVersion == null) { return; } BundleInfo source = byVersion.get(version); if (source == null) { return; } addArtifact(source, new BundleArtifact(true, uri, format)); } private void addArtifact(BundleInfo bundle, BundleArtifact artifact) { // find an existing artifact that might be a duplicate BundleArtifact same = null; for (BundleArtifact a : bundle.getArtifacts()) { if (a.isSource() == artifact.isSource()) { same = a; break; } } BundleArtifact best = artifact; if (same != null) { // we have two artifacts for the same bundle, let's choose a "packed" one if (artifact.getFormat() == null || same.getFormat() != null) { // the new one cannot be better return; } bundle.removeArtifact(same); } bundle.addArtifact(best); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/P2MetadataParser.java000066400000000000000000000762201226750426600246030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.core.BundleCapability; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleRequirement; import org.apache.ivy.osgi.core.ExportPackage; import org.apache.ivy.osgi.core.ManifestParser; import org.apache.ivy.osgi.p2.PropertiesParser.PropertiesHandler; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.osgi.util.VersionRange; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class P2MetadataParser implements XMLInputParser { private final P2Descriptor p2Descriptor; private int logLevel = Message.MSG_INFO; public P2MetadataParser(P2Descriptor p2Descriptor) { this.p2Descriptor = p2Descriptor; } public void setLogLevel(int logLevel) { this.logLevel = logLevel; } public void parse(InputStream in) throws ParseException, IOException, SAXException { RepositoryHandler handler = new RepositoryHandler(p2Descriptor); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } } private class RepositoryHandler extends DelegatingHandler { // private static final String P2_TIMESTAMP = "p2.timestamp"; private static final String REPOSITORY = "repository"; // private static final String NAME = "name"; // // private static final String TYPE = "type"; // // private static final String VERSION = "version"; // // private static final String DESCRIPTION = "description"; // // private static final String PROVIDER = "provider"; public RepositoryHandler(final P2Descriptor p2Descriptor) { super(REPOSITORY); // addChild(new PropertiesHandler(P2_TIMESTAMP), // new ChildElementHandler() { // public void childHanlded(PropertiesHandler child) { // String timestamp = child.properties.get(P2_TIMESTAMP); // if (timestamp != null) { // p2Descriptor.setTimestamp(Long.parseLong(timestamp)); // } // } // }); addChild(new UnitsHandler(), new ChildElementHandler() { public void childHanlded(UnitsHandler child) { for (BundleInfo bundle : child.bundles) { p2Descriptor.addBundle(bundle); } } }); addChild(new ReferencesHandler(), new ChildElementHandler() { public void childHanlded(ReferencesHandler child) { } }); } // protected void handleAttributes(Attributes atts) { // String name = atts.getValue(NAME); // String type = atts.getValue(TYPE); // String version = atts.getValue(VERSION); // String description = atts.getValue(DESCRIPTION); // String provider = atts.getValue(PROVIDER); // } } private class ReferencesHandler extends DelegatingHandler { private static final String REFERENCES = "references"; private static final String SIZE = "size"; List repositoryUris; public ReferencesHandler() { super(REFERENCES); addChild(new RepositoryReferenceHandler(), new ChildElementHandler() { public void childHanlded(RepositoryReferenceHandler child) { repositoryUris.add(child.uri); } }); } protected void handleAttributes(Attributes atts) throws SAXException { int size = Integer.parseInt(atts.getValue(SIZE)); repositoryUris = new ArrayList(size); } } private class RepositoryReferenceHandler extends DelegatingHandler { private static final String REPOSITORY = "repository"; // private static final String TYPE = "type"; // // private static final String OPTIONS = "options"; // // private static final String NAME = "name"; private static final String URI = "uri"; private static final String URL = "url"; public RepositoryReferenceHandler() { super(REPOSITORY); } // int type; // // int options; // // String name; URI uri; protected void handleAttributes(Attributes atts) throws SAXException { // type = Integer.parseInt(atts.getValue(TYPE)); // options = Integer.parseInt(atts.getValue(OPTIONS)); // name = atts.getValue(NAME); String uriAtt = atts.getValue(URI); String urlAtt = atts.getValue(URL); if (uriAtt != null) { try { uri = new URI(uriAtt); } catch (URISyntaxException e) { throw new SAXParseException("Invalid uri attribute " + uriAtt + "(" + e.getMessage() + ")", getLocator()); } } if (uri != null && urlAtt != null) { try { uri = new URI(urlAtt); } catch (URISyntaxException e) { throw new SAXParseException("Invalid url attribute " + urlAtt + "(" + e.getMessage() + ")", getLocator()); } } } } private class UnitsHandler extends DelegatingHandler { private static final String UNITS = "units"; private static final String SIZE = "size"; List bundles; public UnitsHandler() { super(UNITS); addChild(new UnitHandler(), new ChildElementHandler() { public void childHanlded(UnitHandler child) { if (child.bundleInfo != null && !child.bundleInfo.getCapabilities().isEmpty()) { bundles.add(child.bundleInfo); } } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); bundles = new ArrayList(size); } } class UnitHandler extends DelegatingHandler { private static final String CATEGORY_PROPERTY = "org.eclipse.equinox.p2.type.category"; private static final String UNIT = "unit"; private static final String ID = "id"; private static final String VERSION = "version"; // private static final String SINGLETON = "singleton"; BundleInfo bundleInfo; public UnitHandler() { super(UNIT); // addChild(new UpdateHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); addChild(new PropertiesHandler(CATEGORY_PROPERTY), new ChildElementHandler() { public void childHanlded(PropertiesHandler child) { String category = child.properties.get(CATEGORY_PROPERTY); if (category != null && Boolean.valueOf(category).booleanValue()) { // this is a category definition, this is useless, skip this unit child.getParent().skip(); bundleInfo = null; } } }); addChild(new ProvidesHandler(), new ChildElementHandler() { public void childHanlded(ProvidesHandler child) { if ("source".equals(child.eclipseType)) { // this is some source of some bundle bundleInfo.setSource(true); // we need to parse the manifest in the toupointData to figure out the // targeted bundle // in case we won't have the proper data in the manifest, prepare the source // data from the convention String symbolicName = bundleInfo.getSymbolicName(); if (symbolicName.endsWith(".source")) { bundleInfo.setSymbolicNameTarget(symbolicName.substring(0, symbolicName.length() - 7)); bundleInfo.setVersionTarget(bundleInfo.getVersion()); } } for (BundleCapability capability : child.capabilities) { bundleInfo.addCapability(capability); } } }); addChild(new FilterHandler(), new ChildElementHandler() { public void childHanlded(FilterHandler child) { } }); addChild(new RequiresHandler(), new ChildElementHandler() { public void childHanlded(RequiresHandler child) { for (BundleRequirement requirement : child.requirements) { bundleInfo.addRequirement(requirement); } } }); addChild(new HostRequirementsHandler(), new ChildElementHandler() { public void childHanlded(HostRequirementsHandler child) { } }); addChild(new MetaRequirementsHandler(), new ChildElementHandler() { public void childHanlded(MetaRequirementsHandler child) { } }); addChild(new ArtifactsHandler(), new ChildElementHandler() { public void childHanlded(ArtifactsHandler child) { } }); // addChild(new TouchpointHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); addChild(new TouchpointDataHandler(), new ChildElementHandler() { public void childHanlded(TouchpointDataHandler child) throws SAXParseException { if (child.zipped != null) { bundleInfo.setHasInnerClasspath(child.zipped.booleanValue()); } if (!bundleInfo.isSource()) { // we only care about parsing the manifest if it is a source return; } if (child.manifest != null) { // Eclipse may have serialized a little bit weirdly String manifest = ManifestParser.formatLines(child.manifest.trim()); BundleInfo embeddedInfo; try { embeddedInfo = ManifestParser.parseManifest(manifest); } catch (IOException e) { if (logLevel >= Message.MSG_VERBOSE) { Message.verbose( "The Manifest of the source bundle " + bundleInfo.getSymbolicName() + " could not be parsed", e); } return; } catch (ParseException e) { if (logLevel >= Message.MSG_VERBOSE) { Message.verbose( "The Manifest of the source bundle " + bundleInfo.getSymbolicName() + " is ill formed", e); } return; } if (!embeddedInfo.isSource()) { if (logLevel >= Message.MSG_VERBOSE) { Message.verbose("The Manifest of the source bundle " + bundleInfo.getSymbolicName() + " is not declaring being a source."); } return; } String symbolicNameTarget = embeddedInfo.getSymbolicNameTarget(); if (symbolicNameTarget == null) { if (logLevel >= Message.MSG_VERBOSE) { Message.verbose("The Manifest of the source bundle " + bundleInfo.getSymbolicName() + " is not declaring a target symbolic name."); } return; } Version versionTarget = embeddedInfo.getVersionTarget(); if (versionTarget == null) { if (logLevel >= Message.MSG_VERBOSE) { Message.verbose("The Manifest of the source bundle " + bundleInfo.getSymbolicName() + " is not declaring a target version."); } return; } bundleInfo.setSymbolicNameTarget(symbolicNameTarget); bundleInfo.setVersionTarget(versionTarget); } } }); // addChild(new LicensesHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); // addChild(new CopyrightHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); // addChild(new ChangesHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); } protected void handleAttributes(Attributes atts) throws SAXException { String id = atts.getValue(ID); String version = atts.getValue(VERSION); // Boolean singleton = Boolean.valueOf(atts.getValue(SINGLETON)); try { bundleInfo = new BundleInfo(id, new Version(version)); } catch (ParseException e) { throw new SAXException("Incorrect version on bundle '" + id + "': " + version + " (" + e.getMessage() + ")"); } } } // static class UpdateHandler extends DelegetingHandler { // // private static final String UPDATE = "update"; // // private static final String ID = "id"; // // private static final String RANGE = "range"; // // private static final String SEVERITY = "severity"; // // public UpdateHandler() { // super(UPDATE); // } // // protected void handleAttributes(Attributes atts) { // String id = atts.getValue(ID); // String range = atts.getValue(RANGE); // String severity = atts.getValue(SEVERITY); // } // // } private static class FilterHandler extends DelegatingHandler { private static final String FILTER = "filter"; public FilterHandler() { super(FILTER); setBufferingChar(true); } } private static String namespace2Type(String namespace) { if (namespace.equals("java.package")) { return BundleInfo.PACKAGE_TYPE; } if (namespace.equals("osgi.bundle")) { return BundleInfo.BUNDLE_TYPE; } return null; } private class ProvidesHandler extends DelegatingHandler { private static final String PROVIDES = "provides"; private static final String SIZE = "size"; List capabilities; String eclipseType; public ProvidesHandler() { super(PROVIDES); addChild(new ProvidedHandler(), new ChildElementHandler() { public void childHanlded(ProvidedHandler child) { if (child.namespace.equals("org.eclipse.equinox.p2.eclipse.type")) { eclipseType = child.name; } else { String type = namespace2Type(child.namespace); if (type == null) { if (logLevel >= Message.MSG_DEBUG) { Message.debug("Unsupported provided capability " + child.namespace + " " + child.name + " " + child.version); } return; } BundleCapability capability; if (type == BundleInfo.PACKAGE_TYPE) { capability = new ExportPackage(child.name, child.version); } else { capability = new BundleCapability(type, child.name, child.version); } capabilities.add(capability); } } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); capabilities = new ArrayList(size); } } private static class ProvidedHandler extends DelegatingHandler { private static final String PROVIDED = "provided"; private static final String NAMESPACE = "namespace"; private static final String NAME = "name"; private static final String VERSION = "version"; String namespace; String name; Version version; public ProvidedHandler() { super(PROVIDED); } protected void handleAttributes(Attributes atts) throws SAXException { namespace = atts.getValue(NAMESPACE); name = atts.getValue(NAME); try { version = new Version(atts.getValue(VERSION)); } catch (ParseException e) { throw new SAXException("Incorrect version on provided capability: " + version + " (" + e.getMessage() + ")"); } } } abstract class AbstractRequirementHandler extends DelegatingHandler { private static final String SIZE = "size"; List requirements; public AbstractRequirementHandler(String name) { super(name); addChild(new RequiredHandler(), new ChildElementHandler() { public void childHanlded(RequiredHandler child) { String name = child.name; VersionRange range = child.range; String type = namespace2Type(child.namespace); if (type == null) { if (logLevel >= Message.MSG_DEBUG) { Message.debug("Unsupported required capability " + child.namespace + " " + name + " " + range); } } else { String resolution = child.optional ? "optional" : null; requirements.add(new BundleRequirement(type, name, range, resolution)); } } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); requirements = new ArrayList(size); } } private class RequiresHandler extends AbstractRequirementHandler { private static final String REQUIRES = "requires"; public RequiresHandler() { super(REQUIRES); } } private class RequiredHandler extends DelegatingHandler { private static final String REQUIRED = "required"; private static final String NAMESPACE = "namespace"; private static final String NAME = "name"; private static final String RANGE = "range"; private static final String OPTIONAL = "optional"; // private static final String GREEDY = "greedy"; String namespace; String name; VersionRange range; // String filter; // // boolean greedy; boolean optional; public RequiredHandler() { super(REQUIRED); // addChild(new FilterHandler(), new ChildElementHandler() { // public void childHanlded(FilterHandler child) { // filter = child.getBufferedChars().trim(); // } // }); } protected void handleAttributes(Attributes atts) throws SAXParseException { namespace = atts.getValue(NAMESPACE); name = atts.getValue(NAME); try { range = new VersionRange(atts.getValue(RANGE)); } catch (ParseException e) { throw new RuntimeException(e); } // greedy = getOptionalBooleanAttribute(atts, GREEDY, Boolean.TRUE).booleanValue(); optional = getOptionalBooleanAttribute(atts, OPTIONAL, Boolean.FALSE).booleanValue(); } } private class HostRequirementsHandler extends AbstractRequirementHandler { private static final String HOST_REQUIREMENTS = "hostRequirements"; public HostRequirementsHandler() { super(HOST_REQUIREMENTS); } } private class MetaRequirementsHandler extends AbstractRequirementHandler { private static final String META_REQUIREMENTS = "metaRequirements"; public MetaRequirementsHandler() { super(META_REQUIREMENTS); } } private class ArtifactsHandler extends DelegatingHandler { private static final String ARTIFACTS = "artifacts"; private static final String SIZE = "size"; List artifacts; public ArtifactsHandler() { super(ARTIFACTS); addChild(new ArtifactHandler(), new ChildElementHandler() { public void childHanlded(ArtifactHandler child) { artifacts.add(child.artifact); } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); artifacts = new ArrayList(size); } } private class ArtifactHandler extends DelegatingHandler { private static final String ARTIFACT = "artifact"; private static final String ID = "id"; private static final String VERSION = "version"; private static final String CLASSIFIER = "classifier"; P2Artifact artifact; public ArtifactHandler() { super(ARTIFACT); } protected void handleAttributes(Attributes atts) throws SAXException { String id = atts.getValue(ID); String version = atts.getValue(VERSION); String classifier = atts.getValue(CLASSIFIER); try { artifact = new P2Artifact(id, new Version(version), classifier); } catch (ParseException e) { throw new SAXException("Incorrect version on artifact '" + id + "': " + version + " (" + e.getMessage() + ")"); } } } // private static class TouchpointHandler extends DelegetingHandler { // // private static final String TOUCHPOINT = "touchpoint"; // // private static final String ID = "id"; // // private static final String VERSION = "version"; // // public TouchpointHandler() { // super(TOUCHPOINT); // } // // protected void handleAttributes(Attributes atts) { // String id = atts.getValue(ID); // String version = atts.getValue(VERSION); // } // // } private class TouchpointDataHandler extends DelegatingHandler { private static final String TOUCHPOINTDATA = "touchpointData"; // private static final String SIZE = "size"; String manifest; Boolean zipped; public TouchpointDataHandler() { super(TOUCHPOINTDATA); addChild(new InstructionsHandler(), new ChildElementHandler() { public void childHanlded(InstructionsHandler child) { manifest = child.manifest; zipped = child.zipped; } }); } protected void handleAttributes(Attributes atts) { // String size = atts.getValue(SIZE); } } private class InstructionsHandler extends DelegatingHandler { private static final String INSTRUCTIONS = "instructions"; // private static final String SIZE = "size"; String manifest; Boolean zipped; public InstructionsHandler() { super(INSTRUCTIONS); addChild(new InstructionHandler(), new ChildElementHandler() { public void childHanlded(InstructionHandler child) { manifest = null; zipped = null; String buffer = child.getBufferedChars().trim(); if ("manifest".equals(child.key)) { manifest = buffer; } else if ("zipped".equals(child.key) && buffer.length() != 0) { zipped = Boolean.valueOf(buffer); } } }); } protected void handleAttributes(Attributes atts) { // String size = atts.getValue(SIZE); } } private class InstructionHandler extends DelegatingHandler { private static final String INSTRUCTION = "instruction"; private static final String KEY = "key"; String key; public InstructionHandler() { super(INSTRUCTION); setBufferingChar(true); } protected void handleAttributes(Attributes atts) { key = atts.getValue(KEY); } } // private static class LicensesHandler extends DelegetingHandler { // // private static final String LICENSES = "licenses"; // // private static final String SIZE = "size"; // // public LicensesHandler() { // super(LICENSES); // addChild(new LicenseHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // } // }); // } // // protected void handleAttributes(Attributes atts) { // String size = atts.getValue(SIZE); // } // // } // private static class LicenseHandler extends DelegetingHandler { // // private static final String LICENSE = "license"; // // private static final String URI = "uri"; // // private static final String URL = "url"; // // public LicenseHandler() { // super(LICENSE); // setBufferingChar(true); // } // // protected void handleAttributes(Attributes atts) { // String uri = atts.getValue(URI); // String url = atts.getValue(URL); // } // // } // private static class CopyrightHandler extends DelegetingHandler { // // private static final String COPYRIGHT = "copyright"; // // private static final String URI = "uri"; // // private static final String URL = "url"; // // public CopyrightHandler() { // super(COPYRIGHT); // } // // protected void handleAttributes(Attributes atts) { // String uri = atts.getValue(URI); // String url = atts.getValue(URL); // } // // } // private class ChangesHandler extends DelegetingHandler { // // private static final String CHANGES = "changes"; // // private static final String SIZE = "size"; // // public ChangesHandler() { // super(CHANGES); // addChild(new ChangeHandler(), new ChildElementHandler() { // public void childHanlded(ChangeHandler child) { // } // }); // } // // protected void handleAttributes(Attributes atts) { // int size = Integer.parseInt(atts.getValue(SIZE)); // } // } // private class ChangeHandler extends DelegetingHandler { // // private static final String CHANGE = "change"; // // public ChangeHandler() { // super(CHANGE); // } // } // private class FromHandler extends AbstractRequirementHandler { // // private static final String FROM = "from"; // // public FromHandler() { // super(FROM); // } // // } // private class ToHandler extends AbstractRequirementHandler { // // private static final String TO = "to"; // // public ToHandler() { // super(TO); // } // // } // private class PatchScopeHandler extends DelegetingHandler { // // private static final String PATCH_SCOPE = "patchScope"; // // private static final String SIZE = "size"; // // public PatchScopeHandler() { // super(PATCH_SCOPE); // addChild(new PatchScopeHandler(), new ChildElementHandler() { // public void childHanlded(PatchScopeHandler child) { // } // }); // } // // protected void handleAttributes(Attributes atts) { // int size = Integer.parseInt(atts.getValue(SIZE)); // } // } // private class ScopeHandler extends DelegetingHandler { // // private static final String SCOPE = "scope"; // // public ScopeHandler() { // super(SCOPE); // addChild(new RequiresHandler(), new ChildElementHandler() { // public void childHanlded(RequiresHandler child) { // } // }); // } // } // private class LifeCycleHandler extends AbstractRequirementHandler { // // private static final String LIFE_CYCLE = "lifeCycle"; // // public LifeCycleHandler() { // super(LIFE_CYCLE); // } // } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/PropertiesParser.java000066400000000000000000000047111226750426600250110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ivy.osgi.util.DelegatingHandler; import org.xml.sax.Attributes; public class PropertiesParser { static class PropertiesHandler extends DelegatingHandler { private static final String PROPERTIES = "properties"; private static final String SIZE = "size"; Map properties; public PropertiesHandler(String... props) { super(PROPERTIES); final List propList = Arrays.asList(props); addChild(new PropertyHandler(), new ChildElementHandler() { public void childHanlded(PropertyHandler child) { if (propList.isEmpty() || propList.contains(child.name)) { properties.put(child.name, child.value); } } }); } protected void handleAttributes(Attributes atts) { int size = Integer.parseInt(atts.getValue(SIZE)); properties = new HashMap(size); } } static class PropertyHandler extends DelegatingHandler { private static final String PROPERTY = "property"; private static final String NAME = "name"; private static final String VALUE = "value"; String name; String value; public PropertyHandler() { super(PROPERTY); } protected void handleAttributes(Attributes atts) { name = atts.getValue(NAME); value = atts.getValue(VALUE); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/p2/XMLInputParser.java000066400000000000000000000021141226750426600243300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.p2; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import org.xml.sax.SAXException; public interface XMLInputParser { public void parse(InputStream in) throws ParseException, IOException, SAXException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/000077500000000000000000000000001226750426600212565ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/AbstractFSManifestIterable.java000066400000000000000000000135471226750426600272660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Stack; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.apache.ivy.util.Message; // T is the type of the resource "path" public abstract class AbstractFSManifestIterable implements Iterable { private final T root; public AbstractFSManifestIterable(T root) { this.root = root; } public Iterator iterator() { return new FSManifestIterator(); } abstract protected List listBundleFiles(T dir) throws IOException; abstract protected List listDirs(T dir) throws IOException; abstract protected InputStream getInputStream(T f) throws IOException; abstract protected URI buildBundleURI(T location) throws IOException; class FSManifestIterator implements Iterator { private ManifestAndLocation next = null; /** * Stack of list of directories. An iterator in the stack represents the current directory * being lookup. The first element in the stack is the root directory. The next element in * the stack is an iterator on the children on the root. The last iterator in the stack * points to {@link #currentDir}. */ private Stack> dirs = new Stack>(); /** * The bundles files being lookup. */ private Iterator bundleCandidates = null; private T currentDir = null; FSManifestIterator() { dirs.add(Collections. singleton(root).iterator()); } /** * Deep first tree lookup for the directories and the bundles are searched on each found * directory. */ public boolean hasNext() { while (next == null) { // no current directory if (currentDir == null) { // so get the next one if (dirs.peek().hasNext()) { currentDir = dirs.peek().next(); try { bundleCandidates = listBundleFiles(currentDir).iterator(); } catch (IOException e) { Message.warn("Unlistable dir: " + currentDir, e); currentDir = null; } } else if (dirs.size() <= 1) { // no next directory, but we are at the root: finished return false; } else { // remove the top of the stack and continue with a sibling. dirs.pop(); } } else if (bundleCandidates.hasNext()) { T bundleCandidate = bundleCandidates.next(); JarInputStream in = null; try { in = new JarInputStream(getInputStream(bundleCandidate)); Manifest manifest = in.getManifest(); if (manifest != null) { next = new ManifestAndLocation(manifest, buildBundleURI(bundleCandidate), null); } else { Message.debug("No manifest in jar: " + bundleCandidate); } } catch (FileNotFoundException e) { Message.debug("Jar file just removed: " + bundleCandidate, e); } catch (IOException e) { Message.warn("Unreadable jar: " + bundleCandidate, e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // Don't care } } } } else { // no more candidate on the current directory // so lookup in the children directories try { dirs.add(listDirs(currentDir).iterator()); } catch (IOException e) { Message.warn("Unlistable dir: " + currentDir + " (" + e + ")"); dirs.add(Collections. emptyList().iterator()); } currentDir = null; } } return true; } public ManifestAndLocation next() { if (!hasNext()) { throw new NoSuchElementException(); } ManifestAndLocation manifest = next; next = null; return manifest; } public void remove() { throw new UnsupportedOperationException(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/AbstractOSGiResolver.java000066400000000000000000000561541226750426600261430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.File; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleInfoAdapter; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.BasicResolver; import org.apache.ivy.plugins.resolver.util.MDResolvedResource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.plugins.resolver.util.ResourceMDParser; import org.apache.ivy.util.Message; public abstract class AbstractOSGiResolver extends BasicResolver { private static final String CAPABILITY_EXTRA_ATTR = "osgi_bundle"; protected static final RepoDescriptor FAILING_REPO_DESCRIPTOR = new EditableRepoDescriptor( null, null); private RepoDescriptor repoDescriptor = null; private URLRepository repository = new URLRepository(); public static class RequirementStrategy { // take the first matching public static RequirementStrategy first = new RequirementStrategy(); // if there are any ambiguity, fail to resolve public static RequirementStrategy noambiguity = new RequirementStrategy(); public static RequirementStrategy valueOf(String strategy) { if (strategy.equals("first")) { return first; } if (strategy.equals("noambiguity")) { return noambiguity; } throw new IllegalStateException(); } } private RequirementStrategy requirementStrategy = RequirementStrategy.noambiguity; public void setRequirementStrategy(RequirementStrategy importPackageStrategy) { this.requirementStrategy = importPackageStrategy; } public void setRequirementStrategy(String strategy) { setRequirementStrategy(RequirementStrategy.valueOf(strategy)); } protected void setRepoDescriptor(RepoDescriptor repoDescriptor) { this.repoDescriptor = repoDescriptor; } public URLRepository getRepository() { return repository; } protected void ensureInit() { if (repoDescriptor == null) { try { init(); } catch (Exception e) { repoDescriptor = FAILING_REPO_DESCRIPTOR; throw new RuntimeException("Error while loading the OSGi repo descriptor" + e.getMessage() + " (" + e.getClass().getName() + ")", e); } } else if (repoDescriptor == FAILING_REPO_DESCRIPTOR) { throw new RuntimeException("The repository " + getName() + " already failed to load"); } } abstract protected void init(); public RepoDescriptor getRepoDescriptor() { ensureInit(); return repoDescriptor; } @Override public boolean isAllownomd() { // this a repo based resolver, we always have md return false; } public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { ModuleRevisionId mrid = dd.getDependencyRevisionId(); String osgiType = mrid.getOrganisation(); if (osgiType == null) { throw new RuntimeException("Unsupported OSGi module Id: " + mrid.getModuleId()); } String id = mrid.getName(); Collection mds = ModuleDescriptorWrapper.unwrap(getRepoDescriptor() .findModules(osgiType, id)); if (mds == null || mds.isEmpty()) { Message.verbose("\t " + id + " not found."); return null; } ResolvedResource[] ret; if (BundleInfo.BUNDLE_TYPE.equals(osgiType)) { ret = findBundle(dd, data, mds); } else { ret = findCapability(dd, data, mds); } ResolvedResource found = findResource(ret, getDefaultRMDParser(dd.getDependencyId()), mrid, data.getDate()); if (found == null) { Message.debug("\t" + getName() + ": no resource found for " + mrid); } return found; } public ResolvedResource[] findBundle(DependencyDescriptor dd, ResolveData data, Collection mds) { ResolvedResource[] ret = new ResolvedResource[mds.size()]; int i = 0; for (ModuleDescriptor md : mds) { MetadataArtifactDownloadReport report = new MetadataArtifactDownloadReport(null); report.setDownloadStatus(DownloadStatus.NO); report.setSearched(true); ResolvedModuleRevision rmr = new ResolvedModuleRevision(this, this, md, report); MDResolvedResource mdrr = new MDResolvedResource(null, md.getRevision(), rmr); ret[i++] = mdrr; } return ret; } public ResolvedResource[] findCapability(DependencyDescriptor dd, ResolveData data, Collection mds) { ResolvedResource[] ret = new ResolvedResource[mds.size()]; int i = 0; for (ModuleDescriptor md : mds) { IvyNode node = data.getNode(md.getModuleRevisionId()); if (node != null && node.getDescriptor() != null) { // already resolved import, no need to go further return new ResolvedResource[] {buildResolvedCapabilityMd(dd, node.getDescriptor())}; } ret[i++] = buildResolvedCapabilityMd(dd, md); } return ret; } private MDResolvedResource buildResolvedCapabilityMd(DependencyDescriptor dd, ModuleDescriptor md) { String org = dd.getDependencyRevisionId().getOrganisation(); String name = dd.getDependencyRevisionId().getName(); String rev = (String) md.getExtraInfo().get( BundleInfoAdapter.EXTRA_INFO_EXPORT_PREFIX + name); ModuleRevisionId capabilityRev = ModuleRevisionId.newInstance(org, name, rev, Collections.singletonMap(CAPABILITY_EXTRA_ATTR, md.getModuleRevisionId().toString())); DefaultModuleDescriptor capabilityMd = new DefaultModuleDescriptor(capabilityRev, getSettings().getStatusManager().getDefaultStatus(), new Date()); String useConf = BundleInfoAdapter.CONF_USE_PREFIX + dd.getDependencyRevisionId().getName(); capabilityMd.addConfiguration(BundleInfoAdapter.CONF_DEFAULT); capabilityMd.addConfiguration(BundleInfoAdapter.CONF_OPTIONAL); capabilityMd.addConfiguration(BundleInfoAdapter.CONF_TRANSITIVE_OPTIONAL); capabilityMd.addConfiguration(new Configuration(useConf)); DefaultDependencyDescriptor capabilityDD = new DefaultDependencyDescriptor( md.getModuleRevisionId(), false); capabilityDD.addDependencyConfiguration(BundleInfoAdapter.CONF_NAME_DEFAULT, BundleInfoAdapter.CONF_NAME_DEFAULT); capabilityDD.addDependencyConfiguration(BundleInfoAdapter.CONF_NAME_OPTIONAL, BundleInfoAdapter.CONF_NAME_OPTIONAL); capabilityDD.addDependencyConfiguration(BundleInfoAdapter.CONF_NAME_TRANSITIVE_OPTIONAL, BundleInfoAdapter.CONF_NAME_TRANSITIVE_OPTIONAL); capabilityDD.addDependencyConfiguration(useConf, useConf); capabilityMd.addDependency(capabilityDD); MetadataArtifactDownloadReport report = new MetadataArtifactDownloadReport(null); report.setDownloadStatus(DownloadStatus.NO); report.setSearched(true); ResolvedModuleRevision rmr = new ResolvedModuleRevision(this, this, capabilityMd, report); return new MDResolvedResource(null, capabilityMd.getRevision(), rmr); } @Override public ResolvedResource findResource(ResolvedResource[] rress, ResourceMDParser rmdparser, ModuleRevisionId mrid, Date date) { ResolvedResource found = super.findResource(rress, rmdparser, mrid, date); String osgiType = mrid.getOrganisation(); // for non bundle requirement : log the selected bundle if (!BundleInfo.BUNDLE_TYPE.equals(osgiType)) { // several candidates with different symbolic name : make an warning about the ambiguity if (rress.length != 1) { // several candidates with different symbolic name ? Map> matching = new HashMap>(); for (int i = 0; i < rress.length; i++) { String name = ((MDResolvedResource) rress[i]).getResolvedModuleRevision() .getDescriptor().getExtraAttribute(CAPABILITY_EXTRA_ATTR); List list = matching.get(name); if (list == null) { list = new ArrayList(); matching.put(name, list); } list.add((MDResolvedResource) rress[i]); } if (matching.keySet().size() != 1) { if (requirementStrategy == RequirementStrategy.first) { Message.warn("Ambiguity for the '" + osgiType + "' requirement " + mrid.getName() + ";version=" + mrid.getRevision()); for (Entry> entry : matching.entrySet()) { Message.warn("\t" + entry.getKey()); for (MDResolvedResource c : entry.getValue()) { Message.warn("\t\t" + c.getRevision() + (found == c ? " (selected)" : "")); } } } else if (requirementStrategy == RequirementStrategy.noambiguity) { Message.error("Ambiguity for the '" + osgiType + "' requirement " + mrid.getName() + ";version=" + mrid.getRevision()); for (Entry> entry : matching.entrySet()) { Message.error("\t" + entry.getKey()); for (MDResolvedResource c : entry.getValue()) { Message.error("\t\t" + c.getRevision() + (found == c ? " (best match)" : "")); } } return null; } } } Message.info("'" + osgiType + "' requirement " + mrid.getName() + ";version=" + mrid.getRevision() + " satisfied by " + ((MDResolvedResource) found).getResolvedModuleRevision().getId().getName() + ";" + found.getRevision()); } return found; } public ResolvedResource findArtifactRef(Artifact artifact, Date date) { URL url = artifact.getUrl(); if (url == null) { // not an artifact resolved by this resolver return null; } Message.verbose("\tusing url for " + artifact + ": " + url); logArtifactAttempt(artifact, url.toExternalForm()); Resource resource = new URLResource(url); return new ResolvedResource(resource, artifact.getModuleRevisionId().getRevision()); } @Override protected void checkModuleDescriptorRevision(ModuleDescriptor systemMd, ModuleRevisionId systemMrid) { String osgiType = systemMrid.getOrganisation(); // only check revision if we're searching for a bundle (package and bundle have different // version if (osgiType == null || osgiType.equals(BundleInfo.BUNDLE_TYPE)) { super.checkModuleDescriptorRevision(systemMd, systemMrid); } } @Override protected Collection/* */filterNames(Collection/* */names) { getSettings().filterIgnore(names); return names; } @Override protected Collection findNames(Map tokenValues, String token) { if (IvyPatternHelper.ORGANISATION_KEY.equals(token)) { return getRepoDescriptor().getCapabilities(); } String osgiType = (String) tokenValues.get(IvyPatternHelper.ORGANISATION_KEY); if (osgiType == null || osgiType.length() == 0) { return Collections.EMPTY_LIST; } if (IvyPatternHelper.MODULE_KEY.equals(token)) { return getRepoDescriptor().getCapabilityValues(osgiType); } if (IvyPatternHelper.REVISION_KEY.equals(token)) { String name = (String) tokenValues.get(IvyPatternHelper.MODULE_KEY); List versions = new ArrayList(); Set mds = getRepoDescriptor().findModules(osgiType, name); if (mds != null) { for (ModuleDescriptorWrapper md : mds) { versions.add(md.getBundleInfo().getVersion().toString()); } } return versions; } if (IvyPatternHelper.CONF_KEY.equals(token)) { String name = (String) tokenValues.get(IvyPatternHelper.MODULE_KEY); if (name == null) { return Collections.EMPTY_LIST; } if (osgiType.equals(BundleInfo.PACKAGE_TYPE)) { return Collections.singletonList(BundleInfoAdapter.CONF_USE_PREFIX + name); } Collection mds = ModuleDescriptorWrapper.unwrap(getRepoDescriptor() .findModules(osgiType, name)); if (mds == null) { return Collections.EMPTY_LIST; } String version = (String) tokenValues.get(IvyPatternHelper.REVISION_KEY); if (version == null) { return Collections.EMPTY_LIST; } ModuleDescriptor found = null; for (ModuleDescriptor md : mds) { if (md.getRevision().equals(version)) { found = md; } } if (found == null) { return Collections.EMPTY_LIST; } List confs = Arrays.asList(found.getConfigurationsNames()); return confs; } return Collections.EMPTY_LIST; } /** * Populate capabilityValues with capability values for which at least one module match the * expected revision */ private void filterCapabilityValues(Set capabilityValues, Map> moduleByCapbilityValue, Map tokenValues, String rev) { if (rev == null) { // no revision, all match then capabilityValues.addAll(moduleByCapbilityValue.keySet()); } else { for (Entry> entry : moduleByCapbilityValue.entrySet()) { Iterator itModules = entry.getValue().iterator(); boolean moduleMatchRev = false; while (!moduleMatchRev && itModules.hasNext()) { ModuleDescriptor md = itModules.next(); moduleMatchRev = rev.equals(md.getRevision()); } if (moduleMatchRev) { // at least one module matched, the capability value is ok to add capabilityValues.add(entry.getKey()); } } } } @Override public Map[] listTokenValues(String[] tokens, Map criteria) { Set tokenSet = new HashSet(Arrays.asList(tokens)); Set> listTokenValues = listTokenValues(tokenSet, criteria); return listTokenValues.toArray(new Map[listTokenValues.size()]); } private Set> listTokenValues(Set tokens, Map criteria) { if (tokens.isEmpty()) { return Collections.singleton(criteria); } Set remainingTokens = new HashSet(tokens); Map values = new HashMap(); remainingTokens.remove(IvyPatternHelper.ORGANISATION_KEY); String osgiType = criteria.get(IvyPatternHelper.ORGANISATION_KEY); if (osgiType == null || osgiType.length() == 0) { return Collections.emptySet(); } values.put(IvyPatternHelper.ORGANISATION_KEY, osgiType); if (osgiType == null) { Set> tokenValues = new HashSet>(); Map newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.ORGANISATION_KEY, BundleInfo.BUNDLE_TYPE); tokenValues.addAll(listTokenValues(remainingTokens, newCriteria)); newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.ORGANISATION_KEY, BundleInfo.PACKAGE_TYPE); tokenValues.addAll(listTokenValues(remainingTokens, newCriteria)); newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.ORGANISATION_KEY, BundleInfo.SERVICE_TYPE); tokenValues.addAll(listTokenValues(remainingTokens, newCriteria)); return tokenValues; } Set capabilities = getRepoDescriptor().getCapabilityValues(osgiType); if (capabilities == null || capabilities.isEmpty()) { return Collections.emptySet(); } remainingTokens.remove(IvyPatternHelper.MODULE_KEY); String module = criteria.get(IvyPatternHelper.MODULE_KEY); if (module == null) { Set> tokenValues = new HashSet>(); for (String name : capabilities) { Map newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.MODULE_KEY, name); tokenValues.addAll(listTokenValues(remainingTokens, newCriteria)); } return tokenValues; } values.put(IvyPatternHelper.MODULE_KEY, module); remainingTokens.remove(IvyPatternHelper.REVISION_KEY); String rev = criteria.get(IvyPatternHelper.REVISION_KEY); if (rev == null) { Set mdws = getRepoDescriptor().findModules(osgiType, module); if (mdws == null || mdws.isEmpty()) { return Collections.emptySet(); } Set> tokenValues = new HashSet>(); for (ModuleDescriptorWrapper mdw : mdws) { Map newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.REVISION_KEY, mdw.getBundleInfo().getVersion() .toString()); tokenValues.addAll(listTokenValues(remainingTokens, newCriteria)); } return tokenValues; } values.put(IvyPatternHelper.REVISION_KEY, rev); remainingTokens.remove(IvyPatternHelper.CONF_KEY); String conf = criteria.get(IvyPatternHelper.CONF_KEY); if (conf == null) { if (osgiType.equals(BundleInfo.PACKAGE_TYPE)) { values.put(IvyPatternHelper.CONF_KEY, BundleInfoAdapter.CONF_USE_PREFIX + module); return Collections.singleton(values); } Set bundles = getRepoDescriptor() .findModules(osgiType, module); if (bundles == null) { return Collections.emptySet(); } Version v; try { v = new Version(rev); } catch (ParseException e) { return Collections.emptySet(); } ModuleDescriptorWrapper found = null; for (ModuleDescriptorWrapper bundle : bundles) { if (bundle.getBundleInfo().getVersion().equals(v)) { found = bundle; } } if (found == null) { return Collections.emptySet(); } Set> tokenValues = new HashSet>(); List configurations = BundleInfoAdapter .getConfigurations(found.getBundleInfo()); for (int i = 0; i < configurations.size(); i++) { Map newCriteria = new HashMap(criteria); newCriteria.put(IvyPatternHelper.CONF_KEY, configurations.get(i)); tokenValues.add(newCriteria); } return tokenValues; } values.put(IvyPatternHelper.CONF_KEY, conf); return Collections.singleton(values); } protected long get(Resource resource, File dest) throws IOException { Message.verbose("\t" + getName() + ": downloading " + resource.getName()); Message.debug("\t\tto " + dest); if (dest.getParentFile() != null) { dest.getParentFile().mkdirs(); } getRepository().get(resource.getName(), dest); return dest.length(); } protected Resource getResource(String source) throws IOException { return getRepository().getResource(source); } public void publish(Artifact artifact, File src, boolean overwrite) throws IOException { throw new UnsupportedOperationException(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/AggregatedOSGiResolver.java000066400000000000000000000026661226750426600264310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.util.ArrayList; import java.util.List; public class AggregatedOSGiResolver extends AbstractOSGiResolver { private List resolvers = new ArrayList(); public void add(AbstractOSGiResolver resolver) { resolvers.add(resolver); } @Override protected void init() { List repos = new ArrayList(); for (AbstractOSGiResolver resolver : resolvers) { repos.add(resolver.getRepoDescriptor()); } setRepoDescriptor(new AggregatedRepoDescriptor(repos)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/AggregatedRepoDescriptor.java000066400000000000000000000072431226750426600270460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; public class AggregatedRepoDescriptor extends RepoDescriptor { private List repos; public AggregatedRepoDescriptor(List repos) { this.repos = repos; } @Override public Iterator getModules() { final Iterator itRepos = repos.iterator(); return new Iterator() { private Iterator current = null; private ModuleDescriptorWrapper next = null; public boolean hasNext() { while (next == null) { if (current == null) { if (!itRepos.hasNext()) { return false; } RepoDescriptor repo = itRepos.next(); current = repo.getModules(); } if (current.hasNext()) { next = current.next(); } else { current = null; } } return true; } public ModuleDescriptorWrapper next() { if (!hasNext()) { throw new NoSuchElementException(); } ModuleDescriptorWrapper ret = next; next = null; return ret; } public void remove() { throw new UnsupportedOperationException(); } }; } @Override public Set getCapabilities() { Set ret = new HashSet(); for (RepoDescriptor repo : repos) { Set capabilities = repo.getCapabilities(); if (capabilities != null) { ret.addAll(capabilities); } } return ret; } @Override public Set findModules(String requirement, String value) { Set ret = new HashSet(); for (RepoDescriptor repo : repos) { Set modules = repo.findModules(requirement, value); if (modules != null) { ret.addAll(modules); } } return ret; } @Override public Set getCapabilityValues(String capabilityName) { Set ret = new HashSet(); for (RepoDescriptor repo : repos) { Set capabilityValues = repo.getCapabilityValues(capabilityName); if (capabilityValues != null) { ret.addAll(capabilityValues); } } return ret; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/ArtifactReportManifestIterable.java000066400000000000000000000154331226750426600302170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.util.Message; public class ArtifactReportManifestIterable implements Iterable { private final Map> artifactReports = new HashMap>(); private List sourceTypes; public ArtifactReportManifestIterable(List reports, List sourceTypes) { this.sourceTypes = sourceTypes; for (ArtifactDownloadReport report : reports) { ModuleRevisionId mrid = report.getArtifact().getModuleRevisionId(); List moduleReports = artifactReports.get(mrid); if (moduleReports == null) { moduleReports = new ArrayList(); artifactReports.put(mrid, moduleReports); } moduleReports.add(report); } } public Iterator iterator() { return new ArtifactReportManifestIterator(); } class ArtifactReportManifestIterator implements Iterator { private ManifestAndLocation next = null; private Iterator it; public ArtifactReportManifestIterator() { it = artifactReports.keySet().iterator(); } public boolean hasNext() { while (next == null && it.hasNext()) { ModuleRevisionId mrid = it.next(); List reports = artifactReports.get(mrid); ArtifactDownloadReport jar = null; ArtifactDownloadReport source = null; for (ArtifactDownloadReport report : reports) { if (sourceTypes != null && sourceTypes.contains(report.getArtifact().getType())) { source = report; } else { jar = report; } } if (jar == null) { // didn't found any suitable jar continue; } URI sourceURI = null; if (source != null) { if (source.getUnpackedLocalFile() != null) { sourceURI = source.getUnpackedLocalFile().toURI(); } else { sourceURI = source.getLocalFile().toURI(); } } if (jar.getUnpackedLocalFile() != null && jar.getUnpackedLocalFile().isDirectory()) { FileInputStream in = null; try { in = new FileInputStream(new File(jar.getUnpackedLocalFile(), "META-INF/MANIFEST.MF")); next = new ManifestAndLocation(new Manifest(in), jar.getUnpackedLocalFile() .toURI(), sourceURI); return true; } catch (FileNotFoundException e) { Message.debug( "Bundle directory file just removed: " + jar.getUnpackedLocalFile(), e); } catch (IOException e) { Message.debug("The Manifest in the bundle directory could not be read: " + jar.getUnpackedLocalFile(), e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } } } else { File artifact; if (jar.getUnpackedLocalFile() != null) { artifact = jar.getUnpackedLocalFile(); } else { artifact = jar.getLocalFile(); } JarInputStream in = null; try { in = new JarInputStream(new FileInputStream(artifact)); Manifest manifest = in.getManifest(); if (manifest != null) { next = new ManifestAndLocation(manifest, artifact.toURI(), sourceURI); return true; } Message.debug("No manifest in jar: " + artifact); } catch (FileNotFoundException e) { Message.debug("Jar file just removed: " + artifact, e); } catch (IOException e) { Message.warn("Unreadable jar: " + artifact, e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // Don't care } } } } } if (next == null) { return false; } return true; } public ManifestAndLocation next() { if (!hasNext()) { throw new NoSuchElementException(); } ManifestAndLocation manifest = next; next = null; return manifest; } public void remove() { throw new UnsupportedOperationException(); } } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/BundleCapabilityAndLocation.java000066400000000000000000000031341226750426600274510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.util.Version; public class BundleCapabilityAndLocation { private final String name; private final Version version; private final BundleInfo bundleInfo; private final String type; public BundleCapabilityAndLocation(String type, String name, Version version, BundleInfo bundleInfo) { this.type = type; this.name = name; this.version = version; this.bundleInfo = bundleInfo; } public BundleInfo getBundleInfo() { return bundleInfo; } public String getName() { return name; } public String getType() { return type; } public Version getVersion() { return version; } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/BundleRepoDescriptor.java000066400000000000000000000045511226750426600262240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.net.URI; import java.text.ParseException; import java.util.Iterator; import org.apache.ivy.osgi.core.BundleArtifact; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.core.ManifestParser; import org.apache.ivy.util.Message; public class BundleRepoDescriptor extends EditableRepoDescriptor { private String name; private String lastModified; public BundleRepoDescriptor(URI baseUri, ExecutionEnvironmentProfileProvider profileProvider) { super(baseUri, profileProvider); } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setLastModified(String lastModified) { this.lastModified = lastModified; } public String getLastModified() { return lastModified; } public void populate(Iterator it) { while (it.hasNext()) { ManifestAndLocation manifestAndLocation = it.next(); try { BundleInfo bundleInfo = ManifestParser.parseManifest(manifestAndLocation .getManifest()); bundleInfo .addArtifact(new BundleArtifact(false, manifestAndLocation.getUri(), null)); addBundle(bundleInfo); } catch (ParseException e) { Message.error("Rejected " + manifestAndLocation.getUri() + ": " + e.getMessage()); } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/EditableRepoDescriptor.java000066400000000000000000000134351226750426600265250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.ivy.osgi.core.BundleCapability; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.Message; public class EditableRepoDescriptor extends RepoDescriptor { private final Map>> moduleByCapabilities = new HashMap>>(); private final Set modules = new HashSet(); private final ExecutionEnvironmentProfileProvider profileProvider; private final URI baseUri; private int logLevel = Message.MSG_INFO; public EditableRepoDescriptor(URI baseUri, ExecutionEnvironmentProfileProvider profileProvider) { this.baseUri = baseUri; this.profileProvider = profileProvider; } public void setLogLevel(int logLevel) { this.logLevel = logLevel; } public int getLogLevel() { return logLevel; } public URI getBaseUri() { return baseUri; } public Iterator getModules() { return modules.iterator(); } public Set getCapabilities() { return moduleByCapabilities.keySet(); } public Set findModules(String requirement, String value) { Map> modules = moduleByCapabilities.get(requirement); if (modules == null) { return null; } return modules.get(value); } public ModuleDescriptorWrapper findModule(String symbolicName, Version version) { Set modules = findModules(BundleInfo.BUNDLE_TYPE, symbolicName); if (modules == null) { return null; } for (ModuleDescriptorWrapper module : modules) { if (module.getBundleInfo().getVersion().equals(version)) { return module; } } return null; } public Set getCapabilityValues(String capabilityName) { Map> modules = moduleByCapabilities .get(capabilityName); if (modules == null) { return Collections.emptySet(); } return modules.keySet(); } private void add(String type, String value, ModuleDescriptorWrapper md) { modules.add(md); Map> map = moduleByCapabilities.get(type); if (map == null) { map = new HashMap>(); moduleByCapabilities.put(type, map); } Set bundleReferences = map.get(value); if (bundleReferences == null) { bundleReferences = new HashSet(); map.put(value, bundleReferences); } if (!bundleReferences.add(md)) { if (logLevel <= Message.MSG_DEBUG) { Message.debug("Duplicate module in the repo " + baseUri + " for " + type + " " + value + ": " + md.getBundleInfo().getSymbolicName() + "#" + md.getBundleInfo().getVersion()); } } } public void addBundle(BundleInfo bundleInfo) { ModuleDescriptorWrapper module = findModule(bundleInfo.getSymbolicName(), bundleInfo.getVersion()); if (module != null) { Message.debug("Duplicate module " + bundleInfo.getSymbolicName() + "@" + bundleInfo.getVersion()); return; } ModuleDescriptorWrapper md = new ModuleDescriptorWrapper(bundleInfo, baseUri, profileProvider); add(BundleInfo.BUNDLE_TYPE, bundleInfo.getSymbolicName(), md); for (BundleCapability capability : bundleInfo.getCapabilities()) { add(capability.getType(), capability.getName(), md); } } @Override public String toString() { return modules.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((modules == null) ? 0 : modules.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } EditableRepoDescriptor other = (EditableRepoDescriptor) obj; if (modules == null) { if (other.modules != null) { return false; } } else if (!modules.equals(other.modules)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/FSManifestIterable.java000066400000000000000000000101161226750426600255670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; public class FSManifestIterable extends AbstractFSManifestIterable { /** * List of directory name that usually contains jars but are not bundles */ public static final Set NON_BUNDLE_DIRS = new HashSet(Arrays.asList("source", "sources", "javadoc", "javadocs", "doc", "docs")); /** * Default directory filter that doesn't select .svn directories, neither the directories that * match {@link #NON_BUNDLE_DIRS}. */ public static final FilenameFilter DEFAULT_DIR_FILTER = new FilenameFilter() { public boolean accept(File dir, String name) { return !name.equals(".svn") && !NON_BUNDLE_DIRS.contains(name); } }; /** * Default bundle filter that select only .jar files */ public static final FilenameFilter DEFAULT_BUNLDE_FILTER = new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".jar"); } }; private FilenameFilter dirFilter = DEFAULT_DIR_FILTER; private FilenameFilter bundleFilter = DEFAULT_BUNLDE_FILTER; /** * Default constructor * * @param root * the root directory of the file system to lookup */ public FSManifestIterable(File root) { super(root); } public FilenameFilter getDirFilter() { return dirFilter; } public void setDirFilter(FilenameFilter dirFilter) { this.dirFilter = dirFilter; } public FilenameFilter getBundleFilter() { return bundleFilter; } public void setBundleFilter(FilenameFilter bundleFilter) { this.bundleFilter = bundleFilter; } protected URI buildBundleURI(File location) { try { return new URI(location.toURI().toURL().toExternalForm()); } catch (MalformedURLException e) { throw new RuntimeException("Unexpected file to url conversion error", e); } catch (URISyntaxException e) { throw new RuntimeException("Unexpected url to uri conversion error", e); } } protected InputStream getInputStream(File f) throws FileNotFoundException { return new FileInputStream(f); } protected List listBundleFiles(File dir) { return Arrays.asList(dir.listFiles(new FileFilter() { public boolean accept(File f) { if (!f.isFile()) { return false; } return bundleFilter.accept(f.getParentFile(), f.getName()); } })); } protected List listDirs(File dir) { return Arrays.asList(dir.listFiles(new FileFilter() { public boolean accept(File f) { if (!f.isDirectory()) { return false; } return dirFilter == null || dirFilter.accept(f.getParentFile(), f.getName()); } })); } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/ManifestAndLocation.java000066400000000000000000000027321226750426600260070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.net.URI; import java.util.jar.Manifest; public class ManifestAndLocation { private final Manifest manifest; /** * location of the jar */ private final URI uri; /** * location of the source jar */ private final URI sourceURI; public ManifestAndLocation(Manifest manifest, URI uri, URI sourceURI) { this.manifest = manifest; this.uri = uri; this.sourceURI = sourceURI; } public URI getUri() { return uri; } public Manifest getManifest() { return manifest; } public URI getSourceURI() { return sourceURI; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/ModuleDescriptorWrapper.java000066400000000000000000000062271226750426600267550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleInfoAdapter; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.core.OSGiManifestParser; public class ModuleDescriptorWrapper { private BundleInfo bundleInfo; private DefaultModuleDescriptor md; private URI baseUri; private ExecutionEnvironmentProfileProvider profileProvider; public ModuleDescriptorWrapper(BundleInfo bundleInfo, URI baseUri, ExecutionEnvironmentProfileProvider profileProvider) { this.bundleInfo = bundleInfo; this.baseUri = baseUri; this.profileProvider = profileProvider; } public BundleInfo getBundleInfo() { return bundleInfo; } public DefaultModuleDescriptor getModuleDescriptor() { if (md == null) { synchronized (this) { if (md != null) { return md; } md = BundleInfoAdapter.toModuleDescriptor(OSGiManifestParser.getInstance(), baseUri, bundleInfo, profileProvider); } } return md; } public static Collection unwrap(Collection collection) { if (collection == null) { return null; } if (collection.isEmpty()) { return Collections.emptyList(); } List unwrapped = new ArrayList(); for (ModuleDescriptorWrapper wrapped : collection) { unwrapped.add(wrapped.getModuleDescriptor()); } return unwrapped; } @Override public int hashCode() { return bundleInfo.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof ModuleDescriptorWrapper)) { return false; } return bundleInfo.equals(((ModuleDescriptorWrapper) obj).bundleInfo); } @Override public String toString() { return getModuleDescriptor().toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/RelativeURLRepository.java000066400000000000000000000045421226750426600263640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Map; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; public class RelativeURLRepository extends URLRepository { private final URL baseUrl; public RelativeURLRepository() { super(); baseUrl = null; } public RelativeURLRepository(URL baseUrl) { super(); this.baseUrl = baseUrl; } private Map resourcesCache = new HashMap(); public Resource getResource(String source) throws IOException { source = encode(source); Resource res = resourcesCache.get(source); if (res == null) { URI uri; try { uri = new URI(source); } catch (URISyntaxException e) { // very wierd URL, let's assume it is absolute uri = null; } if (uri == null || uri.isAbsolute()) { res = new URLResource(new URL(source)); } else { res = new URLResource(new URL(baseUrl + source)); } resourcesCache.put(source, res); } return res; } private static String encode(String source) { // TODO: add some more URL encodings here return source.trim().replaceAll(" ", "%20"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/RepoDescriptor.java000066400000000000000000000023271226750426600250710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.util.Iterator; import java.util.Set; public abstract class RepoDescriptor { abstract public Iterator getModules(); abstract public Set getCapabilities(); abstract public Set findModules(String requirement, String value); abstract public Set getCapabilityValues(String capabilityName); } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/RepositoryManifestIterable.java000066400000000000000000000047551226750426600274520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.util.ResolverHelper; public class RepositoryManifestIterable extends AbstractFSManifestIterable { private final Repository repo; /** * Default constructor * * @param root * the root directory of the file system to lookup */ public RepositoryManifestIterable(Repository repo) { super(""); this.repo = repo; } protected URI buildBundleURI(String location) throws IOException { Resource resource = repo.getResource(location); // We have a resource to transform into an URI, let's use some heuristics try { return new URI(resource.getName()); } catch (URISyntaxException e) { return new File(resource.getName()).toURI(); } } protected InputStream getInputStream(String f) throws IOException { return repo.getResource(f).openStream(); } protected List listBundleFiles(String dir) throws IOException { return asList(ResolverHelper.listAll(repo, dir)); } protected List listDirs(String dir) throws IOException { return asList(ResolverHelper.listAll(repo, dir)); } private List asList(String[] array) { return array == null ? Collections. emptyList() : Arrays. asList(array); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/repo/ResolverManifestIterable.java000066400000000000000000000170141226750426600270640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.repo; import java.io.IOException; import java.net.URI; import java.text.ParseException; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.sort.SortEngine; import org.apache.ivy.osgi.core.BundleInfoAdapter; import org.apache.ivy.plugins.resolver.BasicResolver; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; public class ResolverManifestIterable implements Iterable { // We should support the interface DependencyResolver, but the API is not convenient to get // references to artifact private final BasicResolver resolver; public ResolverManifestIterable(BasicResolver resolver) { this.resolver = resolver; } public Iterator iterator() { return new ResolverManifestIterator(); } class ResolverManifestIterator implements Iterator { private OrganisationEntry[] organisations; private int indexOrganisation = 0; private OrganisationEntry organisation; private ModuleEntry[] modules; private int indexModule = -1; private ModuleEntry module; private ManifestAndLocation next = null; private RevisionEntry[] revisions; private int indexRevision; private RevisionEntry revision; private Artifact[] artifacts; private int indexArtifact; private Artifact artifact; private ModuleRevisionId mrid; private ResolveData data; public ResolverManifestIterator() { organisations = resolver.listOrganisations(); IvySettings settings = new IvySettings(); ResolveEngine engine = new ResolveEngine(settings, new EventManager(), new SortEngine( settings)); data = new ResolveData(engine, new ResolveOptions()); } public boolean hasNext() { while (next == null) { if (organisation == null) { if (indexOrganisation >= organisations.length) { return false; } organisation = organisations[indexOrganisation++]; modules = resolver.listModules(organisation); indexModule = 0; module = null; } if (module == null) { if (indexModule >= modules.length) { organisation = null; continue; } module = modules[indexModule++]; revisions = resolver.listRevisions(module); indexRevision = 0; revision = null; } if (revision == null) { if (indexRevision >= revisions.length) { module = null; continue; } revision = revisions[indexRevision++]; mrid = ModuleRevisionId.newInstance(organisation.getOrganisation(), module.getModule(), revision.getRevision()); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(mrid, false); ResolvedModuleRevision dependency; try { dependency = resolver.getDependency(dd, data); } catch (ParseException e) { Message.error("Error while resolving " + mrid + " : " + e.getMessage()); revision = null; continue; } if (dependency == null) { revision = null; continue; } ModuleDescriptor md = dependency.getDescriptor(); mrid = md.getModuleRevisionId(); artifacts = md.getAllArtifacts(); indexArtifact = 0; artifact = null; } if (artifact == null) { if (indexArtifact >= artifacts.length) { revision = null; continue; } artifact = artifacts[indexArtifact++]; } ResolvedResource resource = resolver.doFindArtifactRef(artifact, null); if (resource == null) { artifact = null; continue; } JarInputStream in; try { in = new JarInputStream(resource.getResource().openStream()); } catch (IOException e) { Message.warn("Unreadable jar " + resource.getResource().getName() + " (" + e.getMessage() + ")"); artifact = null; continue; } Manifest manifest; try { manifest = in.getManifest(); } finally { try { in.close(); } catch (IOException e) { // don't care } } if (manifest == null) { Message.debug("No manifest on " + artifact); } else { URI uri = BundleInfoAdapter.buildIvyURI(artifact); next = new ManifestAndLocation(manifest, uri, null); } artifact = null; } return true; } public ManifestAndLocation next() { if (!hasNext()) { throw new NoSuchElementException(); } ManifestAndLocation manifest = next; next = null; return manifest; } public void remove() { throw new UnsupportedOperationException(); } } }ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/000077500000000000000000000000001226750426600224605ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/PluginAdapter.java000066400000000000000000000061311226750426600260630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite; import java.net.URI; import org.apache.ivy.osgi.core.BundleArtifact; import org.apache.ivy.osgi.core.BundleInfo; import org.apache.ivy.osgi.core.BundleRequirement; import org.apache.ivy.osgi.updatesite.xml.EclipseFeature; import org.apache.ivy.osgi.updatesite.xml.EclipsePlugin; import org.apache.ivy.osgi.updatesite.xml.Require; import org.apache.ivy.osgi.util.VersionRange; public class PluginAdapter { public static BundleInfo featureAsBundle(URI baseUri, EclipseFeature feature) { BundleInfo b = new BundleInfo(feature.getId(), feature.getVersion()); URI uri; if (feature.getUrl() == null) { uri = baseUri.resolve("features/" + feature.getId() + '_' + feature.getVersion() + ".jar"); } else { uri = baseUri.resolve(feature.getUrl()); } b.addArtifact(new BundleArtifact(false, uri, null)); b.setDescription(feature.getDescription()); b.setLicense(feature.getLicense()); for (EclipsePlugin plugin : feature.getPlugins()) { BundleRequirement r = new BundleRequirement(BundleInfo.BUNDLE_TYPE, plugin.getId(), new VersionRange(plugin.getVersion()), null); b.addRequirement(r); } for (Require require : feature.getRequires()) { String id; if (require.getPlugin() != null) { id = require.getPlugin(); } else { id = require.getFeature(); } VersionRange range; if (require.getMatch().equals("greaterOrEqual")) { range = new VersionRange(require.getVersion()); } else { throw new IllegalStateException("unsupported match " + require.getMatch()); } BundleRequirement r = new BundleRequirement(BundleInfo.BUNDLE_TYPE, id, range, null); b.addRequirement(r); } return b; } public static BundleInfo pluginAsBundle(URI baseUri, EclipsePlugin plugin) { BundleInfo b = new BundleInfo(plugin.getId(), plugin.getVersion()); URI uri = baseUri.resolve("plugins/" + plugin.getId() + '_' + plugin.getVersion() + ".jar"); b.addArtifact(new BundleArtifact(false, uri, null)); return b; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/UpdateSiteDescriptor.java000066400000000000000000000031221226750426600274270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite; import java.net.URI; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.repo.EditableRepoDescriptor; import org.apache.ivy.osgi.updatesite.xml.EclipseFeature; import org.apache.ivy.osgi.updatesite.xml.EclipsePlugin; public class UpdateSiteDescriptor extends EditableRepoDescriptor { public UpdateSiteDescriptor(URI baseUri, ExecutionEnvironmentProfileProvider profileProvider) { super(baseUri, profileProvider); } public void addFeature(EclipseFeature feature) { addBundle(PluginAdapter.featureAsBundle(getBaseUri(), feature)); for (EclipsePlugin plugin : feature.getPlugins()) { addBundle(PluginAdapter.pluginAsBundle(getBaseUri(), plugin)); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/UpdateSiteLoader.java000066400000000000000000000316321226750426600265260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.ivy.core.cache.CacheResourceOptions; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.p2.P2ArtifactParser; import org.apache.ivy.osgi.p2.P2CompositeParser; import org.apache.ivy.osgi.p2.P2Descriptor; import org.apache.ivy.osgi.p2.P2MetadataParser; import org.apache.ivy.osgi.p2.XMLInputParser; import org.apache.ivy.osgi.repo.RepoDescriptor; import org.apache.ivy.osgi.updatesite.xml.EclipseFeature; import org.apache.ivy.osgi.updatesite.xml.EclipseUpdateSiteParser; import org.apache.ivy.osgi.updatesite.xml.FeatureParser; import org.apache.ivy.osgi.updatesite.xml.UpdateSite; import org.apache.ivy.osgi.updatesite.xml.UpdateSiteDigestParser; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; public class UpdateSiteLoader { private final RepositoryCacheManager repositoryCacheManager; private final URLRepository urlRepository = new URLRepository(); private final CacheResourceOptions options; private int logLevel = Message.MSG_INFO; public UpdateSiteLoader(RepositoryCacheManager repositoryCacheManager, EventManager eventManager, CacheResourceOptions options) { this.repositoryCacheManager = repositoryCacheManager; this.options = options; if (eventManager != null) { urlRepository.addTransferListener(eventManager); } } public void setLogLevel(int logLevel) { this.logLevel = logLevel; } public RepoDescriptor load(URI repoUri) throws IOException, ParseException, SAXException { if (!repoUri.toString().endsWith("/")) { try { repoUri = new URI(repoUri.toString() + "/"); } catch (URISyntaxException e) { throw new RuntimeException("Cannot make an uri for the repo"); } } Message.info("Loading the update site " + repoUri); // first look for a p2 repository RepoDescriptor repo = loadP2(repoUri); if (repo != null) { return repo; } Message.verbose("\tNo P2 artifacts, falling back on the old fashioned updatesite"); // then try the old update site UpdateSite site = loadSite(repoUri); if (site == null) { return null; } repo = loadFromDigest(site); if (repo != null) { return repo; } return loadFromSite(site); } private P2Descriptor loadP2(URI repoUri) throws IOException, ParseException, SAXException { P2Descriptor p2Descriptor = new P2Descriptor(repoUri, ExecutionEnvironmentProfileProvider.getInstance()); p2Descriptor.setLogLevel(logLevel); if (!populateP2Descriptor(repoUri, p2Descriptor)) { return null; } p2Descriptor.finish(); return p2Descriptor; } private boolean populateP2Descriptor(URI repoUri, P2Descriptor p2Descriptor) throws IOException, ParseException, SAXException { Message.verbose("Loading P2 repository " + repoUri); boolean contentExists = readContent(repoUri, p2Descriptor); boolean artifactExists = readArtifacts(repoUri, p2Descriptor); return artifactExists || contentExists; } private boolean readContent(URI repoUri, P2Descriptor p2Descriptor) throws IOException, ParseException, SAXException { boolean contentExists = readCompositeContent(repoUri, "compositeContent", p2Descriptor); if (!contentExists) { P2MetadataParser metadataParser = new P2MetadataParser(p2Descriptor); metadataParser.setLogLevel(logLevel); contentExists = readJarOrXml(repoUri, "content", metadataParser); } return contentExists; } private boolean readArtifacts(URI repoUri, P2Descriptor p2Descriptor) throws IOException, ParseException, SAXException { boolean artifactExists = readCompositeArtifact(repoUri, "compositeArtifacts", p2Descriptor); if (!artifactExists) { artifactExists = readJarOrXml(repoUri, "artifacts", new P2ArtifactParser(p2Descriptor, repoUri.toURL().toExternalForm())); } return artifactExists; } private boolean readCompositeContent(URI repoUri, String name, P2Descriptor p2Descriptor) throws IOException, ParseException, SAXException { P2CompositeParser p2CompositeParser = new P2CompositeParser(); boolean exist = readJarOrXml(repoUri, name, p2CompositeParser); if (exist) { for (String childLocation : p2CompositeParser.getChildLocations()) { if (!childLocation.endsWith("/")) { childLocation += "/"; } URI childUri = repoUri.resolve(childLocation); readContent(childUri, p2Descriptor); } } return exist; } private boolean readCompositeArtifact(URI repoUri, String name, P2Descriptor p2Descriptor) throws IOException, ParseException, SAXException { P2CompositeParser p2CompositeParser = new P2CompositeParser(); boolean exist = readJarOrXml(repoUri, name, p2CompositeParser); if (exist) { for (String childLocation : p2CompositeParser.getChildLocations()) { if (!childLocation.endsWith("/")) { childLocation += "/"; } URI childUri = repoUri.resolve(childLocation); readArtifacts(childUri, p2Descriptor); } } return exist; } private boolean readJarOrXml(URI repoUri, String baseName, XMLInputParser reader) throws IOException, ParseException, SAXException { InputStream readIn = null; // the input stream from which the xml should be read URL contentUrl = repoUri.resolve(baseName + ".jar").toURL(); URLResource res = new URLResource(contentUrl); ArtifactDownloadReport report = repositoryCacheManager.downloadRepositoryResource(res, baseName, baseName, "jar", options, urlRepository); if (report.getDownloadStatus() == DownloadStatus.FAILED) { // no jar file, try the xml one contentUrl = repoUri.resolve(baseName + ".xml").toURL(); res = new URLResource(contentUrl); report = repositoryCacheManager.downloadRepositoryResource(res, baseName, baseName, "xml", options, urlRepository); if (report.getDownloadStatus() == DownloadStatus.FAILED) { // no xml either return false; } readIn = new FileInputStream(report.getLocalFile()); } else { InputStream in = new FileInputStream(report.getLocalFile()); try { // compressed, let's get the pointer on the actual xml readIn = findEntry(in, baseName + ".xml"); if (readIn == null) { in.close(); return false; } } catch (IOException e) { in.close(); throw e; } } try { reader.parse(readIn); } finally { readIn.close(); } return true; } private UpdateSite loadSite(URI repoUri) throws IOException, ParseException, SAXException { URI siteUri = normalizeSiteUri(repoUri, null); URL u = siteUri.resolve("site.xml").toURL(); URLResource res = new URLResource(u); ArtifactDownloadReport report = repositoryCacheManager.downloadRepositoryResource(res, "site", "updatesite", "xml", options, urlRepository); if (report.getDownloadStatus() == DownloadStatus.FAILED) { return null; } InputStream in = new FileInputStream(report.getLocalFile()); try { UpdateSite site = EclipseUpdateSiteParser.parse(in); site.setUri(normalizeSiteUri(site.getUri(), siteUri)); return site; } finally { in.close(); } } private URI normalizeSiteUri(URI uri, URI defaultValue) { if (uri == null) { return defaultValue; } String uriString = uri.toString(); if (uriString.endsWith("site.xml")) { try { return new URI(uriString.substring(0, uriString.length() - 8)); } catch (URISyntaxException e) { throw new RuntimeException("Illegal uri", e); } } if (!uriString.endsWith("/")) { try { return new URI(uriString + "/"); } catch (URISyntaxException e) { throw new RuntimeException("Illegal uri", e); } } return uri; } private UpdateSiteDescriptor loadFromDigest(UpdateSite site) throws IOException, ParseException, SAXException { URI digestBaseUri = site.getDigestUri(); if (digestBaseUri == null) { digestBaseUri = site.getUri(); } else if (!digestBaseUri.isAbsolute()) { digestBaseUri = site.getUri().resolve(digestBaseUri); } URL digest = digestBaseUri.resolve("digest.zip").toURL(); Message.verbose("\tReading " + digest); URLResource res = new URLResource(digest); ArtifactDownloadReport report = repositoryCacheManager.downloadRepositoryResource(res, "digest", "digest", "zip", options, urlRepository); if (report.getDownloadStatus() == DownloadStatus.FAILED) { return null; } InputStream in = new FileInputStream(report.getLocalFile()); try { ZipInputStream zipped = findEntry(in, "digest.xml"); if (zipped == null) { return null; } return UpdateSiteDigestParser.parse(zipped, site); } finally { in.close(); } } private UpdateSiteDescriptor loadFromSite(UpdateSite site) throws IOException, ParseException, SAXException { UpdateSiteDescriptor repoDescriptor = new UpdateSiteDescriptor(site.getUri(), ExecutionEnvironmentProfileProvider.getInstance()); for (EclipseFeature feature : site.getFeatures()) { URL url = site.getUri().resolve(feature.getUrl()).toURL(); URLResource res = new URLResource(url); ArtifactDownloadReport report = repositoryCacheManager.downloadRepositoryResource(res, feature.getId(), "feature", "jar", options, urlRepository); if (report.getDownloadStatus() == DownloadStatus.FAILED) { return null; } InputStream in = new FileInputStream(report.getLocalFile()); try { ZipInputStream zipped = findEntry(in, "feature.xml"); if (zipped == null) { return null; } EclipseFeature f = FeatureParser.parse(zipped); f.setURL(feature.getUrl()); repoDescriptor.addFeature(f); } finally { in.close(); } } return repoDescriptor; } private ZipInputStream findEntry(InputStream in, String entryName) throws IOException { ZipInputStream zipped = new ZipInputStream(in); ZipEntry zipEntry = zipped.getNextEntry(); while (zipEntry != null && !zipEntry.getName().equals(entryName)) { zipEntry = zipped.getNextEntry(); } if (zipEntry == null) { return null; } return zipped; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/UpdateSiteResolver.java000066400000000000000000000125661226750426600271260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.CacheResourceOptions; import org.apache.ivy.core.cache.DownloadListener; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.osgi.repo.AbstractOSGiResolver; import org.apache.ivy.osgi.repo.RepoDescriptor; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; public class UpdateSiteResolver extends AbstractOSGiResolver { private String url; private Long metadataTtl; private Boolean forceMetadataUpdate; private String logLevel; public void setUrl(String url) { this.url = url; } public void setMetadataTtl(Long metadataTtl) { this.metadataTtl = metadataTtl; } public void setForceMetadataUpdate(Boolean forceMetadataUpdate) { this.forceMetadataUpdate = forceMetadataUpdate; } public void setLogLevel(String logLevel) { this.logLevel = logLevel; } protected void init() { if (url == null) { throw new RuntimeException("Missing url"); } CacheResourceOptions options = new CacheResourceOptions(); if (metadataTtl != null) { options.setTtl(metadataTtl.longValue()); } if (forceMetadataUpdate != null) { options.setForce(forceMetadataUpdate.booleanValue()); } final int log; if (logLevel != null) { if ("debug".equalsIgnoreCase(logLevel)) { log = Message.MSG_DEBUG; } else if ("verbose".equalsIgnoreCase(logLevel)) { log = Message.MSG_VERBOSE; } else if ("info".equalsIgnoreCase(logLevel)) { log = Message.MSG_INFO; } else if ("warn".equalsIgnoreCase(logLevel)) { log = Message.MSG_WARN; } else if ("error".equalsIgnoreCase(logLevel)) { log = Message.MSG_ERR; } else { throw new RuntimeException("Unknown log level: " + logLevel); } } else { log = Message.MSG_INFO; } options.setListener(new DownloadListener() { public void startArtifactDownload(RepositoryCacheManager cache, ResolvedResource rres, Artifact artifact, ArtifactOrigin origin) { if (log <= Message.MSG_INFO) { Message.info("\tdownloading " + rres.getResource().getName()); } } public void needArtifact(RepositoryCacheManager cache, Artifact artifact) { if (log <= Message.MSG_VERBOSE) { Message.verbose("\ttrying to download " + artifact); } } public void endArtifactDownload(RepositoryCacheManager cache, Artifact artifact, ArtifactDownloadReport adr, File archiveFile) { if (log <= Message.MSG_VERBOSE) { if (adr.isDownloaded()) { Message.verbose("\tdownloaded to " + archiveFile.getAbsolutePath()); } else { Message.verbose("\tnothing to download"); } } } }); UpdateSiteLoader loader = new UpdateSiteLoader(getRepositoryCacheManager(), getEventManager(), options); loader.setLogLevel(log); RepoDescriptor repoDescriptor; try { repoDescriptor = loader.load(new URI(url)); } catch (IOException e) { throw new RuntimeException("IO issue while trying to read the update site (" + e.getMessage() + ")"); } catch (ParseException e) { throw new RuntimeException("Failed to parse the updatesite (" + e.getMessage() + ")", e); } catch (SAXException e) { throw new RuntimeException("Illformed updatesite (" + e.getMessage() + ")", e); } catch (URISyntaxException e) { throw new RuntimeException("Illformed url (" + e.getMessage() + ")", e); } if (repoDescriptor == null) { setRepoDescriptor(FAILING_REPO_DESCRIPTOR); throw new RuntimeException("No update site was found at the location: " + url); } setRepoDescriptor(repoDescriptor); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/000077500000000000000000000000001226750426600232605ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/Archive.java000066400000000000000000000020521226750426600255030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; public class Archive { public void setPath(String path) { // TODO Auto-generated method stub } public void setURL(String url) { // TODO Auto-generated method stub } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/CategoryDef.java000066400000000000000000000022231226750426600263160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; public class CategoryDef { public void setLabel(String label) { // TODO Auto-generated method stub } public void setName(String name) { // TODO Auto-generated method stub } public void setDescription(String trim) { // TODO Auto-generated method stub } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/EclipseFeature.java000066400000000000000000000074541226750426600270350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import java.util.ArrayList; import java.util.List; import org.apache.ivy.osgi.util.Version; public class EclipseFeature { private String id; private Version version; private List plugins = new ArrayList(); private List requires = new ArrayList(); private String url; private String description; private String license; public EclipseFeature(String id, Version version) { this.id = id; this.version = version; this.url = "features/" + id + '_' + version + ".jar"; } public void setURL(String url) { this.url = url; } public String getUrl() { return url; } public void setType(String type) { // TODO Auto-generated method stub } public String getId() { return id; } public Version getVersion() { return version; } public void setLabel(String label) { // TODO Auto-generated method stub } public void setOS(String os) { // TODO Auto-generated method stub } public void setWS(String ws) { // TODO Auto-generated method stub } public void setNL(String nl) { // TODO Auto-generated method stub } public void setArch(String arch) { // TODO Auto-generated method stub } public void setPatch(String patch) { // TODO Auto-generated method stub } public void addCategory(String name) { // TODO Auto-generated method stub } public void setDescription(String description) { this.description = description; } public String getDescription() { return description; } public void setCopyright(String trim) { // not useful } public void setLicense(String license) { this.license = license; } public String getLicense() { return license; } public void addPlugin(EclipsePlugin plugin) { plugins.add(plugin); } public List getPlugins() { return plugins; } public void addRequire(Require require) { requires.add(require); } public List getRequires() { return requires; } public void setApplication(String value) { // TODO Auto-generated method stub } public void setPlugin(String value) { // TODO Auto-generated method stub } public void setExclusive(boolean booleanValue) { // TODO Auto-generated method stub } public void setPrimary(boolean booleanValue) { // TODO Auto-generated method stub } public void setColocationAffinity(String value) { // TODO Auto-generated method stub } public void setProviderName(String value) { // TODO Auto-generated method stub } public void setImage(String value) { // TODO Auto-generated method stub } public String toString() { return id + "#" + version; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/EclipsePlugin.java000066400000000000000000000030061226750426600266650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import org.apache.ivy.osgi.util.Version; public class EclipsePlugin { private String id; private Version version; public void setId(String id) { this.id = id; } public String getId() { return id; } public void setVersion(Version version) { this.version = version; } public Version getVersion() { return version; } public void setUnpack(boolean valueOf) { // TODO Auto-generated method stub } public void setFragment(String value) { // TODO Auto-generated method stub } public void setFilter(String value) { // TODO Auto-generated method stub } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/EclipseUpdateSiteParser.java000066400000000000000000000216521226750426600306620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; public class EclipseUpdateSiteParser { public static UpdateSite parse(InputStream in) throws ParseException, IOException, SAXException { SiteHandler handler = new SiteHandler(); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } return handler.updatesite; } private static class SiteHandler extends DelegatingHandler { private static final String SITE = "site"; private static final String URL = "url"; private static final String PACK200 = "pack200"; private static final String MIRRORS_URL = "mirrorsURL"; private static final String ASSOCIATE_SITES_URL = "associateSitesURL"; private static final String DIGEST_URL = "digestURL"; UpdateSite updatesite; public SiteHandler() { super(SITE); // addChild(new DescriptionHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // updateSite.setDescription(child.getBufferedChars().trim()); // } // }); addChild(new FeatureHandler(), new ChildElementHandler() { public void childHanlded(FeatureHandler child) { updatesite.addFeature(child.feature); } }); // addChild(new ArchiveHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // updateSite.addArchive(((ArchiveHandler) child).archive); // } // }); // addChild(new CategoryDefHandler(), new ChildElementHandler() { // public void childHanlded(DelegetingHandler child) { // updateSite.addCategoryDef(((CategoryDefHandler) child).categoryDef); // } // }); } protected void handleAttributes(Attributes atts) { updatesite = new UpdateSite(); String url = atts.getValue(URL); if (url != null && !("".equals(url.trim()))) { if (!url.endsWith("/") && !url.endsWith(File.separator)) { url += "/"; } try { updatesite.setUri(new URI(url)); } catch (URISyntaxException e) { throw new RuntimeException("illegal url", e); } } String mirrorsURL = atts.getValue(MIRRORS_URL); if (mirrorsURL != null && mirrorsURL.trim().length() > 0) { updatesite.setMirrorsURL(mirrorsURL); } String pack200 = atts.getValue(PACK200); if (pack200 != null && new Boolean(pack200).booleanValue()) { updatesite.setPack200(true); } String digestURL = atts.getValue(DIGEST_URL); if (digestURL != null) { try { updatesite.setDigestUri(new URI(digestURL)); } catch (URISyntaxException e) { throw new RuntimeException("illegal url", e); } } String associateSitesURL = atts.getValue(ASSOCIATE_SITES_URL); if (associateSitesURL != null) { updatesite.setAssociateSitesURL(associateSitesURL); } } } // private static class DescriptionHandler extends DelegetingHandler { // // private static final String DESCRIPTION = "description"; // // private static final String URL = "url"; // // public DescriptionHandler() { // super(DESCRIPTION); // setBufferingChar(true); // } // // protected void handleAttributes(Attributes atts) { // String url = atts.getValue(URL); // } // } private static class FeatureHandler extends DelegatingHandler { private static final String FEATURE = "feature"; private static final String VERSION = "version"; private static final String ID = "id"; private static final String URL = "url"; private static final String PATCH = "patch"; private static final String ARCH = "arch"; private static final String NL = "nl"; private static final String WS = "ws"; private static final String OS = "os"; private static final String LABEL = "label"; private static final String TYPE = "type"; private EclipseFeature feature; public FeatureHandler() { super(FEATURE); addChild(new CategoryHandler(), new ChildElementHandler() { public void childHanlded(CategoryHandler child) { feature.addCategory(child.name); } }); } protected void handleAttributes(Attributes atts) throws SAXException { String id = atts.getValue(ID); String version = atts.getValue(VERSION); try { feature = new EclipseFeature(id, new Version(version)); } catch (ParseException e) { throw new SAXException("Incorrect version on the feature '" + id + "': " + version + " (" + e.getMessage() + ")"); } String url = atts.getValue(URL); if (url != null) { feature.setURL(url); } feature.setType(atts.getValue(TYPE)); feature.setLabel(atts.getValue(LABEL)); feature.setOS(atts.getValue(OS)); feature.setWS(atts.getValue(WS)); feature.setNL(atts.getValue(NL)); feature.setArch(atts.getValue(ARCH)); feature.setPatch(atts.getValue(PATCH)); } } private static class CategoryHandler extends DelegatingHandler { private static final String CATEGORY = "category"; private static final String NAME = "name"; String name; public CategoryHandler() { super(CATEGORY); } protected void handleAttributes(Attributes atts) throws SAXException { name = atts.getValue(NAME); } } // private static class ArchiveHandler extends DelegetingHandler { // // private static final String ARCHIVE = "archive"; // // private static final String URL = "url"; // // private static final String PATH = "path"; // // private Archive archive; // // public ArchiveHandler() { // super(ARCHIVE); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // archive = new Archive(); // // String path = atts.getValue(PATH); // archive.setPath(path); // // String url = atts.getValue(URL); // archive.setURL(url); // // } // } // private static class CategoryDefHandler extends DelegetingHandler { // // private static final String CATEGORY_DEF = "category-def"; // // private static final String NAME = "name"; // // private static final String LABEL = "label"; // // private CategoryDef categoryDef; // // public CategoryDefHandler() { // super(CATEGORY_DEF); // addChild(new DescriptionHandler(), new ChildElementHandler() { // public void childHanlded(DescriptionHandler child) { // categoryDef.setDescription(child.getBufferedChars().trim()); // } // }); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // categoryDef = new CategoryDef(); // // String name = atts.getValue(NAME); // categoryDef.setName(name); // // String label = atts.getValue(LABEL); // categoryDef.setLabel(label); // } // } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/FeatureParser.java000066400000000000000000000310101226750426600266660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.osgi.util.Version; import org.apache.ivy.util.XMLHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; public class FeatureParser { public static EclipseFeature parse(InputStream in) throws ParseException, IOException, SAXException { FeatureHandler handler = new FeatureHandler(); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } return handler.feature; } static class FeatureHandler extends DelegatingHandler { private static final String FEATURE = "feature"; private static final String COLOCATION_AFFINITY = "colocation-affinity"; private static final String PRIMARY = "primary"; private static final String EXCLUSIVE = "exclusive"; private static final String PLUGIN = "plugin"; private static final String APPLICATION = "application"; private static final String ARCH = "arch"; private static final String NL = "nl"; private static final String WS = "ws"; private static final String OS = "os"; private static final String VERSION = "version"; private static final String ID = "id"; private static final String PROVIDER_NAME = "provider-name"; private static final String LABEL = "label"; private static final String IMAGE = "image"; EclipseFeature feature; public FeatureHandler() { super(FEATURE); addChild(new DescriptionHandler(), new ChildElementHandler() { public void childHanlded(DescriptionHandler child) { feature.setDescription(child.getBufferedChars().trim()); } }); addChild(new LicenseHandler(), new ChildElementHandler() { public void childHanlded(LicenseHandler child) { feature.setLicense(child.getBufferedChars().trim()); } }); addChild(new CopyrightHandler(), new ChildElementHandler() { public void childHanlded(CopyrightHandler child) { feature.setCopyright(child.getBufferedChars().trim()); } }); addChild(new PluginHandler(), new ChildElementHandler() { public void childHanlded(PluginHandler child) { feature.addPlugin(child.plugin); } }); addChild(new RequiresHandler(), new ChildElementHandler() { public void childHanlded(RequiresHandler child) { for (Require require : child.requires) { feature.addRequire(require); } } }); // addChild(new UrlHandler(), new ChildElementHandler() { // public void childHanlded(UrlHandler child) { // } // }); } protected void handleAttributes(Attributes atts) throws SAXException { String id = atts.getValue(ID); String version = atts.getValue(VERSION); try { feature = new EclipseFeature(id, new Version(version)); } catch (ParseException e) { throw new SAXException("Incorrect version on feature '" + id + "': " + version + " (" + e.getMessage() + ")"); } feature.setOS(atts.getValue(OS)); feature.setWS(atts.getValue(WS)); feature.setNL(atts.getValue(NL)); feature.setArch(atts.getValue(ARCH)); feature.setApplication(atts.getValue(APPLICATION)); feature.setPlugin(atts.getValue(PLUGIN)); feature.setExclusive(Boolean.valueOf(atts.getValue(EXCLUSIVE)).booleanValue()); feature.setPrimary(Boolean.valueOf(atts.getValue(PRIMARY)).booleanValue()); feature.setColocationAffinity(atts.getValue(COLOCATION_AFFINITY)); feature.setProviderName(atts.getValue(PROVIDER_NAME)); feature.setLabel(atts.getValue(LABEL)); feature.setImage(atts.getValue(IMAGE)); } } private static class PluginHandler extends DelegatingHandler { private static final String PLUGIN = "plugin"; private static final String FILTER = "filter"; private static final String FRAGMENT = "fragment"; private static final String UNPACK = "unpack"; private static final String VERSION = "version"; private static final String ID = "id"; private EclipsePlugin plugin; public PluginHandler() { super(PLUGIN); } protected void handleAttributes(Attributes atts) throws SAXException { plugin = new EclipsePlugin(); String id = atts.getValue(ID); String version = atts.getValue(VERSION); plugin.setId(id); try { plugin.setVersion(new Version(version)); } catch (ParseException e) { throw new SAXException("Incorrect version on feature's plugin '" + id + "': " + version + " (" + e.getMessage() + ")"); } plugin.setUnpack(Boolean.valueOf(atts.getValue(UNPACK)).booleanValue()); plugin.setFragment(atts.getValue(FRAGMENT)); plugin.setFilter(atts.getValue(FILTER)); } } private static class DescriptionHandler extends DelegatingHandler { private static final String DESCRIPTION = "description"; // private static final String URL = "url"; public DescriptionHandler() { super(DESCRIPTION); setBufferingChar(true); } protected void handleAttributes(Attributes atts) throws SAXException { // String url = atts.getValue(URL); } } private static class LicenseHandler extends DelegatingHandler { private static final String LICENSE = "license"; // private static final String URL = "url"; public LicenseHandler() { super(LICENSE); setBufferingChar(true); } protected void handleAttributes(Attributes atts) throws SAXException { // String url = atts.getValue(URL); } } private static class CopyrightHandler extends DelegatingHandler { private static final String COPYRIGHT = "copyright"; // private static final String URL = "url"; public CopyrightHandler() { super(COPYRIGHT); setBufferingChar(true); } protected void handleAttributes(Attributes atts) throws SAXException { // String url = atts.getValue(URL); } } static class RequiresHandler extends DelegatingHandler { private static final String REQUIRES = "requires"; List requires = new ArrayList(); public RequiresHandler() { super(REQUIRES); addChild(new ImportHandler(), new ChildElementHandler() { public void childHanlded(ImportHandler child) { requires.add(child.require); } }); } } private static class ImportHandler extends DelegatingHandler { Require require; private static final String IMPORT = "import"; private static final String FILTER = "filter"; private static final String MATCH = "match"; private static final String VERSION = "version"; private static final String PLUGIN = "plugin"; private static final String FEATURE = "feature"; public ImportHandler() { super(IMPORT); } protected void handleAttributes(Attributes atts) throws SAXException { require = new Require(); String version = atts.getValue(VERSION); require.setFeature(atts.getValue(FEATURE)); require.setPlugin(atts.getValue(PLUGIN)); try { require.setVersion(new Version(version)); } catch (ParseException e) { throw new SAXException("Incorrect version on feature's import: " + version + " (" + e.getMessage() + ")"); } require.setMatch(atts.getValue(MATCH)); require.setFilter(atts.getValue(FILTER)); } } // private static class IncludesHandler extends DelegetingHandler { // // private static final String INCLUDES = "includes"; // // private static final String FILTER = "filter"; // // private static final String OPTIONAL = "optional"; // // private static final String VERSION = "version"; // // private static final String ID = "id"; // // public IncludesHandler() { // super(INCLUDES); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // String id = atts.getValue(ID); // String version = atts.getValue(VERSION); // String optional = atts.getValue(OPTIONAL); // String filter = atts.getValue(FILTER); // } // // } // private static class InstallHandlerHandler extends DelegetingHandler { // // private static final String INSTALL_HANDLER = "install-handler"; // // private static final String URL = "url"; // // private static final String LIBRARY = "library"; // // private static final String HANDLER = "handler"; // // public InstallHandlerHandler() { // super(INSTALL_HANDLER); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // String handler = atts.getValue(HANDLER); // String library = atts.getValue(LIBRARY); // String url = atts.getValue(URL); // } // // } // private static class UrlHandler extends DelegetingHandler { // // private static final String URL = "url"; // // public UrlHandler() { // super(URL); // addChild(new UpdateHandler(), new ChildElementHandler() { // public void childHanlded(UpdateHandler child) { // } // }); // addChild(new DiscoveryHandler(), new ChildElementHandler() { // public void childHanlded(DiscoveryHandler child) { // } // }); // } // // } // private static class UpdateHandler extends DelegetingHandler { // // private static final String UPDATE = "update"; // // private static final String LABEL = "label"; // // private static final String URL = "url"; // // public UpdateHandler() { // super(UPDATE); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // String label = atts.getValue(LABEL); // String url = atts.getValue(URL); // } // // } // private static class DiscoveryHandler extends DelegetingHandler { // // private static final String DISCOVERY = "discovery"; // // private static final String URL = "url"; // // private static final String LABEL = "label"; // // private static final String TYPE = "type"; // // public DiscoveryHandler() { // super(DISCOVERY); // } // // protected void handleAttributes(Attributes atts) throws SAXException { // String type = atts.getValue(TYPE); // String label = atts.getValue(LABEL); // String url = atts.getValue(URL); // } // // } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/Require.java000066400000000000000000000033751226750426600255470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import org.apache.ivy.osgi.util.Version; public class Require { private String plugin; private String feature; private Version version; private String match; private String filter; public void setFeature(String feature) { this.feature = feature; } public String getFeature() { return feature; } public void setPlugin(String plugin) { this.plugin = plugin; } public String getPlugin() { return plugin; } public void setVersion(Version version) { this.version = version; } public Version getVersion() { return version; } public void setMatch(String match) { this.match = match; } public String getMatch() { return match; } public void setFilter(String filter) { this.filter = filter; } public String getFilter() { return filter; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/UpdateSite.java000066400000000000000000000035301226750426600261730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import java.net.URI; import java.util.ArrayList; import java.util.List; public class UpdateSite { private URI uri; private String mirrorsURL; private boolean pack200; private URI digestUri; private List features = new ArrayList(); public void setUri(URI uri) { this.uri = uri; } public URI getUri() { return uri; } public void setMirrorsURL(String mirrorsURL) { this.mirrorsURL = mirrorsURL; } public void setPack200(boolean pack200) { this.pack200 = pack200; } public void setDigestUri(URI digestUri) { this.digestUri = digestUri; } public URI getDigestUri() { return digestUri; } public void addFeature(EclipseFeature feature) { features.add(feature); } public List getFeatures() { return features; } public void setAssociateSitesURL(String associateSitesURL) { // TODO what's that ? } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/updatesite/xml/UpdateSiteDigestParser.java000066400000000000000000000046031226750426600305120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.updatesite.xml; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.osgi.core.ExecutionEnvironmentProfileProvider; import org.apache.ivy.osgi.updatesite.UpdateSiteDescriptor; import org.apache.ivy.osgi.updatesite.xml.FeatureParser.FeatureHandler; import org.apache.ivy.osgi.util.DelegatingHandler; import org.apache.ivy.util.XMLHelper; import org.xml.sax.SAXException; public class UpdateSiteDigestParser { public static UpdateSiteDescriptor parse(InputStream in, UpdateSite site) throws ParseException, IOException, SAXException { DigestHandler handler = new DigestHandler(site); try { XMLHelper.parse(in, null, handler, null); } catch (ParserConfigurationException e) { throw new SAXException(e); } return handler.repoDescriptor; } static class DigestHandler extends DelegatingHandler { private static final String DIGEST = "digest"; UpdateSiteDescriptor repoDescriptor; public DigestHandler(final UpdateSite site) { super(DIGEST); repoDescriptor = new UpdateSiteDescriptor(site.getUri(), ExecutionEnvironmentProfileProvider.getInstance()); addChild(new FeatureHandler(), new ChildElementHandler() { public void childHanlded(FeatureHandler child) { repoDescriptor.addFeature(child.feature); } }); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/000077500000000000000000000000001226750426600212665ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/DelegatingHandler.java000066400000000000000000000464211226750426600255010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.ivy.util.Message; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; public class DelegatingHandler extends DefaultHandler implements DTDHandler, ContentHandler, ErrorHandler { private DelegatingHandler delegate = null; DelegatingHandler parent; private final Map saxHandlerMapping = new HashMap(); private final Map> childHandlerMapping = new HashMap>(); private final String tagName; private boolean started = false; private boolean skip = false; private boolean skipOnError = false; private StringBuffer charBuffer = new StringBuffer(); private boolean bufferingChar = false; private Locator locator; public DelegatingHandler(String name) { this.tagName = name; charBuffer.setLength(0); } protected void addChild(DH saxHandler, ChildElementHandler elementHandler) { saxHandlerMapping.put(saxHandler.getName(), saxHandler); childHandlerMapping.put(saxHandler.getName(), elementHandler); saxHandler.parent = this; } public String getName() { return tagName; } public DelegatingHandler getParent() { return parent; } public void setBufferingChar(boolean bufferingChar) { this.bufferingChar = bufferingChar; } public void setSkipOnError(boolean skipOnError) { this.skipOnError = skipOnError; } public boolean isBufferingChar() { return bufferingChar; } public String getBufferedChars() { return charBuffer.toString(); } public void setDocumentLocator(Locator locator) { this.locator = locator; for (DelegatingHandler subHandler : saxHandlerMapping.values()) { subHandler.setDocumentLocator(locator); } } public Locator getLocator() { return locator; } /** * Return an sort of identifier of the current element being parsed. It will only be used for * logging purpose. * * @return an empty string by default */ protected String getCurrentElementIdentifier() { return ""; } public void skip() { skip = true; for (DelegatingHandler subHandler : saxHandlerMapping.values()) { subHandler.stopDelegating(); } } protected void stopDelegating() { parent.delegate = null; skip = false; started = false; for (DelegatingHandler/* */subHandler : saxHandlerMapping.values()) { subHandler.stopDelegating(); } } private interface SkipOnErrorCallback { public void call() throws SAXException; } private void skipOnError(SkipOnErrorCallback callback) throws SAXException { try { callback.call(); } catch (SAXException e) { if (skipOnError) { skip(); log(Message.MSG_ERR, e.getMessage(), e); } else { throw e; } } } public final void startDocument() throws SAXException { if (skip) { return; } if (delegate != null) { delegate.startDocument(); } else { doStartDocument(); } } /** * @throws SAXException */ protected void doStartDocument() throws SAXException { // by default do nothing } public final void endDocument() throws SAXException { if (skip) { return; } if (delegate != null) { delegate.endDocument(); } else { doEndDocument(); } } /** * @throws SAXException */ protected void doEndDocument() throws SAXException { // by default do nothing } public final void startElement(final String uri, final String localName, final String n, final Attributes atts) throws SAXException { // reset the char buffer charBuffer.setLength(0); if (delegate != null) { // we are already delegating, let's continue skipOnError(new SkipOnErrorCallback() { public void call() throws SAXException { delegate.startElement(uri, localName, n, atts); } }); } else { if (!started) { // first time called ? // just for the root, check the expected element name // not need to check the delegated as the mapping is already taking care of it if (parent == null && !localName.equals(tagName)) { // we are at the root and the saxed element doesn't match throw new SAXException("The root element of the parsed document '" + localName + "' didn't matched the expected one: '" + tagName + "'"); } skipOnError(new SkipOnErrorCallback() { public void call() throws SAXException { handleAttributes(atts); } }); started = true; } else { if (skip) { // we con't care anymore about that part of the xml tree return; } // time now to delegate for a new element delegate = saxHandlerMapping.get(localName); if (delegate != null) { skipOnError(new SkipOnErrorCallback() { public void call() throws SAXException { delegate.startElement(uri, localName, n, atts); } }); } } } } /** * Called when the expected node is achieved * * @param atts * the xml attributes attached to the expected node * @exception SAXException * in case the parsing should be completely stopped */ protected void handleAttributes(Attributes atts) throws SAXException { // nothing to do by default } /** * @throws SAXException */ protected void doStartElement(String uri, String localName, String name, Attributes atts) throws SAXException { // by default do nothing } public final void endElement(final String uri, final String localName, final String n) throws SAXException { if (delegate != null) { final DelegatingHandler savedDelegate = delegate; // we are already delegating, let's continue skipOnError(new SkipOnErrorCallback() { public void call() throws SAXException { delegate.endElement(uri, localName, n); } }); if (delegate == null) { // we just stopped delegating, it means that the child has ended final ChildElementHandler childHandler = childHandlerMapping.get(localName); if (childHandler != null) { skipOnError(new SkipOnErrorCallback() { public void call() throws SAXException { childHandler._childHanlded(savedDelegate); } }); } } } else { if (!skip) { doEndElement(uri, localName, n); } if (parent != null && tagName.equals(localName)) { // the current element is closed, let's tell the parent to stop delegating stopDelegating(); } } } /** * @throws SAXException */ protected void doEndElement(String uri, String localName, String name) throws SAXException { // by default do nothing } public static abstract class ChildElementHandler { public abstract void childHanlded(DH child) throws SAXParseException; // because we know what we're doing @SuppressWarnings("unchecked") private void _childHanlded(DelegatingHandler delegate) throws SAXParseException { childHanlded((DH) delegate); } } public final void characters(char[] ch, int start, int length) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.characters(ch, start, length); } else { doCharacters(ch, start, length); } } /** * @throws SAXException */ protected void doCharacters(char[] ch, int start, int length) throws SAXException { if (bufferingChar) { charBuffer.append(ch, start, length); } } public final void startPrefixMapping(String prefix, String uri) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.startPrefixMapping(prefix, uri); } else { doStartPrefixMapping(prefix, uri); } } /** * @throws SAXException */ protected void doStartPrefixMapping(String prefix, String uri) throws SAXException { // by default do nothing } public final void endPrefixMapping(String prefix) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.endPrefixMapping(prefix); } else { doEndPrefixMapping(prefix); } } /** * @throws SAXException */ protected void doEndPrefixMapping(String prefix) throws SAXException { // by default do nothing } public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.ignorableWhitespace(ch, start, length); } else { doIgnorableWhitespace(ch, start, length); } } /** * @throws SAXException */ protected void doIgnorableWhitespace(char[] ch, int start, int length) throws SAXException { // by default do nothing } public final void notationDecl(String name, String publicId, String systemId) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.notationDecl(name, publicId, systemId); } else { doNotationDecl(name, publicId, systemId); } } /** * @throws SAXException */ protected void doNotationDecl(String name, String publicId, String systemId) throws SAXException { // by default do nothing } public final void processingInstruction(String target, String data) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.processingInstruction(target, data); } else { doProcessingInstruction(target, data); } } /** * @throws SAXException */ protected void doProcessingInstruction(String target, String data) throws SAXException { // by default do nothing } public final void skippedEntity(String name) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.skippedEntity(name); } else { doSkippedEntity(name); } } /** * @throws SAXException */ protected void doSkippedEntity(String name) throws SAXException { // by default do nothing } /** * @throws SAXException */ public final void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.unparsedEntityDecl(name, publicId, systemId, notationName); } else { doUnparsedEntityDecl(name, publicId, systemId, notationName); } } /** * @throws SAXException */ protected void doUnparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { // by default do nothing } // ERROR HANDLING public final void warning(SAXParseException exception) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.warning(exception); } else { doWarning(exception); } } /** * @throws SAXException */ protected void doWarning(SAXParseException exception) throws SAXException { // by default do nothing } public final void error(SAXParseException exception) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.error(exception); } else { doError(exception); } } /** * @throws SAXException */ protected void doError(SAXParseException exception) throws SAXException { // by default do nothing } public final void fatalError(SAXParseException exception) throws SAXException { if (skip) { return; } if (delegate != null) { delegate.fatalError(exception); } else { doFatalError(exception); } } /** * @throws SAXException */ protected void doFatalError(SAXParseException exception) throws SAXException { // by default do nothing } // ////////////////////// // Functions related to error handling // ////////////////////// protected void log(int logLevel, String message, Throwable t) { Message.debug(t); log(logLevel, message); } protected void log(int logLevel, String message) { Message.log(logLevel, getLocation(getLocator()) + message); } protected static String getLocation(Locator locator) { if (locator == null) { return ""; } return "[line " + locator.getLineNumber() + " col. " + locator.getColumnNumber() + "] "; } private void skipOnError(DelegatingHandler currentHandler, Class handlerClassToSkip, String message) { DelegatingHandler handlerToSkip = currentHandler; while (!(handlerClassToSkip.isAssignableFrom(handlerToSkip.getClass()))) { handlerToSkip = handlerToSkip.getParent(); } log(Message.MSG_ERR, message + ". The '" + handlerToSkip.getName() + "' element " + getCurrentElementIdentifier() + " is then ignored."); handlerToSkip.skip(); } // ////////////////////// // Helpers to parse the attributes // ////////////////////// protected String getRequiredAttribute(Attributes atts, String name) throws SAXParseException { String value = atts.getValue(name); if (value == null) { throw new SAXParseException("Required attribute '" + name + "' not found", getLocator()); } return value; } protected String getOptionalAttribute(Attributes atts, String name, String defaultValue) { String value = atts.getValue(name); if (value == null) { return defaultValue; } return value; } protected int getRequiredIntAttribute(Attributes atts, String name, Integer logLevel) throws SAXParseException { return parseInt(name, getRequiredAttribute(atts, name)); } protected Integer getOptionalIntAttribute(Attributes atts, String name, Integer defaultValue) throws SAXParseException { String value = atts.getValue(name); if (value == null) { return defaultValue; } return new Integer(parseInt(name, value)); } private int parseInt(String name, String value) throws SAXParseException { try { return Integer.parseInt(value); } catch (NumberFormatException e) { throw new SAXParseException("Attribute '" + name + "' is expected to be an integer but was '" + value + "' (" + e.getMessage() + ")", getLocator()); } } protected long getRequiredLongAttribute(Attributes atts, String name) throws SAXParseException { return parseLong(name, getRequiredAttribute(atts, name)); } protected Long getOptionalLongAttribute(Attributes atts, String name, Long defaultValue) throws SAXParseException { String value = atts.getValue(name); if (value == null) { return defaultValue; } return new Long(parseLong(name, value)); } private long parseLong(String name, String value) throws SAXParseException { try { return Long.parseLong(value); } catch (NumberFormatException e) { throw new SAXParseException("Attribute '" + name + "' is expected to be an long but was '" + value + "' (" + e.getMessage() + ")", getLocator()); } } protected boolean getRequiredBooleanAttribute(Attributes atts, String name) throws SAXParseException { return parseBoolean(name, getRequiredAttribute(atts, name)); } protected Boolean getOptionalBooleanAttribute(Attributes atts, String name, Boolean defaultValue) throws SAXParseException { String value = atts.getValue(name); if (value == null) { return defaultValue; } return Boolean.valueOf(parseBoolean(name, value)); } static final String TRUE = Boolean.TRUE.toString().toLowerCase(Locale.US); static final String FALSE = Boolean.FALSE.toString().toLowerCase(Locale.US); private boolean parseBoolean(String name, String value) throws SAXParseException { String lowerValue = value.toLowerCase(Locale.US); if (lowerValue.equals(TRUE)) { return true; } if (lowerValue.equals(FALSE)) { return false; } throw new SAXParseException("Attribute '" + name + "' is expected to be a boolean but was '" + value + "'", getLocator()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/ParseUtil.java000066400000000000000000000057651226750426600240560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.util.ArrayList; import java.util.List; public class ParseUtil { /** * Parses delimited string and returns an array containing the tokens. This parser obeys quotes, * so the delimiter character will be ignored if it is inside of a quote. This method assumes * that the quote character is not included in the set of delimiter characters. * * @param value * the delimited string to parse. * @param delim * the characters delimiting the tokens. * @return an array of string tokens or null if there were no tokens. */ // method largely inspired by Apache Felix 1.0.4 ManifestParser method public static String[] parseDelimitedString(String value, String delim) { if (value == null) { value = ""; } final List list = new ArrayList(); final int CHAR = 1; final int DELIMITER = 2; final int STARTQUOTE = 4; final int ENDQUOTE = 8; final StringBuffer sb = new StringBuffer(); int expecting = (CHAR | DELIMITER | STARTQUOTE); for (int i = 0; i < value.length(); i++) { final char c = value.charAt(i); final boolean isDelimiter = (delim.indexOf(c) >= 0); final boolean isQuote = (c == '"'); if (isDelimiter && ((expecting & DELIMITER) > 0)) { list.add(sb.toString().trim()); sb.delete(0, sb.length()); expecting = (CHAR | DELIMITER | STARTQUOTE); } else if (isQuote && ((expecting & STARTQUOTE) > 0)) { sb.append(c); expecting = CHAR | ENDQUOTE; } else if (isQuote && ((expecting & ENDQUOTE) > 0)) { sb.append(c); expecting = (CHAR | STARTQUOTE | DELIMITER); } else if ((expecting & CHAR) > 0) { sb.append(c); } else { throw new IllegalArgumentException("Invalid delimited string: " + value); } } if (sb.length() > 0) { list.add(sb.toString().trim()); } return list.toArray(new String[list.size()]); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/Version.java000066400000000000000000000150461226750426600235640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.text.ParseException; /** * Provides OSGi version support. */ public class Version implements Comparable { private int major; private int minor; private int patch; private String qualifier; private String version; private String input; private boolean splitted = false; private boolean toString = false; public Version(String versionStr, String qualifier) throws ParseException { this(qualifier == null ? versionStr : (versionStr + "." + qualifier)); } public Version(String versionStr) throws ParseException { this.input = versionStr; splitted = false; toString = false; } public Version(int major, int minor, int patch, String qualifier) { this.major = major; this.minor = minor; this.patch = patch; this.qualifier = qualifier; splitted = true; toString = false; } /** * Build a version from another one while appending an extra qualifier * * @param baseVersion * @param qualifier */ public Version(Version baseVersion, String extraQualifier) { this.major = baseVersion.major; this.minor = baseVersion.minor; this.patch = baseVersion.patch; this.qualifier = baseVersion.qualifier == null ? extraQualifier : (baseVersion.qualifier + extraQualifier); splitted = true; toString = false; } private void ensureSplitted() { if (!splitted) { synchronized (this) { if (splitted) { return; } String[] splits = input.split("\\."); if (splits == null || splits.length == 0 || splits.length > 4) { throw new RuntimeException(new ParseException("Ill formed OSGi version", 0)); } try { major = Integer.parseInt(splits[0]); } catch (NumberFormatException e) { throw new RuntimeException(new ParseException( "Major part of an OSGi version should be an integer", 0)); } try { minor = splits.length >= 2 ? Integer.parseInt(splits[1]) : 0; } catch (NumberFormatException e) { throw new RuntimeException(new ParseException( "Minor part of an OSGi version should be an integer", 0)); } try { patch = splits.length >= 3 ? Integer.parseInt(splits[2]) : 0; } catch (NumberFormatException e) { throw new RuntimeException(new ParseException( "Patch part of an OSGi version should be an integer", 0)); } qualifier = splits.length == 4 ? splits[3] : null; splitted = true; } } } private void ensureToString() { if (!toString) { synchronized (this) { if (toString) { return; } ensureSplitted(); version = major + "." + minor + "." + patch + (qualifier == null ? "" : "." + qualifier); toString = true; } } } public String toString() { ensureToString(); return version; } public int hashCode() { ensureSplitted(); final int prime = 31; int result = 1; result = prime * result + major; result = prime * result + minor; result = prime * result + patch; result = prime * result + ((qualifier == null) ? 0 : qualifier.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Version)) { return false; } Version other = (Version) obj; ensureSplitted(); other.ensureSplitted(); if (major != other.major) { return false; } if (minor != other.minor) { return false; } if (patch != other.patch) { return false; } if (qualifier == null) { if (other.qualifier != null) { return false; } } else if (!qualifier.equals(other.qualifier)) { return false; } return true; } public Version withNudgedPatch() { ensureSplitted(); return new Version(major, minor, patch + 1, null); } public Version withoutQualifier() { ensureSplitted(); return new Version(major, minor, patch, null); } public String qualifier() { ensureSplitted(); return qualifier == null ? "" : qualifier; } public int compareUnqualified(Version other) { ensureSplitted(); other.ensureSplitted(); int diff = major - other.major; if (diff != 0) { return diff; } diff = minor - other.minor; if (diff != 0) { return diff; } diff = patch - other.patch; if (diff != 0) { return diff; } return 0; } public int compareTo(Version other) { ensureSplitted(); other.ensureSplitted(); int diff = compareUnqualified(other); if (diff != 0) { return diff; } if (qualifier == null) { return other.qualifier != null ? -1 : 0; } if (other.qualifier == null) { return 1; } return qualifier.compareTo(other.qualifier); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/VersionComparator.java000066400000000000000000000025571226750426600256170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.util.Comparator; public class VersionComparator implements Comparator { public static final Comparator ASCENDING = new VersionComparator(false); public static final Comparator DESCENDING = new VersionComparator(true); public final boolean reverse; private VersionComparator(boolean reverse) { this.reverse = reverse; } public int compare(Version objA, Version objB) { final int val = objA.compareTo(objB); return (reverse ? -val : val); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/VersionRange.java000066400000000000000000000252621226750426600245420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.text.ParseException; /** * Provides version range support. */ public class VersionRange { private boolean startExclusive; private Version startVersion; private boolean endExclusive; private Version endVersion; public VersionRange(String versionStr) throws ParseException { if (versionStr == null || versionStr.length() == 0) { startExclusive = false; startVersion = new Version(0, 0, 0, null); endExclusive = true; endVersion = null; } else { new VersionRangeParser(versionStr).parse(); } } class VersionRangeParser { /** * value to parse */ private final String version; /** * the length of the source */ private int length; /** * position in the source */ private int pos = 0; /** * last read character */ private char c; /** * Default constructor * * @param header * the header to parse */ VersionRangeParser(String version) { this.version = version; this.length = version.length(); } /** * Do the parsing * * @throws ParseException */ void parse() throws ParseException { boolean range = parseStart(); startVersion = parseVersion(); if (startVersion == null) { throw new ParseException("Expecting a number", pos); } if (parseVersionSeparator()) { endVersion = parseVersion(); parseEnd(); } else if (range) { throw new ParseException("Expecting ,", pos); } else { // simple number endVersion = null; startExclusive = false; endExclusive = false; } } private char readNext() { if (pos == length) { c = '\0'; } else { c = version.charAt(pos++); } return c; } private void unread() { if (pos > 0) { pos--; } } private boolean parseStart() { skipWhiteSpace(); switch (readNext()) { case '[': startExclusive = false; return true; case '(': startExclusive = true; return true; default: unread(); return false; } } private void skipWhiteSpace() { do { switch (readNext()) { case ' ': continue; default: unread(); return; } } while (pos < length); } private Version parseVersion() { Integer major = parseNumber(); if (major == null) { return null; } Integer minor = new Integer(0); Integer patch = new Integer(0); String qualififer = null; if (parseNumberSeparator()) { minor = parseNumber(); if (minor == null) { minor = new Integer(0); } else if (parseNumberSeparator()) { patch = parseNumber(); if (patch == null) { patch = new Integer(0); } else if (parseNumberSeparator()) { qualififer = parseQualifier(); } } } return new Version(major.intValue(), minor.intValue(), patch.intValue(), qualififer); } private Integer parseNumber() { skipWhiteSpace(); Integer n = null; do { switch (readNext()) { case '\0': return n; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = new Integer((n == null ? 0 : n.intValue() * 10) + c - '0'); break; default: unread(); return n; } } while (pos < length); return n; } private boolean parseNumberSeparator() { switch (readNext()) { case '.': return true; default: unread(); return false; } } private boolean parseVersionSeparator() { skipWhiteSpace(); switch (readNext()) { case ',': return true; default: unread(); return false; } } private String parseQualifier() { StringBuffer q = new StringBuffer(); do { readNext(); if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_') { q.append(c); } else { unread(); break; } } while (pos < length); if (q.length() == 0) { return null; } return q.toString(); } private void parseEnd() throws ParseException { skipWhiteSpace(); switch (readNext()) { case ']': endExclusive = false; break; case ')': endExclusive = true; break; default: unread(); throw new ParseException("Expexting ] or )", pos); } } } public VersionRange(boolean startExclusive, Version startVersion, boolean endExclusive, Version endVersion) { this.startExclusive = startExclusive; this.startVersion = startVersion; this.endExclusive = endExclusive; this.endVersion = endVersion; } public VersionRange(Version startVersion) { this.startExclusive = false; this.startVersion = startVersion; this.endExclusive = true; this.endVersion = null; } public String toString() { return (startExclusive ? "(" : "[") + startVersion + "," + (endVersion == null ? "" : endVersion.toString()) + (endExclusive ? ")" : "]"); } public String toIvyRevision() { StringBuffer buffer = new StringBuffer(); buffer.append(startExclusive ? "(" : "["); buffer.append(startVersion); if (endVersion == null) { buffer.append(",)"); } else if (!endExclusive || startVersion.equals(endVersion)) { buffer.append(","); buffer.append(endVersion.withNudgedPatch()); buffer.append(")"); } else { buffer.append(","); buffer.append(endVersion); buffer.append(")"); } return buffer.toString(); } public boolean isEndExclusive() { return this.endExclusive; } public Version getEndVersion() { return this.endVersion; } public boolean isStartExclusive() { return this.startExclusive; } public Version getStartVersion() { return this.startVersion; } public boolean isClosedRange() { return startVersion.equals(endVersion); } public boolean contains(String versionStr) throws ParseException { return contains(new Version(versionStr)); } public boolean contains(Version version) { if (startExclusive ? version.compareUnqualified(startVersion) <= 0 : version .compareUnqualified(startVersion) < 0) { return false; } if (endVersion == null) { return true; } if (endExclusive ? version.compareUnqualified(endVersion) >= 0 : version .compareUnqualified(endVersion) > 0) { return false; } return true; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (endExclusive ? 1231 : 1237); result = prime * result + ((endVersion == null) ? 0 : endVersion.hashCode()); result = prime * result + (startExclusive ? 1231 : 1237); result = prime * result + ((startVersion == null) ? 0 : startVersion.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof VersionRange)) { return false; } VersionRange other = (VersionRange) obj; if (endExclusive != other.endExclusive) { return false; } if (endVersion == null) { if (other.endVersion != null) { return false; } } else if (!endVersion.equals(other.endVersion)) { return false; } if (startExclusive != other.startExclusive) { return false; } if (startVersion == null) { if (other.startVersion != null) { return false; } } else if (!startVersion.equals(other.startVersion)) { return false; } return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/osgi/util/ZipUtil.java000066400000000000000000000047331226750426600235400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.osgi.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * Class derived from code posted here: http://forums.sun.com/thread.jspa?messageID=2160923 */ public class ZipUtil { public static void zip(File sourceDir, OutputStream targetStream) throws IOException { if (!sourceDir.isFile() && !sourceDir.isDirectory()) { return; } final ZipOutputStream cpZipOutputStream = new ZipOutputStream(targetStream); cpZipOutputStream.setLevel(9); zipFiles(sourceDir, sourceDir, cpZipOutputStream); cpZipOutputStream.finish(); cpZipOutputStream.close(); } private static void zipFiles(File rootDir, File currDir, ZipOutputStream zos) throws IOException { if (currDir.isDirectory()) { final File[] files = currDir.listFiles(); for (int i = 0; i < files.length; i++) { zipFiles(rootDir, files[i], zos); } } else { final String strAbsPath = currDir.getPath(); final String strZipEntryName = strAbsPath.substring(rootDir.getPath().length() + 1, strAbsPath.length()); final byte[] b = new byte[(int) (currDir.length())]; final FileInputStream fis = new FileInputStream(currDir); fis.read(b); fis.close(); final ZipEntry entry = new ZipEntry(strZipEntryName); zos.putNextEntry(entry); zos.write(b, 0, (int) currDir.length()); zos.closeEntry(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/000077500000000000000000000000001226750426600210315ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/IvySettingsAware.java000066400000000000000000000017261226750426600251520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins; import org.apache.ivy.core.settings.IvySettings; public interface IvySettingsAware { void setSettings(IvySettings settings); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/000077500000000000000000000000001226750426600226355ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/AbstractCircularDependencyStrategy.java000066400000000000000000000022671226750426600324610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; public abstract class AbstractCircularDependencyStrategy implements CircularDependencyStrategy { private String name; protected AbstractCircularDependencyStrategy(String name) { this.name = name; } public String getName() { return this.name; } public String toString() { return getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/AbstractLogCircularDependencyStrategy.java000066400000000000000000000041041226750426600331130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; public abstract class AbstractLogCircularDependencyStrategy extends AbstractCircularDependencyStrategy { protected AbstractLogCircularDependencyStrategy(String name) { super(name); } private Collection/* */circularDependencies = new HashSet(); public void handleCircularDependency(ModuleRevisionId[] mrids) { String circularDependencyId = getCircularDependencyId(mrids); if (!circularDependencies.contains(circularDependencyId)) { circularDependencies.add(circularDependencyId); logCircularDependency(mrids); } } protected abstract void logCircularDependency(ModuleRevisionId[] mrids); protected String getCircularDependencyId(ModuleRevisionId[] mrids) { String contextPrefix = ""; ResolveData data = IvyContext.getContext().getResolveData(); if (data != null) { contextPrefix = data.getOptions().getResolveId() + " "; } return contextPrefix + Arrays.asList(mrids); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/CircularDependencyException.java000066400000000000000000000027011226750426600311220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * Unchecked exception thrown when a circular dependency exists between projects. */ public class CircularDependencyException extends RuntimeException { private ModuleRevisionId[] mrids; /** * @param descriptors * module descriptors in order of circular dependency */ public CircularDependencyException(final ModuleRevisionId[] mrids) { super(CircularDependencyHelper.formatMessage(mrids)); this.mrids = mrids; } public ModuleRevisionId[] getPath() { return this.mrids; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/CircularDependencyHelper.java000066400000000000000000000057031226750426600304100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; public final class CircularDependencyHelper { /** CircularDependencyHelper is not designed to be an instance */ private CircularDependencyHelper() { } /** * Returns a string representation of this circular dependency graph * * @param descriptors * in order of circular dependency * @return a string representation of this circular dependency graph */ public static String formatMessage(final ModuleRevisionId[] mrids) { Set alreadyAdded = new HashSet(); StringBuffer buff = new StringBuffer(); buff.append(mrids[0]); alreadyAdded.add(mrids[0]); for (int i = 1; i < mrids.length; i++) { buff.append("->"); if (alreadyAdded.add(mrids[i])) { buff.append(mrids[i]); } else { buff.append("..."); break; } } return buff.toString(); } public static String formatMessage(final ModuleDescriptor[] descriptors) { return formatMessage(toMrids(descriptors)); } /** * @param loopElements * a List */ public static String formatMessageFromDescriptors(List loopElements) { ModuleRevisionId[] mrids = new ModuleRevisionId[loopElements.size()]; int pos = 0; for (Iterator it = loopElements.iterator(); it.hasNext();) { ModuleDescriptor descriptor = (ModuleDescriptor) it.next(); mrids[pos] = descriptor.getModuleRevisionId(); pos++; } return formatMessage(mrids); } public static ModuleRevisionId[] toMrids(ModuleDescriptor[] descriptors) { ModuleRevisionId[] mrids = new ModuleRevisionId[descriptors.length]; for (int i = 0; i < descriptors.length; i++) { mrids[i] = descriptors[i].getModuleRevisionId(); } return mrids; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/CircularDependencyStrategy.java000066400000000000000000000023441226750426600307710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * A CircularDependencyStrategy indicates what ivy does when a circular dependency is detected. Ivy * can ignore it, warn the user, or interupt the processing. */ public interface CircularDependencyStrategy { String getName(); void handleCircularDependency(ModuleRevisionId[] mrids) throws CircularDependencyException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/ErrorCircularDependencyStrategy.java000066400000000000000000000026711226750426600320060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import org.apache.ivy.core.module.id.ModuleRevisionId; public final class ErrorCircularDependencyStrategy extends AbstractCircularDependencyStrategy { private static final CircularDependencyStrategy INSTANCE = new ErrorCircularDependencyStrategy(); public static CircularDependencyStrategy getInstance() { return INSTANCE; } private ErrorCircularDependencyStrategy() { super("error"); } public void handleCircularDependency(ModuleRevisionId[] mrids) throws CircularDependencyException { throw new CircularDependencyException(mrids); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/IgnoreCircularDependencyStrategy.java000066400000000000000000000027701226750426600321400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.Message; public final class IgnoreCircularDependencyStrategy extends AbstractLogCircularDependencyStrategy { private static final CircularDependencyStrategy INSTANCE = new IgnoreCircularDependencyStrategy(); public static CircularDependencyStrategy getInstance() { return INSTANCE; } private IgnoreCircularDependencyStrategy() { super("ignore"); } protected void logCircularDependency(ModuleRevisionId[] mrids) { Message.verbose("circular dependency found: " + CircularDependencyHelper.formatMessage(mrids)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/circular/WarnCircularDependencyStrategy.java000066400000000000000000000027351226750426600316250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.circular; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.Message; public final class WarnCircularDependencyStrategy extends AbstractLogCircularDependencyStrategy { private static final CircularDependencyStrategy INSTANCE = new WarnCircularDependencyStrategy(); public static CircularDependencyStrategy getInstance() { return INSTANCE; } private WarnCircularDependencyStrategy() { super("warn"); } protected void logCircularDependency(ModuleRevisionId[] mrids) { Message.warn("circular dependency found: " + CircularDependencyHelper.formatMessage(mrids)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/000077500000000000000000000000001226750426600226325ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/AbstractConflictManager.java000066400000000000000000000032071226750426600302170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Collection; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; public abstract class AbstractConflictManager implements ConflictManager, IvySettingsAware { private String name; private IvySettings settings; public IvySettings getSettings() { return settings; } public void setSettings(IvySettings settings) { this.settings = settings; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return name; } public void handleAllBlacklistedRevisions(DependencyDescriptor dd, Collection foundBlacklisted) { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/ConflictManager.java000066400000000000000000000052221226750426600265320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Collection; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.resolve.IvyNode; public interface ConflictManager { /** * Resolves the eventual conflicts found in the given collection of IvyNode. This method return * a Collection of IvyNode which have not been evicted. The given conflicts Collection contains * at least one IvyNode. This method can be called with IvyNodes which are not yet loaded. If * this conflict manager is not able to resolve conflicts with the current data found in the * IvyNodes and need them to be fully loaded, it will return null to indicate that no conflict * resolution has been done. * * @param parent * the ivy node parent for which the conflict is to be resolved * @param conflicts * the collection of IvyNode to check for conflicts * @return a Collection of IvyNode which have not been evicted, or null if conflict management * resolution is not possible yet */ Collection resolveConflicts(IvyNode parent, Collection conflicts); String getName(); /** * Method called when all revisions available for a version constraint have been blacklisted, * and thus the dependency can't be resolved. *

    * This will never happen if the conflict manager doesn't blacklist any module, so providing an * empty implementation in this case is fine. *

    * * @param dd * the dependency descriptor for which all revisions are blacklisted. * @param foundBlacklisted * the list of all ModuleRevisionId found which are blacklisted */ void handleAllBlacklistedRevisions(DependencyDescriptor dd, Collection/* */foundBlacklisted); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/FixedConflictManager.java000066400000000000000000000033751226750426600275210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import org.apache.ivy.core.resolve.IvyNode; public class FixedConflictManager extends AbstractConflictManager { private Collection revisions; public FixedConflictManager(String[] revs) { revisions = Arrays.asList(revs); setName("fixed" + revisions); } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { Collection resolved = new ArrayList(conflicts.size()); for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); String revision = node.getResolvedId().getRevision(); if (revisions.contains(revision)) { resolved.add(node); } } return resolved; } public Collection getRevs() { return revisions; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/LatestCompatibleConflictManager.java000066400000000000000000000334551226750426600317200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Stack; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.IvyNodeBlacklist; import org.apache.ivy.core.resolve.IvyNodeCallers.Caller; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.RestartResolveProcess; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; /** * This conflict manager can be used to allow only compatible dependencies to be used together (like * the strict conflict manager), but it has the advantage of using a best effort algorithm to find a * set of compatible dependencies, even if it requires stepping back to older revisions (as long as * they are in the set of compatibility). *

    * Here is an example of what this conflict manager is able to do:
    * Available Modules: * *

     * #A;2->{ #B;[1.0,1.5] #C;[2.0,2.5] }
     * #B;1.4->#D;1.5
     * #B;1.5->#D;2.0
     * #C;2.5->#D;[1.0,1.6]
     * 
    * * Result: #B;1.4, #C;2.5, #D;1.5
    * DetailsThe conflict manager finds that the latest matching version of #B (1.5) depends on * a version of #D incompatible with what is expected by the latest matching version of #C. Hence * the conflict manager blacklists #B;1.5, and the version range [1.0,1.5] is resolved again to end * up with #B;1.4 which depends on #D;1.5, which is fine to work with #C;2.5. *

    */ public class LatestCompatibleConflictManager extends LatestConflictManager { public LatestCompatibleConflictManager() { } public LatestCompatibleConflictManager(String name, LatestStrategy strategy) { super(name, strategy); } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { if (conflicts.size() < 2) { return conflicts; } VersionMatcher versionMatcher = getSettings().getVersionMatcher(); Iterator iter = conflicts.iterator(); IvyNode node = (IvyNode) iter.next(); ModuleRevisionId mrid = node.getResolvedId(); if (versionMatcher.isDynamic(mrid)) { while (iter.hasNext()) { IvyNode other = (IvyNode) iter.next(); if (versionMatcher.isDynamic(other.getResolvedId())) { // two dynamic versions in conflict, not enough information yet return null; } else if (!versionMatcher.accept(mrid, other.getResolvedId())) { // incompatibility found if (!handleIncompatibleConflict(parent, conflicts, node, other)) { return null; } } } // no incompatibility nor dynamic version found, let's return the latest static version if (conflicts.size() == 2) { // very common special case of only two modules in conflict, // let's return the second one (static) Iterator it = conflicts.iterator(); it.next(); return Collections.singleton(it.next()); } Collection newConflicts = new LinkedHashSet(conflicts); newConflicts.remove(node); return super.resolveConflicts(parent, newConflicts); } else { // the first node is a static revision, let's see if all other versions match while (iter.hasNext()) { IvyNode other = (IvyNode) iter.next(); if (!versionMatcher.accept(other.getResolvedId(), mrid)) { // incompatibility found if (!handleIncompatibleConflict(parent, conflicts, node, other)) { return null; } } } // no incompatibility found, let's return this static version return Collections.singleton(node); } } /** * Handles an incompatible conflict *

    * An incompatible conflicts is handled with this pseudo algorithm: * *

         * take latest among two nodes in conflict
         *   for all callers
         *      if dependency is a version constraint (dynamic)
         *         blacklist the mapped version
         *      else
         *         recurse for all callers
         *   if a version constraint has been found
         *     restart resolve
         *   else
         *     throw strict conflict exception
         * 
    * *

    * * @param parent * the parent node of nodes in conflict * @param conflicts * all the nodes in conflict * @param node * one of the two incompatible nodes * @param other * the other incompatible node * @return true if the incompatible conflict has been handled, false otherwise (in which case * resolveConflicts should return null) */ private boolean handleIncompatibleConflict(IvyNode parent, Collection conflicts, IvyNode node, IvyNode other) { // we never actually return anything else than false or throw an exception, // but returning a boolean make the calling code cleaner try { IvyNodeArtifactInfo latest = (IvyNodeArtifactInfo) getStrategy().findLatest( toArtifactInfo(Arrays.asList(new IvyNode[] {node, other})), null); if (latest != null) { IvyNode latestNode = latest.getNode(); IvyNode oldestNode = latestNode == node ? other : node; blackListIncompatibleCallerAndRestartResolveIfPossible(getSettings(), parent, oldestNode, latestNode); // if we arrive here, we haven't managed to blacklist all paths to the latest // node, we try with the oldest blackListIncompatibleCallerAndRestartResolveIfPossible(getSettings(), parent, latestNode, oldestNode); // still not possible, we aren't able to find a solution to the incompatibility handleUnsolvableConflict(parent, conflicts, node, other); return true; // never actually reached } else { return false; } } catch (NoConflictResolvedYetException ex) { // we have not enough informations in the nodes to resolve conflict // according to the resolveConflicts contract, resolveConflicts must return null return false; } } private void blackListIncompatibleCallerAndRestartResolveIfPossible(IvySettings settings, IvyNode parent, IvyNode selected, IvyNode evicted) { Stack callerStack = new Stack(); callerStack.push(evicted); final Collection toBlacklist = blackListIncompatibleCaller(settings.getVersionMatcher(), parent, selected, evicted, callerStack); if (toBlacklist != null) { final StringBuffer blacklisted = new StringBuffer(); for (Iterator iterator = toBlacklist.iterator(); iterator.hasNext();) { IvyNodeBlacklist blacklist = (IvyNodeBlacklist) iterator.next(); blacklist.getBlacklistedNode().blacklist(blacklist); blacklisted.append(blacklist.getBlacklistedNode()); if (iterator.hasNext()) { blacklisted.append(" "); } } String rootModuleConf = parent.getData().getReport().getConfiguration(); evicted.markEvicted(new EvictionData(rootModuleConf, parent, this, Collections .singleton(selected), "with blacklisting of " + blacklisted)); if (settings.debugConflictResolution()) { Message.debug("evicting " + evicted + " by " + evicted.getEvictedData(rootModuleConf)); } throw new RestartResolveProcess("trying to handle incompatibilities between " + selected + " and " + evicted); } } private boolean handleIncompatibleCaller(Stack callerStack, IvyNode node, IvyNode callerNode, IvyNode conflictParent, IvyNode selectedNode, IvyNode evictedNode, Collection blacklisted, VersionMatcher versionMatcher) { if (callerStack.subList(0, callerStack.size() - 1).contains(node)) { // circular dependency found and handled: the current top of the stack (node) // was already contained in the rest of the stack, the circle is closed, nothing // else to do return true; } else { callerStack.push(callerNode); Collection sub = blackListIncompatibleCaller(versionMatcher, conflictParent, selectedNode, evictedNode, callerStack); callerStack.pop(); if (sub == null) { // propagate the fact that a path with unblacklistable caller has been found return false; } else { blacklisted.addAll(sub); return true; } } } /** * Tries to blacklist exactly one version for all callers paths. * * @param versionMatcher * the version matcher to use to interpret versions * @param conflictParent * the node in which the conflict is occurring * @param selectedNode * the node in favor of which the conflict is resolved * @param evictedNode * the node which will be evicted if we are able to blacklist all paths * @param node * the node for which callers should be considered * @return the collection of blacklisting to do, null if a blacklist is not possible in at least * one caller path */ private Collection/* */blackListIncompatibleCaller( VersionMatcher versionMatcher, IvyNode conflictParent, IvyNode selectedNode, IvyNode evictedNode, Stack/* */callerStack) { Collection/* */blacklisted = new ArrayList/* */(); IvyNode node = (IvyNode) callerStack.peek(); String rootModuleConf = conflictParent.getData().getReport().getConfiguration(); Caller[] callers = node.getCallers(rootModuleConf); for (int i = 0; i < callers.length; i++) { IvyNode callerNode = node.findNode(callers[i].getModuleRevisionId()); if (callerNode.isBlacklisted(rootModuleConf)) { continue; } if (versionMatcher.isDynamic(callers[i].getAskedDependencyId(node.getData()))) { blacklisted.add(new IvyNodeBlacklist(conflictParent, selectedNode, evictedNode, node, rootModuleConf)); if (node.isEvicted(rootModuleConf) && !handleIncompatibleCaller(callerStack, node, callerNode, conflictParent, selectedNode, evictedNode, blacklisted, versionMatcher)) { return null; } } else if (!handleIncompatibleCaller(callerStack, node, callerNode, conflictParent, selectedNode, evictedNode, blacklisted, versionMatcher)) { return null; } } if (blacklisted.isEmpty() && !callerStack.subList(0, callerStack.size() - 1).contains(node)) { return null; } return blacklisted; } protected void handleUnsolvableConflict(IvyNode parent, Collection conflicts, IvyNode node1, IvyNode node2) { throw new StrictConflictException(node1, node2); } public void handleAllBlacklistedRevisions(DependencyDescriptor dd, Collection/* */foundBlacklisted) { ResolveData resolveData = IvyContext.getContext().getResolveData(); Collection/* */blacklisted = new HashSet(); for (Iterator iterator = foundBlacklisted.iterator(); iterator.hasNext();) { ModuleRevisionId mrid = (ModuleRevisionId) iterator.next(); blacklisted.add(resolveData.getNode(mrid)); } for (Iterator iterator = blacklisted.iterator(); iterator.hasNext();) { IvyNode node = (IvyNode) iterator.next(); IvyNodeBlacklist bdata = node.getBlacklistData(resolveData.getReport() .getConfiguration()); handleUnsolvableConflict(bdata.getConflictParent(), Arrays.asList(new Object[] {bdata.getEvictedNode(), bdata.getSelectedNode()}), bdata.getEvictedNode(), bdata.getSelectedNode()); } } public String toString() { return getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/LatestConflictManager.java000066400000000000000000000131051226750426600277060ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.util.Message; public class LatestConflictManager extends AbstractConflictManager { public static class NoConflictResolvedYetException extends RuntimeException { } protected static final class IvyNodeArtifactInfo implements ArtifactInfo { private final IvyNode node; private IvyNodeArtifactInfo(IvyNode dep) { node = dep; } public long getLastModified() { long lastModified = node.getLastModified(); if (lastModified == 0) { // if the last modified timestamp is unknown, we can't resolve // the conflicts now, and trigger an exception which will be catched // in the main resolveConflicts method throw new NoConflictResolvedYetException(); } else { return lastModified; } } public String getRevision() { return node.getResolvedId().getRevision(); } public IvyNode getNode() { return node; } } private LatestStrategy strategy; private String strategyName; public LatestConflictManager() { } public LatestConflictManager(LatestStrategy strategy) { this.strategy = strategy; } public LatestConflictManager(String name, LatestStrategy strategy) { setName(name); this.strategy = strategy; } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { if (conflicts.size() < 2) { return conflicts; } for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); DependencyDescriptor dd = node.getDependencyDescriptor(parent); if (dd != null && dd.isForce() && parent.getResolvedId().equals(dd.getParentRevisionId())) { return Collections.singleton(node); } } /* * If the list of conflicts contains dynamic revisions, delay the conflict calculation until * they are resolved. TODO: we probably could already evict some of the dynamic revisions! */ for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); ModuleRevisionId modRev = node.getResolvedId(); if (getSettings().getVersionMatcher().isDynamic(modRev)) { return null; } } try { IvyNodeArtifactInfo latest = (IvyNodeArtifactInfo) getStrategy().findLatest( toArtifactInfo(conflicts), null); if (latest != null) { return Collections.singleton(latest.getNode()); } else { return conflicts; } } catch (NoConflictResolvedYetException ex) { // we have not enough informations in the nodes to resolve conflict // according to the resolveConflicts contract, we must return null return null; } } protected ArtifactInfo[] toArtifactInfo(Collection conflicts) { List artifacts = new ArrayList(conflicts.size()); for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); artifacts.add(new IvyNodeArtifactInfo(node)); } return (ArtifactInfo[]) artifacts.toArray(new ArtifactInfo[artifacts.size()]); } public LatestStrategy getStrategy() { if (strategy == null) { if (strategyName != null) { strategy = getSettings().getLatestStrategy(strategyName); if (strategy == null) { Message.error("unknown latest strategy: " + strategyName); strategy = getSettings().getDefaultLatestStrategy(); } } else { strategy = getSettings().getDefaultLatestStrategy(); } } return strategy; } /** * To conform to configurator API * * @param latestStrategy */ public void setLatest(String strategyName) { this.strategyName = strategyName; } public void setStrategy(LatestStrategy strategy) { this.strategy = strategy; } public String toString() { return strategy != null ? String.valueOf(strategy) : strategyName; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/NoConflictManager.java000066400000000000000000000022301226750426600270230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Collection; import org.apache.ivy.core.resolve.IvyNode; public class NoConflictManager extends AbstractConflictManager { public NoConflictManager() { setName("all"); } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { return conflicts; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/RegexpConflictManager.java000066400000000000000000000110021226750426600276760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.util.Message; /** * A ConflictManager that can be used to resolve conflicts based on regular expressions of the * revision of the module. The conflict manager is added like this: * *
     *    <!-- Match all revisions, but ignore the last dot(.) and the character after it.
     *        Used to match api changes in out milestones. -->
     *    <conflict-managers>
     *        <regexp-cm name="regexp" 
     *                   regexp="(.*)\..$" ignoreNonMatching="true"/>
     *    </conflict-managers>
     * 
    * * The regular expression must contain a capturing group. The group will be used to resolve the * conflicts by an String.equals() test. If ignoreNonMatching is false non matching modules will * result in an exception. If it is true they will be compaired by their full revision. */ public class RegexpConflictManager extends AbstractConflictManager { private Pattern pattern = Pattern.compile("(.*)"); private boolean mIgnoreNonMatching; public RegexpConflictManager() { } public void setRegexp(String regexp) { pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher("abcdef"); if (matcher.groupCount() != 1) { String message = "Pattern does not contain ONE (capturing group): '" + pattern + "'"; Message.error(message); throw new IllegalArgumentException(message); } } public void setIgnoreNonMatching(boolean ignoreNonMatching) { mIgnoreNonMatching = ignoreNonMatching; } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { IvyNode lastNode = null; for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); if (lastNode != null && !matchEquals(node, lastNode)) { String msg = lastNode + ":" + getMatch(lastNode) + " (needed by " + Arrays.asList(lastNode.getAllRealCallers()) + ") conflicts with " + node + ":" + getMatch(node) + " (needed by " + Arrays.asList(node.getAllRealCallers()) + ")"; throw new StrictConflictException(msg); } if (lastNode == null || nodeIsGreater(node, lastNode)) { lastNode = node; } } return Collections.singleton(lastNode); } private boolean nodeIsGreater(IvyNode node, IvyNode lastNode) { return getMatch(node).compareTo(getMatch(lastNode)) > 0; } private boolean matchEquals(IvyNode lastNode, IvyNode node) { return getMatch(lastNode).equals(getMatch(node)); } private String getMatch(IvyNode node) { String revision = node.getId().getRevision(); Matcher matcher = pattern.matcher(revision); if (matcher.matches()) { String match = matcher.group(1); if (match != null) { return match; } warnOrThrow("First group of pattern: '" + pattern + "' does not match: " + revision + " " + node); } else { warnOrThrow("Pattern: '" + pattern + "' does not match: " + revision + " " + node); } return revision; } private void warnOrThrow(String message) { if (mIgnoreNonMatching) { Message.warn(message); } else { throw new StrictConflictException(message); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/StrictConflictException.java000066400000000000000000000031661226750426600303140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Arrays; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveProcessException; public class StrictConflictException extends ResolveProcessException { public StrictConflictException() { super(); } public StrictConflictException(IvyNode node1, IvyNode node2) { super(node1 + " (needed by " + Arrays.asList(node1.getAllRealCallers()) + ") conflicts with " + node2 + " (needed by " + Arrays.asList(node2.getAllRealCallers()) + ")"); } public StrictConflictException(String msg) { super(msg); } public StrictConflictException(Throwable t) { super(t); } public StrictConflictException(String msg, Throwable t) { super(msg, t); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/conflict/StrictConflictManager.java000066400000000000000000000035521226750426600277270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.conflict; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.plugins.version.VersionMatcher; public class StrictConflictManager extends AbstractConflictManager { public StrictConflictManager() { } public Collection resolveConflicts(IvyNode parent, Collection conflicts) { VersionMatcher versionMatcher = getSettings().getVersionMatcher(); IvyNode lastNode = null; for (Iterator iter = conflicts.iterator(); iter.hasNext();) { IvyNode node = (IvyNode) iter.next(); if (versionMatcher.isDynamic(node.getResolvedId())) { // dynamic revision, not enough information to resolve conflict return null; } if (lastNode != null && !lastNode.equals(node)) { throw new StrictConflictException(lastNode, node); } lastNode = node; } return Collections.singleton(lastNode); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/000077500000000000000000000000001226750426600223255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/AbstractLatestStrategy.java000066400000000000000000000033311226750426600276330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.Date; import java.util.List; import java.util.ListIterator; public abstract class AbstractLatestStrategy implements LatestStrategy { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return name; } public ArtifactInfo findLatest(ArtifactInfo[] infos, Date date) { List l = sort(infos); // the latest revision comes last, use a ListIterator to iterate the // sorted list in the reverse direction. for (ListIterator iter = l.listIterator(l.size()); iter.hasPrevious();) { ArtifactInfo info = (ArtifactInfo) iter.previous(); if (date == null || info.getLastModified() < date.getTime()) { return info; } } return null; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/ArtifactInfo.java000066400000000000000000000016621226750426600255460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; public interface ArtifactInfo { String getRevision(); long getLastModified(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/ComparatorLatestStrategy.java000066400000000000000000000031011226750426600301720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ComparatorLatestStrategy extends AbstractLatestStrategy { private Comparator comparator; public ComparatorLatestStrategy() { } public ComparatorLatestStrategy(Comparator comparator) { this.comparator = comparator; } public List sort(ArtifactInfo[] infos) { List ret = new ArrayList(Arrays.asList(infos)); Collections.sort(ret, comparator); return ret; } public Comparator getComparator() { return comparator; } public void setComparator(Comparator comparator) { this.comparator = comparator; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/LatestLexicographicStrategy.java000066400000000000000000000041671226750426600306610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.Comparator; public class LatestLexicographicStrategy extends ComparatorLatestStrategy { /** * Compares two revisions. Revisions are compared lexicographically unless a 'latest' revision * is found. If the latest revision found is an absolute latest (latest. like), then it is * assumed to be the greater. If a partial latest is found, then it is assumed to be greater * than any matching fixed revision. */ private static final Comparator COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { String rev1 = ((ArtifactInfo) o1).getRevision(); String rev2 = ((ArtifactInfo) o2).getRevision(); if (rev1.startsWith("latest")) { return 1; } if (rev1.endsWith("+") && rev2.startsWith(rev1.substring(0, rev1.length() - 1))) { return 1; } if (rev2.startsWith("latest")) { return -1; } if (rev2.endsWith("+") && rev1.startsWith(rev2.substring(0, rev2.length() - 1))) { return -1; } return rev1.compareTo(rev2); } }; public LatestLexicographicStrategy() { super(COMPARATOR); setName("latest-lexico"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/LatestRevisionStrategy.java000066400000000000000000000166401226750426600276750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.Comparator; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.version.VersionMatcher; public class LatestRevisionStrategy extends ComparatorLatestStrategy { /** * Compares two ModuleRevisionId by their revision. Revisions are compared using an algorithm * inspired by PHP version_compare one. */ final class MridComparator implements Comparator { public int compare(Object o1, Object o2) { String rev1 = ((ModuleRevisionId) o1).getRevision(); String rev2 = ((ModuleRevisionId) o2).getRevision(); rev1 = rev1.replaceAll("([a-zA-Z])(\\d)", "$1.$2"); rev1 = rev1.replaceAll("(\\d)([a-zA-Z])", "$1.$2"); rev2 = rev2.replaceAll("([a-zA-Z])(\\d)", "$1.$2"); rev2 = rev2.replaceAll("(\\d)([a-zA-Z])", "$1.$2"); String[] parts1 = rev1.split("[\\._\\-\\+]"); String[] parts2 = rev2.split("[\\._\\-\\+]"); int i = 0; for (; i < parts1.length && i < parts2.length; i++) { if (parts1[i].equals(parts2[i])) { continue; } boolean is1Number = isNumber(parts1[i]); boolean is2Number = isNumber(parts2[i]); if (is1Number && !is2Number) { return 1; } if (is2Number && !is1Number) { return -1; } if (is1Number && is2Number) { return Long.valueOf(parts1[i]).compareTo(Long.valueOf(parts2[i])); } // both are strings, we compare them taking into account special meaning Map specialMeanings = getSpecialMeanings(); Integer sm1 = (Integer) specialMeanings.get(parts1[i].toLowerCase(Locale.US)); Integer sm2 = (Integer) specialMeanings.get(parts2[i].toLowerCase(Locale.US)); if (sm1 != null) { sm2 = sm2 == null ? new Integer(0) : sm2; return sm1.compareTo(sm2); } if (sm2 != null) { return new Integer(0).compareTo(sm2); } return parts1[i].compareTo(parts2[i]); } if (i < parts1.length) { return isNumber(parts1[i]) ? 1 : -1; } if (i < parts2.length) { return isNumber(parts2[i]) ? -1 : 1; } return 0; } private boolean isNumber(String str) { return str.matches("\\d+"); } } /** * Compares two ArtifactInfo by their revision. Revisions are compared using an algorithm * inspired by PHP version_compare one, unless a dynamic revision is given, in which case the * version matcher is used to perform the comparison. */ final class ArtifactInfoComparator implements Comparator { public int compare(Object o1, Object o2) { String rev1 = ((ArtifactInfo) o1).getRevision(); String rev2 = ((ArtifactInfo) o2).getRevision(); /* * The revisions can still be not resolved, so we use the current version matcher to * know if one revision is dynamic, and in this case if it should be considered greater * or lower than the other one. Note that if the version matcher compare method returns * 0, it's because it's not possible to know which revision is greater. In this case we * consider the dynamic one to be greater, because most of the time it will then be * actually resolved and a real comparison will occur. */ VersionMatcher vmatcher = IvyContext.getContext().getSettings().getVersionMatcher(); ModuleRevisionId mrid1 = ModuleRevisionId.newInstance("", "", rev1); ModuleRevisionId mrid2 = ModuleRevisionId.newInstance("", "", rev2); if (vmatcher.isDynamic(mrid1)) { int c = vmatcher.compare(mrid1, mrid2, mridComparator); return c >= 0 ? 1 : -1; } else if (vmatcher.isDynamic(mrid2)) { int c = vmatcher.compare(mrid2, mrid1, mridComparator); return c >= 0 ? -1 : 1; } return mridComparator.compare(mrid1, mrid2); } } public static class SpecialMeaning { private String name; private Integer value; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public void validate() { if (name == null) { throw new IllegalStateException("a special meaning should have a name"); } if (value == null) { throw new IllegalStateException("a special meaning should have a value"); } } } private static final Map DEFAULT_SPECIAL_MEANINGS; static { DEFAULT_SPECIAL_MEANINGS = new HashMap(); DEFAULT_SPECIAL_MEANINGS.put("dev", new Integer(-1)); DEFAULT_SPECIAL_MEANINGS.put("rc", new Integer(1)); DEFAULT_SPECIAL_MEANINGS.put("final", new Integer(2)); } private final Comparator mridComparator = new MridComparator(); private final Comparator artifactInfoComparator = new ArtifactInfoComparator(); private Map specialMeanings = null; private boolean usedefaultspecialmeanings = true; public LatestRevisionStrategy() { setComparator(artifactInfoComparator); setName("latest-revision"); } public void addConfiguredSpecialMeaning(SpecialMeaning meaning) { meaning.validate(); getSpecialMeanings().put(meaning.getName().toLowerCase(Locale.US), meaning.getValue()); } public synchronized Map getSpecialMeanings() { if (specialMeanings == null) { specialMeanings = new HashMap(); if (isUsedefaultspecialmeanings()) { specialMeanings.putAll(DEFAULT_SPECIAL_MEANINGS); } } return specialMeanings; } public boolean isUsedefaultspecialmeanings() { return usedefaultspecialmeanings; } public void setUsedefaultspecialmeanings(boolean usedefaultspecialmeanings) { this.usedefaultspecialmeanings = usedefaultspecialmeanings; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/LatestStrategy.java000066400000000000000000000032441226750426600261520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.Date; import java.util.List; public interface LatestStrategy { /** * Finds the latest artifact among the given artifacts info. The definition of 'latest' depends * on the strategy itself. Given artifacts info are all good candidate. If the given date is not * null, then found artifact should not be later than this date. * * @param infos * @param date * @return the latest artifact among the given ones. */ ArtifactInfo findLatest(ArtifactInfo[] infos, Date date); /** * Sorts the given artifacts info from the oldest one to the latest one. The definition of * 'latest' depends on the strategy itself. Given artifacts info are all good candidate. * * @param infos * @return */ List sort(ArtifactInfo[] infos); String getName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/latest/LatestTimeStrategy.java000066400000000000000000000025341226750426600267720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.latest; import java.util.Comparator; public class LatestTimeStrategy extends ComparatorLatestStrategy { private static final Comparator COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { long d1 = ((ArtifactInfo) o1).getLastModified(); long d2 = ((ArtifactInfo) o2).getLastModified(); return new Long(d1).compareTo(new Long(d2)); } }; public LatestTimeStrategy() { super(COMPARATOR); setName("latest-time"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/000077500000000000000000000000001226750426600217615ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/AbstractLockStrategy.java000066400000000000000000000026031226750426600267240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; public abstract class AbstractLockStrategy implements LockStrategy { private String name; private boolean debugLocking = false; protected AbstractLockStrategy() { } protected AbstractLockStrategy(boolean debugLocking) { this.debugLocking = debugLocking; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return name; } public boolean isDebugLocking() { return debugLocking; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/ArtifactLockStrategy.java000066400000000000000000000027601226750426600267220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; public abstract class ArtifactLockStrategy extends FileBasedLockStrategy { protected ArtifactLockStrategy(FileLocker locker, boolean debugLocking) { super(locker, debugLocking); } public boolean lockArtifact(Artifact artifact, File artifactFileToDownload) throws InterruptedException { return acquireLock(new File(artifactFileToDownload.getAbsolutePath() + ".lck")); } public void unlockArtifact(Artifact artifact, File artifactFileToDownload) { releaseLock(new File(artifactFileToDownload.getAbsolutePath() + ".lck")); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/CreateFileLockStrategy.java000066400000000000000000000021011226750426600271550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; public class CreateFileLockStrategy extends ArtifactLockStrategy { public CreateFileLockStrategy(boolean debugLocking) { super(new CreateFileLocker(debugLocking), debugLocking); setName("artifact-lock"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/DeleteOnExitHook.java000066400000000000000000000030671226750426600260040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; import java.io.File; import java.util.Iterator; import java.util.LinkedHashSet; class DeleteOnExitHook { static { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { runHook(); } }); } private static LinkedHashSet files = new LinkedHashSet(); private DeleteOnExitHook() { } static synchronized void add(File file) { files.add(file); } static synchronized void remove(File file) { files.remove(file); } static synchronized void runHook() { Iterator itr = files.iterator(); while (itr.hasNext()) { ((File) itr.next()).delete(); itr.remove(); } } }ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/FileBasedLockStrategy.java000066400000000000000000000311061226750426600267770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileLock; import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.ivy.util.Message; public abstract class FileBasedLockStrategy extends AbstractLockStrategy { private static final int SLEEP_TIME = 100; private static final long DEFAULT_TIMEOUT = 2 * 60 * 1000; /** * The locker to use to make file lock attempts. */ private FileLocker locker; private long timeout = DEFAULT_TIMEOUT; /** * Lock counter list must be static: locks are implicitly shared to the entire process, so the * list too much be. */ private static ConcurrentMap/* > */currentLockHolders = new ConcurrentHashMap(); protected FileBasedLockStrategy() { this(new CreateFileLocker(false), false); } protected FileBasedLockStrategy(boolean debugLocking) { this(new CreateFileLocker(debugLocking), debugLocking); } protected FileBasedLockStrategy(FileLocker locker, boolean debugLocking) { super(debugLocking); this.locker = locker; } protected boolean acquireLock(File file) throws InterruptedException { Thread currentThread = Thread.currentThread(); if (isDebugLocking()) { debugLocking("acquiring lock on " + file); } long start = System.currentTimeMillis(); do { synchronized (currentLockHolders) { if (isDebugLocking()) { debugLocking("entered synchronized area (locking)"); } int lockCount = hasLock(file, currentThread); if (isDebugLocking()) { debugLocking("current status for " + file + " is " + lockCount + " held locks: " + getCurrentLockHolderNames(file)); } if (lockCount < 0) { /* Another thread in this process holds the lock; we need to wait */ if (isDebugLocking()) { debugLocking("waiting for another thread to release the lock: " + getCurrentLockHolderNames(file)); } } else if (lockCount > 0) { int holdLocks = incrementLock(file, currentThread); if (isDebugLocking()) { debugLocking("reentrant lock acquired on " + file + " in " + (System.currentTimeMillis() - start) + "ms" + " - hold locks = " + holdLocks); } return true; } else { /* No prior lock on this file is held at all */ if (locker.tryLock(file)) { if (isDebugLocking()) { debugLocking("lock acquired on " + file + " in " + (System.currentTimeMillis() - start) + "ms"); } incrementLock(file, currentThread); return true; } } } if (isDebugLocking()) { debugLocking("failed to acquire lock; sleeping for retry..."); } Thread.sleep(SLEEP_TIME); } while (System.currentTimeMillis() - start < timeout); return false; } protected void releaseLock(File file) { Thread currentThread = Thread.currentThread(); if (isDebugLocking()) { debugLocking("releasing lock on " + file); } synchronized (currentLockHolders) { if (isDebugLocking()) { debugLocking("entered synchronized area (unlocking)"); } int holdLocks = decrementLock(file, currentThread); if (holdLocks == 0) { locker.unlock(file); if (isDebugLocking()) { debugLocking("lock released on " + file); } } else { if (isDebugLocking()) { debugLocking("reentrant lock released on " + file + " - hold locks = " + holdLocks); } } } } private static void debugLocking(String msg) { Message.info(Thread.currentThread() + " " + System.currentTimeMillis() + " " + msg); } /** * Determine the state of the lockfile. * * Must be called from within a synchronized block. * * Three possibilities exist: - The lock is held by the current thread (>0) - The lock is held * by one or more different threads (-1) - The lock is not held at all (0). * * @param file * file to lock * @param forThread * thread for which lock status is being queried */ private int hasLock(File file, Thread forThread) { Map locksPerThread = (Map) currentLockHolders.get(file); if (locksPerThread == null) { return 0; } if (locksPerThread.isEmpty()) { return 0; } Integer counterObj = (Integer) locksPerThread.get(forThread); int counter = counterObj == null ? 0 : counterObj.intValue(); if (counter > 0) { return counter; } else { return -1; } } /** * Record that this thread holds the lock. * * Asserts that the lock has been previously grabbed by this thread. Must be called from a * synchronized block in which the lock was grabbed. * * @param file * file which has been locked * @param forThread * thread for which locking occurred * @return number of times this thread has grabbed the lock */ private int incrementLock(File file, Thread forThread) { Map locksPerThread = (Map) currentLockHolders.get(file); if (locksPerThread == null) { locksPerThread = new ConcurrentHashMap(); currentLockHolders.put(file, locksPerThread); } Integer c = (Integer) locksPerThread.get(forThread); int holdLocks = c == null ? 1 : c.intValue() + 1; locksPerThread.put(forThread, new Integer(holdLocks)); return holdLocks; } /** * Decrease depth of this thread's lock. * * Must be called within a synchronized block. * * If this returns 0, the caller is responsible for releasing the lock within that same block. * * @param file * file for which lock depth is being decreased * @param forThread * thread for which lock depth is being decreased * @return remaining depth of this lock */ private int decrementLock(File file, Thread forThread) { ConcurrentHashMap locksPerThread = (ConcurrentHashMap) currentLockHolders.get(file); if (locksPerThread == null) { throw new RuntimeException("Calling decrementLock on a thread which holds no locks"); } Integer c = (Integer) locksPerThread.get(forThread); int oldHeldLocks = c == null ? 0 : c.intValue(); if (oldHeldLocks <= 0) { throw new RuntimeException("Calling decrementLock on a thread which holds no locks"); } int newHeldLocks = oldHeldLocks - 1; if (newHeldLocks > 0) { locksPerThread.put(forThread, new Integer(newHeldLocks)); } else { locksPerThread.remove(forThread); } return newHeldLocks; } /** * Return a string naming the threads which currently hold this lock. */ protected String getCurrentLockHolderNames(File file) { StringBuilder sb = new StringBuilder(); ConcurrentHashMap m = (ConcurrentHashMap) currentLockHolders.get(file); if (m == null) { return "(NULL)"; } Enumeration threads = m.keys(); while (threads.hasMoreElements()) { Thread t = (Thread) threads.nextElement(); sb.append(t.toString()); if (threads.hasMoreElements()) { sb.append(", "); } } return sb.toString(); } public static interface FileLocker { boolean tryLock(File f); void unlock(File f); } /** * "locks" a file by creating it if it doesn't exist, relying on the * {@link File#createNewFile()} atomicity. */ public static class CreateFileLocker implements FileLocker { private boolean debugLocking; public CreateFileLocker(boolean debugLocking) { this.debugLocking = debugLocking; } public boolean tryLock(File file) { try { if (file.getParentFile().exists() || file.getParentFile().mkdirs()) { if (file.createNewFile()) { DeleteOnExitHook.add(file); return true; } else { if (debugLocking) { debugLocking("file creation failed " + file); } } } } catch (IOException e) { // ignored Message.verbose("file creation failed due to an exception: " + e.getMessage() + " (" + file + ")"); } return false; } public void unlock(File file) { file.delete(); DeleteOnExitHook.remove(file); } } /** * Locks a file using the {@link FileLock} mechanism. */ public static class NIOFileLocker implements FileLocker { private Map locks = new ConcurrentHashMap(); private boolean debugLocking; public NIOFileLocker(boolean debugLocking) { this.debugLocking = debugLocking; } private static class LockData { private RandomAccessFile raf; private FileLock l; LockData(RandomAccessFile raf, FileLock l) { this.raf = raf; this.l = l; } } public boolean tryLock(File file) { try { if (file.getParentFile().exists() || file.getParentFile().mkdirs()) { // this must not be closed until unlock RandomAccessFile raf = new RandomAccessFile(file, "rw"); FileLock l = raf.getChannel().tryLock(); if (l != null) { synchronized (this) { locks.put(file, new LockData(raf, l)); } return true; } else { if (debugLocking) { debugLocking("failed to acquire lock on " + file); } } } } catch (IOException e) { // ignored Message.verbose("file lock failed due to an exception: " + e.getMessage() + " (" + file + ")"); } return false; } public void unlock(File file) { synchronized (this) { LockData data = (LockData) locks.get(file); if (data == null) { throw new IllegalArgumentException("file not previously locked: " + file); } try { locks.remove(file); data.l.release(); data.raf.close(); } catch (IOException e) { Message.error("problem while releasing lock on " + file + ": " + e.getMessage()); } } } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/LockStrategy.java000066400000000000000000000052361226750426600252450ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; /** * A lock strategy determines when and how lock should be performed when downloading data to a * cache. *

    * Note that some implementations may actually choose to NOT perform locking, when no lock is * necessary (cache not shared). Some other implementations may choose to lock the cache for the * download of a whole module (not possible yet), or at the artifact level. *

    *

    * The lock methods should return true when the lock is either actually acquired or not performed by * the strategy.

    *

    * Locking used in the locking strategy must support reentrant lock. Reentrant locking should be * performed for the whole strategy. *

    */ public interface LockStrategy { /** * Returns the name of the strategy * * @return the name of the strategy */ String getName(); /** * Performs a lock before downloading the given {@link Artifact} to the given file. * * @param artifact * the artifact about to be downloaded * @param artifactFileToDownload * the file where the artifact will be downloaded * @return true if the artifact is locked, false otherwise * @throws InterruptedException * if the thread is interrupted while waiting to acquire the lock */ boolean lockArtifact(Artifact artifact, File artifactFileToDownload) throws InterruptedException; /** * Release the lock acquired for an artifact download. * * @param artifact * the artifact for which the lock was acquired * @param artifactFileToDownload * the file where the artifact is supposed to have been downloaded */ void unlockArtifact(Artifact artifact, File artifactFileToDownload); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/NIOFileLockStrategy.java000066400000000000000000000020741226750426600264100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; public class NIOFileLockStrategy extends ArtifactLockStrategy { public NIOFileLockStrategy(boolean debugLocking) { super(new NIOFileLocker(debugLocking), debugLocking); setName("artifact-lock-nio"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/lock/NoLockStrategy.java000066400000000000000000000023641226750426600255410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.lock; import java.io.File; import org.apache.ivy.core.module.descriptor.Artifact; public class NoLockStrategy extends AbstractLockStrategy { public NoLockStrategy() { setName("no-lock"); } public final boolean lockArtifact(Artifact artifact, File artifactFileToDownload) { return true; } public final void unlockArtifact(Artifact artifact, File artifactFileToDownload) { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/000077500000000000000000000000001226750426600224545ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/AbstractPatternMatcher.java000066400000000000000000000040301226750426600277210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * An abstract implementation of the pattern matcher providing base template methods */ public abstract class AbstractPatternMatcher implements PatternMatcher { private final String name; /** * Create a new instance of a pattern matcher * * @param name * the name of the pattern matcher. Never null. */ public AbstractPatternMatcher(/* @NotNull */String name) { this.name = name; } public/* @NotNull */Matcher getMatcher(/* @NotNull */String expression) { if (expression == null) { throw new NullPointerException(); } if (ANY_EXPRESSION.equals(expression)) { return AnyMatcher.INSTANCE; } return newMatcher(expression); } public/* @NotNull */String getName() { return name; } /** * Returns an instance of the implementation specific matcher. * * @param expression * the string to be matched. * @return the instance of the related matcher. Never null. */ protected abstract/* @NotNull */Matcher newMatcher(/* @NotNull */String expression); public String toString() { return getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/AnyMatcher.java000066400000000000000000000024001226750426600253460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * A matcher that will match everything. */ public/* @Immutable */class AnyMatcher implements Matcher { public static final Matcher INSTANCE = new AnyMatcher(); public AnyMatcher() { } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return true; } public boolean isExact() { return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/ExactOrRegexpPatternMatcher.java000066400000000000000000000044351226750426600307070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * A pattern matcher that tries to match exactly the input with the expression, or match it as a * pattern. *

    * The evaluation for matching is perform first by checking if expression and input are equals (via * equals method) else it attempts to do it by trying to match the input using the expression as a * regexp. * * @see ExactPatternMatcher * @see RegexpPatternMatcher */ public/* @Immutable */final class ExactOrRegexpPatternMatcher extends AbstractPatternMatcher { public static final ExactOrRegexpPatternMatcher INSTANCE = new ExactOrRegexpPatternMatcher(); public ExactOrRegexpPatternMatcher() { super(EXACT_OR_REGEXP); } protected Matcher newMatcher(String expression) { return new ExactOrRegexpMatcher(expression); } private static final class ExactOrRegexpMatcher implements Matcher { private Matcher exact; private Matcher regexp; public ExactOrRegexpMatcher(String expression) { exact = ExactPatternMatcher.INSTANCE.getMatcher(expression); regexp = RegexpPatternMatcher.INSTANCE.getMatcher(expression); } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return exact.matches(input) || regexp.matches(input); } public boolean isExact() { return regexp.isExact(); // && exact.isExact(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/ExactPatternMatcher.java000066400000000000000000000035731226750426600272350ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * Implementation of an exact matcher. *

    * The matching will be performed against an expression being a string. It will only matches if both * strings are equal (per equals()) rule or if both strings are null. */ public/* @Immutable */final class ExactPatternMatcher extends AbstractPatternMatcher { public static final ExactPatternMatcher INSTANCE = new ExactPatternMatcher(); public ExactPatternMatcher() { super(EXACT); } protected Matcher newMatcher(String expression) { return new ExactMatcher(expression); } private static/* @Immutable */class ExactMatcher implements Matcher { private String expression; public ExactMatcher(String expression) { this.expression = expression; } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return input.equals(expression); } public boolean isExact() { return true; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/GlobPatternMatcher.java000066400000000000000000000067741226750426600270620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; import java.util.regex.PatternSyntaxException; import org.apache.oro.text.GlobCompiler; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.Perl5Matcher; /** * A pattern matcher matching input using unix-like glob matcher expressions. Meta characters are: *

      *
    • * - Matches zero or more characters
    • *
    • ? - Matches exactly one character.
    • *
    *

    * Note that this matcher is available only with in your classpath. * * @see GlobCompiler */ public/* @Immutable */final class GlobPatternMatcher extends AbstractPatternMatcher { public static final GlobPatternMatcher INSTANCE = new GlobPatternMatcher(); /* * NOTE: GlobCompiler does ~100K compilation/s - If necessary look into using ThreadLocal for * GlobCompiler/Perl5Matcher to cut on useless object creation - If expression are reused over * and over a LRU cache could make sense */ public GlobPatternMatcher() { super(GLOB); } protected Matcher newMatcher(String expression) { return new GlobMatcher(expression); } private static class GlobMatcher implements Matcher { private Pattern pattern; private String expression; private Boolean exact; public GlobMatcher(String expression) throws PatternSyntaxException { this.expression = expression; try { pattern = new GlobCompiler().compile(expression); } catch (MalformedPatternException e) { throw new PatternSyntaxException(e.getMessage(), expression, 0); } } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return new Perl5Matcher().matches(input, pattern); } public boolean isExact() { if (exact == null) { exact = calculateExact(); } return exact.booleanValue(); } private Boolean calculateExact() { Boolean result = Boolean.TRUE; char[] expressionChars = expression.toCharArray(); for (int i = 0; i < expressionChars.length; i++) { char ch = expressionChars[i]; if (ch == '*' || ch == '?' || ch == '[' || ch == ']') { result = Boolean.FALSE; break; } } return result; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/MapMatcher.java000066400000000000000000000043601226750426600253430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; public class MapMatcher { private Map/* */matchers = new HashMap(); private PatternMatcher pm; private Map attributes; public MapMatcher(Map attributes, PatternMatcher pm) { this.attributes = attributes; this.pm = pm; for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry) iter.next(); String value = (String) entry.getValue(); if (value != null) { matchers.put(entry.getKey(), pm.getMatcher(value)); } } } public boolean matches(Map/* */m) { for (Iterator iter = matchers.entrySet().iterator(); iter.hasNext();) { Entry entry = (Entry) iter.next(); Matcher matcher = (Matcher) entry.getValue(); String value = (String) m.get(entry.getKey()); if ((value == null) || !matcher.matches(value)) { return false; } } return true; } public String toString() { return attributes + " (" + pm.getName() + ")"; } public Map getAttributes() { return Collections.unmodifiableMap(attributes); } public PatternMatcher getPatternMatcher() { return pm; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/Matcher.java000066400000000000000000000034141226750426600247040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * An interface that defines a string matcher. */ public interface Matcher { /** * Check whether a given string is matched by this matcher. * * @param input * the string to be matched. Cannot be null. * @return true if the input string is matched, false otherwise. */ public boolean matches(/* @NotNull */String input); /** * Return if the matcher will match *only* if the expression equals the input. WARN: This is * used only as a performance trick, to avoid scanning for things when you already know exactly * what you want. In the install task where it used it avoid scanning the repository to list all * modules to find that only one matches, and that it has the name requested. * * @return true if the matcher only matches when the expression is equals to the input, false * otherwise. */ public boolean isExact(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/MatcherHelper.java000066400000000000000000000053021226750426600260420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * Set of helper methods to match ModuleId, ModuleRevisionId, ArtifactId */ public final class MatcherHelper { // TODO this class might be better off as MatcherUtils in util package private MatcherHelper() { } public static boolean matches(PatternMatcher m, String expression, String input) { return m.getMatcher(expression).matches(input); } public static boolean matches(PatternMatcher m, ModuleId exp, ModuleId mid) { return matches(m, exp.getOrganisation(), mid.getOrganisation()) && matches(m, exp.getName(), mid.getName()); } public static boolean matches(PatternMatcher m, ModuleRevisionId exp, ModuleRevisionId mrid) { return matches(m, exp.getOrganisation(), mrid.getOrganisation()) && matches(m, exp.getName(), mrid.getName()) && matches(m, exp.getRevision(), mrid.getRevision()); } public static boolean matches(PatternMatcher m, ArtifactId exp, ArtifactId aid) { return matches(m, exp.getModuleId(), aid.getModuleId()) && matches(m, exp.getName(), aid.getName()) && matches(m, exp.getExt(), aid.getExt()) && matches(m, exp.getType(), aid.getType()); } public static boolean isExact(PatternMatcher m, ModuleRevisionId exp) { return isExact(m, exp.getOrganisation()) && isExact(m, exp.getName()) && isExact(m, exp.getRevision()); } // unused public static boolean isExact(PatternMatcher m, ModuleId exp) { return isExact(m, exp.getOrganisation()) && isExact(m, exp.getName()); } public static boolean isExact(PatternMatcher m, String exp) { return m.getMatcher(exp).isExact(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/NoMatcher.java000066400000000000000000000023761226750426600252070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * A matcher that matches nothing. */ public final/* @Immutable */class NoMatcher implements Matcher { public static final Matcher INSTANCE = new NoMatcher(); public NoMatcher() { } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return false; } public boolean isExact() { return true; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/PatternMatcher.java000066400000000000000000000042661226750426600262500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; /** * Interface for a pattern matcher. *

    * The pattern matcher is the main abstraction regarding the matching of an expression. * Implementation may vary depending on the expression syntax handling that is desired. */ public interface PatternMatcher { /** * 'exact' pattern matcher name */ public static final String EXACT = "exact"; /** * pattern matcher name 'regexp' */ public static final String REGEXP = "regexp"; /** * pattern matcher 'glob' */ public static final String GLOB = "glob"; /** * pattern matcher name 'exactOrRegexp' */ public static final String EXACT_OR_REGEXP = "exactOrRegexp"; /** * Any expression string: '*' */ public static final String ANY_EXPRESSION = "*"; /** * Return the matcher for the given expression. * * @param expression * the expression to be matched. Cannot be null ? * @return the matcher instance for the given expression. Never null. */ public/* @NotNull */Matcher getMatcher(/* @NotNull */String expression); /** * return the name of this pattern matcher * * @return the name of this pattern matcher. Never null. * @see #EXACT * @see #REGEXP * @see #GLOB * @see #EXACT_OR_REGEXP */ public/* @NotNull */String getName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/matcher/RegexpPatternMatcher.java000066400000000000000000000057001226750426600274150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * A pattern matcher matching input using regular expressions. * * @see Pattern */ public final/* @Immutable */class RegexpPatternMatcher extends AbstractPatternMatcher { public static final RegexpPatternMatcher INSTANCE = new RegexpPatternMatcher(); /* * NOTE: Regexp compiler does ~200K compilation/s - If necessary look into using ThreadLocal * Pattern to cut on useless object creation - If expression are reused over and over a LRU * cache could make sense */ public RegexpPatternMatcher() { super(REGEXP); } protected Matcher newMatcher(String expression) { return new RegexpMatcher(expression); } private static/* @Immutable */class RegexpMatcher implements Matcher { private Pattern pattern; private String expression; private Boolean exact; public RegexpMatcher(String expression) throws PatternSyntaxException { if (expression == null) { throw new NullPointerException(); } this.expression = expression; pattern = Pattern.compile(expression); } public boolean matches(String input) { if (input == null) { throw new NullPointerException(); } return pattern.matcher(input).matches(); } public boolean isExact() { if (exact == null) { exact = calculateExact(); } return exact.booleanValue(); } private Boolean calculateExact() { Boolean result = Boolean.TRUE; char[] expressionChars = expression.toCharArray(); for (int i = 0; i < expressionChars.length; i++) { char ch = expressionChars[i]; if (!Character.isLetterOrDigit(ch) && !Character.isWhitespace(ch) && ('-' != ch) && ('_' != ch)) { result = Boolean.FALSE; break; } } return result; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/000077500000000000000000000000001226750426600227655ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/MRIDRule.java000066400000000000000000000034501226750426600252150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; public class MRIDRule { private String org; private String module; private String branch; private String rev; public MRIDRule(String org, String mod, String rev) { this.org = org; this.module = mod; this.rev = rev; } public MRIDRule() { } public String getModule() { return module; } public void setModule(String module) { this.module = module; } public String getOrg() { return org; } public void setOrg(String org) { this.org = org; } public String getRev() { return rev; } public void setRev(String rev) { this.rev = rev; } public String toString() { return "[ " + org + " " + module + (branch != null ? " " + branch : "") + " " + rev + " ]"; } public String getBranch() { return branch; } public void setBranch(String branch) { this.branch = branch; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/MRIDTransformationRule.java000066400000000000000000000123201226750426600301400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.util.Message; public class MRIDTransformationRule implements NamespaceTransformer { private static class MridRuleMatcher { private static final String[] TYPES = new String[] {"o", "m", "b", "r"}; private Matcher[] matchers = new Matcher[TYPES.length]; public boolean match(MRIDRule src, ModuleRevisionId mrid) { // CheckStyle:MagicNumber| OFF matchers[0] = Pattern.compile(getPattern(src.getOrg())).matcher(mrid.getOrganisation()); if (!matchers[0].matches()) { return false; } matchers[1] = Pattern.compile(getPattern(src.getModule())).matcher(mrid.getName()); if (!matchers[1].matches()) { return false; } if (mrid.getBranch() == null) { matchers[2] = null; } else { matchers[2] = Pattern.compile(getPattern(src.getBranch())) .matcher(mrid.getBranch()); if (!matchers[2].matches()) { return false; } } matchers[3] = Pattern.compile(getPattern(src.getRev())).matcher(mrid.getRevision()); if (!matchers[3].matches()) { return false; } return true; // CheckStyle:MagicNumber| ON } public ModuleRevisionId apply(MRIDRule dest, ModuleRevisionId mrid) { String org = applyRules(dest.getOrg(), "o"); String mod = applyRules(dest.getModule(), "m"); String branch = applyRules(dest.getBranch(), "b"); String rev = applyRules(dest.getRev(), "r"); return ModuleRevisionId.newInstance(org, mod, branch, rev, mrid.getQualifiedExtraAttributes()); } private String applyRules(String str, String type) { for (int i = 0; i < TYPES.length; i++) { str = applyTypeRule(str, TYPES[i], type, matchers[i]); } return str; } private String applyTypeRule(String rule, String type, String ruleType, Matcher m) { if (m == null) { return rule; } String res = rule == null ? "$" + ruleType + "0" : rule; for (int i = 0; i < TYPES.length; i++) { if (TYPES[i].equals(type)) { res = res.replaceAll("([^\\\\])\\$" + type, "$1\\$"); res = res.replaceAll("^\\$" + type, "\\$"); } else { res = res.replaceAll("([^\\\\])\\$" + TYPES[i], "$1\\\\\\$" + TYPES[i]); res = res.replaceAll("^\\$" + TYPES[i], "\\\\\\$" + TYPES[i]); } } StringBuffer sb = new StringBuffer(); m.reset(); m.find(); m.appendReplacement(sb, res); String str = sb.toString(); // null rule not replaced, let it be null if (rule == null && ("$" + ruleType + "0").equals(str)) { return null; } return str; } private String getPattern(String p) { return p == null ? ".*" : p; } } private List src = new ArrayList(); private MRIDRule dest; public void addSrc(MRIDRule src) { this.src.add(src); } public void addDest(MRIDRule dest) { if (this.dest != null) { throw new IllegalArgumentException("only one dest is allowed per mapping"); } this.dest = dest; } public ModuleRevisionId transform(ModuleRevisionId mrid) { MridRuleMatcher matcher = new MridRuleMatcher(); for (Iterator iter = src.iterator(); iter.hasNext();) { MRIDRule rule = (MRIDRule) iter.next(); if (matcher.match(rule, mrid)) { ModuleRevisionId destMrid = matcher.apply(dest, mrid); Message.debug("found matching namespace rule: " + rule + ". Applied " + dest + " on " + mrid + ". Transformed to " + destMrid); return destMrid; } } return mrid; } public boolean isIdentity() { return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java000066400000000000000000000113471226750426600266320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.ResolvedModuleRevision; public final class NameSpaceHelper { private NameSpaceHelper() { } public static DependencyDescriptor toSystem(DependencyDescriptor dd, Namespace ns) { return DefaultDependencyDescriptor.transformInstance(dd, ns); } public static DependencyDescriptor transform(DependencyDescriptor dd, NamespaceTransformer t, boolean fromSystem) { return DefaultDependencyDescriptor.transformInstance(dd, t, fromSystem); } public static ModuleDescriptor toSystem(ModuleDescriptor md, Namespace ns) { return DefaultModuleDescriptor.transformInstance(md, ns); } public static ResolvedModuleRevision toSystem(ResolvedModuleRevision rmr, Namespace ns) { if (ns.getToSystemTransformer().isIdentity()) { return rmr; } ModuleDescriptor md = toSystem(rmr.getDescriptor(), ns); if (md.equals(rmr.getDescriptor())) { return rmr; } return new ResolvedModuleRevision(rmr.getResolver(), rmr.getArtifactResolver(), md, transform(rmr.getReport(), ns.getToSystemTransformer()), rmr.isForce()); } public static Artifact transform(Artifact artifact, NamespaceTransformer t) { if (t.isIdentity()) { return artifact; } ModuleRevisionId mrid = t.transform(artifact.getModuleRevisionId()); if (artifact.getModuleRevisionId().equals(mrid)) { return artifact; } return new DefaultArtifact(mrid, artifact.getPublicationDate(), artifact.getName(), artifact.getType(), artifact.getExt(), artifact.getUrl(), artifact.getQualifiedExtraAttributes()); } public static MetadataArtifactDownloadReport transform(MetadataArtifactDownloadReport report, NamespaceTransformer t) { if (t.isIdentity()) { return report; } MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(transform( report.getArtifact(), t)); madr.setSearched(report.isSearched()); madr.setDownloadStatus(report.getDownloadStatus()); madr.setDownloadDetails(report.getDownloadDetails()); madr.setArtifactOrigin(report.getArtifactOrigin()); madr.setDownloadTimeMillis(report.getDownloadTimeMillis()); madr.setOriginalLocalFile(report.getOriginalLocalFile()); madr.setLocalFile(report.getLocalFile()); madr.setSize(report.getSize()); return madr; } public static ArtifactId transform(ArtifactId artifactId, NamespaceTransformer t) { if (t.isIdentity()) { return artifactId; } ModuleId mid = transform(artifactId.getModuleId(), t); if (mid.equals(artifactId.getModuleId())) { return artifactId; } return new ArtifactId(mid, artifactId.getName(), artifactId.getType(), artifactId.getExt()); } public static ModuleId transform(ModuleId mid, NamespaceTransformer t) { if (t.isIdentity()) { return mid; } return t.transform(new ModuleRevisionId(mid, "")).getModuleId(); } public static String transformOrganisation(String org, NamespaceTransformer t) { return transform(new ModuleId(org, ""), t).getOrganisation(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/Namespace.java000066400000000000000000000064341226750426600255330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.module.id.ModuleRevisionId; public class Namespace { public static final Namespace SYSTEM_NAMESPACE; static { SYSTEM_NAMESPACE = new Namespace(); } private List/* */rules = new ArrayList(); private String name; private boolean chainRules = false; private NamespaceTransformer fromSystemTransformer = new NamespaceTransformer() { public ModuleRevisionId transform(ModuleRevisionId mrid) { if (mrid == null) { return null; } for (Iterator iter = rules.iterator(); iter.hasNext();) { NamespaceRule rule = (NamespaceRule) iter.next(); ModuleRevisionId nmrid = rule.getFromSystem().transform(mrid); if (chainRules) { mrid = nmrid; } else if (!nmrid.equals(mrid)) { return nmrid; } } return mrid; } public boolean isIdentity() { return rules.isEmpty(); } }; private NamespaceTransformer toSystemTransformer = new NamespaceTransformer() { public ModuleRevisionId transform(ModuleRevisionId mrid) { if (mrid == null) { return null; } for (Iterator iter = rules.iterator(); iter.hasNext();) { NamespaceRule rule = (NamespaceRule) iter.next(); ModuleRevisionId nmrid = rule.getToSystem().transform(mrid); if (chainRules) { mrid = nmrid; } else if (!nmrid.equals(mrid)) { return nmrid; } } return mrid; } public boolean isIdentity() { return rules.isEmpty(); } }; public void addRule(NamespaceRule rule) { rules.add(rule); } public String getName() { return name; } public void setName(String name) { this.name = name; } public NamespaceTransformer getFromSystemTransformer() { return fromSystemTransformer; } public NamespaceTransformer getToSystemTransformer() { return toSystemTransformer; } public boolean isChainrules() { return chainRules; } public void setChainrules(boolean chainRules) { this.chainRules = chainRules; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/NamespaceRule.java000066400000000000000000000037251226750426600263630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; public class NamespaceRule { private String name; private String description; private MRIDTransformationRule fromSystem; private MRIDTransformationRule toSystem; public MRIDTransformationRule getFromSystem() { return fromSystem; } public void addFromsystem(MRIDTransformationRule fromSystem) { if (this.fromSystem != null) { throw new IllegalArgumentException("only one fromsystem is allowed per rule"); } this.fromSystem = fromSystem; } public MRIDTransformationRule getToSystem() { return toSystem; } public void addTosystem(MRIDTransformationRule toSystem) { if (this.toSystem != null) { throw new IllegalArgumentException("only one tosystem is allowed per rule"); } this.toSystem = toSystem; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/namespace/NamespaceTransformer.java000066400000000000000000000020361226750426600277500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.namespace; import org.apache.ivy.core.module.id.ModuleRevisionId; public interface NamespaceTransformer { public ModuleRevisionId transform(ModuleRevisionId mrid); public boolean isIdentity(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/000077500000000000000000000000001226750426600223255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/AbstractModuleDescriptorParser.java000066400000000000000000000353041226750426600313220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser; import java.io.IOException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.ResourceHelper; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; public abstract class AbstractModuleDescriptorParser implements ModuleDescriptorParser { public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, boolean validate) throws ParseException, IOException { return parseDescriptor(ivySettings, descriptorURL, new URLResource(descriptorURL), validate); } public String getType() { return "ivy"; } public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) { return DefaultArtifact.newIvyArtifact(mrid, new Date(res.getLastModified())); } protected abstract static class AbstractParser extends DefaultHandler { private static final String DEFAULT_CONF_MAPPING = "*->*"; private String defaultConf; // used only as defaultconf, not used for // guesssing right side part of a mapping private String defaultConfMapping; // same as default conf but is used // for guesssing right side part of a mapping private DefaultDependencyDescriptor defaultConfMappingDescriptor; private Resource res; private List errors = new ArrayList(); private DefaultModuleDescriptor md; private ModuleDescriptorParser parser; protected AbstractParser(ModuleDescriptorParser parser) { this.parser = parser; } public ModuleDescriptorParser getModuleDescriptorParser() { return parser; } protected void checkErrors() throws ParseException { if (!errors.isEmpty()) { throw new ParseException(errors.toString(), 0); } } public void setResource(Resource res) { this.res = res; // used for log and date only md = new DefaultModuleDescriptor(parser, res); md.setLastModified(ResourceHelper.getLastModifiedOrDefault(res)); } protected Resource getResource() { return res; } protected String getDefaultConfMapping() { return defaultConfMapping; } protected void setDefaultConfMapping(String defaultConf) { defaultConfMapping = defaultConf; getMd().setDefaultConfMapping(defaultConf); } protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd) { parseDepsConfs(confs, dd, defaultConfMapping != null); } protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande) { parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande, true); } protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) { if (confs == null) { return; } String[] conf = confs.split(";"); parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, evaluateConditions); } protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande) { parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, true); } protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) { replaceConfigurationWildcards(md); for (int i = 0; i < conf.length; i++) { String[] ops = conf[i].split("->"); if (ops.length == 1) { String[] modConfs = ops[0].split(","); if (!useDefaultMappingToGuessRightOperande) { for (int j = 0; j < modConfs.length; j++) { dd.addDependencyConfiguration(modConfs[j].trim(), modConfs[j].trim()); } } else { for (int j = 0; j < modConfs.length; j++) { String[] depConfs = getDefaultConfMappingDescriptor() .getDependencyConfigurations(modConfs[j]); if (depConfs.length > 0) { for (int k = 0; k < depConfs.length; k++) { String mappedDependency = evaluateConditions ? evaluateCondition( depConfs[k].trim(), dd) : depConfs[k].trim(); if (mappedDependency != null) { dd.addDependencyConfiguration(modConfs[j].trim(), mappedDependency); } } } else { // no default mapping found for this configuration, map // configuration to itself dd.addDependencyConfiguration(modConfs[j].trim(), modConfs[j].trim()); } } } } else if (ops.length == 2) { String[] modConfs = ops[0].split(","); String[] depConfs = ops[1].split(","); for (int j = 0; j < modConfs.length; j++) { for (int k = 0; k < depConfs.length; k++) { String mappedDependency = evaluateConditions ? evaluateCondition( depConfs[k].trim(), dd) : depConfs[k].trim(); if (mappedDependency != null) { dd.addDependencyConfiguration(modConfs[j].trim(), mappedDependency); } } } } else { addError("invalid conf " + conf[i] + " for " + dd); } } if (md.isMappingOverride()) { addExtendingConfigurations(conf, dd, useDefaultMappingToGuessRightOperande); } } /** * Evaluate the optional condition in the given configuration, like "[org=MYORG]confX". If * the condition evaluates to true, the configuration is returned, if the condition * evaluatate to false, null is returned. If there are no conditions, the configuration * itself is returned. * * @param conf * the configuration to evaluate * @param dd * the dependencydescriptor to which the configuration will be added * @return the evaluated condition */ private String evaluateCondition(String conf, DefaultDependencyDescriptor dd) { if (conf.charAt(0) != '[') { return conf; } int endConditionIndex = conf.indexOf(']'); if (endConditionIndex == -1) { addError("invalid conf " + conf + " for " + dd); return null; } String condition = conf.substring(1, endConditionIndex); int notEqualIndex = condition.indexOf("!="); if (notEqualIndex == -1) { int equalIndex = condition.indexOf('='); if (equalIndex == -1) { addError("invalid conf " + conf + " for " + dd.getDependencyRevisionId()); return null; } String leftOp = condition.substring(0, equalIndex).trim(); String rightOp = condition.substring(equalIndex + 1).trim(); // allow organisation synonyms, like 'org' or 'organization' if (leftOp.equals("org") || leftOp.equals("organization")) { leftOp = "organisation"; } String attrValue = dd.getAttribute(leftOp); if (!rightOp.equals(attrValue)) { return null; } } else { String leftOp = condition.substring(0, notEqualIndex).trim(); String rightOp = condition.substring(notEqualIndex + 2).trim(); // allow organisation synonyms, like 'org' or 'organization' if (leftOp.equals("org") || leftOp.equals("organization")) { leftOp = "organisation"; } String attrValue = dd.getAttribute(leftOp); if (rightOp.equals(attrValue)) { return null; } } return conf.substring(endConditionIndex + 1); } private void addExtendingConfigurations(String[] confs, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande) { for (int i = 0; i < confs.length; i++) { addExtendingConfigurations(confs[i], dd, useDefaultMappingToGuessRightOperande); } } private void addExtendingConfigurations(String conf, DefaultDependencyDescriptor dd, boolean useDefaultMappingToGuessRightOperande) { Set configsToAdd = new HashSet(); Configuration[] configs = md.getConfigurations(); for (int i = 0; i < configs.length; i++) { String[] ext = configs[i].getExtends(); for (int j = 0; j < ext.length; j++) { if (conf.equals(ext[j])) { String configName = configs[i].getName(); configsToAdd.add(configName); addExtendingConfigurations(configName, dd, useDefaultMappingToGuessRightOperande); } } } String[] confs = (String[]) configsToAdd.toArray(new String[configsToAdd.size()]); parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande); } protected DependencyDescriptor getDefaultConfMappingDescriptor() { if (defaultConfMappingDescriptor == null) { defaultConfMappingDescriptor = new DefaultDependencyDescriptor( ModuleRevisionId.newInstance("", "", ""), false); parseDepsConfs(defaultConfMapping, defaultConfMappingDescriptor, false, false); } return defaultConfMappingDescriptor; } protected void addError(String msg) { if (res != null) { errors.add(msg + " in " + res + "\n"); } else { errors.add(msg + "\n"); } } public void warning(SAXParseException ex) { Message.warn("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage()); } public void error(SAXParseException ex) { addError("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage()); } public void fatalError(SAXParseException ex) throws SAXException { addError("[Fatal Error] " + getLocationString(ex) + ": " + ex.getMessage()); } /** Returns a string of the location. */ private String getLocationString(SAXParseException ex) { StringBuffer str = new StringBuffer(); String systemId = ex.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) { systemId = systemId.substring(index + 1); } str.append(systemId); } else if (getResource() != null) { str.append(getResource().toString()); } str.append(':'); str.append(ex.getLineNumber()); str.append(':'); str.append(ex.getColumnNumber()); return str.toString(); } // getLocationString(SAXParseException):String protected String getDefaultConf() { return defaultConf != null ? defaultConf : (defaultConfMapping != null ? defaultConfMapping : DEFAULT_CONF_MAPPING); } protected void setDefaultConf(String defaultConf) { this.defaultConf = defaultConf; getMd().setDefaultConf(defaultConf); } public ModuleDescriptor getModuleDescriptor() throws ParseException { checkErrors(); return md; } protected Date getDefaultPubDate() { return new Date(md.getLastModified()); } private void replaceConfigurationWildcards(ModuleDescriptor md) { Configuration[] configs = md.getConfigurations(); for (int i = 0; i < configs.length; i++) { configs[i].replaceWildcards(md); } } protected void setMd(DefaultModuleDescriptor md) { this.md = md; } protected DefaultModuleDescriptor getMd() { return md; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/ModuleDescriptorParser.java000066400000000000000000000052401226750426600276320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.repository.Resource; public interface ModuleDescriptorParser { public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, boolean validate) throws ParseException, IOException; public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, Resource res, boolean validate) throws ParseException, IOException; /** * Convert a module descriptor to an ivy file. This method MUST close the given input stream * when job is finished * * @param is * input stream with opened on original module descriptor resource */ public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws ParseException, IOException; public boolean accept(Resource res); /** * Return the 'type' of module artifacts this parser is parsing * * @return the 'type' of module artifacts this parser is parsing */ public String getType(); /** * Returns the module metadata artifact corresponding to the given module revision id that this * parser parses * * @param res * the resource for which the module artifact should be returned * @param mrid * the module revision id for which the module artifact should be returned * @return the module artifact corresponding to the given mrid and resource */ public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/ModuleDescriptorParserRegistry.java000066400000000000000000000073611226750426600313710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.osgi.core.OSGiManifestParser; import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorParser; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; public final class ModuleDescriptorParserRegistry extends AbstractModuleDescriptorParser { private static final ModuleDescriptorParserRegistry INSTANCE = new ModuleDescriptorParserRegistry(); public static ModuleDescriptorParserRegistry getInstance() { return INSTANCE; } private List parsers = new LinkedList(); private ModuleDescriptorParserRegistry() { parsers.add(PomModuleDescriptorParser.getInstance()); parsers.add(OSGiManifestParser.getInstance()); parsers.add(XmlModuleDescriptorParser.getInstance()); } /** * Adds a the given parser to this registry. * * @param parser * the parser to add */ public void addParser(ModuleDescriptorParser parser) { /* * The parser is added in the front of the list of parsers. This is necessary because the * XmlModuleDescriptorParser accepts all resources! */ parsers.add(0, parser); } public ModuleDescriptorParser[] getParsers() { return (ModuleDescriptorParser[]) parsers .toArray(new ModuleDescriptorParser[parsers.size()]); } public ModuleDescriptorParser getParser(Resource res) { for (Iterator iter = parsers.iterator(); iter.hasNext();) { ModuleDescriptorParser parser = (ModuleDescriptorParser) iter.next(); if (parser.accept(res)) { return parser; } } return null; } public ModuleDescriptor parseDescriptor(ParserSettings settings, URL descriptorURL, Resource res, boolean validate) throws ParseException, IOException { ModuleDescriptorParser parser = getParser(res); if (parser == null) { Message.warn("no module descriptor parser found for " + res); return null; } return parser.parseDescriptor(settings, descriptorURL, res, validate); } public boolean accept(Resource res) { return getParser(res) != null; } public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws ParseException, IOException { ModuleDescriptorParser parser = getParser(res); if (parser == null) { Message.warn("no module descriptor parser found for " + res); } else { parser.toIvyFile(is, res, destFile, md); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/ParserSettings.java000066400000000000000000000041111226750426600261420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser; import java.io.File; import java.util.Map; import org.apache.ivy.core.RelativeUrlResolver; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.resolver.DependencyResolver; public interface ParserSettings { String substitute(String value); Map/* */substitute(Map/* */strings); ResolutionCacheManager getResolutionCacheManager(); ConflictManager getConflictManager(String name); PatternMatcher getMatcher(String matcherName); Namespace getNamespace(String namespace); StatusManager getStatusManager(); RelativeUrlResolver getRelativeUrlResolver(); DependencyResolver getResolver(ModuleRevisionId mRevId); File resolveFile(String filename); String getDefaultBranch(ModuleId moduleId); /** * Returns the namespace context in which the current descriptor is parsed. */ Namespace getContextNamespace(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/000077500000000000000000000000001226750426600226435ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/DefaultPomDependencyMgt.java000066400000000000000000000034211226750426600302150ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.util.List; public class DefaultPomDependencyMgt implements PomDependencyMgt { private String groupId; private String artifactId; private String version; private String scope; private List /* */excludedModules; public DefaultPomDependencyMgt(String groupId, String artifactId, String version, String scope, List /* */excludedModules) { this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.scope = scope; this.excludedModules = excludedModules; } public String getScope() { return scope; } public String getGroupId() { return groupId; } public String getArtifactId() { return artifactId; } public String getVersion() { return version; } public List /* */getExcludedModules() { return excludedModules; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomDependencyMgt.java000066400000000000000000000021711226750426600267110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.util.List; public interface PomDependencyMgt { public abstract String getGroupId(); public abstract String getArtifactId(); public abstract String getVersion(); public abstract String getScope(); public List /* */getExcludedModules(); }ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorBuilder.java000066400000000000000000000761251226750426600307700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.Ivy; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.License; import org.apache.ivy.core.module.descriptor.MDArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyData; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; /** * Build a module descriptor. This class handle the complexity of the structure of an ivy * ModuleDescriptor and isolate the PomModuleDescriptorParser from it. */ public class PomModuleDescriptorBuilder { private static final int DEPENDENCY_MANAGEMENT_KEY_PARTS_COUNT = 4; public static final Configuration[] MAVEN2_CONFIGURATIONS = new Configuration[] { new Configuration("default", Visibility.PUBLIC, "runtime dependencies and master artifact can be used with this conf", new String[] {"runtime", "master"}, true, null), new Configuration("master", Visibility.PUBLIC, "contains only the artifact published by this module itself, " + "with no transitive dependencies", new String[0], true, null), new Configuration("compile", Visibility.PUBLIC, "this is the default scope, used if none is specified. " + "Compile dependencies are available in all classpaths.", new String[0], true, null), new Configuration( "provided", Visibility.PUBLIC, "this is much like compile, but indicates you expect the JDK or a container " + "to provide it. " + "It is only available on the compilation classpath, and is not transitive.", new String[0], true, null), new Configuration("runtime", Visibility.PUBLIC, "this scope indicates that the dependency is not required for compilation, " + "but is for execution. It is in the runtime and test classpaths, " + "but not the compile classpath.", new String[] {"compile"}, true, null), new Configuration( "test", Visibility.PRIVATE, "this scope indicates that the dependency is not required for normal use of " + "the application, and is only available for the test compilation and " + "execution phases.", new String[] {"runtime"}, true, null), new Configuration( "system", Visibility.PUBLIC, "this scope is similar to provided except that you have to provide the JAR " + "which contains it explicitly. The artifact is always available and is not " + "looked up in a repository.", new String[0], true, null), new Configuration("sources", Visibility.PUBLIC, "this configuration contains the source artifact of this module, if any.", new String[0], true, null), new Configuration("javadoc", Visibility.PUBLIC, "this configuration contains the javadoc artifact of this module, if any.", new String[0], true, null), new Configuration("optional", Visibility.PUBLIC, "contains all optional dependencies", new String[0], true, null)}; static final Map MAVEN2_CONF_MAPPING = new HashMap(); private static final String DEPENDENCY_MANAGEMENT = "m:dependency.management"; private static final String PROPERTIES = "m:properties"; private static final String EXTRA_INFO_DELIMITER = "__"; private static final Collection/* */JAR_PACKAGINGS = Arrays.asList(new String[] { "ejb", "bundle", "maven-plugin", "eclipse-plugin", "jbi-component", "jbi-shared-library", "orbit", "hk2-jar"}); static interface ConfMapper { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional); } static { MAVEN2_CONF_MAPPING.put("compile", new ConfMapper() { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional) { if (isOptional) { dd.addDependencyConfiguration("optional", "compile(*)"); // dd.addDependencyConfiguration("optional", "provided(*)"); dd.addDependencyConfiguration("optional", "master(*)"); } else { dd.addDependencyConfiguration("compile", "compile(*)"); // dd.addDependencyConfiguration("compile", "provided(*)"); dd.addDependencyConfiguration("compile", "master(*)"); dd.addDependencyConfiguration("runtime", "runtime(*)"); } } }); MAVEN2_CONF_MAPPING.put("provided", new ConfMapper() { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional) { if (isOptional) { dd.addDependencyConfiguration("optional", "compile(*)"); dd.addDependencyConfiguration("optional", "provided(*)"); dd.addDependencyConfiguration("optional", "runtime(*)"); dd.addDependencyConfiguration("optional", "master(*)"); } else { dd.addDependencyConfiguration("provided", "compile(*)"); dd.addDependencyConfiguration("provided", "provided(*)"); dd.addDependencyConfiguration("provided", "runtime(*)"); dd.addDependencyConfiguration("provided", "master(*)"); } } }); MAVEN2_CONF_MAPPING.put("runtime", new ConfMapper() { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional) { if (isOptional) { dd.addDependencyConfiguration("optional", "compile(*)"); dd.addDependencyConfiguration("optional", "provided(*)"); dd.addDependencyConfiguration("optional", "master(*)"); } else { dd.addDependencyConfiguration("runtime", "compile(*)"); dd.addDependencyConfiguration("runtime", "runtime(*)"); dd.addDependencyConfiguration("runtime", "master(*)"); } } }); MAVEN2_CONF_MAPPING.put("test", new ConfMapper() { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional) { // optional doesn't make sense in the test scope dd.addDependencyConfiguration("test", "runtime(*)"); dd.addDependencyConfiguration("test", "master(*)"); } }); MAVEN2_CONF_MAPPING.put("system", new ConfMapper() { public void addMappingConfs(DefaultDependencyDescriptor dd, boolean isOptional) { // optional doesn't make sense in the system scope dd.addDependencyConfiguration("system", "master(*)"); } }); } private final PomModuleDescriptor ivyModuleDescriptor; private ModuleRevisionId mrid; private DefaultArtifact mainArtifact; private ParserSettings parserSettings; private static final String WRONG_NUMBER_OF_PARTS_MSG = "what seemed to be a dependency " + "management extra info exclusion had the wrong number of parts (should have 2) "; public PomModuleDescriptorBuilder(ModuleDescriptorParser parser, Resource res, ParserSettings ivySettings) { ivyModuleDescriptor = new PomModuleDescriptor(parser, res); ivyModuleDescriptor.setResolvedPublicationDate(new Date(res.getLastModified())); for (int i = 0; i < MAVEN2_CONFIGURATIONS.length; i++) { ivyModuleDescriptor.addConfiguration(MAVEN2_CONFIGURATIONS[i]); } ivyModuleDescriptor.setMappingOverride(true); ivyModuleDescriptor.addExtraAttributeNamespace("m", Ivy.getIvyHomeURL() + "maven"); parserSettings = ivySettings; } public ModuleDescriptor getModuleDescriptor() { return ivyModuleDescriptor; } public void setModuleRevId(String groupId, String artifactId, String version) { mrid = ModuleRevisionId.newInstance(groupId, artifactId, version); ivyModuleDescriptor.setModuleRevisionId(mrid); if ((version == null) || version.endsWith("SNAPSHOT")) { ivyModuleDescriptor.setStatus("integration"); } else { ivyModuleDescriptor.setStatus("release"); } } public void setHomePage(String homePage) { ivyModuleDescriptor.setHomePage(homePage); } public void setDescription(String description) { ivyModuleDescriptor.setDescription(description); } public void setLicenses(License[] licenses) { for (int i = 0; i < licenses.length; i++) { ivyModuleDescriptor.addLicense(licenses[i]); } } public void addMainArtifact(String artifactId, String packaging) { String ext; /* * TODO: we should make packaging to ext mapping configurable, since it's not possible to * cover all cases. */ if ("pom".equals(packaging)) { // no artifact defined! Add the default artifact if it exist. DependencyResolver resolver = parserSettings.getResolver(mrid); if (resolver != null) { DefaultArtifact artifact = new DefaultArtifact(mrid, new Date(), artifactId, "jar", "jar"); ArtifactOrigin artifactOrigin = resolver.locate(artifact); if (!ArtifactOrigin.isUnknown(artifactOrigin)) { mainArtifact = artifact; ivyModuleDescriptor.addArtifact("master", mainArtifact); } } return; } else if (JAR_PACKAGINGS.contains(packaging)) { ext = "jar"; } else if ("pear".equals(packaging)) { ext = "phar"; } else { ext = packaging; } mainArtifact = new DefaultArtifact(mrid, new Date(), artifactId, packaging, ext); ivyModuleDescriptor.addArtifact("master", mainArtifact); } public void addDependency(Resource res, PomDependencyData dep) { String scope = dep.getScope(); if ((scope != null) && (scope.length() > 0) && !MAVEN2_CONF_MAPPING.containsKey(scope)) { // unknown scope, defaulting to 'compile' scope = "compile"; } String version = dep.getVersion(); version = (version == null || version.length() == 0) ? getDefaultVersion(dep) : version; ModuleRevisionId moduleRevId = ModuleRevisionId.newInstance(dep.getGroupId(), dep.getArtifactId(), version); // Some POMs depend on theirselfves, don't add this dependency: Ivy doesn't allow this! // Example: http://repo2.maven.org/maven2/net/jini/jsk-platform/2.1/jsk-platform-2.1.pom ModuleRevisionId mRevId = ivyModuleDescriptor.getModuleRevisionId(); if ((mRevId != null) && mRevId.getModuleId().equals(moduleRevId.getModuleId())) { return; } DefaultDependencyDescriptor dd = new PomDependencyDescriptor(dep, ivyModuleDescriptor, moduleRevId); scope = (scope == null || scope.length() == 0) ? getDefaultScope(dep) : scope; ConfMapper mapping = (ConfMapper) MAVEN2_CONF_MAPPING.get(scope); mapping.addMappingConfs(dd, dep.isOptional()); Map extraAtt = new HashMap(); if ((dep.getClassifier() != null) || ((dep.getType() != null) && !"jar".equals(dep.getType()))) { String type = "jar"; if (dep.getType() != null) { type = dep.getType(); } String ext = type; // if type is 'test-jar', the extension is 'jar' and the classifier is 'tests' // Cfr. http://maven.apache.org/guides/mini/guide-attached-tests.html if ("test-jar".equals(type)) { ext = "jar"; extraAtt.put("m:classifier", "tests"); } else if (JAR_PACKAGINGS.contains(type)) { ext = "jar"; } // we deal with classifiers by setting an extra attribute and forcing the // dependency to assume such an artifact is published if (dep.getClassifier() != null) { extraAtt.put("m:classifier", dep.getClassifier()); } DefaultDependencyArtifactDescriptor depArtifact = new DefaultDependencyArtifactDescriptor( dd, dd.getDependencyId().getName(), type, ext, null, extraAtt); // here we have to assume a type and ext for the artifact, so this is a limitation // compared to how m2 behave with classifiers String optionalizedScope = dep.isOptional() ? "optional" : scope; dd.addDependencyArtifact(optionalizedScope, depArtifact); } // experimentation shows the following, excluded modules are // inherited from parent POMs if either of the following is true: // the element is missing or the element // is present, but empty. List /* */excluded = dep.getExcludedModules(); if (excluded.isEmpty()) { excluded = getDependencyMgtExclusions(ivyModuleDescriptor, dep.getGroupId(), dep.getArtifactId()); } for (Iterator itExcl = excluded.iterator(); itExcl.hasNext();) { ModuleId excludedModule = (ModuleId) itExcl.next(); String[] confs = dd.getModuleConfigurations(); for (int k = 0; k < confs.length; k++) { dd.addExcludeRule(confs[k], new DefaultExcludeRule(new ArtifactId(excludedModule, PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION), ExactPatternMatcher.INSTANCE, null)); } } ivyModuleDescriptor.addDependency(dd); } public void addDependency(DependencyDescriptor descriptor) { // Some POMs depend on themselves through their parent pom, don't add this dependency // since Ivy doesn't allow this! // Example: // http://repo2.maven.org/maven2/com/atomikos/atomikos-util/3.6.4/atomikos-util-3.6.4.pom ModuleId dependencyId = descriptor.getDependencyId(); ModuleRevisionId mRevId = ivyModuleDescriptor.getModuleRevisionId(); if ((mRevId != null) && mRevId.getModuleId().equals(dependencyId)) { return; } ivyModuleDescriptor.addDependency(descriptor); } public void addDependencyMgt(PomDependencyMgt dep) { ivyModuleDescriptor.addDependencyManagement(dep); String key = getDependencyMgtExtraInfoKeyForVersion(dep.getGroupId(), dep.getArtifactId()); ivyModuleDescriptor.addExtraInfo(key, dep.getVersion()); if (dep.getScope() != null) { String scopeKey = getDependencyMgtExtraInfoKeyForScope(dep.getGroupId(), dep.getArtifactId()); ivyModuleDescriptor.addExtraInfo(scopeKey, dep.getScope()); } if (!dep.getExcludedModules().isEmpty()) { final String exclusionPrefix = getDependencyMgtExtraInfoPrefixForExclusion( dep.getGroupId(), dep.getArtifactId()); int index = 0; for (final Iterator iter = dep.getExcludedModules().iterator(); iter.hasNext();) { final ModuleId excludedModule = (ModuleId) iter.next(); ivyModuleDescriptor.addExtraInfo( exclusionPrefix + index, excludedModule.getOrganisation() + EXTRA_INFO_DELIMITER + excludedModule.getName()); index += 1; } } // dependency management info is also used for version mediation of transitive dependencies ivyModuleDescriptor.addDependencyDescriptorMediator( ModuleId.newInstance(dep.getGroupId(), dep.getArtifactId()), ExactPatternMatcher.INSTANCE, new OverrideDependencyDescriptorMediator(null, dep.getVersion())); } public void addPlugin(PomDependencyMgt plugin) { String pluginValue = plugin.getGroupId() + EXTRA_INFO_DELIMITER + plugin.getArtifactId() + EXTRA_INFO_DELIMITER + plugin.getVersion(); String pluginExtraInfo = (String) ivyModuleDescriptor.getExtraInfo().get("m:maven.plugins"); if (pluginExtraInfo == null) { pluginExtraInfo = pluginValue; } else { pluginExtraInfo = pluginExtraInfo + "|" + pluginValue; } ivyModuleDescriptor.getExtraInfo().put("m:maven.plugins", pluginExtraInfo); } public static List /* */getPlugins(ModuleDescriptor md) { List result = new ArrayList(); String plugins = (String) md.getExtraInfo().get("m:maven.plugins"); if (plugins == null) { return new ArrayList(); } String[] pluginsArray = plugins.split("\\|"); for (int i = 0; i < pluginsArray.length; i++) { String[] parts = pluginsArray[i].split(EXTRA_INFO_DELIMITER); result.add(new PomPluginElement(parts[0], parts[1], parts[2])); } return result; } private static class PomPluginElement implements PomDependencyMgt { private String groupId; private String artifactId; private String version; public PomPluginElement(String groupId, String artifactId, String version) { this.groupId = groupId; this.artifactId = artifactId; this.version = version; } public String getGroupId() { return groupId; } public String getArtifactId() { return artifactId; } public String getVersion() { return version; } public String getScope() { return null; } public List /* */getExcludedModules() { return Collections.EMPTY_LIST; // probably not used? } } private String getDefaultVersion(PomDependencyData dep) { ModuleId moduleId = ModuleId.newInstance(dep.getGroupId(), dep.getArtifactId()); if (ivyModuleDescriptor.getDependencyManagementMap().containsKey(moduleId)) { return ((PomDependencyMgt) ivyModuleDescriptor.getDependencyManagementMap().get( moduleId)).getVersion(); } String key = getDependencyMgtExtraInfoKeyForVersion(dep.getGroupId(), dep.getArtifactId()); return (String) ivyModuleDescriptor.getExtraInfo().get(key); } private String getDefaultScope(PomDependencyData dep) { String result; ModuleId moduleId = ModuleId.newInstance(dep.getGroupId(), dep.getArtifactId()); if (ivyModuleDescriptor.getDependencyManagementMap().containsKey(moduleId)) { result = ((PomDependencyMgt) ivyModuleDescriptor.getDependencyManagementMap().get( moduleId)).getScope(); } else { String key = getDependencyMgtExtraInfoKeyForScope(dep.getGroupId(), dep.getArtifactId()); result = (String) ivyModuleDescriptor.getExtraInfo().get(key); } if ((result == null) || !MAVEN2_CONF_MAPPING.containsKey(result)) { result = "compile"; } return result; } private static String getDependencyMgtExtraInfoKeyForVersion(String groupId, String artifaceId) { return DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + groupId + EXTRA_INFO_DELIMITER + artifaceId + EXTRA_INFO_DELIMITER + "version"; } private static String getDependencyMgtExtraInfoKeyForScope(String groupId, String artifaceId) { return DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + groupId + EXTRA_INFO_DELIMITER + artifaceId + EXTRA_INFO_DELIMITER + "scope"; } private static String getPropertyExtraInfoKey(String propertyName) { return PROPERTIES + EXTRA_INFO_DELIMITER + propertyName; } private static String getDependencyMgtExtraInfoPrefixForExclusion(String groupId, String artifaceId) { return DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + groupId + EXTRA_INFO_DELIMITER + artifaceId + EXTRA_INFO_DELIMITER + "exclusion_"; } private static List /* */getDependencyMgtExclusions(ModuleDescriptor descriptor, String groupId, String artifactId) { if (descriptor instanceof PomModuleDescriptor) { PomDependencyMgt dependencyMgt = (PomDependencyMgt) ((PomModuleDescriptor) descriptor) .getDependencyManagementMap().get(ModuleId.newInstance(groupId, artifactId)); if (dependencyMgt != null) { return dependencyMgt.getExcludedModules(); } } String exclusionPrefix = getDependencyMgtExtraInfoPrefixForExclusion(groupId, artifactId); List /* */exclusionIds = new LinkedList /* */(); Map /* */extras = descriptor.getExtraInfo(); for (final Iterator entIter = extras.entrySet().iterator(); entIter.hasNext();) { Map.Entry /* */ent = (Map.Entry) entIter.next(); String key = (String) ent.getKey(); if (key.startsWith(exclusionPrefix)) { String fullExclusion = (String) ent.getValue(); String[] exclusionParts = fullExclusion.split(EXTRA_INFO_DELIMITER); if (exclusionParts.length != 2) { Message.error(WRONG_NUMBER_OF_PARTS_MSG + exclusionParts.length + " : " + fullExclusion); continue; } exclusionIds.add(ModuleId.newInstance(exclusionParts[0], exclusionParts[1])); } } return exclusionIds; } public static Map/* */ getDependencyManagementMap(ModuleDescriptor md) { Map ret = new LinkedHashMap(); if (md instanceof PomModuleDescriptor) { for (final Iterator iterator = ((PomModuleDescriptor) md).getDependencyManagementMap() .entrySet().iterator(); iterator.hasNext();) { Map.Entry e = (Entry) iterator.next(); PomDependencyMgt dependencyMgt = (PomDependencyMgt) e.getValue(); ret.put(e.getKey(), dependencyMgt.getVersion()); } } else { for (Iterator iterator = md.getExtraInfo().entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); String key = (String) entry.getKey(); if ((key).startsWith(DEPENDENCY_MANAGEMENT)) { String[] parts = key.split(EXTRA_INFO_DELIMITER); if (parts.length != DEPENDENCY_MANAGEMENT_KEY_PARTS_COUNT) { Message.warn("what seem to be a dependency management extra info " + "doesn't match expected pattern: " + key); } else { ret.put(ModuleId.newInstance(parts[1], parts[2]), entry.getValue()); } } } } return ret; } public static List getDependencyManagements(ModuleDescriptor md) { List result = new ArrayList(); if (md instanceof PomModuleDescriptor) { result.addAll(((PomModuleDescriptor) md).getDependencyManagementMap().values()); } else { for (Iterator iterator = md.getExtraInfo().entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); String key = (String) entry.getKey(); if ((key).startsWith(DEPENDENCY_MANAGEMENT)) { String[] parts = key.split(EXTRA_INFO_DELIMITER); if (parts.length != DEPENDENCY_MANAGEMENT_KEY_PARTS_COUNT) { Message.warn("what seem to be a dependency management extra info " + "doesn't match expected pattern: " + key); } else { String versionKey = DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + parts[1] + EXTRA_INFO_DELIMITER + parts[2] + EXTRA_INFO_DELIMITER + "version"; String scopeKey = DEPENDENCY_MANAGEMENT + EXTRA_INFO_DELIMITER + parts[1] + EXTRA_INFO_DELIMITER + parts[2] + EXTRA_INFO_DELIMITER + "scope"; String version = (String) md.getExtraInfo().get(versionKey); String scope = (String) md.getExtraInfo().get(scopeKey); List /* */exclusions = getDependencyMgtExclusions(md, parts[1], parts[2]); result.add(new DefaultPomDependencyMgt(parts[1], parts[2], version, scope, exclusions)); } } } } return result; } public void addExtraInfos(Map extraAttributes) { for (Iterator it = extraAttributes.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); addExtraInfo(key, value); } } private void addExtraInfo(String key, String value) { if (!ivyModuleDescriptor.getExtraInfo().containsKey(key)) { ivyModuleDescriptor.addExtraInfo(key, value); } } public static Map extractPomProperties(Map extraInfo) { Map r = new HashMap(); for (Iterator it = extraInfo.entrySet().iterator(); it.hasNext();) { Map.Entry extraInfoEntry = (Map.Entry) it.next(); if (((String) extraInfoEntry.getKey()).startsWith(PROPERTIES)) { String prop = ((String) extraInfoEntry.getKey()).substring(PROPERTIES.length() + EXTRA_INFO_DELIMITER.length()); r.put(prop, extraInfoEntry.getValue()); } } return r; } public void addProperty(String propertyName, String value) { addExtraInfo(getPropertyExtraInfoKey(propertyName), value); } public Artifact getMainArtifact() { return mainArtifact; } public Artifact getSourceArtifact() { return new MDArtifact(ivyModuleDescriptor, mrid.getName(), "source", "jar", null, Collections.singletonMap("m:classifier", "sources")); } public Artifact getSrcArtifact() { return new MDArtifact(ivyModuleDescriptor, mrid.getName(), "source", "jar", null, Collections.singletonMap("m:classifier", "src")); } public Artifact getJavadocArtifact() { return new MDArtifact(ivyModuleDescriptor, mrid.getName(), "javadoc", "jar", null, Collections.singletonMap("m:classifier", "javadoc")); } public void addSourceArtifact() { ivyModuleDescriptor.addArtifact("sources", getSourceArtifact()); } public void addSrcArtifact() { ivyModuleDescriptor.addArtifact("sources", getSrcArtifact()); } public void addJavadocArtifact() { ivyModuleDescriptor.addArtifact("javadoc", getJavadocArtifact()); } /** * DependencyDescriptor that provides access to the original * PomDependencyData. */ public static class PomDependencyDescriptor extends DefaultDependencyDescriptor { private final PomDependencyData pomDependencyData; private PomDependencyDescriptor(PomDependencyData pomDependencyData, ModuleDescriptor moduleDescriptor, ModuleRevisionId revisionId) { super(moduleDescriptor, revisionId, true, false, true); this.pomDependencyData = pomDependencyData; } /** * Get PomDependencyData. * * @return PomDependencyData */ public PomDependencyData getPomDependencyData() { return pomDependencyData; } } public static class PomModuleDescriptor extends DefaultModuleDescriptor { private final Map/* */dependencyManagementMap = new HashMap(); public PomModuleDescriptor(ModuleDescriptorParser parser, Resource res) { super(parser, res); } public void addDependencyManagement(PomDependencyMgt dependencyMgt) { dependencyManagementMap.put( ModuleId.newInstance(dependencyMgt.getGroupId(), dependencyMgt.getArtifactId()), dependencyMgt); } public Map getDependencyManagementMap() { return dependencyManagementMap; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorParser.java000066400000000000000000000445761226750426600306430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder.PomDependencyDescriptor; import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyData; import org.apache.ivy.plugins.parser.m2.PomReader.PomDependencyMgtElement; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.Message; import org.xml.sax.SAXException; /** * A parser for Maven 2 POM. *

    * The configurations used in the generated module descriptor mimics the behavior defined by maven 2 * scopes, as documented here:
    * http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html The * PomModuleDescriptorParser use a PomDomReader to read the pom, and the PomModuleDescriptorBuilder * to write the ivy module descriptor using the info read by the PomDomReader. */ public final class PomModuleDescriptorParser implements ModuleDescriptorParser { private static final PomModuleDescriptorParser INSTANCE = new PomModuleDescriptorParser(); public static PomModuleDescriptorParser getInstance() { return INSTANCE; } private PomModuleDescriptorParser() { } public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws ParseException, IOException { try { XmlModuleDescriptorWriter.write(md, destFile); } finally { if (is != null) { is.close(); } } } public boolean accept(Resource res) { return res.getName().endsWith(".pom") || res.getName().endsWith("pom.xml") || res.getName().endsWith("project.xml"); } public String toString() { return "pom parser"; } public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) { return DefaultArtifact.newPomArtifact(mrid, new Date(res.getLastModified())); } public String getType() { return "pom"; } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, boolean validate) throws ParseException, IOException { URLResource resource = new URLResource(descriptorURL); return parseDescriptor(ivySettings, descriptorURL, resource, validate); } public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, Resource res, boolean validate) throws ParseException, IOException { PomModuleDescriptorBuilder mdBuilder = new PomModuleDescriptorBuilder(this, res, ivySettings); try { PomReader domReader = new PomReader(descriptorURL, res); domReader.setProperty("parent.version", domReader.getParentVersion()); domReader.setProperty("parent.groupId", domReader.getParentGroupId()); domReader.setProperty("project.parent.version", domReader.getParentVersion()); domReader.setProperty("project.parent.groupId", domReader.getParentGroupId()); Map pomProperties = domReader.getPomProperties(); for (Iterator iter = pomProperties.entrySet().iterator(); iter.hasNext();) { Map.Entry prop = (Map.Entry) iter.next(); domReader.setProperty((String) prop.getKey(), (String) prop.getValue()); mdBuilder.addProperty((String) prop.getKey(), (String) prop.getValue()); } ModuleDescriptor parentDescr = null; if (domReader.hasParent()) { // Is there any other parent properties? ModuleRevisionId parentModRevID = ModuleRevisionId.newInstance( domReader.getParentGroupId(), domReader.getParentArtifactId(), domReader.getParentVersion()); ResolvedModuleRevision parentModule = parseOtherPom(ivySettings, parentModRevID); if (parentModule != null) { parentDescr = parentModule.getDescriptor(); } else { throw new IOException("Impossible to load parent for " + res.getName() + "." + " Parent=" + parentModRevID); } if (parentDescr != null) { Map parentPomProps = PomModuleDescriptorBuilder .extractPomProperties(parentDescr.getExtraInfo()); for (Iterator iter = parentPomProps.entrySet().iterator(); iter.hasNext();) { Map.Entry prop = (Map.Entry) iter.next(); domReader.setProperty((String) prop.getKey(), (String) prop.getValue()); } } } String groupId = domReader.getGroupId(); String artifactId = domReader.getArtifactId(); String version = domReader.getVersion(); mdBuilder.setModuleRevId(groupId, artifactId, version); mdBuilder.setHomePage(domReader.getHomePage()); mdBuilder.setDescription(domReader.getDescription()); mdBuilder.setLicenses(domReader.getLicenses()); ModuleRevisionId relocation = domReader.getRelocation(); if (relocation != null) { if (groupId != null && artifactId != null && artifactId.equals(relocation.getName()) && groupId.equals(relocation.getOrganisation())) { Message.error("Relocation to an other version number not supported in ivy : " + mdBuilder.getModuleDescriptor().getModuleRevisionId() + " relocated to " + relocation + ". Please update your dependency to directly use the right version."); Message.warn("Resolution will only pick dependencies of the relocated element." + " Artefact and other metadata will be ignored."); ResolvedModuleRevision relocatedModule = parseOtherPom(ivySettings, relocation); if (relocatedModule == null) { throw new ParseException("impossible to load module " + relocation + " to which " + mdBuilder.getModuleDescriptor().getModuleRevisionId() + " has been relocated", 0); } DependencyDescriptor[] dds = relocatedModule.getDescriptor().getDependencies(); for (int i = 0; i < dds.length; i++) { mdBuilder.addDependency(dds[i]); } } else { Message.info(mdBuilder.getModuleDescriptor().getModuleRevisionId() + " is relocated to " + relocation + ". Please update your dependencies."); Message.verbose("Relocated module will be considered as a dependency"); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor( mdBuilder.getModuleDescriptor(), relocation, true, false, true); /* Map all public dependencies */ Configuration[] m2Confs = PomModuleDescriptorBuilder.MAVEN2_CONFIGURATIONS; for (int i = 0; i < m2Confs.length; i++) { if (Visibility.PUBLIC.equals(m2Confs[i].getVisibility())) { dd.addDependencyConfiguration(m2Confs[i].getName(), m2Confs[i].getName()); } } mdBuilder.addDependency(dd); } } else { domReader.setProperty("project.groupId", groupId); domReader.setProperty("pom.groupId", groupId); domReader.setProperty("groupId", groupId); domReader.setProperty("project.artifactId", artifactId); domReader.setProperty("pom.artifactId", artifactId); domReader.setProperty("artifactId", artifactId); domReader.setProperty("project.version", version); domReader.setProperty("pom.version", version); domReader.setProperty("version", version); if (parentDescr != null) { mdBuilder.addExtraInfos(parentDescr.getExtraInfo()); // add dependency management info from parent List depMgt = PomModuleDescriptorBuilder.getDependencyManagements(parentDescr); for (Iterator it = depMgt.iterator(); it.hasNext();) { PomDependencyMgt dep = (PomDependencyMgt) it.next(); if (dep instanceof PomDependencyMgtElement) { dep = domReader.new PomDependencyMgtElement( (PomDependencyMgtElement) dep); } mdBuilder.addDependencyMgt(dep); } // add plugins from parent List /* */plugins = PomModuleDescriptorBuilder .getPlugins(parentDescr); for (Iterator it = plugins.iterator(); it.hasNext();) { mdBuilder.addPlugin((PomDependencyMgt) it.next()); } } for (Iterator it = domReader.getDependencyMgt().iterator(); it.hasNext();) { PomDependencyMgt dep = (PomDependencyMgt) it.next(); if ("import".equals(dep.getScope())) { ModuleRevisionId importModRevID = ModuleRevisionId.newInstance( dep.getGroupId(), dep.getArtifactId(), dep.getVersion()); ResolvedModuleRevision importModule = parseOtherPom(ivySettings, importModRevID); if (importModule != null) { ModuleDescriptor importDescr = importModule.getDescriptor(); // add dependency management info from imported module List depMgt = PomModuleDescriptorBuilder .getDependencyManagements(importDescr); for (Iterator it2 = depMgt.iterator(); it2.hasNext();) { PomDependencyMgt importedDepMgt = (PomDependencyMgt) it2.next(); mdBuilder.addDependencyMgt(new DefaultPomDependencyMgt( importedDepMgt.getGroupId(), importedDepMgt.getArtifactId(), importedDepMgt.getVersion(), importedDepMgt.getScope(), importedDepMgt.getExcludedModules())); } } else { throw new IOException("Impossible to import module for " + res.getName() + "." + " Import=" + importModRevID); } } else { mdBuilder.addDependencyMgt(dep); } } for (Iterator it = domReader.getDependencies().iterator(); it.hasNext();) { PomReader.PomDependencyData dep = (PomReader.PomDependencyData) it.next(); mdBuilder.addDependency(res, dep); } if (parentDescr != null) { for (int i = 0; i < parentDescr.getDependencies().length; i++) { DependencyDescriptor descriptor = parentDescr.getDependencies()[i]; if (descriptor instanceof PomDependencyDescriptor) { PomDependencyData parentDep = ((PomDependencyDescriptor) descriptor) .getPomDependencyData(); PomDependencyData dep = domReader.new PomDependencyData(parentDep); mdBuilder.addDependency(res, dep); } else { mdBuilder.addDependency(descriptor); } } } for (Iterator it = domReader.getPlugins().iterator(); it.hasNext();) { PomReader.PomPluginElement plugin = (PomReader.PomPluginElement) it.next(); mdBuilder.addPlugin(plugin); } mdBuilder.addMainArtifact(artifactId, domReader.getPackaging()); addSourcesAndJavadocArtifactsIfPresent(mdBuilder, ivySettings); } } catch (SAXException e) { throw newParserException(e); } return mdBuilder.getModuleDescriptor(); } private void addSourcesAndJavadocArtifactsIfPresent(PomModuleDescriptorBuilder mdBuilder, ParserSettings ivySettings) { if (mdBuilder.getMainArtifact() == null) { // no main artifact in pom, we don't need to search for meta artifacts return; } ModuleDescriptor md = mdBuilder.getModuleDescriptor(); ModuleRevisionId mrid = md.getModuleRevisionId(); DependencyResolver resolver = ivySettings.getResolver(mrid); if (resolver == null) { Message.debug("no resolver found for " + mrid + ": no source or javadoc artifact lookup"); } else { ArtifactOrigin mainArtifact = resolver.locate(mdBuilder.getMainArtifact()); if (!ArtifactOrigin.isUnknown(mainArtifact)) { String mainArtifactLocation = mainArtifact.getLocation(); ArtifactOrigin sourceArtifact = resolver.locate(mdBuilder.getSourceArtifact()); if (!ArtifactOrigin.isUnknown(sourceArtifact) && !sourceArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("source artifact found for " + mrid); mdBuilder.addSourceArtifact(); } else { // it seems that sometimes the 'src' classifier is used instead of 'sources' // Cfr. IVY-1138 ArtifactOrigin srcArtifact = resolver.locate(mdBuilder.getSrcArtifact()); if (!ArtifactOrigin.isUnknown(srcArtifact) && !srcArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("source artifact found for " + mrid); mdBuilder.addSrcArtifact(); } else { Message.debug("no source artifact found for " + mrid); } } ArtifactOrigin javadocArtifact = resolver.locate(mdBuilder.getJavadocArtifact()); if (!ArtifactOrigin.isUnknown(javadocArtifact) && !javadocArtifact.getLocation().equals(mainArtifactLocation)) { Message.debug("javadoc artifact found for " + mrid); mdBuilder.addJavadocArtifact(); } else { Message.debug("no javadoc artifact found for " + mrid); } } } } private ResolvedModuleRevision parseOtherPom(ParserSettings ivySettings, ModuleRevisionId parentModRevID) throws ParseException { DependencyDescriptor dd = new DefaultDependencyDescriptor(parentModRevID, true); ResolveData data = IvyContext.getContext().getResolveData(); if (data == null) { ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine(); ResolveOptions options = new ResolveOptions(); options.setDownload(false); data = new ResolveData(engine, options); } DependencyResolver resolver = ivySettings.getResolver(parentModRevID); if (resolver == null) { // TODO: Throw exception here? return null; } else { dd = NameSpaceHelper.toSystem(dd, ivySettings.getContextNamespace()); ResolvedModuleRevision otherModule = resolver.getDependency(dd, data); return otherModule; } } private ParseException newParserException(Exception e) { Message.error(e.getMessage()); ParseException pe = new ParseException(e.getMessage(), 0); pe.initCause(e); return pe; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorWriter.java000066400000000000000000000356161226750426600306560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.core.settings.IvyVariableContainer; import org.apache.ivy.plugins.parser.m2.PomWriterOptions.ConfigurationScopeMapping; import org.apache.ivy.plugins.parser.m2.PomWriterOptions.ExtraDependency; import org.apache.ivy.util.ConfigurationUtils; public final class PomModuleDescriptorWriter { private static final String SKIP_LINE = "SKIP_LINE"; private static final ConfigurationScopeMapping DEFAULT_MAPPING = new ConfigurationScopeMapping( new HashMap() { { put("compile", "compile"); put("runtime", "runtime"); put("provided", "provided"); put("test", "test"); put("system", "system"); } }); private PomModuleDescriptorWriter() { } public static void write(ModuleDescriptor md, File output, PomWriterOptions options) throws IOException { LineNumberReader in; if (options.getTemplate() == null) { in = new LineNumberReader(new InputStreamReader( PomModuleDescriptorWriter.class.getResourceAsStream("pom.template"))); } else { in = new LineNumberReader(new InputStreamReader(new FileInputStream( options.getTemplate()))); } if (output.getParentFile() != null) { output.getParentFile().mkdirs(); } PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF-8")); try { IvySettings settings = IvyContext.getContext().getSettings(); IvyVariableContainer variables = new IvyVariableContainerWrapper( settings.getVariableContainer()); variables.setVariable("ivy.pom.license", SKIP_LINE, true); variables.setVariable("ivy.pom.header", SKIP_LINE, true); variables.setVariable("ivy.pom.groupId", SKIP_LINE, true); variables.setVariable("ivy.pom.artifactId", SKIP_LINE, true); variables.setVariable("ivy.pom.version", SKIP_LINE, true); variables.setVariable("ivy.pom.packaging", SKIP_LINE, true); variables.setVariable("ivy.pom.name", SKIP_LINE, true); variables.setVariable("ivy.pom.description", SKIP_LINE, true); variables.setVariable("ivy.pom.url", SKIP_LINE, true); if (options.getLicenseHeader() != null) { variables.setVariable("ivy.pom.license", options.getLicenseHeader(), true); } if (options.isPrintIvyInfo()) { String header = ""; variables.setVariable("ivy.pom.header", header, true); } setModuleVariables(md, variables, options); boolean dependenciesPrinted = false; int lastIndent = 0; int indent = 0; String line = in.readLine(); while (line != null) { line = IvyPatternHelper.substituteVariables(line, variables); if (line.indexOf(SKIP_LINE) != -1) { // skip this line line = in.readLine(); continue; } if (line.trim().length() == 0) { // empty line out.println(line); line = in.readLine(); continue; } lastIndent = indent; indent = line.indexOf('<'); if (!dependenciesPrinted && line.indexOf("") != -1) { printDependencies(md, out, options, indent, false); dependenciesPrinted = true; } if (!dependenciesPrinted && line.indexOf("") != -1) { printDependencies(md, out, options, lastIndent, true); dependenciesPrinted = true; } out.println(line); line = in.readLine(); } } finally { in.close(); out.close(); } } private static void setModuleVariables(ModuleDescriptor md, IvyVariableContainer variables, PomWriterOptions options) { ModuleRevisionId mrid = md.getModuleRevisionId(); variables.setVariable("ivy.pom.groupId", mrid.getOrganisation(), true); String artifactId = options.getArtifactName(); if (artifactId == null) { artifactId = mrid.getName(); } String packaging = options.getArtifactPackaging(); if (packaging == null) { // find artifact to determine the packaging Artifact artifact = findArtifact(md, artifactId); if (artifact == null) { // no suitable artifact found, default to 'pom' packaging = "pom"; } else { packaging = artifact.getType(); } } variables.setVariable("ivy.pom.artifactId", artifactId, true); variables.setVariable("ivy.pom.packaging", packaging, true); if (mrid.getRevision() != null) { variables.setVariable("ivy.pom.version", mrid.getRevision(), true); } if (options.getDescription() != null) { variables.setVariable("ivy.pom.description", options.getDescription(), true); } if (md.getHomePage() != null) { variables.setVariable("ivy.pom.url", md.getHomePage(), true); } } /** * Returns the first artifact with the correct name and without a classifier. */ private static Artifact findArtifact(ModuleDescriptor md, String artifactName) { Artifact[] artifacts = md.getAllArtifacts(); for (int i = 0; i < artifacts.length; i++) { if (artifacts[i].getName().equals(artifactName) && artifacts[i].getAttribute("classifier") == null) { return artifacts[i]; } } return null; } private static void indent(PrintWriter out, int indent) { for (int i = 0; i < indent; i++) { out.print(' '); } } private static void printDependencies(ModuleDescriptor md, PrintWriter out, PomWriterOptions options, int indent, boolean printDependencies) { List extraDeps = options.getExtraDependencies(); DependencyDescriptor[] dds = getDependencies(md, options); if (!extraDeps.isEmpty() || (dds.length > 0)) { if (printDependencies) { indent(out, indent); out.println(""); } // print the extra dependencies first for (Iterator it = extraDeps.iterator(); it.hasNext();) { PomWriterOptions.ExtraDependency dep = (ExtraDependency) it.next(); String groupId = dep.getGroup(); if (groupId == null) { groupId = md.getModuleRevisionId().getOrganisation(); } String version = dep.getVersion(); if (version == null) { version = md.getModuleRevisionId().getRevision(); } printDependency(out, indent, groupId, dep.getArtifact(), version, dep.getType(), dep.getClassifier(), dep.getScope(), dep.isOptional(), null); } // now print the dependencies listed in the ModuleDescriptor ConfigurationScopeMapping mapping = options.getMapping(); if (mapping == null) { mapping = DEFAULT_MAPPING; } for (int i = 0; i < dds.length; i++) { ModuleRevisionId mrid = dds[i].getDependencyRevisionId(); ExcludeRule[] excludes = null; if (dds[i].canExclude()) { excludes = dds[i].getAllExcludeRules(); } DependencyArtifactDescriptor[] dads = dds[i].getAllDependencyArtifacts(); if (dads.length > 0) { for (int j = 0; j < dads.length; j++) { String type = dads[j].getType(); String classifier = dads[j].getExtraAttribute("classifier"); String scope = mapping.getScope(dds[i].getModuleConfigurations()); boolean optional = mapping.isOptional(dds[i].getModuleConfigurations()); printDependency(out, indent, mrid.getOrganisation(), mrid.getName(), mrid.getRevision(), type, classifier, scope, optional, excludes); } } else { String scope = mapping.getScope(dds[i].getModuleConfigurations()); boolean optional = mapping.isOptional(dds[i].getModuleConfigurations()); printDependency(out, indent, mrid.getOrganisation(), mrid.getName(), mrid.getRevision(), null, null, scope, optional, excludes); } } if (printDependencies) { indent(out, indent); out.println(""); } } } private static void printDependency(PrintWriter out, int indent, String groupId, String artifactId, String version, String type, String classifier, String scope, boolean isOptional, ExcludeRule[] excludes) { indent(out, indent * 2); out.println(""); indent(out, indent * 3); out.println("" + groupId + ""); indent(out, indent * 3); out.println("" + artifactId + ""); indent(out, indent * 3); out.println("" + version + ""); if (type != null && !"jar".equals(type)) { indent(out, indent * 3); out.println("" + type + ""); } if (classifier != null) { indent(out, indent * 3); out.println("" + classifier + ""); } if (scope != null) { indent(out, indent * 3); out.println("" + scope + ""); } if (isOptional) { indent(out, indent * 3); out.println("true"); } if (excludes != null) { printExclusions(excludes, out, indent); } indent(out, indent * 2); out.println(""); } private static void printExclusions(ExcludeRule[] exclusions, PrintWriter out, int indent) { indent(out, indent * 3); out.println(""); for (int i = 0; i < exclusions.length; i++) { indent(out, indent * 4); out.println(""); ExcludeRule rule = exclusions[i]; indent(out, indent * 5); out.println("" + rule.getId().getModuleId().getOrganisation() + ""); indent(out, indent * 5); out.println("" + rule.getId().getModuleId().getName() + ""); indent(out, indent * 4); out.println(""); } indent(out, indent * 3); out.println(""); } private static DependencyDescriptor[] getDependencies(ModuleDescriptor md, PomWriterOptions options) { String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md); List result = new ArrayList(); DependencyDescriptor[] dds = md.getDependencies(); for (int i = 0; i < dds.length; i++) { String[] depConfs = dds[i].getDependencyConfigurations(confs); if ((depConfs != null) && (depConfs.length > 0)) { result.add(dds[i]); } } return (DependencyDescriptor[]) result.toArray(new DependencyDescriptor[result.size()]); } /** * Wraps an {@link IvyVariableContainer} delegating most method calls to the wrapped instance, * except for a set of variables which are only stored locally in the wrapper, and not * propagated to the wrapped instance. */ private static final class IvyVariableContainerWrapper implements IvyVariableContainer { private final IvyVariableContainer variables; private Map localVariables = new HashMap(); private IvyVariableContainerWrapper(IvyVariableContainer variables) { this.variables = variables; } public void setVariable(String varName, String value, boolean overwrite) { localVariables.put(varName, value); } public void setEnvironmentPrefix(String prefix) { variables.setEnvironmentPrefix(prefix); } public String getVariable(String name) { String result = variables.getVariable(name); if (result == null) { result = (String) localVariables.get(name); } return result; } public Object clone() { throw new UnsupportedOperationException(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java000066400000000000000000000520401226750426600253650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.io.BufferedInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.License; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.url.URLHandlerRegistry; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * Provides the method to read some data out of the DOM tree of a pom file. */ public class PomReader { private static final String PACKAGING = "packaging"; private static final String DEPENDENCY = "dependency"; private static final String DEPENDENCIES = "dependencies"; private static final String DEPENDENCY_MGT = "dependencyManagement"; private static final String PROJECT = "project"; private static final String MODEL = "model"; private static final String GROUP_ID = "groupId"; private static final String ARTIFACT_ID = "artifactId"; private static final String VERSION = "version"; private static final String DESCRIPTION = "description"; private static final String HOMEPAGE = "url"; private static final String LICENSES = "licenses"; private static final String LICENSE = "license"; private static final String LICENSE_NAME = "name"; private static final String LICENSE_URL = "url"; private static final String PARENT = "parent"; private static final String SCOPE = "scope"; private static final String CLASSIFIER = "classifier"; private static final String OPTIONAL = "optional"; private static final String EXCLUSIONS = "exclusions"; private static final String EXCLUSION = "exclusion"; private static final String DISTRIBUTION_MGT = "distributionManagement"; private static final String RELOCATION = "relocation"; private static final String PROPERTIES = "properties"; private static final String PLUGINS = "plugins"; private static final String PLUGIN = "plugin"; private static final String TYPE = "type"; private HashMap properties = new HashMap(); private final Element projectElement; private final Element parentElement; public PomReader(URL descriptorURL, Resource res) throws IOException, SAXException { InputStream stream = new AddDTDFilterInputStream(URLHandlerRegistry.getDefault() .openStream(descriptorURL)); InputSource source = new InputSource(stream); source.setSystemId(XMLHelper.toSystemId(descriptorURL)); try { Document pomDomDoc = XMLHelper.parseToDom(source, new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { if ((systemId != null) && systemId.endsWith("m2-entities.ent")) { return new InputSource(PomReader.class .getResourceAsStream("m2-entities.ent")); } return null; } }); projectElement = pomDomDoc.getDocumentElement(); if (!PROJECT.equals(projectElement.getNodeName()) && !MODEL.equals(projectElement.getNodeName())) { throw new SAXParseException("project must be the root tag", res.getName(), res.getName(), 0, 0); } parentElement = getFirstChildElement(projectElement, PARENT); } finally { try { stream.close(); } catch (IOException e) { // ignore } } } public boolean hasParent() { return parentElement != null; } /** * Add a property if not yet set and value is not null. This garantee that property keep the * first value that is put on it and that the properties are never null. */ public void setProperty(String prop, String val) { if (!properties.containsKey(prop) && val != null) { properties.put(prop, val); } } public String getGroupId() { String groupId = getFirstChildText(projectElement, GROUP_ID); if (groupId == null) { groupId = getFirstChildText(parentElement, GROUP_ID); } return replaceProps(groupId); } public String getParentGroupId() { String groupId = getFirstChildText(parentElement, GROUP_ID); if (groupId == null) { groupId = getFirstChildText(projectElement, GROUP_ID); } return replaceProps(groupId); } public String getArtifactId() { String val = getFirstChildText(projectElement, ARTIFACT_ID); if (val == null) { val = getFirstChildText(parentElement, ARTIFACT_ID); } return replaceProps(val); } public String getParentArtifactId() { String val = getFirstChildText(parentElement, ARTIFACT_ID); if (val == null) { val = getFirstChildText(projectElement, ARTIFACT_ID); } return replaceProps(val); } public String getVersion() { String val = getFirstChildText(projectElement, VERSION); if (val == null) { val = getFirstChildText(parentElement, VERSION); } return replaceProps(val); } public String getParentVersion() { String val = getFirstChildText(parentElement, VERSION); if (val == null) { val = getFirstChildText(projectElement, VERSION); } return replaceProps(val); } public String getPackaging() { String val = getFirstChildText(projectElement, PACKAGING); if (val == null) { val = "jar"; } return val; } public String getHomePage() { String val = getFirstChildText(projectElement, HOMEPAGE); if (val == null) { val = ""; } return val; } public String getDescription() { String val = getFirstChildText(projectElement, DESCRIPTION); if (val == null) { val = ""; } return val.trim(); } public License[] getLicenses() { Element licenses = getFirstChildElement(projectElement, LICENSES); if (licenses == null) { return new License[0]; } licenses.normalize(); List/* */lics = new ArrayList(); for (Iterator it = getAllChilds(licenses).iterator(); it.hasNext();) { Element license = (Element) it.next(); if (LICENSE.equals(license.getNodeName())) { String name = getFirstChildText(license, LICENSE_NAME); String url = getFirstChildText(license, LICENSE_URL); if ((name == null) && (url == null)) { // move to next license continue; } if (name == null) { // The license name is required in Ivy but not in a POM! name = "Unknown License"; } lics.add(new License(name, url)); } } return (License[]) lics.toArray(new License[lics.size()]); } public ModuleRevisionId getRelocation() { Element distrMgt = getFirstChildElement(projectElement, DISTRIBUTION_MGT); Element relocation = getFirstChildElement(distrMgt, RELOCATION); if (relocation == null) { return null; } else { String relocGroupId = getFirstChildText(relocation, GROUP_ID); String relocArtId = getFirstChildText(relocation, ARTIFACT_ID); String relocVersion = getFirstChildText(relocation, VERSION); relocGroupId = relocGroupId == null ? getGroupId() : relocGroupId; relocArtId = relocArtId == null ? getArtifactId() : relocArtId; relocVersion = relocVersion == null ? getVersion() : relocVersion; return ModuleRevisionId.newInstance(relocGroupId, relocArtId, relocVersion); } } public List /* */getDependencies() { Element dependenciesElement = getFirstChildElement(projectElement, DEPENDENCIES); LinkedList dependencies = new LinkedList(); if (dependenciesElement != null) { NodeList childs = dependenciesElement.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element && DEPENDENCY.equals(node.getNodeName())) { dependencies.add(new PomDependencyData((Element) node)); } } } return dependencies; } public List /* */getDependencyMgt() { Element dependenciesElement = getFirstChildElement(projectElement, DEPENDENCY_MGT); dependenciesElement = getFirstChildElement(dependenciesElement, DEPENDENCIES); LinkedList dependencies = new LinkedList(); if (dependenciesElement != null) { NodeList childs = dependenciesElement.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element && DEPENDENCY.equals(node.getNodeName())) { dependencies.add(new PomDependencyMgtElement((Element) node)); } } } return dependencies; } public class PomDependencyMgtElement implements PomDependencyMgt { private final Element depElement; public PomDependencyMgtElement(PomDependencyMgtElement copyFrom) { this(copyFrom.depElement); } PomDependencyMgtElement(Element depElement) { this.depElement = depElement; } /* * (non-Javadoc) * * @see org.apache.ivy.plugins.parser.m2.PomDependencyMgt#getGroupId() */ public String getGroupId() { String val = getFirstChildText(depElement, GROUP_ID); return replaceProps(val); } /* * (non-Javadoc) * * @see org.apache.ivy.plugins.parser.m2.PomDependencyMgt#getArtifaceId() */ public String getArtifactId() { String val = getFirstChildText(depElement, ARTIFACT_ID); return replaceProps(val); } /* * (non-Javadoc) * * @see org.apache.ivy.plugins.parser.m2.PomDependencyMgt#getVersion() */ public String getVersion() { String val = getFirstChildText(depElement, VERSION); return replaceProps(val); } public String getScope() { String val = getFirstChildText(depElement, SCOPE); return replaceProps(val); } public List /* */getExcludedModules() { Element exclusionsElement = getFirstChildElement(depElement, EXCLUSIONS); LinkedList exclusions = new LinkedList(); if (exclusionsElement != null) { NodeList childs = exclusionsElement.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element && EXCLUSION.equals(node.getNodeName())) { String groupId = getFirstChildText((Element) node, GROUP_ID); String artifactId = getFirstChildText((Element) node, ARTIFACT_ID); if ((groupId != null) && (artifactId != null)) { exclusions.add(ModuleId.newInstance(groupId, artifactId)); } } } } return exclusions; } } public List /* */getPlugins() { LinkedList plugins = new LinkedList(); Element buildElement = getFirstChildElement(projectElement, "build"); if (buildElement == null) { return plugins; } Element pluginsElement = getFirstChildElement(buildElement, PLUGINS); if (pluginsElement != null) { NodeList childs = pluginsElement.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element && PLUGIN.equals(node.getNodeName())) { plugins.add(new PomPluginElement((Element) node)); } } } return plugins; } public class PomPluginElement implements PomDependencyMgt { private Element pluginElement; PomPluginElement(Element pluginElement) { this.pluginElement = pluginElement; } public String getGroupId() { String val = getFirstChildText(pluginElement, GROUP_ID); return replaceProps(val); } public String getArtifactId() { String val = getFirstChildText(pluginElement, ARTIFACT_ID); return replaceProps(val); } public String getVersion() { String val = getFirstChildText(pluginElement, VERSION); return replaceProps(val); } public String getScope() { return null; // not used } public List /* */getExcludedModules() { return Collections.EMPTY_LIST; // probably not used? } } public class PomDependencyData extends PomDependencyMgtElement { private final Element depElement; public PomDependencyData(PomDependencyData copyFrom) { this(copyFrom.depElement); } PomDependencyData(Element depElement) { super(depElement); this.depElement = depElement; } public String getScope() { String val = getFirstChildText(depElement, SCOPE); return replaceProps(val); } public String getClassifier() { String val = getFirstChildText(depElement, CLASSIFIER); return replaceProps(val); } public String getType() { String val = getFirstChildText(depElement, TYPE); return replaceProps(val); } public boolean isOptional() { Element e = getFirstChildElement(depElement, OPTIONAL); return (e != null) && "true".equalsIgnoreCase(getTextContent(e)); } } /** * @return the content of the properties tag into the pom. */ public Map/* */getPomProperties() { Map pomProperties = new HashMap(); Element propsEl = getFirstChildElement(projectElement, PROPERTIES); if (propsEl != null) { propsEl.normalize(); } for (Iterator it = getAllChilds(propsEl).iterator(); it.hasNext();) { Element prop = (Element) it.next(); pomProperties.put(prop.getNodeName(), getTextContent(prop)); } return pomProperties; } private String replaceProps(String val) { if (val == null) { return null; } else { return IvyPatternHelper.substituteVariables(val, properties).trim(); } } private static String getTextContent(Element element) { StringBuffer result = new StringBuffer(); NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node child = childNodes.item(i); switch (child.getNodeType()) { case Node.CDATA_SECTION_NODE: case Node.TEXT_NODE: result.append(child.getNodeValue()); break; default: break; } } return result.toString(); } private static String getFirstChildText(Element parentElem, String name) { Element node = getFirstChildElement(parentElem, name); if (node != null) { return getTextContent(node); } else { return null; } } private static Element getFirstChildElement(Element parentElem, String name) { if (parentElem == null) { return null; } NodeList childs = parentElem.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element && name.equals(node.getNodeName())) { return (Element) node; } } return null; } private static List/* */getAllChilds(Element parent) { List r = new LinkedList(); if (parent != null) { NodeList childs = parent.getChildNodes(); for (int i = 0; i < childs.getLength(); i++) { Node node = childs.item(i); if (node instanceof Element) { r.add(node); } } } return r; } private static final class AddDTDFilterInputStream extends FilterInputStream { private static final int MARK = 10000; private static final String DOCTYPE = "\n"; private int count; private byte[] prefix = DOCTYPE.getBytes(); private AddDTDFilterInputStream(InputStream in) throws IOException { super(new BufferedInputStream(in)); this.in.mark(MARK); // TODO: we should really find a better solution for this... // maybe we could use a FilterReader instead of a FilterInputStream? int byte1 = this.in.read(); int byte2 = this.in.read(); int byte3 = this.in.read(); if (byte1 == 239 && byte2 == 187 && byte3 == 191) { // skip the UTF-8 BOM this.in.mark(MARK); } else { this.in.reset(); } int bytesToSkip = 0; LineNumberReader reader = new LineNumberReader(new InputStreamReader(this.in, "UTF-8"), 100); String firstLine = reader.readLine(); if (firstLine != null) { String trimmed = firstLine.trim(); if (trimmed.startsWith(""); String xmlDecl = trimmed.substring(0, endIndex + 2); prefix = (xmlDecl + "\n" + DOCTYPE).getBytes(); bytesToSkip = xmlDecl.getBytes().length; } } else { prefix = new byte[0]; } this.in.reset(); for (int i = 0; i < bytesToSkip; i++) { this.in.read(); } } public int read() throws IOException { if (count < prefix.length) { return prefix[count++]; } int result = super.read(); return result; } public int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int nbrBytesCopied = 0; if (count < prefix.length) { int nbrBytesFromPrefix = Math.min(prefix.length - count, len); System.arraycopy(prefix, count, b, off, nbrBytesFromPrefix); nbrBytesCopied = nbrBytesFromPrefix; } if (nbrBytesCopied < len) { nbrBytesCopied += in.read(b, off + nbrBytesCopied, len - nbrBytesCopied); } count += nbrBytesCopied; return nbrBytesCopied; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/PomWriterOptions.java000066400000000000000000000127011226750426600270130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.m2; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class PomWriterOptions { private String[] confs; private String licenseHeader; private ConfigurationScopeMapping mapping; private boolean printIvyInfo = true; private String artifactName; private String artifactPackaging; private List/* */extraDependencies = new ArrayList(); private String description; private File template; public File getTemplate() { return template; } public PomWriterOptions setTemplate(File template) { this.template = template; return this; } public String[] getConfs() { return confs; } public PomWriterOptions setConfs(String[] confs) { this.confs = confs; return this; } public String getLicenseHeader() { return licenseHeader; } public PomWriterOptions setLicenseHeader(String licenseHeader) { this.licenseHeader = licenseHeader; if (this.licenseHeader != null) { this.licenseHeader = this.licenseHeader.trim(); } return this; } public ConfigurationScopeMapping getMapping() { return mapping; } public PomWriterOptions setMapping(ConfigurationScopeMapping mapping) { this.mapping = mapping; return this; } public boolean isPrintIvyInfo() { return printIvyInfo; } public PomWriterOptions setPrintIvyInfo(boolean printIvyInfo) { this.printIvyInfo = printIvyInfo; return this; } public List/* */getExtraDependencies() { return extraDependencies; } public PomWriterOptions setExtraDependencies(List/* */extraDependencies) { this.extraDependencies = extraDependencies; return this; } public String getArtifactName() { return artifactName; } public PomWriterOptions setArtifactName(String artifactName) { this.artifactName = artifactName; return this; } public String getArtifactPackaging() { return artifactPackaging; } public PomWriterOptions setArtifactPackaging(String artifactPackaging) { this.artifactPackaging = artifactPackaging; return this; } public String getDescription() { return description; } public PomWriterOptions setDescription(String description) { this.description = description; return this; } public static class ConfigurationScopeMapping { private Map/* */scopes; public ConfigurationScopeMapping(Map/* */scopesMapping) { this.scopes = new HashMap(scopesMapping); } /** * Returns the scope mapped to the given configuration array. * * @param confs * the configurations for which the scope should be returned * @return the scope to which the conf is mapped */ public String getScope(String[] confs) { for (int i = 0; i < confs.length; i++) { if (scopes.containsKey(confs[i])) { return (String) scopes.get(confs[i]); } } return null; } public boolean isOptional(String[] confs) { return getScope(confs) == null; } } public static class ExtraDependency { private String group; private String artifact; private String version; private String scope; private String type; private String classifier; private boolean optional; public ExtraDependency(String group, String artifact, String version, String scope, String type, String classifier, boolean optional) { this.group = group; this.artifact = artifact; this.version = version; this.scope = scope; this.type = type; this.classifier = classifier; this.optional = optional; } public String getGroup() { return group; } public String getArtifact() { return artifact; } public String getVersion() { return version; } public String getScope() { return scope; } public String getType() { return type; } public String getClassifier() { return classifier; } public boolean isOptional() { return optional; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/m2-entities.ent000066400000000000000000000063521226750426600255210ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/m2/pom.template000066400000000000000000000033431226750426600251760ustar00rootroot00000000000000SKIP_LINE *************************************************************** SKIP_LINE * Licensed to the Apache Software Foundation (ASF) under one SKIP_LINE * or more contributor license agreements. See the NOTICE file SKIP_LINE * distributed with this work for additional information SKIP_LINE * regarding copyright ownership. The ASF licenses this file SKIP_LINE * to you under the Apache License, Version 2.0 (the SKIP_LINE * "License"); you may not use this file except in compliance SKIP_LINE * with the License. You may obtain a copy of the License at SKIP_LINE * SKIP_LINE * http://www.apache.org/licenses/LICENSE-2.0 SKIP_LINE * SKIP_LINE * Unless required by applicable law or agreed to in writing, SKIP_LINE * software distributed under the License is distributed on an SKIP_LINE * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY SKIP_LINE * KIND, either express or implied. See the License for the SKIP_LINE * specific language governing permissions and limitations SKIP_LINE * under the License. SKIP_LINE *************************************************************** ${ivy.pom.license} ${ivy.pom.header} 4.0.0 ${ivy.pom.groupId} ${ivy.pom.artifactId} ${ivy.pom.packaging} ${ivy.pom.version} ${ivy.pom.name} ${ivy.pom.description} ${ivy.pom.url} ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/000077500000000000000000000000001226750426600231255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/UpdateOptions.java000066400000000000000000000134611226750426600265730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.xml; import java.util.Collections; import java.util.Date; import java.util.Map; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; public class UpdateOptions { /** * Settings to use for update, may be null. */ private ParserSettings settings = null; /** * Namespace in which the module to update is, may be null. */ private Namespace namespace = null; /** * Map from ModuleId of dependencies to new revision (as String) */ private Map resolvedRevisions = Collections.EMPTY_MAP; /** * Map from ModuleId of dependencies to new branch (as String) */ private Map resolvedBranches = Collections.EMPTY_MAP; /** * the new status, null to keep the old one */ private String status = null; /** * the new revision, null to keep the old one */ private String revision = null; /** * the new publication date, null to keep the old one */ private Date pubdate = null; /** * Should included information be replaced */ private boolean replaceInclude = true; /** * Should parent descriptor be merged inline */ private boolean merge = true; private ModuleDescriptor mergedDescriptor = null; /** * Configurations to exclude during update, or null to keep all confs. */ private String[] confsToExclude = null; /** * True to set branch information on dependencies to default branch when omitted, false to keep * it as is. */ private boolean updateBranch = true; private String branch; /** * True to indicate that the revConstraint attribute should be generated if applicable, false to * never generate the revConstraint attribute. */ private boolean generateRevConstraint = true; public ParserSettings getSettings() { return settings; } public UpdateOptions setSettings(ParserSettings settings) { this.settings = settings; return this; } public Namespace getNamespace() { return namespace; } public UpdateOptions setNamespace(Namespace ns) { this.namespace = ns; return this; } public Map getResolvedRevisions() { return resolvedRevisions; } public UpdateOptions setResolvedRevisions(Map resolvedRevisions) { this.resolvedRevisions = resolvedRevisions; return this; } public String getStatus() { return status; } public UpdateOptions setStatus(String status) { this.status = status; return this; } public String getRevision() { return revision; } public UpdateOptions setRevision(String revision) { this.revision = revision; return this; } public Date getPubdate() { return pubdate; } public UpdateOptions setPubdate(Date pubdate) { this.pubdate = pubdate; return this; } public boolean isReplaceInclude() { return replaceInclude; } public UpdateOptions setReplaceInclude(boolean replaceInclude) { this.replaceInclude = replaceInclude; return this; } public boolean isMerge() { // only return true if merge is set to true and if there is something to merge! return merge && (mergedDescriptor != null) && (mergedDescriptor.getInheritedDescriptors().length > 0); } public UpdateOptions setMerge(boolean merge) { this.merge = merge; return this; } public ModuleDescriptor getMergedDescriptor() { return mergedDescriptor; } public UpdateOptions setMergedDescriptor(ModuleDescriptor mergedDescriptor) { this.mergedDescriptor = mergedDescriptor; return this; } public String[] getConfsToExclude() { return confsToExclude; } public UpdateOptions setConfsToExclude(String[] confsToExclude) { this.confsToExclude = confsToExclude; return this; } public boolean isUpdateBranch() { return updateBranch; } public UpdateOptions setUpdateBranch(boolean updateBranch) { this.updateBranch = updateBranch; return this; } public String getBranch() { return branch; } public UpdateOptions setBranch(String pubBranch) { this.branch = pubBranch; return this; } public boolean isGenerateRevConstraint() { return generateRevConstraint; } public UpdateOptions setGenerateRevConstraint(boolean generateRevConstraint) { this.generateRevConstraint = generateRevConstraint; return this; } public Map getResolvedBranches() { return resolvedBranches; } public UpdateOptions setResolvedBranches(Map resolvedBranches) { this.resolvedBranches = resolvedBranches; return this; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java000066400000000000000000001703751226750426600311270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.xml; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Stack; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.ConfigurationAware; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DefaultDependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultExcludeRule; import org.apache.ivy.core.module.descriptor.DefaultExtendsDescriptor; import org.apache.ivy.core.module.descriptor.DefaultIncludeRule; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.ExtraInfoHolder; import org.apache.ivy.core.module.descriptor.IncludeRule; import org.apache.ivy.core.module.descriptor.License; import org.apache.ivy.core.module.descriptor.MDArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveEngine; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.conflict.FixedConflictManager; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.file.FileResource; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.extendable.ExtendableItemHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** * Parses an xml ivy file and output a ModuleDescriptor. For dependency and performance reasons, it * uses only the SAX API, which makes the parsing code harder to understand. */ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { static final String[] DEPENDENCY_REGULAR_ATTRIBUTES = new String[] {"org", "name", "branch", "branchConstraint", "rev", "revConstraint", "force", "transitive", "changing", "conf"}; private static final XmlModuleDescriptorParser INSTANCE = new XmlModuleDescriptorParser(); public static XmlModuleDescriptorParser getInstance() { return INSTANCE; } protected XmlModuleDescriptorParser() { } /** * @param settings * @param xmlURL * the url pointing to the file to parse * @param res * the real resource to parse, used for log only * @param validate * @return * @throws ParseException * @throws IOException */ public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL xmlURL, Resource res, boolean validate) throws ParseException, IOException { Parser parser = newParser(ivySettings); parser.setValidate(validate); parser.setResource(res); parser.setInput(xmlURL); parser.parse(); return parser.getModuleDescriptor(); } /** Used for test purpose */ ModuleDescriptor parseDescriptor(ParserSettings ivySettings, InputStream descriptor, Resource res, boolean validate) throws ParseException, IOException { Parser parser = newParser(ivySettings); parser.setValidate(validate); parser.setResource(res); parser.setInput(descriptor); parser.parse(); return parser.getModuleDescriptor(); } /** * Instantiates a Parser instance responsible for actual parsing of Ivy files. *

    * Override this method if you want to use a custom Parser. *

    * * @param ivySettings * the settings to use during parsing * @return the Parser instance used for parsing Ivy files */ protected Parser newParser(ParserSettings ivySettings) { return new Parser(this, ivySettings); } public boolean accept(Resource res) { return true; // this the default parser, it thus accepts all resources } public void toIvyFile(InputStream is, Resource res, File destFile, ModuleDescriptor md) throws IOException, ParseException { try { Namespace ns = null; if (md instanceof DefaultModuleDescriptor) { DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md; ns = dmd.getNamespace(); } XmlModuleDescriptorUpdater.update( is, res, destFile, new UpdateOptions().setSettings(IvyContext.getContext().getSettings()) .setStatus(md.getStatus()) .setRevision(md.getResolvedModuleRevisionId().getRevision()) .setPubdate(md.getResolvedPublicationDate()).setUpdateBranch(false) .setNamespace(ns)); } catch (SAXException e) { ParseException ex = new ParseException("exception occurred while parsing " + res, 0); ex.initCause(e); throw ex; } finally { if (is != null) { is.close(); } } } public static class Parser extends AbstractParser { public static final class State { public static final int NONE = 0; public static final int INFO = 1; public static final int CONF = 2; public static final int PUB = 3; public static final int DEP = 4; public static final int DEP_ARTIFACT = 5; public static final int ARTIFACT_INCLUDE = 6; public static final int ARTIFACT_EXCLUDE = 7; public static final int CONFLICT = 8; public static final int EXCLUDE = 9; public static final int DEPS = 10; public static final int DESCRIPTION = 11; public static final int EXTRA_INFO = 12; private State() { } } protected static final List ALLOWED_VERSIONS = Arrays.asList(new String[] {"1.0", "1.1", "1.2", "1.3", "1.4", "2.0", "2.1", "2.2", "2.3"}); /* how and what do we have to parse */ private ParserSettings settings; private boolean validate = true; private URL descriptorURL; private InputStream descriptorInput; /* Parsing state */ private int state = State.NONE; private PatternMatcher defaultMatcher; private DefaultDependencyDescriptor dd; private ConfigurationAware confAware; private MDArtifact artifact; private String conf; private boolean artifactsDeclared = false; private StringBuffer buffer; private String descriptorVersion; private String[] publicationsDefaultConf; private Stack extraInfoStack = new Stack(); public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) { super(parser); settings = ivySettings; } public void setInput(InputStream descriptorInput) { this.descriptorInput = descriptorInput; } public void setInput(URL descriptorURL) { this.descriptorURL = descriptorURL; } public void setValidate(boolean validate) { this.validate = validate; } public void parse() throws ParseException, IOException { try { URL schemaURL = validate ? getSchemaURL() : null; if (descriptorURL != null) { XMLHelper.parse(descriptorURL, schemaURL, this); } else { XMLHelper.parse(descriptorInput, schemaURL, this, null); } checkConfigurations(); replaceConfigurationWildcards(); getMd().setModuleArtifact( DefaultArtifact.newIvyArtifact(getMd().getResolvedModuleRevisionId(), getMd() .getPublicationDate())); if (!artifactsDeclared) { String[] confs = getMd().getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { getMd().addArtifact( confs[i], new MDArtifact(getMd(), getMd().getModuleRevisionId().getName(), "jar", "jar")); } } getMd().check(); } catch (ParserConfigurationException ex) { IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + descriptorURL); ise.initCause(ex); throw ise; } catch (Exception ex) { checkErrors(); ParseException pe = new ParseException(ex.getMessage() + " in " + descriptorURL, 0); pe.initCause(ex); throw pe; } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { if (state == State.DESCRIPTION) { // make sure we don't interpret any tag while in description tag getBuffer().append("<").append(qName); for (int i = 0; i < attributes.getLength(); i++) { getBuffer().append(" "); getBuffer().append(attributes.getQName(i)); getBuffer().append("=\""); getBuffer().append(attributes.getValue(i)); getBuffer().append("\""); } getBuffer().append(">"); return; } else if ("ivy-module".equals(qName)) { ivyModuleStarted(attributes); } else if ("info".equals(qName)) { infoStarted(attributes); } else if (state == State.INFO && "extends".equals(qName)) { extendsStarted(attributes); } else if (state == State.INFO && "license".equals(qName)) { getMd().addLicense( new License(settings.substitute(attributes.getValue("name")), settings .substitute(attributes.getValue("url")))); } else if (state == State.INFO && "description".equals(qName)) { getMd().setHomePage(settings.substitute(attributes.getValue("homepage"))); state = State.DESCRIPTION; buffer = new StringBuffer(); } else if (state == State.INFO && "ivyauthor".equals(qName)) { // nothing to do, we don't store this } else if (state == State.INFO && "repository".equals(qName)) { // nothing to do, we don't store this } else if (state == State.EXTRA_INFO || state == State.INFO && isOtherNamespace(qName)) { buffer = new StringBuffer(); state = State.EXTRA_INFO; ExtraInfoHolder extraInfo = new ExtraInfoHolder(); extraInfo.setName(qName); for (int i = 0; i < attributes.getLength(); i++) { extraInfo.getAttributes().put(attributes.getQName(i), attributes.getValue(i)); } extraInfoStack.push(extraInfo); } else if ("configurations".equals(qName)) { configurationStarted(attributes); } else if ("publications".equals(qName)) { publicationsStarted(attributes); } else if ("dependencies".equals(qName)) { dependenciesStarted(attributes); } else if ("conflicts".equals(qName)) { if (!descriptorVersion.startsWith("1.")) { Message.deprecated("using conflicts section is deprecated: " + "please use hints section instead. Ivy file URL: " + descriptorURL); } state = State.CONFLICT; checkConfigurations(); } else if ("artifact".equals(qName)) { artifactStarted(qName, attributes); } else if ("include".equals(qName) && state == State.DEP) { addIncludeRule(qName, attributes); } else if ("exclude".equals(qName) && state == State.DEP) { addExcludeRule(qName, attributes); } else if ("exclude".equals(qName) && state == State.DEPS) { state = State.EXCLUDE; parseRule(qName, attributes); getMd().addExcludeRule((ExcludeRule) confAware); } else if ("dependency".equals(qName)) { dependencyStarted(attributes); } else if ("conf".equals(qName)) { confStarted(attributes); } else if ("mapped".equals(qName)) { dd.addDependencyConfiguration(conf, settings.substitute(attributes.getValue("name"))); } else if (("conflict".equals(qName) && state == State.DEPS) || "manager".equals(qName) && state == State.CONFLICT) { managerStarted(attributes, state == State.CONFLICT ? "name" : "manager"); } else if ("override".equals(qName) && state == State.DEPS) { mediationOverrideStarted(attributes); } else if ("include".equals(qName) && state == State.CONF) { includeConfStarted(attributes); } else if (validate && state != State.EXTRA_INFO && state != State.DESCRIPTION) { addError("unknown tag " + qName); } } catch (Exception ex) { if (ex instanceof SAXException) { throw (SAXException) ex; } SAXException sax = new SAXException("Problem occurred while parsing ivy file: " + ex.getMessage(), ex); sax.initCause(ex); throw sax; } } /** * Default parent location to check (for dev ONLY) * * @return a relative path to a parent module descriptor */ protected String getDefaultParentLocation() { return "../ivy.xml"; } /** * Handle extends elements. It checks : *
      *
    • filesystem based on location attribute, if no one is specified it will check the * default parent location
    • *
    • cache to find a resolved parent descriptor
    • *
    • ask repositories to retrieve the parent module descriptor
    • *
    * * @param attributes * @throws ParseException */ protected void extendsStarted(Attributes attributes) throws ParseException { String parentOrganisation = settings.substitute(attributes.getValue("organisation")); String parentModule = settings.substitute(attributes.getValue("module")); String parentRevision = attributes.getValue("revision") != null ? settings .substitute(attributes.getValue("revision")) : Ivy.getWorkingRevision(); String location = attributes.getValue("location") != null ? settings .substitute(attributes.getValue("location")) : getDefaultParentLocation(); ModuleDescriptor parent = null; String extendType = attributes.getValue("extendType") != null ? settings .substitute(attributes.getValue("extendType").toLowerCase(Locale.US)) : "all"; List/* */extendTypes = Arrays.asList(extendType.split(",")); ModuleId parentMid = new ModuleId(parentOrganisation, parentModule); ModuleRevisionId parentMrid = new ModuleRevisionId(parentMid, parentRevision); // check on filesystem based on location attribute (for dev ONLY) boolean local = false; try { parent = parseParentModuleOnFilesystem(location); if (parent != null) { ModuleId foundMid = parent.getResolvedModuleRevisionId().getModuleId(); if (!foundMid.equals(parentMid)) { // the filesystem contains a parent module with different organisation // or module name; ignore that parent module Message.info("Found a parent module with unexpected ModuleRevisionId at source location " + location + "! Expected: " + parentMid + ". Found: " + foundMid + ". This parent module will be ignored."); parent = null; } } local = parent != null; } catch (IOException e) { Message.warn("Unable to parse included ivy file " + location, e); } // if not found, tries to resolve using repositories if (parent == null) { try { parent = parseOtherIvyFile(parentMrid); } catch (ParseException e) { Message.warn("Unable to parse included ivy file for " + parentMrid.toString(), e); } } // if still not found throw an exception if (parent == null) { throw new ParseException("Unable to parse included ivy file for " + parentMrid.toString(), 0); } DefaultExtendsDescriptor ed = new DefaultExtendsDescriptor(parent, location, (String[]) extendTypes.toArray(new String[extendTypes.size()]), local); getMd().addInheritedDescriptor(ed); mergeWithOtherModuleDescriptor(extendTypes, parent); } /** * Merge current module with a given module descriptor and specify what should be inherited * through extendTypes argument * * @param extendTypes * specify what should be inherited * @param parent * a given parent module descriptor */ protected void mergeWithOtherModuleDescriptor(List/* */extendTypes, ModuleDescriptor parent) throws ParseException { if (extendTypes.contains("all")) { mergeAll(parent); } else { if (extendTypes.contains("info")) { mergeInfo(parent); } if (extendTypes.contains("configurations")) { mergeConfigurations(parent); } if (extendTypes.contains("dependencies")) { mergeDependencies(parent.getDependencies()); } if (extendTypes.contains("description")) { mergeDescription(parent.getDescription()); } if (extendTypes.contains("licenses")) { mergeLicenses(parent.getLicenses()); } if (extendTypes.contains("excludes")) { mergeExcludes(parent.getAllExcludeRules()); } } } /** * Merge everything from a given parent * * @param parent * a given parent module desciptor */ protected void mergeAll(ModuleDescriptor parent) { mergeInfo(parent); mergeConfigurations(parent); mergeDependencies(parent.getDependencies()); mergeDescription(parent.getDescription()); mergeLicenses(parent.getLicenses()); mergeExcludes(parent.getAllExcludeRules()); } /** * Explain how to inherit metadatas related to info element * * @param parent * a given parent module decriptor */ protected void mergeInfo(ModuleDescriptor parent) { ModuleRevisionId parentMrid = parent.getModuleRevisionId(); DefaultModuleDescriptor descriptor = getMd(); ModuleRevisionId currentMrid = descriptor.getModuleRevisionId(); ModuleRevisionId mergedMrid = ModuleRevisionId.newInstance( mergeValue(parentMrid.getOrganisation(), currentMrid.getOrganisation()), currentMrid.getName(), mergeValue(parentMrid.getBranch(), currentMrid.getBranch()), mergeRevisionValue(parentMrid.getRevision(), currentMrid.getRevision()), mergeValues(parentMrid.getQualifiedExtraAttributes(), currentMrid.getQualifiedExtraAttributes())); descriptor.setModuleRevisionId(mergedMrid); descriptor.setResolvedModuleRevisionId(mergedMrid); descriptor.setStatus(mergeValue(parent.getStatus(), descriptor.getStatus())); if (descriptor.getNamespace() == null && parent instanceof DefaultModuleDescriptor) { Namespace parentNamespace = ((DefaultModuleDescriptor) parent).getNamespace(); descriptor.setNamespace(parentNamespace); } } private static String mergeRevisionValue(String inherited, String override) { if (override == null || override.equals(Ivy.getWorkingRevision())) { return inherited; } else { return override; } } private static String mergeValue(String inherited, String override) { return override == null ? inherited : override; } private static Map mergeValues(Map inherited, Map overrides) { LinkedHashMap dup = new LinkedHashMap(inherited.size() + overrides.size()); dup.putAll(inherited); dup.putAll(overrides); return dup; } /** * Describes how to merge configurations elements * * @param sourceMrid * the source module revision id * @param configurations * array of configurations to be inherited */ protected void mergeConfigurations(ModuleDescriptor parent) { ModuleRevisionId sourceMrid = parent.getModuleRevisionId(); Configuration[] configurations = parent.getConfigurations(); for (int i = 0; i < configurations.length; i++) { Configuration configuration = configurations[i]; Message.debug("Merging configuration with: " + configuration.getName()); // copy configuration from parent descriptor getMd().addConfiguration(new Configuration(configuration, sourceMrid)); } if (parent instanceof DefaultModuleDescriptor) { setDefaultConfMapping(((DefaultModuleDescriptor) parent).getDefaultConfMapping()); setDefaultConf(((DefaultModuleDescriptor) parent).getDefaultConf()); getMd().setMappingOverride(((DefaultModuleDescriptor) parent).isMappingOverride()); } } /** * Describes how dependencies should be inherited * * @param dependencies * array of dependencies to inherit */ protected void mergeDependencies(DependencyDescriptor[] dependencies) { DefaultModuleDescriptor md = getMd(); for (int i = 0; i < dependencies.length; i++) { DependencyDescriptor dependencyDescriptor = dependencies[i]; Message.debug("Merging dependency with: " + dependencyDescriptor.getDependencyRevisionId().toString()); md.addDependency(dependencyDescriptor); } } /** * Describes how to merge description * * @param description * description going to be inherited */ protected void mergeDescription(String description) { String current = getMd().getDescription(); if (current == null || current.trim().length() == 0) { getMd().setDescription(description); } } /** * Describes how to merge licenses * * @param licenses * licenses going to be inherited */ public void mergeLicenses(License[] licenses) { for (int i = 0; i < licenses.length; i++) { getMd().addLicense(licenses[i]); } } /** * Describes how to merge exclude rules * * @param excludeRules * exclude rules going to be inherited */ public void mergeExcludes(ExcludeRule[] excludeRules) { for (int i = 0; i < excludeRules.length; i++) { getMd().addExcludeRule(excludeRules[i]); } } /** * Returns the parent module using the location attribute (for dev purpose). * * @param location * a given location * @throws IOException * @throws ParseException */ private ModuleDescriptor parseParentModuleOnFilesystem(String location) throws IOException, ParseException { if (!"file".equals(descriptorURL.getProtocol())) { return null; } File file = new File(location); if (!file.isAbsolute()) { URL url = settings.getRelativeUrlResolver().getURL(descriptorURL, location); try { file = new File(new URI(url.toExternalForm())); } catch (URISyntaxException e) { file = new File(url.getPath()); } } file = FileUtil.normalize(file.getAbsolutePath()); if (!file.exists()) { Message.verbose("Parent module doesn't exist on the filesystem: " + file.getAbsolutePath()); return null; } FileResource res = new FileResource(null, file); ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser( res); return parser.parseDescriptor(getSettings(), file.toURL(), res, isValidate()); } /** * Describe how to parse a {@link ModuleDescriptor} by asking repositories * * @param parentMrid * a given {@link ModuleRevisionId} to find * @return a {@link ModuleDescriptor} if found. Return null if no {@link ModuleDescriptor} * was found * @throws ParseException */ protected ModuleDescriptor parseOtherIvyFile(ModuleRevisionId parentMrid) throws ParseException { Message.debug("Trying to parse included ivy file by asking repository for module :" + parentMrid.toString()); DependencyDescriptor dd = new DefaultDependencyDescriptor(parentMrid, true); ResolveData data = IvyContext.getContext().getResolveData(); if (data == null) { ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine(); ResolveOptions options = new ResolveOptions(); options.setDownload(false); data = new ResolveData(engine, options); } DependencyResolver resolver = getSettings().getResolver(parentMrid); dd = NameSpaceHelper.toSystem(dd, getSettings().getContextNamespace()); ResolvedModuleRevision otherModule = resolver.getDependency(dd, data); if (otherModule == null) { throw new ParseException("Unable to find " + parentMrid.toString(), 0); } return otherModule.getDescriptor(); } protected void publicationsStarted(Attributes attributes) { state = State.PUB; artifactsDeclared = true; checkConfigurations(); String defaultConf = settings.substitute(attributes.getValue("defaultconf")); if (defaultConf != null) { setPublicationsDefaultConf(defaultConf); } } protected void setPublicationsDefaultConf(String defaultConf) { this.publicationsDefaultConf = defaultConf == null ? null : defaultConf.split(","); } protected boolean isOtherNamespace(String qName) { return qName.indexOf(':') != -1; } protected void managerStarted(Attributes attributes, String managerAtt) { String org = settings.substitute(attributes.getValue("org")); org = org == null ? PatternMatcher.ANY_EXPRESSION : org; String mod = settings.substitute(attributes.getValue("module")); mod = mod == null ? PatternMatcher.ANY_EXPRESSION : mod; ConflictManager cm; String name = settings.substitute(attributes.getValue(managerAtt)); String rev = settings.substitute(attributes.getValue("rev")); if (rev != null) { String[] revs = rev.split(","); for (int i = 0; i < revs.length; i++) { revs[i] = revs[i].trim(); } cm = new FixedConflictManager(revs); } else if (name != null) { cm = settings.getConflictManager(name); if (cm == null) { addError("unknown conflict manager: " + name); return; } } else { addError("bad conflict manager: no manager nor rev"); return; } String matcherName = settings.substitute(attributes.getValue("matcher")); PatternMatcher matcher = matcherName == null ? defaultMatcher : settings .getMatcher(matcherName); if (matcher == null) { addError("unknown matcher: " + matcherName); return; } getMd().addConflictManager(new ModuleId(org, mod), matcher, cm); } protected void mediationOverrideStarted(Attributes attributes) { String org = settings.substitute(attributes.getValue("org")); org = org == null ? PatternMatcher.ANY_EXPRESSION : org; String mod = settings.substitute(attributes.getValue("module")); mod = mod == null ? PatternMatcher.ANY_EXPRESSION : mod; String rev = settings.substitute(attributes.getValue("rev")); String branch = settings.substitute(attributes.getValue("branch")); String matcherName = settings.substitute(attributes.getValue("matcher")); PatternMatcher matcher = matcherName == null ? defaultMatcher : settings .getMatcher(matcherName); if (matcher == null) { addError("unknown matcher: " + matcherName); return; } getMd().addDependencyDescriptorMediator(new ModuleId(org, mod), matcher, new OverrideDependencyDescriptorMediator(branch, rev)); } protected void includeConfStarted(Attributes attributes) throws SAXException, IOException, ParserConfigurationException, ParseException { URL url = settings.getRelativeUrlResolver().getURL(descriptorURL, settings.substitute(attributes.getValue("file")), settings.substitute(attributes.getValue("url"))); if (url == null) { throw new SAXException("include tag must have a file or an url attribute"); } // create a new temporary parser to read the configurations from // the specified file. Parser parser = new Parser(getModuleDescriptorParser(), settings); parser.setInput(url); parser.setMd(new DefaultModuleDescriptor(getModuleDescriptorParser(), new URLResource( url))); XMLHelper.parse(url, null, parser); // add the configurations from this temporary parser to this module descriptor Configuration[] configs = parser.getModuleDescriptor().getConfigurations(); for (int i = 0; i < configs.length; i++) { getMd().addConfiguration(configs[i]); } if (parser.getDefaultConfMapping() != null) { Message.debug("setting default conf mapping from imported configurations file: " + parser.getDefaultConfMapping()); setDefaultConfMapping(parser.getDefaultConfMapping()); } if (parser.getDefaultConf() != null) { Message.debug("setting default conf from imported configurations file: " + parser.getDefaultConf()); setDefaultConf(parser.getDefaultConf()); } if (parser.getMd().isMappingOverride()) { Message.debug("enabling mapping-override from imported configurations" + " file"); getMd().setMappingOverride(true); } } protected void confStarted(Attributes attributes) { String conf = settings.substitute(attributes.getValue("name")); switch (state) { case State.CONF: String visibility = settings.substitute(attributes.getValue("visibility")); String ext = settings.substitute(attributes.getValue("extends")); String transitiveValue = attributes.getValue("transitive"); boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf( attributes.getValue("transitive")).booleanValue(); String deprecated = attributes.getValue("deprecated"); Configuration configuration = new Configuration(conf, Configuration.Visibility.getVisibility(visibility == null ? "public" : visibility), settings.substitute(attributes .getValue("description")), ext == null ? null : ext.split(","), transitive, deprecated); ExtendableItemHelper.fillExtraAttributes(settings, configuration, attributes, new String[] {"name", "visibility", "extends", "transitive", "description", "deprecated"}); getMd().addConfiguration(configuration); break; case State.PUB: if ("*".equals(conf)) { String[] confs = getMd().getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { artifact.addConfiguration(confs[i]); getMd().addArtifact(confs[i], artifact); } } else { artifact.addConfiguration(conf); getMd().addArtifact(conf, artifact); } break; case State.DEP: this.conf = conf; String mappeds = settings.substitute(attributes.getValue("mapped")); if (mappeds != null) { String[] mapped = mappeds.split(","); for (int i = 0; i < mapped.length; i++) { dd.addDependencyConfiguration(conf, mapped[i].trim()); } } break; case State.DEP_ARTIFACT: case State.ARTIFACT_INCLUDE: case State.ARTIFACT_EXCLUDE: addConfiguration(conf); break; default: if (validate) { addError("conf tag found in invalid tag: " + state); } break; } } protected void dependencyStarted(Attributes attributes) { state = State.DEP; String org = settings.substitute(attributes.getValue("org")); if (org == null) { org = getMd().getModuleRevisionId().getOrganisation(); } boolean force = Boolean.valueOf(settings.substitute(attributes.getValue("force"))) .booleanValue(); boolean changing = Boolean .valueOf(settings.substitute(attributes.getValue("changing"))).booleanValue(); String transitiveValue = settings.substitute(attributes.getValue("transitive")); boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf( attributes.getValue("transitive")).booleanValue(); String name = settings.substitute(attributes.getValue("name")); String branch = settings.substitute(attributes.getValue("branch")); String branchConstraint = settings.substitute(attributes.getValue("branchConstraint")); // if (branchConstraint == null) { // // there was no branch constraint before, so we should // // set the branchConstraint to the current default branch // branchConstraint = settings.getDefaultBranch(ModuleId.newInstance(org, name)); // } String rev = settings.substitute(attributes.getValue("rev")); String revConstraint = settings.substitute(attributes.getValue("revConstraint")); Map extraAttributes = ExtendableItemHelper.getExtraAttributes(settings, attributes, DEPENDENCY_REGULAR_ATTRIBUTES); ModuleRevisionId revId = ModuleRevisionId.newInstance(org, name, branch, rev, extraAttributes); ModuleRevisionId dynamicId = null; if ((revConstraint == null) && (branchConstraint == null)) { // no dynamic constraints defined, so dynamicId equals revId dynamicId = ModuleRevisionId.newInstance(org, name, branch, rev, extraAttributes, false); } else { if (branchConstraint == null) { // this situation occurs when there was no branch defined // in the original dependency descriptor. So the dynamicId // shouldn't contain a branch neither dynamicId = ModuleRevisionId.newInstance(org, name, null, revConstraint, extraAttributes, false); } else { dynamicId = ModuleRevisionId.newInstance(org, name, branchConstraint, revConstraint, extraAttributes); } } dd = new DefaultDependencyDescriptor(getMd(), revId, dynamicId, force, changing, transitive); getMd().addDependency(dd); String confs = settings.substitute(attributes.getValue("conf")); if (confs != null && confs.length() > 0) { parseDepsConfs(confs, dd); } } protected void artifactStarted(String qName, Attributes attributes) throws MalformedURLException { if (state == State.PUB) { // this is a published artifact String artName = settings.substitute(attributes.getValue("name")); artName = artName == null ? getMd().getModuleRevisionId().getName() : artName; String type = settings.substitute(attributes.getValue("type")); type = type == null ? "jar" : type; String ext = settings.substitute(attributes.getValue("ext")); ext = ext != null ? ext : type; String url = settings.substitute(attributes.getValue("url")); artifact = new MDArtifact(getMd(), artName, type, ext, url == null ? null : new URL(url), ExtendableItemHelper.getExtraAttributes(settings, attributes, new String[] {"ext", "type", "name", "conf"})); String confs = settings.substitute(attributes.getValue("conf")); // only add confs if they are specified. if they aren't, endElement will // handle this // only if there are no conf defined in sub elements if (confs != null && confs.length() > 0) { String[] conf; if ("*".equals(confs)) { conf = getMd().getConfigurationsNames(); } else { conf = confs.split(","); } for (int i = 0; i < conf.length; i++) { artifact.addConfiguration(conf[i].trim()); getMd().addArtifact(conf[i].trim(), artifact); } } } else if (state == State.DEP) { // this is an artifact asked for a particular dependency addDependencyArtifacts(qName, attributes); } else if (validate) { addError("artifact tag found in invalid tag: " + state); } } protected void dependenciesStarted(Attributes attributes) { state = State.DEPS; String defaultConf = settings.substitute(attributes.getValue("defaultconf")); if (defaultConf != null) { setDefaultConf(defaultConf); } defaultConf = settings.substitute(attributes.getValue("defaultconfmapping")); if (defaultConf != null) { setDefaultConfMapping(defaultConf); } String confMappingOverride = settings.substitute(attributes .getValue("confmappingoverride")); if (confMappingOverride != null) { getMd().setMappingOverride(Boolean.valueOf(confMappingOverride).booleanValue()); } checkConfigurations(); } protected void configurationStarted(Attributes attributes) { state = State.CONF; setDefaultConfMapping(settings.substitute(attributes.getValue("defaultconfmapping"))); setDefaultConf(settings.substitute(attributes.getValue("defaultconf"))); getMd().setMappingOverride( Boolean.valueOf(settings.substitute(attributes.getValue("confmappingoverride"))) .booleanValue()); } protected void infoStarted(Attributes attributes) { state = State.INFO; String org = settings.substitute(attributes.getValue("organisation")); String module = settings.substitute(attributes.getValue("module")); String revision = settings.substitute(attributes.getValue("revision")); String branch = settings.substitute(attributes.getValue("branch")); getMd().setModuleRevisionId( ModuleRevisionId.newInstance( org, module, branch, revision, ExtendableItemHelper.getExtraAttributes(settings, attributes, new String[] { "organisation", "module", "revision", "status", "publication", "branch", "namespace", "default", "resolver"}))); String namespace = settings.substitute(attributes.getValue("namespace")); if (namespace != null) { Namespace ns = settings.getNamespace(namespace); if (ns == null) { Message.warn("namespace not found for " + getMd().getModuleRevisionId() + ": " + namespace); } else { getMd().setNamespace(ns); } } String status = settings.substitute(attributes.getValue("status")); getMd().setStatus( status == null ? settings.getStatusManager().getDefaultStatus() : status); getMd().setDefault( Boolean.valueOf(settings.substitute(attributes.getValue("default"))).booleanValue()); String pubDate = settings.substitute(attributes.getValue("publication")); if (pubDate != null && pubDate.length() > 0) { try { getMd().setPublicationDate(DateUtil.parse(pubDate)); } catch (ParseException e) { addError("invalid publication date format: " + pubDate); getMd().setPublicationDate(getDefaultPubDate()); } } else { getMd().setPublicationDate(getDefaultPubDate()); } } protected void ivyModuleStarted(Attributes attributes) throws SAXException { descriptorVersion = attributes.getValue("version"); int versionIndex = ALLOWED_VERSIONS.indexOf(descriptorVersion); if (versionIndex == -1) { addError("invalid version " + descriptorVersion); throw new SAXException("invalid version " + descriptorVersion); } if (versionIndex >= ALLOWED_VERSIONS.indexOf("1.3")) { Message.debug("post 1.3 ivy file: using " + PatternMatcher.EXACT + " as default matcher"); defaultMatcher = settings.getMatcher(PatternMatcher.EXACT); } else { Message.debug("pre 1.3 ivy file: using " + PatternMatcher.EXACT_OR_REGEXP + " as default matcher"); defaultMatcher = settings.getMatcher(PatternMatcher.EXACT_OR_REGEXP); } for (int i = 0; i < attributes.getLength(); i++) { if (attributes.getQName(i).startsWith("xmlns:")) { getMd().addExtraAttributeNamespace( attributes.getQName(i).substring("xmlns:".length()), attributes.getValue(i)); } } } protected void addDependencyArtifacts(String tag, Attributes attributes) throws MalformedURLException { state = State.DEP_ARTIFACT; parseRule(tag, attributes); } protected void addIncludeRule(String tag, Attributes attributes) throws MalformedURLException { state = State.ARTIFACT_INCLUDE; parseRule(tag, attributes); } protected void addExcludeRule(String tag, Attributes attributes) throws MalformedURLException { state = State.ARTIFACT_EXCLUDE; parseRule(tag, attributes); } protected void parseRule(String tag, Attributes attributes) throws MalformedURLException { String name = settings.substitute(attributes.getValue("name")); if (name == null) { name = settings.substitute(attributes.getValue("artifact")); if (name == null) { name = "artifact".equals(tag) ? dd.getDependencyId().getName() : PatternMatcher.ANY_EXPRESSION; } } String type = settings.substitute(attributes.getValue("type")); if (type == null) { type = "artifact".equals(tag) ? "jar" : PatternMatcher.ANY_EXPRESSION; } String ext = settings.substitute(attributes.getValue("ext")); ext = ext != null ? ext : type; if (state == State.DEP_ARTIFACT) { String url = settings.substitute(attributes.getValue("url")); Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, new String[] {"name", "type", "ext", "url", "conf"}); confAware = new DefaultDependencyArtifactDescriptor(dd, name, type, ext, url == null ? null : new URL(url), extraAtt); } else if (state == State.ARTIFACT_INCLUDE) { PatternMatcher matcher = getPatternMatcher(attributes.getValue("matcher")); String org = settings.substitute(attributes.getValue("org")); org = org == null ? PatternMatcher.ANY_EXPRESSION : org; String module = settings.substitute(attributes.getValue("module")); module = module == null ? PatternMatcher.ANY_EXPRESSION : module; ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext); Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"}); confAware = new DefaultIncludeRule(aid, matcher, extraAtt); } else { // _state == ARTIFACT_EXCLUDE || EXCLUDE PatternMatcher matcher = getPatternMatcher(attributes.getValue("matcher")); String org = settings.substitute(attributes.getValue("org")); org = org == null ? PatternMatcher.ANY_EXPRESSION : org; String module = settings.substitute(attributes.getValue("module")); module = module == null ? PatternMatcher.ANY_EXPRESSION : module; ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext); Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"}); confAware = new DefaultExcludeRule(aid, matcher, extraAtt); } String confs = settings.substitute(attributes.getValue("conf")); // only add confs if they are specified. if they aren't, endElement will handle this // only if there are no conf defined in sub elements if (confs != null && confs.length() > 0) { String[] conf; if ("*".equals(confs)) { conf = getMd().getConfigurationsNames(); } else { conf = confs.split(","); } for (int i = 0; i < conf.length; i++) { addConfiguration(conf[i].trim()); } } } protected void addConfiguration(String c) { confAware.addConfiguration(c); if (state == State.EXCLUDE) { // we are adding a configuration to a module wide exclude rule // we have nothing special to do here, the rule has already been added to the module // descriptor } else { // we are currently adding a configuration to either an include, exclude or artifact // element // of a dependency. This means that we have to add this element to the corresponding // conf // of the current dependency descriptor if (confAware instanceof DependencyArtifactDescriptor) { dd.addDependencyArtifact(c, (DependencyArtifactDescriptor) confAware); } else if (confAware instanceof IncludeRule) { dd.addIncludeRule(c, (IncludeRule) confAware); } else if (confAware instanceof ExcludeRule) { dd.addExcludeRule(c, (ExcludeRule) confAware); } } } protected PatternMatcher getPatternMatcher(String m) { String matcherName = settings.substitute(m); PatternMatcher matcher = matcherName == null ? defaultMatcher : settings .getMatcher(matcherName); if (matcher == null) { throw new IllegalArgumentException("unknown matcher " + matcherName); } return matcher; } public void characters(char[] ch, int start, int length) throws SAXException { if (buffer != null) { buffer.append(ch, start, length); } } public void endElement(String uri, String localName, String qName) throws SAXException { if (state == State.PUB && "artifact".equals(qName) && artifact.getConfigurations().length == 0) { String[] confs = publicationsDefaultConf == null ? getMd().getConfigurationsNames() : publicationsDefaultConf; for (int i = 0; i < confs.length; i++) { artifact.addConfiguration(confs[i].trim()); getMd().addArtifact(confs[i].trim(), artifact); } } else if ("configurations".equals(qName)) { checkConfigurations(); } else if ((state == State.DEP_ARTIFACT && "artifact".equals(qName)) || (state == State.ARTIFACT_INCLUDE && "include".equals(qName)) || (state == State.ARTIFACT_EXCLUDE && "exclude".equals(qName))) { state = State.DEP; if (confAware.getConfigurations().length == 0) { String[] confs = getMd().getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { addConfiguration(confs[i]); } } confAware = null; } else if ("exclude".equals(qName) && state == State.EXCLUDE) { if (confAware.getConfigurations().length == 0) { String[] confs = getMd().getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { addConfiguration(confs[i]); } } confAware = null; state = State.DEPS; } else if ("dependency".equals(qName) && state == State.DEP) { if (dd.getModuleConfigurations().length == 0) { parseDepsConfs(getDefaultConf(), dd); } state = State.DEPS; } else if ("dependencies".equals(qName) && state == State.DEPS) { state = State.NONE; } else if (state == State.INFO && "info".equals(qName)) { state = State.NONE; } else if (state == State.DESCRIPTION && "description".equals(qName)) { getMd().setDescription(buffer == null ? "" : buffer.toString().trim()); buffer = null; state = State.INFO; } else if (state == State.EXTRA_INFO) { String content = buffer == null ? "" : buffer.toString(); buffer = null; getMd().addExtraInfo(qName, content); ExtraInfoHolder extraInfo = extraInfoStack.pop(); extraInfo.setContent(content); if (extraInfoStack.isEmpty()) { getMd().addExtraInfo(extraInfo); state = State.INFO; } else { ExtraInfoHolder parentHolder = extraInfoStack.peek(); parentHolder.getNestedExtraInfoHolder().add(extraInfo); } } else if (state == State.DESCRIPTION) { if (buffer.toString().endsWith("<" + qName + ">")) { buffer.deleteCharAt(buffer.length() - 1); buffer.append("/>"); } else { buffer.append(""); } } } protected void checkConfigurations() { if (getMd().getConfigurations().length == 0) { getMd().addConfiguration(new Configuration("default")); } } protected void replaceConfigurationWildcards() { Configuration[] configs = getMd().getConfigurations(); for (int i = 0; i < configs.length; i++) { configs[i].replaceWildcards(getMd()); } } /* getters and setters available for extension only */ protected ParserSettings getSettings() { return settings; } protected URL getDescriptorURL() { return descriptorURL; } protected InputStream getDescriptorInput() { return descriptorInput; } protected int getState() { return state; } protected void setState(int state) { this.state = state; } protected PatternMatcher getDefaultMatcher() { return defaultMatcher; } protected DefaultDependencyDescriptor getDd() { return dd; } protected void setDd(DefaultDependencyDescriptor dd) { this.dd = dd; } protected ConfigurationAware getConfAware() { return confAware; } protected void setConfAware(ConfigurationAware confAware) { this.confAware = confAware; } protected MDArtifact getArtifact() { return artifact; } protected void setArtifact(MDArtifact artifact) { this.artifact = artifact; } protected String getConf() { return conf; } protected void setConf(String conf) { this.conf = conf; } protected boolean isArtifactsDeclared() { return artifactsDeclared; } protected void setArtifactsDeclared(boolean artifactsDeclared) { this.artifactsDeclared = artifactsDeclared; } protected StringBuffer getBuffer() { return buffer; } protected void setBuffer(StringBuffer buffer) { this.buffer = buffer; } protected String getDescriptorVersion() { return descriptorVersion; } protected void setDescriptorVersion(String descriptorVersion) { this.descriptorVersion = descriptorVersion; } protected String[] getPublicationsDefaultConf() { return publicationsDefaultConf; } protected void setPublicationsDefaultConf(String[] publicationsDefaultConf) { this.publicationsDefaultConf = publicationsDefaultConf; } protected boolean isValidate() { return validate; } protected URL getSchemaURL() { return getClass().getResource("ivy.xsd"); } } public String toString() { return "ivy parser"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java000066400000000000000000001622511226750426600312710ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.xml; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.StringTokenizer; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ExtendsDescriptor; import org.apache.ivy.core.module.descriptor.InheritableItem; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.file.FileResource; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.util.Checks; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.extendable.ExtendableItemHelper; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; /** * Used to update ivy files. Uses ivy file as source and not ModuleDescriptor to preserve as much as * possible the original syntax */ public final class XmlModuleDescriptorUpdater { // CheckStyle:StaticVariableName| OFF // LINE_SEPARATOR is actually a constant, but we have to modify it for the tests public static String LINE_SEPARATOR = System.getProperty("line.separator"); // CheckStyle:StaticVariableName| ON private XmlModuleDescriptorUpdater() { } /** * used to copy a module descriptor xml file (also known as ivy file) and update the revisions * of its dependencies, its status and revision * * @param srcURL * the url of the source module descriptor file * @param destFile * The file to which the updated module descriptor should be output */ public static void update(URL srcURL, File destFile, UpdateOptions options) throws IOException, SAXException { if (destFile.getParentFile() != null) { destFile.getParentFile().mkdirs(); } OutputStream destStream = new FileOutputStream(destFile); try { update(srcURL, destStream, options); } finally { try { destStream.close(); } catch (IOException e) { Message.warn("failed to close a stream : " + e.toString()); } } } public static void update(URL srcURL, OutputStream destFile, UpdateOptions options) throws IOException, SAXException { InputStream in = srcURL.openStream(); try { update(srcURL, in, destFile, options); } finally { try { in.close(); } catch (IOException e) { Message.warn("failed to close a stream : " + e.toString()); } try { destFile.close(); } catch (IOException e) { Message.warn("failed to close a stream : " + e.toString()); } } } public static void update(InputStream in, Resource res, File destFile, UpdateOptions options) throws IOException, SAXException { if (destFile.getParentFile() != null) { destFile.getParentFile().mkdirs(); } OutputStream fos = new FileOutputStream(destFile); try { // TODO: use resource as input stream context? URL inputStreamContext = null; if (res instanceof URLResource) { inputStreamContext = ((URLResource) res).getURL(); } else if (res instanceof FileResource) { inputStreamContext = ((FileResource) res).getFile().toURI().toURL(); } update(inputStreamContext, in, fos, options); } finally { try { in.close(); } catch (IOException e) { Message.warn("failed to close a stream : " + e.toString()); } try { fos.close(); } catch (IOException e) { Message.warn("failed to close a stream : " + e.toString()); } } } private static class UpdaterHandler extends DefaultHandler implements LexicalHandler { /** standard attributes of ivy-module/info */ private static final Collection STD_ATTS = Arrays.asList(new String[] {"organisation", "module", "branch", "revision", "status", "publication", "namespace"}); /** elements that may appear inside ivy-module, in expected order */ private static final List MODULE_ELEMENTS = Arrays.asList(new String[] {"info", "configurations", "publications", "dependencies", "conflicts"}); /** element position of "configurations" inside "ivy-module" */ private static final int CONFIGURATIONS_POSITION = MODULE_ELEMENTS .indexOf("configurations"); /** element position of "dependencies" inside "ivy-module" */ private static final int DEPENDENCIES_POSITION = MODULE_ELEMENTS.indexOf("dependencies"); /** elements that may appear inside of ivy-module/info */ private static final Collection INFO_ELEMENTS = Arrays.asList(new String[] {"extends", "ivyauthor", "license", "repository", "description"}); private final ParserSettings settings; private final PrintWriter out; private final Map resolvedRevisions; private final Map resolvedBranches; private final String status; private final String revision; private final Date pubdate; private final Namespace ns; private final boolean replaceInclude; private final boolean generateRevConstraint; private boolean inHeader = true; private final List confs; private final URL relativePathCtx; private final UpdateOptions options; public UpdaterHandler(URL relativePathCtx, PrintWriter out, final UpdateOptions options) { this.options = options; this.settings = options.getSettings(); this.out = out; this.resolvedRevisions = options.getResolvedRevisions(); this.resolvedBranches = options.getResolvedBranches(); this.status = options.getStatus(); this.revision = options.getRevision(); this.pubdate = options.getPubdate(); this.ns = options.getNamespace(); this.replaceInclude = options.isReplaceInclude(); this.generateRevConstraint = options.isGenerateRevConstraint(); this.relativePathCtx = relativePathCtx; if (options.getConfsToExclude() != null) { this.confs = Arrays.asList(options.getConfsToExclude()); } else { this.confs = Collections.EMPTY_LIST; } } // never print *ln* cause \n is found in copied characters stream // nor do we need do handle indentation, original one is maintained except for attributes private String organisation = null; // defaultConfMapping of imported configurations, if any private String defaultConfMapping = null; // confMappingOverride of imported configurations, if any private Boolean confMappingOverride = null; // used to know if the last open tag was empty, to adjust termination // with /> instead of > private String justOpen = null; // track the size of the left indent, so that inserted elements are formatted // like nearby elements. // true when we're reading indent whitespace private boolean indenting; private StringBuffer currentIndent = new StringBuffer(); private ArrayList indentLevels = new ArrayList(); // ArrayList // true if an ivy-module/info/description element has been found in the published descriptor private boolean hasDescription = false; // true if merged configurations have been written private boolean mergedConfigurations = false; // true if merged deps have been written private boolean mergedDependencies = false; // the new value of the defaultconf attribute on the publications tag private String newDefaultConf = null; private Stack context = new Stack(); private Stack buffers = new Stack(); private Stack confAttributeBuffers = new Stack(); public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { inHeader = false; endIndent(); if (justOpen != null) { write(">"); } flushMergedElementsBefore(qName); // according to ivy.xsd, all elements must occur before // the , or elements if (options.isMerge() && ("exclude".equals(localName) || "override".equals(localName) || "conflict" .equals(localName)) && "ivy-module/dependencies".equals(getContext())) { ModuleDescriptor merged = options.getMergedDescriptor(); writeInheritedDependencies(merged); out.println(); out.print(getIndent()); } context.push(qName); String path = getContext(); if ("info".equals(qName)) { infoStarted(attributes); } else if (replaceInclude && "include".equals(qName) && context.contains("configurations")) { // TODO, in the case of !replaceInclude, we should still replace the relative path // by an absolute path. includeStarted(attributes); } else if ("ivy-module/info/extends".equals(path)) { startExtends(attributes); } else if ("ivy-module/dependencies/dependency".equals(path)) { startElementInDependency(attributes); } else if ("dependencies".equals(qName)) { startDependencies(attributes); } else if ("ivy-module/configurations/conf".equals(path)) { startElementInConfigurationsConf(qName, attributes); } else if ("ivy-module/publications/artifact/conf".equals(path) || "ivy-module/dependencies/dependency/conf".equals(path) || "ivy-module/dependencies/dependency/artifact/conf".equals(path)) { buffers.push(new ExtendedBuffer(getContext())); ((ExtendedBuffer) confAttributeBuffers.peek()).setDefaultPrint(false); String confName = substitute(settings, attributes.getValue("name")); if (!confs.contains(confName)) { ((ExtendedBuffer) confAttributeBuffers.peek()).setPrint(true); ((ExtendedBuffer) buffers.peek()).setPrint(true); write("<" + qName); for (int i = 0; i < attributes.getLength(); i++) { write(" " + attributes.getQName(i) + "=\"" + substitute(settings, attributes.getValue(i)) + "\""); } } } else if ("ivy-module/publications/artifact".equals(path)) { ExtendedBuffer buffer = new ExtendedBuffer(getContext()); buffers.push(buffer); confAttributeBuffers.push(buffer); write("<" + qName); buffer.setDefaultPrint(attributes.getValue("conf") == null && ((newDefaultConf == null) || (newDefaultConf.length() > 0))); for (int i = 0; i < attributes.getLength(); i++) { String attName = attributes.getQName(i); if ("conf".equals(attName)) { String confName = substitute(settings, attributes.getValue("conf")); String newConf = removeConfigurationsFromList(confName, confs); if (newConf.length() > 0) { write(" " + attributes.getQName(i) + "=\"" + newConf + "\""); ((ExtendedBuffer) buffers.peek()).setPrint(true); } } else { write(" " + attributes.getQName(i) + "=\"" + substitute(settings, attributes.getValue(i)) + "\""); } } } else if ("ivy-module/dependencies/dependency/artifact".equals(path)) { ExtendedBuffer buffer = new ExtendedBuffer(getContext()); buffers.push(buffer); confAttributeBuffers.push(buffer); write("<" + qName); buffer.setDefaultPrint(attributes.getValue("conf") == null); for (int i = 0; i < attributes.getLength(); i++) { String attName = attributes.getQName(i); if ("conf".equals(attName)) { String confName = substitute(settings, attributes.getValue("conf")); String newConf = removeConfigurationsFromList(confName, confs); if (newConf.length() > 0) { write(" " + attributes.getQName(i) + "=\"" + newConf + "\""); ((ExtendedBuffer) buffers.peek()).setPrint(true); } } else { write(" " + attributes.getQName(i) + "=\"" + substitute(settings, attributes.getValue(i)) + "\""); } } } else if ("ivy-module/publications".equals(path)) { startPublications(attributes); } else { if (options.isMerge() && path.startsWith("ivy-module/info")) { ModuleDescriptor merged = options.getMergedDescriptor(); if (path.equals("ivy-module/info/description")) { // if the descriptor already contains a description, don't bother printing // the merged version. hasDescription = true; } else if (!INFO_ELEMENTS.contains(qName)) { // according to the XSD, we should write description after all of the other // standard elements but before any extended elements. writeInheritedDescription(merged); } } // copy write("<" + qName); for (int i = 0; i < attributes.getLength(); i++) { write(" " + attributes.getQName(i) + "=\"" + substitute(settings, attributes.getValue(i)) + "\""); } } justOpen = qName; // indent.append("\t"); } private void startExtends(Attributes attributes) { // in merge mode, comment out extends element if (options.isMerge()) { write(""); } /** * Collect the given list of inherited descriptor items into lists keyed by parent Id. Thus * all of the items inherited from parent A can be written together, then all of the items * from parent B, and so on. * * @param merged * the merged child descriptor * @param items * the inherited items to collate * @return maps parent ModuleRevisionId to a List of InheritedItems imported from that * parent */ private Map/* */collateInheritedItems(ModuleDescriptor merged, InheritableItem[] items) { LinkedHashMap/* */inheritedItems = new LinkedHashMap(); for (int i = 0; i < items.length; ++i) { ModuleRevisionId source = items[i].getSourceModule(); // ignore items that are defined directly in the child descriptor if (source != null && !source.getModuleId().equals(merged.getModuleRevisionId().getModuleId())) { List accum = (List) inheritedItems.get(source); if (accum == null) { accum = new ArrayList(); inheritedItems.put(source, accum); } accum.add(items[i]); } } return inheritedItems; } /** * If no info/description element has yet been written, write the description inherited from * the parent descriptor, if any. Calling this method more than once has no affect. */ private void writeInheritedDescription(ModuleDescriptor merged) { if (!hasDescription) { hasDescription = true; String description = merged.getDescription(); if ((description != null) && (description.length() > 0)) { PrintWriter writer = getWriter(); if (justOpen != null) { writer.println(">"); } writeInheritanceComment("description", "parent"); writer.println(getIndent() + "" + XMLHelper.escape(description) + ""); // restore the indent that existed before we wrote the extra elements writer.print(currentIndent); justOpen = null; } } } private void writeInheritedConfigurations(ModuleDescriptor merged) { if (!mergedConfigurations) { mergedConfigurations = true; writeInheritedItems(merged, merged.getConfigurations(), ConfigurationPrinter.INSTANCE, "configurations", false); } } private void writeInheritedDependencies(ModuleDescriptor merged) { if (!mergedDependencies) { mergedDependencies = true; writeInheritedItems(merged, merged.getDependencies(), DependencyPrinter.INSTANCE, "dependencies", false); } } /** *

    * If publishing in merge mode, guarantee that any merged elements appearing before * moduleElement have been written. This method should be called before * we write the start tag of moduleElement. This covers cases where merged * elements like "configurations" and "dependencies" appear in the parent descriptor, but * are completely missing in the child descriptor. *

    * *

    * For example, if "moduleElement" is "dependencies", guarantees that "configurations" has * been written. If moduleElement is null, then all missing merged * elements will be flushed. *

    * * @param moduleElement * a descriptor element name, for example "configurations" or "info" */ private void flushMergedElementsBefore(String moduleElement) { if (options.isMerge() && context.size() == 1 && "ivy-module".equals(context.peek()) && !(mergedConfigurations && mergedDependencies)) { // calculate the position of the element in ivy-module int position = moduleElement == null ? MODULE_ELEMENTS.size() : MODULE_ELEMENTS .indexOf(moduleElement); ModuleDescriptor merged = options.getMergedDescriptor(); // see if we should write if (!mergedConfigurations && position > CONFIGURATIONS_POSITION && merged.getConfigurations().length > 0) { mergedConfigurations = true; writeInheritedItems(merged, merged.getConfigurations(), ConfigurationPrinter.INSTANCE, "configurations", true); } // see if we should write if (!mergedDependencies && position > DEPENDENCIES_POSITION && merged.getDependencies().length > 0) { mergedDependencies = true; writeInheritedItems(merged, merged.getDependencies(), DependencyPrinter.INSTANCE, "dependencies", true); } } } private void flushAllMergedElements() { flushMergedElementsBefore(null); } public void endElement(String uri, String localName, String qName) throws SAXException { String path = getContext(); if (options.isMerge()) { ModuleDescriptor merged = options.getMergedDescriptor(); if ("ivy-module/info".equals(path)) { // guarantee that inherited description has been written before // info element closes. writeInheritedDescription(merged); } else if ("ivy-module/configurations".equals(path)) { // write inherited configurations after all child configurations writeInheritedConfigurations(merged); } else if ("ivy-module/dependencies".equals(path)) { // write inherited dependencies after all child dependencies writeInheritedDependencies(merged); } else if ("ivy-module".equals(path)) { // write any remaining inherited data before we close the // descriptor. flushAllMergedElements(); } } if (qName.equals(justOpen)) { write("/>"); } else { write(""); } if (!buffers.isEmpty()) { ExtendedBuffer buffer = (ExtendedBuffer) buffers.peek(); if (buffer.getContext().equals(path)) { buffers.pop(); if (buffer.isPrint()) { write(buffer.toString()); } } } if (!confAttributeBuffers.isEmpty()) { ExtendedBuffer buffer = (ExtendedBuffer) confAttributeBuffers.peek(); if (buffer.getContext().equals(path)) { confAttributeBuffers.pop(); } } // element is commented out when in merge mode. if (options.isMerge() && "ivy-module/info/extends".equals(path)) { write(" -->"); } justOpen = null; context.pop(); } public void endDocument() throws SAXException { out.print(LINE_SEPARATOR); out.flush(); out.close(); } public void processingInstruction(String target, String data) throws SAXException { write(""); write(LINE_SEPARATOR); } public void warning(SAXParseException e) throws SAXException { throw e; } public void error(SAXParseException e) throws SAXException { throw e; } public void fatalError(SAXParseException e) throws SAXException { throw e; } public void endCDATA() throws SAXException { } public void endDTD() throws SAXException { } public void startCDATA() throws SAXException { } public void comment(char[] ch, int start, int length) throws SAXException { if (justOpen != null) { write(">"); justOpen = null; } StringBuffer comment = new StringBuffer(); comment.append(ch, start, length); write(""); if (inHeader) { write(LINE_SEPARATOR); } } public void endEntity(String name) throws SAXException { } public void startEntity(String name) throws SAXException { } public void startDTD(String name, String publicId, String systemId) throws SAXException { } } public static void update(URL inStreamCtx, InputStream inStream, OutputStream outStream, final UpdateOptions options) throws IOException, SAXException { final PrintWriter out = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8")); out.write(""); out.write(LINE_SEPARATOR); try { UpdaterHandler updaterHandler = new UpdaterHandler(inStreamCtx, out, options); InputSource inSrc = new InputSource(new BufferedInputStream(inStream)); if (inStreamCtx != null) { inSrc.setSystemId(inStreamCtx.toExternalForm()); } XMLHelper.parse(inSrc, null, updaterHandler, updaterHandler); } catch (ParserConfigurationException e) { IllegalStateException ise = new IllegalStateException( "impossible to update Ivy files: parser problem"); ise.initCause(e); throw ise; } } private static class ExtendedBuffer { private String context = null; private Boolean print = null; private boolean defaultPrint = false; private StringWriter buffer = new StringWriter(); private PrintWriter writer = new PrintWriter(buffer); ExtendedBuffer(String context) { this.context = context; } boolean isPrint() { if (print == null) { return defaultPrint; } return print.booleanValue(); } void setPrint(boolean print) { this.print = Boolean.valueOf(print); } void setDefaultPrint(boolean print) { this.defaultPrint = print; } PrintWriter getWriter() { return writer; } String getContext() { return context; } public String toString() { writer.flush(); return buffer.toString(); } } /** * Prints a descriptor item's XML representation */ protected static interface ItemPrinter { /** * Print an XML representation of item to out. * * @param parent * the module descriptor containing item * @param item * subcomponent of the descriptor, for example a {@link DependencyDescriptor} or * {@link Configuration} */ public void print(ModuleDescriptor parent, Object item, PrintWriter out); } protected static class DependencyPrinter implements ItemPrinter { public static final DependencyPrinter INSTANCE = new DependencyPrinter(); public void print(ModuleDescriptor parent, Object item, PrintWriter out) { XmlModuleDescriptorWriter.printDependency(parent, (DependencyDescriptor) item, out); } } protected static class ConfigurationPrinter implements ItemPrinter { public static final ConfigurationPrinter INSTANCE = new ConfigurationPrinter(); public void print(ModuleDescriptor parent, Object item, PrintWriter out) { XmlModuleDescriptorWriter.printConfiguration((Configuration) item, out); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java000066400000000000000000000613221226750426600311360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.parser.xml; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptorMediator; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.ExtendsDescriptor; import org.apache.ivy.core.module.descriptor.ExtraInfoHolder; import org.apache.ivy.core.module.descriptor.IncludeRule; import org.apache.ivy.core.module.descriptor.License; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.StringUtils; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.extendable.ExtendableItem; /** * */ public final class XmlModuleDescriptorWriter { private XmlModuleDescriptorWriter() { // Utility class } public static void write(ModuleDescriptor md, File output) throws IOException { write(md, null, output); } public static void write(ModuleDescriptor md, String licenseHeader, File output) throws IOException { if (output.getParentFile() != null) { output.getParentFile().mkdirs(); } PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF-8")); try { out.println(""); if (licenseHeader != null) { out.print(licenseHeader); } StringBuffer xmlNamespace = new StringBuffer(); Map namespaces = md.getExtraAttributesNamespaces(); for (Iterator iter = namespaces.entrySet().iterator(); iter.hasNext();) { Entry ns = (Entry) iter.next(); xmlNamespace.append(" xmlns:").append(ns.getKey()).append("=\"") .append(ns.getValue()).append("\""); } String version = "2.0"; if (md.getInheritedDescriptors().length > 0) { version = "2.2"; } out.println(""); printInfoTag(md, out); printConfigurations(md, out); printPublications(md, out); printDependencies(md, out); out.println(""); } finally { out.close(); } } private static void printDependencies(ModuleDescriptor md, PrintWriter out) { DependencyDescriptor[] dds = md.getDependencies(); if (dds.length > 0) { out.println("\t"); for (int i = 0; i < dds.length; i++) { DependencyDescriptor dep = dds[i]; out.print("\t\t"); printDependency(md, dep, out); } printAllExcludes(md, out); printAllMediators(md, out); out.println("\t"); } } protected static void printDependency(ModuleDescriptor md, DependencyDescriptor dep, PrintWriter out) { out.print(""); for (int k = 0; k < depConfs.length; k++) { out.print(XMLHelper.escape(depConfs[k])); if (k + 1 < depConfs.length) { out.print(","); } } if (j + 1 < modConfs.length) { out.print(";"); } } out.print("\""); printExtraAttributes(dep, out, " "); DependencyArtifactDescriptor[] depArtifacts = dep.getAllDependencyArtifacts(); if (depArtifacts.length > 0) { out.println(">"); } printDependencyArtefacts(md, out, depArtifacts); IncludeRule[] includes = dep.getAllIncludeRules(); if (includes.length > 0 && depArtifacts.length == 0) { out.println(">"); } printDependencyIncludeRules(md, out, includes); ExcludeRule[] excludes = dep.getAllExcludeRules(); if (excludes.length > 0 && includes.length == 0 && depArtifacts.length == 0) { out.println(">"); } printDependencyExcludeRules(md, out, excludes); if (includes.length + excludes.length + depArtifacts.length == 0) { out.println("/>"); } else { out.println("\t\t
    "); } } private static void printAllMediators(ModuleDescriptor md, PrintWriter out) { Map/* */mediators = md .getAllDependencyDescriptorMediators().getAllRules(); for (Iterator iterator = mediators.entrySet().iterator(); iterator.hasNext();) { Map.Entry mediatorRule = (Map.Entry) iterator.next(); MapMatcher matcher = (MapMatcher) mediatorRule.getKey(); DependencyDescriptorMediator mediator = (DependencyDescriptorMediator) mediatorRule .getValue(); if (mediator instanceof OverrideDependencyDescriptorMediator) { OverrideDependencyDescriptorMediator oddm = (OverrideDependencyDescriptorMediator) mediator; out.print("\t\t"); } else { Message.verbose("ignoring unhandled DependencyDescriptorMediator: " + mediator.getClass()); } } } private static void printAllExcludes(ModuleDescriptor md, PrintWriter out) { ExcludeRule[] excludes = md.getAllExcludeRules(); if (excludes.length > 0) { for (int j = 0; j < excludes.length; j++) { out.print("\t\t"); } } } private static void printDependencyExcludeRules(ModuleDescriptor md, PrintWriter out, ExcludeRule[] excludes) { if (excludes.length > 0) { for (int j = 0; j < excludes.length; j++) { out.print("\t\t\t"); } } } private static void printDependencyIncludeRules(ModuleDescriptor md, PrintWriter out, IncludeRule[] includes) { if (includes.length > 0) { for (int j = 0; j < includes.length; j++) { out.print("\t\t\t"); } } } private static void printDependencyArtefacts(ModuleDescriptor md, PrintWriter out, DependencyArtifactDescriptor[] depArtifacts) { if (depArtifacts.length > 0) { for (int j = 0; j < depArtifacts.length; j++) { out.print("\t\t\t"); } } } /** * Writes the extra attributes of the given {@link ExtendableItem} to the given * PrintWriter. * * @param item * the {@link ExtendableItem}, cannot be null * @param out * the writer to use * @param prefix * the string to write before writing the attributes (if any) */ private static void printExtraAttributes(ExtendableItem item, PrintWriter out, String prefix) { printExtraAttributes(item.getQualifiedExtraAttributes(), out, prefix); } /** * Writes the specified Map containing the extra attributes to the given * PrintWriter. * * @param extra * the extra attributes, can be null * @param out * the writer to use * @param prefix * the string to write before writing the attributes (if any) */ private static void printExtraAttributes(Map extra, PrintWriter out, String prefix) { if (extra == null) { return; } String delim = prefix; for (Iterator iter = extra.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); out.print(delim + entry.getKey() + "=\"" + XMLHelper.escape(entry.getValue().toString()) + "\""); delim = " "; } } private static void printPublications(ModuleDescriptor md, PrintWriter out) { out.println("\t"); Artifact[] artifacts = md.getAllArtifacts(); for (int i = 0; i < artifacts.length; i++) { out.print("\t\t"); } out.println("\t"); } private static void printConfigurations(ModuleDescriptor md, PrintWriter out) { Configuration[] confs = md.getConfigurations(); if (confs.length > 0) { out.println("\t"); for (int i = 0; i < confs.length; i++) { Configuration conf = confs[i]; out.print("\t\t"); printConfiguration(conf, out); } out.println("\t"); } } protected static void printConfiguration(Configuration conf, PrintWriter out) { out.print(" 0) { out.print(" extends=\""); for (int j = 0; j < exts.length; j++) { out.print(XMLHelper.escape(exts[j])); if (j + 1 < exts.length) { out.print(","); } } out.print("\""); } if (!conf.isTransitive()) { out.print(" transitive=\"false\""); } if (conf.getDeprecated() != null) { out.print(" deprecated=\"" + XMLHelper.escape(conf.getDeprecated()) + "\""); } printExtraAttributes(conf, out, " "); out.println("/>"); } private static void printInfoTag(ModuleDescriptor md, PrintWriter out) { out.println("\t"); ExtendsDescriptor[] parents = md.getInheritedDescriptors(); for (int i = 0; i < parents.length; i++) { ExtendsDescriptor parent = parents[i]; ModuleRevisionId mrid = parent.getParentRevisionId(); out.print("\t\t"); } License[] licenses = md.getLicenses(); for (int i = 0; i < licenses.length; i++) { License license = licenses[i]; out.print("\t\t"); } if (md.getHomePage() != null || md.getDescription() != null) { out.print("\t\t 0) { out.println(">"); out.println("\t\t" + XMLHelper.escape(md.getDescription())); out.println("\t\t"); } else { out.println(" />"); } } for (ExtraInfoHolder extraInfo : md.getExtraInfos()) { printExtraInfoElement(out, extraInfo, 2); } out.println("\t"); } else { out.println("\t/>"); } } private static void printExtraInfoElement(PrintWriter out, ExtraInfoHolder extraInfo, int indent) { for (int i = 1; i <= indent; i++) { out.print("\t"); } out.print("<"); out.print(extraInfo.getName()); for (Entry entry : extraInfo.getAttributes().entrySet()) { out.print(" "); out.print(entry.getKey()); out.print("="); out.print("\""); out.print(entry.getValue()); out.print("\""); } boolean requireClosingTag = false; if (extraInfo.getContent() != null && extraInfo.getContent().trim().length() > 0) { out.print(">"); out.print(XMLHelper.escape(extraInfo.getContent())); requireClosingTag = true; } if (!extraInfo.getNestedExtraInfoHolder().isEmpty()) { out.println(">"); for (ExtraInfoHolder nestedElement : extraInfo.getNestedExtraInfoHolder()) { printExtraInfoElement(out, nestedElement, indent + 1); } requireClosingTag = true; // prepare indentation for closing tag for (int i = 1; i <= indent; i++) { out.print("\t"); } } if (requireClosingTag) { out.print(""); } else { out.println("/>"); } } private static boolean requireInnerInfoElement(ModuleDescriptor md) { return md.getExtraInfo().size() > 0 || md.getExtraInfos().size() > 0 || md.getHomePage() != null || (md.getDescription() != null && md.getDescription().trim().length() > 0) || md.getLicenses().length > 0 || md.getInheritedDescriptors().length > 0; } private static String getConfs(ModuleDescriptor md, Artifact artifact) { StringBuffer ret = new StringBuffer(); String[] confs = md.getConfigurationsNames(); for (int i = 0; i < confs.length; i++) { if (Arrays.asList(md.getArtifacts(confs[i])).contains(artifact)) { ret.append(confs[i]).append(","); } } if (ret.length() > 0) { ret.setLength(ret.length() - 1); } return ret.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd000066400000000000000000000344201226750426600244570ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/000077500000000000000000000000001226750426600223445ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/LogReportOutputter.java000066400000000000000000000205701226750426600270640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.report; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.util.Message; /** * */ public class LogReportOutputter implements ReportOutputter { public String getName() { return CONSOLE; } public void output(ResolveReport report, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException { IvySettings settings = IvyContext.getContext().getSettings(); if (settings.logModulesInUse() && ResolveOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info("\t:: modules in use:"); List dependencies = new ArrayList(report.getDependencies()); Collections.sort(dependencies); if (dependencies.size() > 0) { String[] confs = report.getConfigurations(); for (int i = 0; i < dependencies.size(); i++) { IvyNode node = (IvyNode) dependencies.get(i); if (node.isCompletelyEvicted() || node.hasProblem()) { continue; } List nodeConfs = new ArrayList(confs.length); for (int j = 0; j < confs.length; j++) { String conf = confs[j]; if (report.getConfigurationReport(conf).getModuleRevisionIds() .contains(node.getResolvedId())) { nodeConfs.add(conf); } } Message.info("\t" + node + " from " + node.getModuleRevision().getResolver().getName() + " in " + nodeConfs); } } } IvyNode[] evicted = report.getEvictedNodes(); if (evicted.length > 0 && ResolveOptions.LOG_DEFAULT.equals(options.getLog())) { Message.info("\t:: evicted modules:"); for (int i = 0; i < evicted.length; i++) { Collection allEvictingNodes = evicted[i].getAllEvictingNodesDetails(); if (allEvictingNodes == null) { Message.info("\t" + evicted[i] + " transitively in " + Arrays.asList(evicted[i].getEvictedConfs())); } else if (allEvictingNodes.isEmpty()) { Message.info("\t" + evicted[i] + " by [] (" + evicted[i].getAllEvictingConflictManagers() + ") in " + Arrays.asList(evicted[i].getEvictedConfs())); } else { Message.info("\t" + evicted[i] + " by " + allEvictingNodes + " in " + Arrays.asList(evicted[i].getEvictedConfs())); } String[] confs = evicted[i].getEvictedConfs(); for (int j = 0; j < confs.length; j++) { EvictionData evictedData = evicted[i].getEvictedData(confs[j]); if (evictedData.getParent() != null) { Message.verbose("\t in " + evictedData.getParent() + " with " + evictedData.getConflictManager()); } } } } if (ResolveOptions.LOG_DEFAULT.equals(options.getLog())) { // CheckStyle:MagicNumber| OFF char[] sep = new char[69]; Arrays.fill(sep, '-'); Message.rawinfo("\t" + new String(sep)); StringBuffer line = new StringBuffer("\t"); append(line, "", 18); append(line, "modules", 31); line.append("|"); append(line, "artifacts", 15); line.append("|"); Message.rawinfo(line.toString()); line = new StringBuffer("\t"); append(line, "conf", 18); append(line, "number", 7); append(line, "search", 7); append(line, "dwnlded", 7); append(line, "evicted", 7); line.append("|"); append(line, "number", 7); append(line, "dwnlded", 7); // CheckStyle:MagicNumber| ON line.append("|"); Message.rawinfo(line.toString()); Message.rawinfo("\t" + new String(sep)); String[] confs = report.getConfigurations(); for (int i = 0; i < confs.length; i++) { output(report.getConfigurationReport(confs[i])); } Message.rawinfo("\t" + new String(sep)); } IvyNode[] unresolved = report.getUnresolvedDependencies(); if (unresolved.length > 0) { Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); Message.warn("\t:: UNRESOLVED DEPENDENCIES ::"); Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); } for (int i = 0; i < unresolved.length; i++) { Message.warn("\t:: " + unresolved[i] + ": " + unresolved[i].getProblemMessage()); } if (unresolved.length > 0) { Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::\n"); } ArtifactDownloadReport[] errors = report.getFailedArtifactsReports(); if (errors.length > 0) { Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); Message.warn("\t:: FAILED DOWNLOADS ::"); Message.warn("\t:: ^ see resolution messages for details ^ ::"); Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); } for (int i = 0; i < errors.length; i++) { Message.warn("\t:: " + errors[i].getArtifact()); } if (errors.length > 0) { Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::\n"); } } public void output(ConfigurationResolveReport report) { StringBuffer line = new StringBuffer("\t"); // CheckStyle:MagicNumber| OFF append(line, report.getConfiguration(), 18); append(line, String.valueOf(report.getNodesNumber()), 7); append(line, String.valueOf(report.getSearchedNodes().length), 7); append(line, String.valueOf(report.getDownloadedNodes().length), 7); append(line, String.valueOf(report.getEvictedNodes().length), 7); line.append("|"); append(line, String.valueOf(report.getArtifactsNumber()), 7); append(line, String.valueOf(report.getDownloadedArtifactsReports().length), 7); // CheckStyle:MagicNumber| ON line.append("|"); Message.rawinfo(line.toString()); } private void append(StringBuffer line, Object o, int limit) { String v = String.valueOf(o); if (v.length() >= limit) { v = v.substring(0, limit); } else { int missing = limit - v.length(); int half = missing / 2; char[] c = new char[limit]; Arrays.fill(c, ' '); System.arraycopy(v.toCharArray(), 0, c, missing - half, v.length()); v = new String(c); } line.append("|"); line.append(v); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ReportOutputter.java000066400000000000000000000025341226750426600264220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.report; import java.io.IOException; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; /** * */ public interface ReportOutputter { public static final String CONSOLE = "console"; public static final String XML = "xml"; public abstract void output(ResolveReport report, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException; public abstract String getName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/XmlReportOutputter.java000066400000000000000000000060241226750426600271010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.report; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; /** * A Report outputter implementation using {@link XmlReportWriter} to write xml reports to the * resolution cache. */ public class XmlReportOutputter implements ReportOutputter { private XmlReportWriter writer = new XmlReportWriter(); public String getName() { return XML; } public void output(ResolveReport report, ResolutionCacheManager cacheMgr, ResolveOptions options) throws IOException { String[] confs = report.getConfigurations(); for (int i = 0; i < confs.length; i++) { output(report.getConfigurationReport(confs[i]), report.getResolveId(), confs, cacheMgr); } } public void output(ConfigurationResolveReport report, String resolveId, String[] confs, ResolutionCacheManager cacheMgr) throws IOException { File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolveId, report.getConfiguration()); File reportParentDir = reportFile.getParentFile(); reportParentDir.mkdirs(); OutputStream stream = new FileOutputStream(reportFile); writer.output(report, confs, stream); stream.close(); Message.verbose("\treport for " + report.getModuleDescriptor().getModuleRevisionId() + " " + report.getConfiguration() + " produced in " + reportFile); File reportXsl = new File(reportParentDir, "ivy-report.xsl"); File reportCss = new File(reportParentDir, "ivy-report.css"); if (!reportXsl.exists()) { FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.xsl"), reportXsl, null); } if (!reportCss.exists()) { FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.css"), reportCss, null); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/XmlReportParser.java000066400000000000000000000354601226750426600263300ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.report; import java.io.File; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.extendable.ExtendableItemHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class XmlReportParser { private static class SaxXmlReportParser { private final class XmlReportParserHandler extends DefaultHandler { private String organisation; private String module; private String branch; private String revision; private int position; private Date pubdate; private boolean skip; private ModuleRevisionId mrid; private boolean isDefault; // Use a TreeMap to order by private SortedMap> revisionsMap = new TreeMap>(); private List revisionArtifacts = null; public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("module".equals(qName)) { organisation = attributes.getValue("organisation"); module = attributes.getValue("name"); } else if ("revision".equals(qName)) { revisionArtifacts = new ArrayList(); branch = attributes.getValue("branch"); revision = attributes.getValue("name"); isDefault = Boolean.valueOf(attributes.getValue("default")).booleanValue(); // retrieve position from file. If no position is found, it may be an old // report generated with a previous version, // in which case, we put it at the last position String pos = attributes.getValue("position"); position = pos == null ? getMaxPos() + 1 : Integer.valueOf(pos).intValue(); if (attributes.getValue("error") != null) { hasError = true; skip = true; } else if (attributes.getValue("evicted") != null) { skip = true; } else { revisionsMap.put(new Integer(position), revisionArtifacts); mrid = ModuleRevisionId.newInstance(organisation, module, branch, revision, ExtendableItemHelper.getExtraAttributes(attributes, "extra-")); mrids.add(mrid); if (isDefault) { defaultMrids.add(mrid); } else { Artifact metadataArtifact = DefaultArtifact.newIvyArtifact(mrid, pubdate); MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport( metadataArtifact); metadataReports.put(mrid, madr); realMrids.add(mrid); } try { String pubDateAttr = attributes.getValue("pubdate"); if (pubDateAttr != null) { pubdate = DateUtil.parse(pubDateAttr); } skip = false; } catch (ParseException e) { throw new IllegalArgumentException("invalid publication date for " + organisation + " " + module + " " + revision + ": " + attributes.getValue("pubdate")); } } } else if ("metadata-artifact".equals(qName)) { if (skip) { return; } MetadataArtifactDownloadReport madr = metadataReports.get(mrid); if (madr != null) { madr.setDownloadStatus(DownloadStatus.fromString(attributes .getValue("status"))); madr.setDownloadDetails(attributes.getValue("details")); madr.setSize(Long.parseLong(attributes.getValue("size"))); madr.setDownloadTimeMillis(Long.parseLong(attributes.getValue("time"))); madr.setSearched(parseBoolean(attributes.getValue("searched"))); if (attributes.getValue("location") != null) { madr.setLocalFile(new File(attributes.getValue("location"))); } if (attributes.getValue("original-local-location") != null) { madr.setOriginalLocalFile(new File(attributes .getValue("original-local-location"))); } if (attributes.getValue("origin-location") != null) { if (ArtifactOrigin.isUnknown(attributes.getValue("origin-location"))) { madr.setArtifactOrigin(ArtifactOrigin.unkwnown(madr.getArtifact())); } else { madr.setArtifactOrigin(new ArtifactOrigin(madr.getArtifact(), parseBoolean(attributes.getValue("origin-is-local")), attributes.getValue("origin-location"))); } } } } else if ("artifact".equals(qName)) { if (skip) { return; } String status = attributes.getValue("status"); String artifactName = attributes.getValue("name"); String type = attributes.getValue("type"); String ext = attributes.getValue("ext"); Artifact artifact = new DefaultArtifact(mrid, pubdate, artifactName, type, ext, ExtendableItemHelper.getExtraAttributes(attributes, "extra-")); ArtifactDownloadReport aReport = new ArtifactDownloadReport(artifact); aReport.setDownloadStatus(DownloadStatus.fromString(status)); aReport.setDownloadDetails(attributes.getValue("details")); aReport.setSize(Long.parseLong(attributes.getValue("size"))); aReport.setDownloadTimeMillis(Long.parseLong(attributes.getValue("time"))); if (attributes.getValue("location") != null) { aReport.setLocalFile(new File(attributes.getValue("location"))); } if (attributes.getValue("unpackedFile") != null) { aReport.setUnpackedLocalFile(new File(attributes.getValue("unpackedFile"))); } revisionArtifacts.add(aReport); } else if ("origin-location".equals(qName)) { if (skip) { return; } ArtifactDownloadReport aReport = revisionArtifacts .get(revisionArtifacts.size() - 1); if (ArtifactOrigin.isUnknown(attributes.getValue("location"))) { aReport.setArtifactOrigin(ArtifactOrigin.unkwnown(aReport.getArtifact())); } else { aReport.setArtifactOrigin(new ArtifactOrigin(aReport.getArtifact(), parseBoolean(attributes.getValue("is-local")), attributes .getValue("location"))); } } else if ("info".equals(qName)) { String organisation = attributes.getValue("organisation"); String name = attributes.getValue("module"); String branch = attributes.getValue("branch"); String revision = attributes.getValue("revision"); Map extraAttributes = new HashMap(); for (int i = 0; i < attributes.getLength(); i++) { String attName = attributes.getQName(i); if (attName.startsWith("extra-")) { String extraAttrName = attName.substring("extra-".length()); String extraAttrValue = attributes.getValue(i); extraAttributes.put(extraAttrName, extraAttrValue); } } mRevisionId = ModuleRevisionId.newInstance(organisation, name, branch, revision, extraAttributes); } } public void endElement(String uri, String localName, String qname) throws SAXException { if ("dependencies".equals(qname)) { // add the artifacts in the correct order for (List artifactReports : revisionsMap.values()) { SaxXmlReportParser.this.artifactReports.addAll(artifactReports); for (ArtifactDownloadReport artifactReport : artifactReports) { if (artifactReport.getDownloadStatus() != DownloadStatus.FAILED) { artifacts.add(artifactReport.getArtifact()); } } } } } private int getMaxPos() { return revisionsMap.isEmpty() ? -1 : ((Integer) revisionsMap.keySet().toArray()[revisionsMap.size() - 1]) .intValue(); } } private List mrids = new ArrayList(); private List defaultMrids = new ArrayList(); private List realMrids = new ArrayList(); private List artifacts = new ArrayList(); private List artifactReports = new ArrayList(); private Map metadataReports = new HashMap(); private ModuleRevisionId mRevisionId; private File report; private boolean hasError = false; SaxXmlReportParser(File report) { this.report = report; } public void parse() throws Exception { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); saxParser.parse(report, new XmlReportParserHandler()); } private static boolean parseBoolean(String str) { return (str != null) && str.equalsIgnoreCase("true"); } public List getArtifacts() { return artifacts; } public List getArtifactReports() { return artifactReports; } public List getModuleRevisionIds() { return mrids; } public List getRealModuleRevisionIds() { return realMrids; } public ModuleRevisionId getResolvedModule() { return mRevisionId; } public MetadataArtifactDownloadReport getMetadataArtifactReport(ModuleRevisionId id) { return metadataReports.get(id); } } private SaxXmlReportParser parser = null; public void parse(File report) throws ParseException { if (!report.exists()) { throw new IllegalStateException("Report file '" + report.getAbsolutePath() + "' does not exist."); } parser = new SaxXmlReportParser(report); try { parser.parse(); } catch (Exception e) { ParseException pe = new ParseException("failed to parse report: " + report + ": " + e.getMessage(), 0); pe.initCause(e); throw pe; } } public Artifact[] getArtifacts() { return parser.getArtifacts().toArray(new Artifact[parser.getArtifacts().size()]); } public ArtifactDownloadReport[] getArtifactReports() { return parser.getArtifactReports().toArray( new ArtifactDownloadReport[parser.getArtifactReports().size()]); } public ModuleRevisionId[] getDependencyRevisionIds() { return parser.getModuleRevisionIds().toArray( new ModuleRevisionId[parser.getModuleRevisionIds().size()]); } public ModuleRevisionId[] getRealDependencyRevisionIds() { return parser.getRealModuleRevisionIds().toArray( new ModuleRevisionId[parser.getRealModuleRevisionIds().size()]); } public MetadataArtifactDownloadReport getMetadataArtifactReport(ModuleRevisionId id) { return parser.getMetadataArtifactReport(id); } /** * Returns the ModuleRevisionId of the resolved module. */ public ModuleRevisionId getResolvedModule() { return parser.getResolvedModule(); } public boolean hasError() { return parser.hasError; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/XmlReportWriter.java000066400000000000000000000365051226750426600263510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.report; import java.io.BufferedWriter; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.License; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.ConfigurationResolveReport; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.IvyNodeCallers.Caller; import org.apache.ivy.core.resolve.IvyNodeEviction.EvictionData; import org.apache.ivy.util.DateUtil; import org.apache.ivy.util.StringUtils; import org.apache.ivy.util.XMLHelper; /** * XmlReportWriter allows to write ResolveReport in an xml format. */ public class XmlReportWriter { static final String REPORT_ENCODING = "UTF-8"; public void output(ConfigurationResolveReport report, OutputStream stream) { output(report, new String[] {report.getConfiguration()}, stream); } public void output(ConfigurationResolveReport report, String[] confs, OutputStream stream) { OutputStreamWriter encodedOutStream; try { encodedOutStream = new OutputStreamWriter(stream, REPORT_ENCODING); } catch (UnsupportedEncodingException e) { throw new RuntimeException(REPORT_ENCODING + " is not known on your jvm", e); } PrintWriter out = new PrintWriter(new BufferedWriter(encodedOutStream)); ModuleRevisionId mrid = report.getModuleDescriptor().getModuleRevisionId(); // out.println(""); out.println(""); out.println(""); out.println(""); out.println("\t"); out.println("\t"); // create a list of ModuleRevisionIds indicating the position for each dependency List dependencies = new ArrayList(report.getModuleRevisionIds()); for (Iterator iter = report.getModuleIds().iterator(); iter.hasNext();) { ModuleId mid = (ModuleId) iter.next(); out.println("\t\t"); for (Iterator it2 = report.getNodes(mid).iterator(); it2.hasNext();) { IvyNode dep = (IvyNode) it2.next(); ouputRevision(report, out, dependencies, dep); } out.println("\t\t"); } out.println("\t"); out.println(""); out.flush(); } private void ouputRevision(ConfigurationResolveReport report, PrintWriter out, List dependencies, IvyNode dep) { Map extraAttributes; ModuleDescriptor md = null; if (dep.getModuleRevision() != null) { md = dep.getModuleRevision().getDescriptor(); } StringBuffer details = new StringBuffer(); if (dep.isLoaded()) { details.append(" status=\""); details.append(XMLHelper.escape(dep.getDescriptor().getStatus())); details.append("\" pubdate=\""); details.append(DateUtil.format(new Date(dep.getPublication()))); details.append("\" resolver=\""); details.append(XMLHelper.escape(dep.getModuleRevision().getResolver().getName())); details.append("\" artresolver=\""); details.append(XMLHelper .escape(dep.getModuleRevision().getArtifactResolver().getName())); details.append("\""); } if (dep.isEvicted(report.getConfiguration())) { EvictionData ed = dep.getEvictedData(report.getConfiguration()); if (ed.getConflictManager() != null) { details.append(" evicted=\"") .append(XMLHelper.escape(ed.getConflictManager().toString())).append("\""); } else { details.append(" evicted=\"transitive\""); } details.append(" evicted-reason=\"") .append(XMLHelper.escape(ed.getDetail() == null ? "" : ed.getDetail())) .append("\""); } if (dep.hasProblem()) { details.append(" error=\"").append(XMLHelper.escape(dep.getProblem().getMessage())) .append("\""); } if (md != null && md.getHomePage() != null) { details.append(" homepage=\"").append(XMLHelper.escape(md.getHomePage())).append("\""); } extraAttributes = md != null ? md.getExtraAttributes() : dep.getResolvedId() .getExtraAttributes(); for (Iterator iterator = extraAttributes.keySet().iterator(); iterator.hasNext();) { String attName = (String) iterator.next(); details.append(" extra-").append(attName).append("=\"") .append(XMLHelper.escape(extraAttributes.get(attName).toString())).append("\""); } String defaultValue = dep.getDescriptor() != null ? " default=\"" + dep.getDescriptor().isDefault() + "\"" : ""; int position = dependencies.indexOf(dep.getResolvedId()); out.println("\t\t\t"); if (md != null) { License[] licenses = md.getLicenses(); for (int i = 0; i < licenses.length; i++) { String lurl; if (licenses[i].getUrl() != null) { lurl = " url=\"" + XMLHelper.escape(licenses[i].getUrl()) + "\""; } else { lurl = ""; } out.println("\t\t\t\t"); } } outputMetadataArtifact(out, dep); outputEvictionInformation(report, out, dep); outputCallers(report, out, dep); outputArtifacts(report, out, dep); out.println("\t\t\t"); } private void outputEvictionInformation(ConfigurationResolveReport report, PrintWriter out, IvyNode dep) { if (dep.isEvicted(report.getConfiguration())) { EvictionData ed = dep.getEvictedData(report.getConfiguration()); Collection selected = ed.getSelected(); if (selected != null) { for (Iterator it3 = selected.iterator(); it3.hasNext();) { IvyNode sel = (IvyNode) it3.next(); out.println("\t\t\t\t"); } } } } private void outputMetadataArtifact(PrintWriter out, IvyNode dep) { if (dep.getModuleRevision() != null) { MetadataArtifactDownloadReport madr = dep.getModuleRevision().getReport(); out.print("\t\t\t\t"); } } private void outputCallers(ConfigurationResolveReport report, PrintWriter out, IvyNode dep) { Caller[] callers = dep.getCallers(report.getConfiguration()); for (int i = 0; i < callers.length; i++) { StringBuffer callerDetails = new StringBuffer(); Map callerExtraAttributes = callers[i].getDependencyDescriptor().getExtraAttributes(); for (Iterator iterator = callerExtraAttributes.keySet().iterator(); iterator.hasNext();) { String attName = (String) iterator.next(); callerDetails.append(" extra-").append(attName).append("=\"") .append(XMLHelper.escape(callerExtraAttributes.get(attName).toString())) .append("\""); } out.println("\t\t\t\t"); } } private void outputArtifacts(ConfigurationResolveReport report, PrintWriter out, IvyNode dep) { Map extraAttributes; ArtifactDownloadReport[] adr = report.getDownloadReports(dep.getResolvedId()); out.println("\t\t\t\t"); for (int i = 0; i < adr.length; i++) { out.print("\t\t\t\t\t"); out.println("\t\t\t\t\t\t"); out.println("\t\t\t\t\t"); } else { out.println("/>"); } } out.println("\t\t\t\t"); } private String toString(String[] strs) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < strs.length; i++) { buf.append(strs[i]); if (i + 1 < strs.length) { buf.append(", "); } } return XMLHelper.escape(buf.toString()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report-dot-all.xsl000066400000000000000000000030551226750426600265510ustar00rootroot00000000000000 /* * directed graph dot input file. * * generated by ivy report */ digraph G { "" "" -> ""; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report-dot.xsl000066400000000000000000000042561226750426600260070ustar00rootroot00000000000000 /* * directed graph dot input file. * * generated by ivy report */ digraph G { "-" [label=""]; "-" [label=" \n (error) (evicted) "]; " - " -> " - " [label=" "] ; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report-graph-all.xsl000066400000000000000000000063351226750426600270700ustar00rootroot00000000000000 - --- - - ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report-graph.xsl000066400000000000000000000107501226750426600263160ustar00rootroot00000000000000 - - (error) (evicted) --- - - ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report.css000066400000000000000000000104231226750426600251760ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ body { font-family:"Trebuchet MS",Verdana,Geneva,Arial,Helvetica,sans-serif; font-size:small; } div#logo { float: right; padding-left: 10px; padding-bottom: 10px; background: white; text-align: center; } #logo img { border: 0; } div#date { font-style: italic; padding-left: 60px; padding-bottom: 40px; } h1 { margin-bottom:2px; border-color:#7A9437; border-style:solid; border-width:0 0 3px 0; } span#module { color:#7A9437; text-decoration:none; } span#organisation { color:black; text-decoration:none; } #confmenu { color: #000; border-bottom: 2px solid black; margin: 12px 0px 0px 0px; padding: 0px; z-index: 1; padding-left: 10px } #confmenu li { display: inline; overflow: hidden; list-style-type: none; } #confmenu a, a.active { color: #DEDECF; background: #898B5E; font: bold 1em "Trebuchet MS", Arial, sans-serif; border: 2px solid black; padding: 2px 5px 0px 5px; text-decoration: none; } /* background: #ABAD85 #CED4BD background: #DEE4CD */ #confmenu a.active { color: #7A9437; background: #DEE4CD; border-bottom: 3px solid #DEE4CD; } #confmenu a:hover { color: #fff; background: #ADC09F; } #confmenu a:visited { color: #DEDECF; } #confmenu a.active:visited { color: #7A9437; } #confmenu a.active:hover { background: #DEE4CD; color: #DEDECF; } #content { background: #DEE4CD; padding: 20px; border: 2px solid black; border-top: none; z-index: 2; } #content a { text-decoration: none; color: #E8E9BE; } #content a:hover { background: #898B5E; } h2 { margin-bottom:2px; font-size:medium; border-color:#7A9437; border-style:solid; border-width:0 0 2px 0; } h3 { margin-top:30px; margin-bottom:2px; padding: 5 5 5 0; font-size: 24px; border-style:solid; border-width:0 0 2px 0; } h4 { margin-bottom:2px; margin-top:2px; font-size:medium; border-color:#7A9437; border-style:dashed; border-width:0 0 1px 0; } h5 { margin-bottom:2px; margin-top:2px; margin-left:20px; font-size:medium; } span.resolved { padding-left: 15px; font-weight: 500; font-size: small; } #content table { border-collapse:collapse; width:90%; margin:auto; margin-top: 5px; } #content thead { background-color:#CED4BD; border:1px solid #7A9437; } #content tbody { border-collapse:collapse; background-color:#FFFFFF; border:1px solid #7A9437; } #content th { font-family:monospace; border:1px solid #7A9437; padding:5px; } #content td { border:1px dotted #7A9437; padding:0 3 0 3; } #content table a { color:#7A9437; text-decoration:none; } #content table a:hover { background-color:#CED4BD; color:#7A9437; } table.deps { border-collapse:collapse; width:90%; margin:auto; margin-top: 5px; } table.deps thead { background-color:#CED4BD; border:1px solid #7A9437; } table.deps tbody { border-collapse:collapse; background-color:#FFFFFF; border:1px solid #7A9437; } table.deps th { font-family:monospace; border:1px solid #7A9437; padding:2; } table.deps td { border:1px dotted #7A9437; padding:0 3 0 3; } table.header { border:0; width:90%; margin:auto; margin-top: 5px; } table.header thead { border:0; } table.header tbody { border:0; } table.header tr { padding:0px; border:0; } table.header td { padding:0 3 0 3; border:0; } td.title { width:150px; margin-right:15px; font-size:small; font-weight:700; } td.title:first-letter { color:#7A9437; background-color:transparent; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/report/ivy-report.xsl000066400000000000000000000510011226750426600252110ustar00rootroot00000000000000
    No dependency
    Module Revision Status Resolver Default Licenses Size
    #- by #-- kB searched downloaded http://ant.apache.org/ivy/images/evicted.gif evicted evicted by http://ant.apache.org/ivy/images/error.gif error error: #- by #--
  • active --.
  • -- :: Ivy report :: <xsl:value-of select="info/@module"/> by <xsl:value-of select="info/@organisation"/> :: <xsl:value-of select="info/@conf"/>

    - by

    resolved on

    Dependencies Stats

    Modules
    Revisions ( searched searched, downloaded downloaded, evicted evicted, errors error)
    Artifacts ( downloaded, failed)
    Artifacts size kB ( kB downloaded, kB in cache)

    Errors

    Module Revision Error

    Conflicts

    Module Selected Evicted
    #- by #-- #--

    Dependencies Overview

    Details

    - by

    -- Revision:

    Home Page
    Status
    Publication
    Resolver
    Configurations
    Artifacts size kB ( kB downloaded, kB in cache)
    Licenses
    Evicted by in conflict manager
    Required by
    Organisation Name Revision In Configurations Asked Revision
    #-
    Dependencies
    Artifacts
    No artifact
    Name Type Ext Download Size
    kB
    ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/000077500000000000000000000000001226750426600232505ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/AbstractRepository.java000066400000000000000000000105111226750426600277540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; import java.io.IOException; import java.util.Arrays; import javax.swing.event.EventListenerList; import org.apache.ivy.core.module.descriptor.Artifact; public abstract class AbstractRepository implements Repository { private EventListenerList listeners = new EventListenerList(); private String name; private TransferEvent evt; public void addTransferListener(TransferListener listener) { listeners.add(TransferListener.class, listener); } public void removeTransferListener(TransferListener listener) { listeners.remove(TransferListener.class, listener); } public boolean hasTransferListener(TransferListener listener) { return Arrays.asList(listeners.getListeners(TransferListener.class)).contains(listener); } protected void fireTransferInitiated(Resource res, int requestType) { evt = new TransferEvent(this, res, TransferEvent.TRANSFER_INITIATED, requestType); fireTransferEvent(evt); } protected void fireTransferStarted() { evt.setEventType(TransferEvent.TRANSFER_STARTED); fireTransferEvent(evt); } protected void fireTransferStarted(long totalLength) { evt.setEventType(TransferEvent.TRANSFER_STARTED); evt.setTotalLength(totalLength); evt.setTotalLengthSet(true); fireTransferEvent(evt); } protected void fireTransferProgress(long length) { evt.setEventType(TransferEvent.TRANSFER_PROGRESS); evt.setLength(length); if (!evt.isTotalLengthSet()) { evt.setTotalLength(evt.getTotalLength() + length); } fireTransferEvent(evt); } protected void fireTransferCompleted() { evt.setEventType(TransferEvent.TRANSFER_COMPLETED); if (evt.getTotalLength() > 0 && !evt.isTotalLengthSet()) { evt.setTotalLengthSet(true); } fireTransferEvent(evt); } protected void fireTransferCompleted(long totalLength) { evt.setEventType(TransferEvent.TRANSFER_COMPLETED); evt.setTotalLength(totalLength); evt.setTotalLengthSet(true); fireTransferEvent(evt); } protected void fireTransferError() { evt.setEventType(TransferEvent.TRANSFER_ERROR); fireTransferEvent(evt); } protected void fireTransferError(Exception ex) { evt.setEventType(TransferEvent.TRANSFER_ERROR); evt.setException(ex); fireTransferEvent(evt); } protected void fireTransferEvent(TransferEvent evt) { Object[] listeners = this.listeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TransferListener.class) { ((TransferListener) listeners[i + 1]).transferProgress(evt); } } } public String getFileSeparator() { return "/"; } public String standardize(String source) { return source.replace('\\', '/'); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return getName(); } public void put(Artifact artifact, File source, String destination, boolean overwrite) throws IOException { put(source, destination, overwrite); } protected void put(File source, String destination, boolean overwrite) throws IOException { throw new UnsupportedOperationException("put in not supported by " + getName()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ArtifactResourceResolver.java000066400000000000000000000022751226750426600311100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.resolver.util.ResolvedResource; /** * An {@link ArtifactResourceResolver} is responsible for the resolution of an artifact into a * {@link ResolvedResource}. */ public interface ArtifactResourceResolver { public ResolvedResource resolve(Artifact artifact); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/BasicResource.java000066400000000000000000000041661226750426600266530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.IOException; import java.io.InputStream; public class BasicResource implements Resource { private boolean local; private String name; private long lastModified; private long contentLength; private boolean exists; public BasicResource(String name, boolean exists, long contentLength, long lastModified, boolean local) { this.name = name; this.exists = exists; this.contentLength = contentLength; this.lastModified = lastModified; this.local = local; } public Resource clone(String cloneName) { throw new UnsupportedOperationException("basic resource do not support the clone method"); } public boolean exists() { return this.exists; } public long getContentLength() { return this.contentLength; } public long getLastModified() { return this.lastModified; } public String getName() { return this.name; } public boolean isLocal() { return this.local; } public InputStream openStream() throws IOException { throw new UnsupportedOperationException( "basic resource do not support the openStream method"); } public String toString() { return getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/LazyResource.java000066400000000000000000000045111226750426600265430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; public abstract class LazyResource implements Resource { private boolean init = false; private boolean local; private String name; private long lastModified; private long contentLength; private boolean exists; public LazyResource(String name) { this.name = name; } protected abstract void init(); private void checkInit() { if (!init) { init(); init = true; } } public boolean exists() { checkInit(); return exists; } public long getContentLength() { checkInit(); return contentLength; } public long getLastModified() { checkInit(); return lastModified; } public String getName() { return name; } public boolean isLocal() { checkInit(); return local; } public String toString() { return getName(); } protected void setContentLength(long contentLength) { this.contentLength = contentLength; } protected void setExists(boolean exists) { this.exists = exists; } protected void setLastModified(long lastModified) { this.lastModified = lastModified; } protected void setLocal(boolean local) { this.local = local; } protected void init(Resource r) { setContentLength(r.getContentLength()); setLocal(r.isLocal()); setLastModified(r.getLastModified()); setExists(r.exists()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/LocalizableResource.java000066400000000000000000000024771226750426600300560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; /** * Resource which can be located locally *

    * If local (checked via {@link #isLocal()}), {@link #getFile()} will return its local location, * without any download or copy involved *

    */ public interface LocalizableResource extends Resource { /** * @return the local file of this resource. * @throws IllegalStateException * when {@link #isLocal()} returns false */ public File getFile(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/Repository.java000066400000000000000000000116701226750426600262770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; import java.io.IOException; import java.util.List; import org.apache.ivy.core.module.descriptor.Artifact; /** * Represents a collection of resources available to Ivy. Ivy uses one or more repositories as both * a source of resources for Ivy enabled build systems and as a distribution center for resources * generated by Ivy enabled build systems.

    *

    * A repository supports the following fundamental operations *

      *
    • retrieving a resource from the repository.
    • *
    • transferring a resource to the repository.
    • *
    • retrieving a listing of resources.
    • *
    *

    *

    Resource Retrieval

    *

    * {@link #get} retrieves a resource specified by a provided identifier creating a new file . *

    *

    resource Publication

    *

    * {@link #put} transfers a file to the repository. *

    *

    resource Listing

    *

    * {@link #list} returns a listing of file like objects belonging to a specified parent directory. *

    *

    */ public interface Repository { /** * Return the resource associated with a specified identifier. If the resource does not exist, * it should return a Resource with exists() returning false. An IOException should only be * thrown when a real IO problem occurs, like the impossibility to connect to a server. * * @param source * A string identifying the resource. * @return The resource associated with the resource identifier. * @throws IOException * On error while trying to get resource. */ Resource getResource(String source) throws IOException; /** * Fetch a resource from the repository. * * @param source * A string identifying the resource to be fetched. * @param destination * Where to place the fetched resource. * @throws IOException * On retrieval failure. */ void get(String source, File destination) throws IOException; /** * Transfer a resource to the repository * * @param artifact * The artifact to be transferred. * @param source * The local file to be transferred. * @param destination * Where to transfer the resource. * @param overwrite * Whether the transfer should overwrite an existing resource. * @throws IOException * On publication failure. */ void put(Artifact artifact, File source, String destination, boolean overwrite) throws IOException; /** * Return a listing of resources names * * @param parent * The parent directory from which to generate the listing. * @return A listing of the parent directory's file content, as a List of String. * @throws IOException * On listing failure. */ List list(String parent) throws IOException; /** * Add a listener to the repository. * * @param listener * The listener to attach to the repository. */ void addTransferListener(TransferListener listener); /** * Remove a listener on the repository * * @param listener * The listener to remove */ void removeTransferListener(TransferListener listener); /** * Determine if a given listener is attached to the repository. * * @param listener * The listener being queried * @return true if the provided listener is attached to the repository, * false if not. */ boolean hasTransferListener(TransferListener listener); /** * Get the repository's file separator string. * * @return The repository's file separator delimiter */ String getFileSeparator(); /** * Normalize a string. * * @param source * The string to normalize. * @return The normalized string. */ String standardize(String source); /** * Return the name of the repository */ String getName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/RepositoryCopyProgressListener.java000066400000000000000000000035761226750426600323730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import org.apache.ivy.util.CopyProgressEvent; import org.apache.ivy.util.CopyProgressListener; public class RepositoryCopyProgressListener implements CopyProgressListener { private final AbstractRepository repository; public RepositoryCopyProgressListener(AbstractRepository repository) { this.repository = repository; } private Long totalLength = null; public void start(CopyProgressEvent evt) { if (totalLength != null) { repository.fireTransferStarted(totalLength.longValue()); } else { repository.fireTransferStarted(); } } public void progress(CopyProgressEvent evt) { repository.fireTransferProgress(evt.getReadBytes()); } public void end(CopyProgressEvent evt) { repository.fireTransferProgress(evt.getReadBytes()); repository.fireTransferCompleted(); } public Long getTotalLength() { return totalLength; } public void setTotalLength(Long totalLength) { this.totalLength = totalLength; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/Resource.java000066400000000000000000000070131226750426600257030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.IOException; import java.io.InputStream; /** * Represents a resource in an Ivy {@link Repository}. The resource interface allows one to obtain * the following information about a resource: *
      *
    • resource name/identifier in repository syntax
    • *
    • date the resource was last modified.
    • *
    • size of the resource in bytes.
    • *
    • if the resource is available.
    • *
    *

    Implementation Notes

    In implementing the interface you need to ensure the following * behaviors: *
      *
    • All of the methods specified in the interface fail by returning an empty value ( * false, 0, ""). In other words, the specified interface * methods should not throw RuntimeExceptions.
    • *
    • Failure conditions should be logged using the {@link org.apache.ivy.util.Message#verbose} * method.
    • *
    • Failure of one of the interface's specified methods results in all other interface specified * methods returning an empty value (false, 0, "").
    • *
    *

    */ public interface Resource { /** * Get the name of the resource. * * @return the repositorie's assigned resource name/identifier. */ public String getName(); /** * Get the date the resource was last modified * * @return A long value representing the time the file was last modified, measured * in milliseconds since the epoch (00:00:00 GMT, January 1, 1970), or 0L * if the file does not exist or if an I/O error occurs. */ public long getLastModified(); /** * Get the resource size * * @return a long value representing the size of the resource in bytes. */ public long getContentLength(); /** * Determine if the resource is available.

    Note that this method only checks for * availability, not for actual existence. * * @return boolean value indicating if the resource is available. */ public boolean exists(); /** * Is this resource local to this host, i.e. is it on the file system? * * @return boolean value indicating if the resource is local. */ public boolean isLocal(); /** * Clones this resource with a new resource with a different name * * @param cloneName * the name of the clone * @return the cloned resource */ public Resource clone(String cloneName); /** * Opens a stream on this resource * * @return the opened input stream */ public InputStream openStream() throws IOException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ResourceDownloader.java000066400000000000000000000030141226750426600277170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; import java.io.IOException; import org.apache.ivy.core.module.descriptor.Artifact; /** * A {@link ResourceDownloader} is able to download a Resource to a File. *

    * Depending on the implementation, the downloader may also choose to download checksums * automatically and check the consistency of the downloaded resource. *

    *

    * The implementation is also responsible for using a .part file during download, to ensure the * destination file will exist only if the download is completed successfully. *

    */ public interface ResourceDownloader { public void download(Artifact artifact, Resource resource, File dest) throws IOException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ResourceHelper.java000066400000000000000000000040111226750426600270360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; import java.net.MalformedURLException; import org.apache.ivy.plugins.repository.file.FileResource; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.util.Message; public final class ResourceHelper { private ResourceHelper() { } public static boolean equals(Resource res, File f) { if (res == null && f == null) { return true; } if (res == null || f == null) { return false; } if (res instanceof FileResource) { return new File(res.getName()).equals(f); } else if (res instanceof URLResource) { try { return f.toURI().toURL().toExternalForm().equals(res.getName()); } catch (MalformedURLException e) { return false; } } return false; } public static long getLastModifiedOrDefault(Resource res) { long last = res.getLastModified(); if (last > 0) { return last; } else { Message.debug("impossible to get date for " + res + ": using 'now'"); return System.currentTimeMillis(); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/TransferEvent.java000066400000000000000000000245301226750426600267050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.io.File; import org.apache.ivy.core.event.IvyEvent; /** * TransferEvent is used to notify TransferListeners about progress in transfer of resources form/to * the respository This class is LARGELY inspired by org.apache.maven.wagon.events.TransferEvent * released under the following copyright license: * *
     * 
     *  Copyright 2001-2005 The Apache Software Foundation.
     * 
     *  Licensed under the Apache License, Version 2.0 (the "License");
     *  you may not use this file except in compliance with the License.
     *  You may obtain a copy of the License at
     * 
     *       http://www.apache.org/licenses/LICENSE-2.0
     * 
     *  Unless required by applicable law or agreed to in writing, software
     *  distributed under the License is distributed on an "AS IS" BASIS,
     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *  See the License for the specific language governing permissions and
     *  limitations under the License.
     * 
     * 
    * * Orginal class written by Michal Maczka. */ public class TransferEvent extends IvyEvent { /** * A transfer was attempted, but has not yet commenced. */ public static final int TRANSFER_INITIATED = 0; /** * A transfer was started. */ public static final int TRANSFER_STARTED = 1; /** * A transfer is completed. */ public static final int TRANSFER_COMPLETED = 2; /** * A transfer is in progress. */ public static final int TRANSFER_PROGRESS = 3; /** * An error occurred during transfer */ public static final int TRANSFER_ERROR = 4; /** * Used to check event type validity: should always be 0 <= type <= LAST_EVENT_TYPE */ private static final int LAST_EVENT_TYPE = TRANSFER_ERROR; /** * Indicates GET transfer (from the repository) */ public static final int REQUEST_GET = 5; /** * Indicates PUT transfer (to the repository) */ public static final int REQUEST_PUT = 6; public static final String TRANSFER_INITIATED_NAME = "transfer-initiated"; public static final String TRANSFER_STARTED_NAME = "transfer-started"; public static final String TRANSFER_PROGRESS_NAME = "transfer-progress"; public static final String TRANSFER_COMPLETED_NAME = "transfer-completed"; public static final String TRANSFER_ERROR_NAME = "transfer-error"; private Resource resource; private int eventType; private int requestType; private Exception exception; private File localFile; private Repository repository; private long length; private long totalLength; private boolean isTotalLengthSet = false; /** * This attribute is used to store the time at which the event enters a type. *

    * The array should better be seen as a Map from event type (int) to the time at which the event * entered that type, 0 if it never entered this type. *

    */ private long[] timeTracking = new long[LAST_EVENT_TYPE + 1]; public TransferEvent(final Repository repository, final Resource resource, final int eventType, final int requestType) { super(getName(eventType)); this.repository = repository; setResource(resource); setEventType(eventType); setRequestType(requestType); } public TransferEvent(final Repository repository, final Resource resource, final Exception exception, final int requestType) { this(repository, resource, TRANSFER_ERROR, requestType); this.exception = exception; } public TransferEvent(final Repository repository, final Resource resource, long length, final int requestType) { this(repository, resource, TRANSFER_PROGRESS, requestType); this.length = length; this.totalLength = length; } private static String getName(int eventType) { switch (eventType) { case TRANSFER_INITIATED: return TRANSFER_INITIATED_NAME; case TRANSFER_STARTED: return TRANSFER_STARTED_NAME; case TRANSFER_PROGRESS: return TRANSFER_PROGRESS_NAME; case TRANSFER_COMPLETED: return TRANSFER_COMPLETED_NAME; case TRANSFER_ERROR: return TRANSFER_ERROR_NAME; default: return null; } } /** * @return Returns the resource. */ public Resource getResource() { return resource; } /** * @return Returns the exception. */ public Exception getException() { return exception; } /** * Returns the request type. * * @return Returns the request type. The Request type is one of * TransferEvent.REQUEST_GET or TransferEvent.REQUEST_PUT */ public int getRequestType() { return requestType; } /** * Sets the request type * * @param requestType * The requestType to set. The Request type value should be either * TransferEvent.REQUEST_GET or TransferEvent.REQUEST_PUT. * @throws IllegalArgumentException * when */ protected void setRequestType(final int requestType) { switch (requestType) { case REQUEST_PUT: break; case REQUEST_GET: break; default: throw new IllegalArgumentException("Illegal request type: " + requestType); } this.requestType = requestType; addAttribute("request-type", requestType == REQUEST_GET ? "get" : "put"); } /** * @return Returns the eventType. */ public int getEventType() { return eventType; } /** * @param eventType * The eventType to set. */ protected void setEventType(final int eventType) { checkEventType(eventType); if (this.eventType != eventType) { this.eventType = eventType; timeTracking[eventType] = System.currentTimeMillis(); if (eventType > TRANSFER_INITIATED) { addAttribute("total-duration", String.valueOf(getElapsedTime(TRANSFER_INITIATED, eventType))); if (eventType > TRANSFER_STARTED) { addAttribute("duration", String.valueOf(getElapsedTime(TRANSFER_STARTED, eventType))); } } } } /** * @param resource * The resource to set. */ protected void setResource(final Resource resource) { this.resource = resource; addAttribute("resource", this.resource.getName()); } /** * @return Returns the local file. */ public File getLocalFile() { return localFile; } /** * @param localFile * The local file to set. */ protected void setLocalFile(File localFile) { this.localFile = localFile; } public long getLength() { return length; } protected void setLength(long length) { this.length = length; } public long getTotalLength() { return totalLength; } protected void setTotalLength(long totalLength) { this.totalLength = totalLength; } public void setException(Exception exception) { this.exception = exception; } public boolean isTotalLengthSet() { return isTotalLengthSet; } public void setTotalLengthSet(boolean isTotalLengthSet) { this.isTotalLengthSet = isTotalLengthSet; } public Repository getRepository() { return repository; } /** * Returns the elapsed time (in ms) between when the event entered one type until it entered * another event time. *

    * This is especially useful to get the elapsed transfer time: * *

         * getElapsedTime(TransferEvent.TRANSFER_STARTED, TransferEvent.TRANSFER_COMPLETED);
         * 
    * *

    *

    * Special cases: *

      *
    • returns -1 if the event never entered the fromEventType or the toEventType.
    • *
    • returns 0 if the event entered toEventType before fromEventType
    • *
    *

    * * @param fromEventType * the event type constant from which time should be measured * @param toEventType * the event type constant to which time should be measured * @return the elapsed time (in ms) between when the event entered fromEventType until it * entered toEventType. * @throws IllegalArgumentException * if either type is not a known constant event type. */ public long getElapsedTime(int fromEventType, int toEventType) { checkEventType(fromEventType); checkEventType(toEventType); long start = timeTracking[fromEventType]; long end = timeTracking[toEventType]; if (start == 0 || end == 0) { return -1; } else if (end < start) { return 0; } else { return end - start; } } /** * Checks the given event type is a valid event type, throws an {@link IllegalArgumentException} * if it isn't * * @param eventType * the event type to check */ private void checkEventType(int eventType) { if (eventType < 0 || eventType > LAST_EVENT_TYPE) { throw new IllegalArgumentException("invalid event type " + eventType); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/TransferListener.java000066400000000000000000000020211226750426600274000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository; import java.util.EventListener; /** * Listen to repository transfer */ public interface TransferListener extends EventListener { void transferProgress(TransferEvent evt); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/file/000077500000000000000000000000001226750426600241675ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java000066400000000000000000000116221226750426600300130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.file; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.util.Checks; import org.apache.ivy.util.FileUtil; public class FileRepository extends AbstractRepository { private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener(this); private File baseDir; private boolean local = true; public FileRepository() { baseDir = null; } public FileRepository(File basedir) { setBaseDir(basedir); } public Resource getResource(String source) throws IOException { return new FileResource(this, getFile(source)); } public void get(String source, File destination) throws IOException { fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); copy(getFile(source), destination, true); } public void put(File source, String destination, boolean overwrite) throws IOException { fireTransferInitiated(getResource(destination), TransferEvent.REQUEST_PUT); copy(source, getFile(destination), overwrite); } public void move(File src, File dest) throws IOException { if (!src.renameTo(dest)) { throw new IOException("impossible to move '" + src + "' to '" + dest + "'"); } } public void delete(File f) throws IOException { if (!FileUtil.forceDelete(f)) { throw new IOException("impossible to delete '" + f + "'"); } } private void copy(File src, File destination, boolean overwrite) throws IOException { try { getProgressListener().setTotalLength(new Long(src.length())); if (!FileUtil.copy(src, destination, getProgressListener(), overwrite)) { if (!overwrite && destination.exists()) { throw new IOException("file copy not done from " + src + " to " + destination + ": destination already exists and overwrite is false"); } else { throw new IOException("file copy not done from " + src + " to " + destination); } } } catch (IOException ex) { fireTransferError(ex); throw ex; } catch (RuntimeException ex) { fireTransferError(ex); throw ex; } finally { getProgressListener().setTotalLength(null); } } protected RepositoryCopyProgressListener getProgressListener() { return progress; } public List list(String parent) throws IOException { File dir = getFile(parent); if (dir.exists() && dir.isDirectory()) { String[] names = dir.list(); if (names != null) { List ret = new ArrayList(names.length); for (int i = 0; i < names.length; i++) { ret.add(parent + getFileSeparator() + names[i]); } return ret; } } return null; } File getFile(String source) { if (baseDir != null) { return FileUtil.resolveFile(baseDir, source); } else { return Checks.checkAbsolute(source, "source"); } } public boolean isLocal() { return local; } public void setLocal(boolean local) { this.local = local; } public File getBaseDir() { return baseDir; } public final void setBaseDir(File baseDir) { Checks.checkAbsolute(baseDir, "basedir"); this.baseDir = baseDir; } public String standardize(String source) { if (baseDir != null) { return FileUtil.resolveFile(baseDir, source).getPath(); } else { return FileUtil.normalize(source).getPath(); } } public String getFileSeparator() { return File.separator; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/file/FileResource.java000066400000000000000000000040221226750426600274170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.file; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.plugins.repository.Resource; public class FileResource implements Resource { private File file; private FileRepository repository; public FileResource(FileRepository repository, File f) { this.repository = repository; this.file = f; } public String getName() { return file.getPath(); } public Resource clone(String cloneName) { return new FileResource(repository, repository.getFile(cloneName)); } public long getLastModified() { return file.lastModified(); } public long getContentLength() { return file.length(); } public boolean exists() { return file.exists(); } public String toString() { return getName(); } public File getFile() { return file; } public FileRepository getRepository() { return repository; } public boolean isLocal() { return repository.isLocal(); } public InputStream openStream() throws IOException { return new FileInputStream(file); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/jar/000077500000000000000000000000001226750426600240245ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/jar/JarRepository.java000066400000000000000000000063261226750426600275120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.jar; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.util.FileUtil; public class JarRepository extends AbstractRepository { private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener(this); private JarFile jarFile; public void setJarFile(JarFile jarFile) { this.jarFile = jarFile; } public Resource getResource(String source) throws IOException { return new JarResource(jarFile, source); } protected RepositoryCopyProgressListener getProgressListener() { return progress; } public void get(String source, File destination) throws IOException { fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); try { ZipEntry entry = jarFile.getEntry(source); if (entry == null) { throw new FileNotFoundException(); } getProgressListener().setTotalLength(new Long(entry.getSize())); FileUtil.copy(jarFile.getInputStream(entry), destination, getProgressListener()); } catch (IOException ex) { fireTransferError(ex); throw ex; } catch (RuntimeException ex) { fireTransferError(ex); throw ex; } finally { getProgressListener().setTotalLength(null); } } public List/* */list(String parent) throws IOException { ZipEntry parentEntry = jarFile.getEntry(parent); if (parentEntry == null || !parentEntry.isDirectory()) { return null; } List/* */children = new ArrayList(); Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); if (entry.getName().startsWith(parent) && entry.getName().equals(parentEntry.getName())) { children.add(entry.getName()); } } return children; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/jar/JarResource.java000066400000000000000000000037731226750426600271250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.jar; import java.io.IOException; import java.io.InputStream; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import org.apache.ivy.plugins.repository.Resource; public class JarResource implements Resource { private final JarFile jarFile; private final String path; private ZipEntry entry; public JarResource(JarFile jarFile, String path) { this.jarFile = jarFile; this.path = path; entry = jarFile.getEntry(path); } public String getName() { return path; } public long getLastModified() { return entry.getTime(); } public long getContentLength() { return entry.getSize(); } public boolean exists() { return entry != null; } public boolean isLocal() { // not local as it is not a directly accessible file return false; } public Resource clone(String cloneName) { return new JarResource(jarFile, cloneName); } public InputStream openStream() throws IOException { return jarFile.getInputStream(entry); } public String toString() { return jarFile.getName() + "!" + getName(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/sftp/000077500000000000000000000000001226750426600242245ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/sftp/SFTPRepository.java000066400000000000000000000252061226750426600277500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.sftp; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.ivy.plugins.repository.BasicResource; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.plugins.repository.ssh.AbstractSshBasedRepository; import org.apache.ivy.plugins.repository.ssh.SshCache; import org.apache.ivy.util.Message; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpException; import com.jcraft.jsch.SftpProgressMonitor; /** * SFTP Repository, allow to use a repository accessed by sftp protocol. It supports all operations: * get, put and list. It relies on jsch for sftp handling, and thus is compatible with sftp version * 0, 1, 2 and 3 */ public class SFTPRepository extends AbstractSshBasedRepository { // this must be a long to ensure the multiplication done below uses longs // instead of ints which are not big enough to hold the result private static final long MILLIS_PER_SECOND = 1000; private final class MyProgressMonitor implements SftpProgressMonitor { private long totalLength; public void init(int op, String src, String dest, long max) { totalLength = max; fireTransferStarted(max); } public void end() { fireTransferCompleted(totalLength); } public boolean count(long count) { fireTransferProgress(count); return true; } } public SFTPRepository() { } public Resource getResource(String source) { return new SFTPResource(this, source); } /** * This method is similar to getResource, except that the returned resource is fully initialized * (resolved in the sftp repository), and that the given string is a full remote path * * @param path * the full remote path in the repository of the resource * @return a fully initialized resource, able to answer to all its methods without needing any * further connection */ public Resource resolveResource(String path) { try { ChannelSftp c = getSftpChannel(path); Collection r = c.ls(getPath(path)); if (r != null) { for (Iterator iter = r.iterator(); iter.hasNext();) { Object obj = iter.next(); if (obj instanceof LsEntry) { LsEntry entry = (LsEntry) obj; SftpATTRS attrs = entry.getAttrs(); return new BasicResource(path, true, attrs.getSize(), attrs.getMTime() * MILLIS_PER_SECOND, false); } } } } catch (Exception e) { Message.debug("Error while resolving resource " + path, e); // silent fail, return unexisting resource } return new BasicResource(path, false, 0, 0, false); } public InputStream openStream(SFTPResource resource) throws IOException { ChannelSftp c = getSftpChannel(resource.getName()); try { String path = getPath(resource.getName()); return c.get(path); } catch (SftpException e) { IOException ex = new IOException("impossible to open stream for " + resource + " on " + getHost() + (e.getMessage() != null ? ": " + e.getMessage() : "")); ex.initCause(e); throw ex; } catch (URISyntaxException e) { IOException ex = new IOException("impossible to open stream for " + resource + " on " + getHost() + (e.getMessage() != null ? ": " + e.getMessage() : "")); ex.initCause(e); throw ex; } } public void get(String source, File destination) throws IOException { fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); ChannelSftp c = getSftpChannel(source); try { String path = getPath(source); c.get(path, destination.getAbsolutePath(), new MyProgressMonitor()); } catch (SftpException e) { IOException ex = new IOException("impossible to get " + source + " on " + getHost() + (e.getMessage() != null ? ": " + e.getMessage() : "")); ex.initCause(e); throw ex; } catch (URISyntaxException e) { IOException ex = new IOException("impossible to get " + source + " on " + getHost() + (e.getMessage() != null ? ": " + e.getMessage() : "")); ex.initCause(e); throw ex; } } public void put(File source, String destination, boolean overwrite) throws IOException { fireTransferInitiated(getResource(destination), TransferEvent.REQUEST_PUT); ChannelSftp c = getSftpChannel(destination); try { String path = getPath(destination); if (!overwrite && checkExistence(path, c)) { throw new IOException("destination file exists and overwrite == false"); } if (path.indexOf('/') != -1) { mkdirs(path.substring(0, path.lastIndexOf('/')), c); } c.put(source.getAbsolutePath(), path, new MyProgressMonitor()); } catch (SftpException e) { IOException ex = new IOException(e.getMessage()); ex.initCause(e); throw ex; } catch (URISyntaxException e) { IOException ex = new IOException(e.getMessage()); ex.initCause(e); throw ex; } } private void mkdirs(String directory, ChannelSftp c) throws IOException, SftpException { try { SftpATTRS att = c.stat(directory); if (att != null) { if (att.isDir()) { return; } } } catch (SftpException ex) { if (directory.indexOf('/') != -1) { mkdirs(directory.substring(0, directory.lastIndexOf('/')), c); } c.mkdir(directory); } } private String getPath(String sftpURI) throws URISyntaxException { String result = null; URI uri = new URI(sftpURI); result = uri.getPath(); if (result == null) { throw new URISyntaxException(sftpURI, "Missing path in URI."); } return result; } public List list(String parent) throws IOException { try { ChannelSftp c = getSftpChannel(parent); String path = getPath(parent); Collection r = c.ls(path); if (r != null) { if (!path.endsWith("/")) { path = parent + "/"; } List result = new ArrayList(); for (Iterator iter = r.iterator(); iter.hasNext();) { Object obj = iter.next(); if (obj instanceof LsEntry) { LsEntry entry = (LsEntry) obj; if (".".equals(entry.getFilename()) || "..".equals(entry.getFilename())) { continue; } result.add(path + entry.getFilename()); } } return result; } } catch (SftpException e) { IOException ex = new IOException("Failed to return a listing for '" + parent + "'"); ex.initCause(e); throw ex; } catch (URISyntaxException usex) { IOException ex = new IOException("Failed to return a listing for '" + parent + "'"); ex.initCause(usex); throw ex; } return null; } /** * Checks the existence for a remote file * * @param file * to check * @param channel * to use * @returns true if file exists, false otherwise * @throws IOException * @throws SftpException */ private boolean checkExistence(String file, ChannelSftp channel) throws IOException, SftpException { try { return channel.stat(file) != null; } catch (SftpException ex) { return false; } } /** * Establish the connection to the server if not yet connected, and listen to ivy events for * closing connection when resolve is finished. Not meant to be used in multi threaded * environment. * * @return the ChannelSftp with which a connection is established * @throws IOException * if any connection problem occurs */ private ChannelSftp getSftpChannel(String pathOrUri) throws IOException { Session session = getSession(pathOrUri); String host = session.getHost(); ChannelSftp channel = SshCache.getInstance().getChannelSftp(session); if (channel == null) { try { channel = (ChannelSftp) session.openChannel("sftp"); channel.connect(); Message.verbose(":: SFTP :: connected to " + host + "!"); SshCache.getInstance().attachChannelSftp(session, channel); } catch (JSchException e) { IOException ex = new IOException(e.getMessage()); ex.initCause(e); throw ex; } } return channel; } protected String getRepositoryScheme() { // use the Resolver type name here? // would be nice if it would be static, so we could use SFTPResolver.getTypeName() return "sftp"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/sftp/SFTPResource.java000066400000000000000000000044301226750426600273540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.sftp; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.plugins.repository.Resource; public class SFTPResource implements Resource { private SFTPRepository repository; private String path; private transient boolean init = false; private transient boolean exists; private transient long lastModified; private transient long contentLength; public SFTPResource(SFTPRepository repository, String path) { this.repository = repository; this.path = path; } public String getName() { return path; } public Resource clone(String cloneName) { return new SFTPResource(repository, cloneName); } public long getLastModified() { init(); return lastModified; } public long getContentLength() { init(); return contentLength; } public boolean exists() { init(); return exists; } private void init() { if (!init) { Resource r = repository.resolveResource(path); contentLength = r.getContentLength(); lastModified = r.getLastModified(); exists = r.exists(); init = true; } } public String toString() { return getName(); } public boolean isLocal() { return false; } public InputStream openStream() throws IOException { return repository.openStream(this); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/000077500000000000000000000000001226750426600240455ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/AbstractSshBasedRepository.java000066400000000000000000000226301226750426600321730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Locale; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.util.Credentials; import org.apache.ivy.util.CredentialsUtil; import org.apache.ivy.util.Message; import com.jcraft.jsch.Session; public abstract class AbstractSshBasedRepository extends AbstractRepository { private File keyFile = null; private File passFile = null; private String userPassword = null; private String keyFilePassword = null; private String user = null; private String host = null; private int port = -1; private boolean allowedAgentUse = false; public AbstractSshBasedRepository() { super(); } /** * hashmap of user/hosts with credentials. key is hostname, value is Credentials **/ private static HashMap credentialsCache = new HashMap(); private static final int MAX_CREDENTILAS_CACHE_SIZE = 100; /** * get a new session using the default attributes if the given String is a full uri, use the * data from the uri instead * * @param pathOrUri * might be just a path or a full ssh or sftp uri * @return matching Session */ protected Session getSession(String pathOrUri) throws IOException { URI uri = parseURI(pathOrUri); String host = getHost(); int port = getPort(); String user = getUser(); String userPassword = getUserPassword(); if (uri != null && uri.getScheme() != null) { if (uri.getHost() != null) { host = uri.getHost(); } if (uri.getPort() != -1) { port = uri.getPort(); } if (uri.getUserInfo() != null) { String userInfo = uri.getUserInfo(); if (userInfo.indexOf(":") == -1) { user = userInfo; } else { user = userInfo.substring(0, userInfo.indexOf(":")); userPassword = userInfo.substring(userInfo.indexOf(":") + 1); } } } if (host == null) { throw new IllegalArgumentException( "missing host information. host should be provided either " + "directly on the repository or in the connection URI"); } if (user == null) { Credentials c = requestCredentials(host); if (c != null) { user = c.getUserName(); userPassword = c.getPasswd(); } else { Message.error("username is not set"); } } return SshCache.getInstance().getSession(host, port, user, userPassword, getKeyFile(), getKeyFilePassword(), getPassFile(), isAllowedAgentUse()); } /** * Just check the uri for sanity * * @param source * String of the uri * @return URI object of the String or null */ private URI parseURI(String source) { try { URI uri = new URI(source); if (uri.getScheme() != null && !uri.getScheme().toLowerCase(Locale.US) .equals(getRepositoryScheme().toLowerCase(Locale.US))) { throw new URISyntaxException(source, "Wrong scheme in URI. Expected " + getRepositoryScheme() + " as scheme!"); } if (uri.getHost() == null && getHost() == null) { throw new URISyntaxException(source, "Missing host in URI or in resolver"); } if (uri.getPath() == null) { throw new URISyntaxException(source, "Missing path in URI"); } // if (uri.getUserInfo() == null && getUser() == null) { // throw new URISyntaxException(source, "Missing username in URI or in resolver"); // } return uri; } catch (URISyntaxException e) { Message.error(e.getMessage()); Message.error("The uri '" + source + "' is in the wrong format."); Message.error("Please use " + getRepositoryScheme() + "://user:pass@hostname/path/to/repository"); return null; } } /** * Called, when user was not found in URL. Maintain static hashe of credentials and retrieve or * ask credentials for host. * * @param host * host for which we want to get credentials. * @return credentials for given host **/ private Credentials requestCredentials(String host) { Object o = credentialsCache.get(host); if (o == null) { Credentials c = CredentialsUtil.promptCredentials(new Credentials(null, host, user, userPassword), getPassFile()); if (c != null) { if (credentialsCache.size() > MAX_CREDENTILAS_CACHE_SIZE) { credentialsCache.clear(); } credentialsCache.put(host, c); } return c; } else { return (Credentials) o; } } /** * closes the session and remove it from the cache (eg. on case of errors) * * @param session * key for the cache * @param pathOrUri * to release */ protected void releaseSession(Session session, String pathOrUri) { session.disconnect(); SshCache.getInstance().clearSession(session); } /** * set the default user to use for the connection if no user is given or a PEM file is used * * @param user * to use */ public void setUser(String user) { this.user = user; } /** * @return the user to use for the connection if no user is given or a PEM file is used */ public String getUser() { return user; } /** * Sets the full file path to use for accessing a PEM key file * * @param filePath * fully qualified name */ public void setKeyFile(File filePath) { this.keyFile = filePath; if (!keyFile.exists()) { Message.warn("Pemfile " + keyFile.getAbsolutePath() + " doesn't exist."); keyFile = null; } else if (!keyFile.canRead()) { Message.warn("Pemfile " + keyFile.getAbsolutePath() + " not readable."); keyFile = null; } else { Message.debug("Using " + keyFile.getAbsolutePath() + " as keyfile."); } } /** * @return the keyFile */ public File getKeyFile() { return keyFile; } /** * @param password * password to use for user/password authentication */ public void setUserPassword(String password) { this.userPassword = password; } /** * @return the keyFile password for public key based authentication */ public String getKeyFilePassword() { return keyFilePassword; } /** * @param keyFilePassword * sets password for public key based authentication */ public void setKeyFilePassword(String keyFilePassword) { this.keyFilePassword = keyFilePassword; } /** * @return the user password */ public String getUserPassword() { return userPassword; } /** * @return the host */ public String getHost() { return host; } /** * @param host * the host to set */ public void setHost(String host) { this.host = host; } /** * @return the port */ public int getPort() { return port; } /** * @param port * the port to set */ public void setPort(int port) { this.port = port; } /** * @param passFile * the passfile to set */ public void setPassFile(File passFile) { this.passFile = passFile; } /** * @return the passFile */ public File getPassFile() { return passFile; } /** * @return allowedAgentUse Whether use of a local SSH agent for authentication is allowed */ public boolean isAllowedAgentUse() { return allowedAgentUse; } /** * @param allowedAgentUse * Whether use of a local SSH agent for authentication is allowed */ public void setAllowedAgentUse(boolean allowedAgentUse) { this.allowedAgentUse = allowedAgentUse; } protected abstract String getRepositoryScheme(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/RemoteScpException.java000066400000000000000000000030111226750426600304630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; /** * This exception will be used for Remote SCP Exceptions (failures on the target system, no * connetion probs) */ public class RemoteScpException extends Exception { private static final long serialVersionUID = 3107198655563736600L; public RemoteScpException() { } /** * @param message */ public RemoteScpException(String message) { super(message); } /** * @param cause */ public RemoteScpException(Throwable cause) { super(cause); } /** * @param message * @param cause */ public RemoteScpException(String message, Throwable cause) { super(message, cause); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/Scp.java000066400000000000000000000461561226750426600254510ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; /** * This class is using the scp client to transfer data and information for the repository. *

    * It is based on the SCPClient from the ganymed ssh library from Christian Plattner, released under * a BSD style license. *

    * To minimize the dependency to the ssh library and because we needed some additional * functionality, we decided to copy'n'paste the single class rather than to inherit or delegate it * somehow. *

    * Nevertheless credit should go to the original author. */ public class Scp { private static final int MODE_LENGTH = 4; private static final int SEND_FILE_BUFFER_LENGTH = 40000; private static final int SEND_BYTES_BUFFER_LENGTH = 512; private static final int MIN_TLINE_LENGTH = 8; private static final int CLINE_SPACE_INDEX2 = 5; private static final int CLINE_SPACE_INDEX1 = 4; private static final int MIN_C_LINE_LENGTH = 8; private static final int DEFAULT_LINE_BUFFER_LENGTH = 30; private static final int BUFFER_SIZE = 64 * 1024; /* * Maximum length authorized for scp lines. This is a random limit - if your path names are * longer, then adjust it. */ private static final int MAX_SCP_LINE_LENGTH = 8192; private Session session; public class FileInfo { private String filename; private long length; private long lastModified; /** * @param filename * The filename to set. */ public void setFilename(String filename) { this.filename = filename; } /** * @return Returns the filename. */ public String getFilename() { return filename; } /** * @param length * The length to set. */ public void setLength(long length) { this.length = length; } /** * @return Returns the length. */ public long getLength() { return length; } /** * @param lastModified * The lastModified to set. */ public void setLastModified(long lastModified) { this.lastModified = lastModified; } /** * @return Returns the lastModified. */ public long getLastModified() { return lastModified; } } public Scp(Session session) { if (session == null) { throw new IllegalArgumentException("Cannot accept null argument!"); } this.session = session; } private void readResponse(InputStream is) throws IOException, RemoteScpException { int c = is.read(); if (c == 0) { return; } if (c == -1) { throw new RemoteScpException("Remote scp terminated unexpectedly."); } if ((c != 1) && (c != 2)) { throw new RemoteScpException("Remote scp sent illegal error code."); } if (c == 2) { throw new RemoteScpException("Remote scp terminated with error."); } String err = receiveLine(is); throw new RemoteScpException("Remote scp terminated with error (" + err + ")."); } private String receiveLine(InputStream is) throws IOException, RemoteScpException { StringBuffer sb = new StringBuffer(DEFAULT_LINE_BUFFER_LENGTH); while (true) { if (sb.length() > MAX_SCP_LINE_LENGTH) { throw new RemoteScpException("Remote scp sent a too long line"); } int c = is.read(); if (c < 0) { throw new RemoteScpException("Remote scp terminated unexpectedly."); } if (c == '\n') { break; } sb.append((char) c); } return sb.toString(); } private void parseCLine(String line, FileInfo fileInfo) throws RemoteScpException { /* Minimum line: "xxxx y z" ---> 8 chars */ long len; if (line.length() < MIN_C_LINE_LENGTH) { throw new RemoteScpException( "Malformed C line sent by remote SCP binary, line too short."); } if ((line.charAt(CLINE_SPACE_INDEX1) != ' ') || (line.charAt(CLINE_SPACE_INDEX2) == ' ')) { throw new RemoteScpException("Malformed C line sent by remote SCP binary."); } int lengthNameSep = line.indexOf(' ', CLINE_SPACE_INDEX2); if (lengthNameSep == -1) { throw new RemoteScpException("Malformed C line sent by remote SCP binary."); } String lengthSubstring = line.substring(CLINE_SPACE_INDEX2, lengthNameSep); String nameSubstring = line.substring(lengthNameSep + 1); if ((lengthSubstring.length() <= 0) || (nameSubstring.length() <= 0)) { throw new RemoteScpException("Malformed C line sent by remote SCP binary."); } if ((CLINE_SPACE_INDEX2 + 1 + lengthSubstring.length() + nameSubstring.length()) != line .length()) { throw new RemoteScpException("Malformed C line sent by remote SCP binary."); } try { len = Long.parseLong(lengthSubstring); } catch (NumberFormatException e) { throw new RemoteScpException( "Malformed C line sent by remote SCP binary, cannot parse file length."); } if (len < 0) { throw new RemoteScpException( "Malformed C line sent by remote SCP binary, illegal file length."); } fileInfo.setLength(len); fileInfo.setFilename(nameSubstring); } private void parseTLine(String line, FileInfo fileInfo) throws RemoteScpException { /* Minimum line: "0 0 0 0" ---> 8 chars */ long modtime; long firstMsec; long atime; long secondMsec; if (line.length() < MIN_TLINE_LENGTH) { throw new RemoteScpException( "Malformed T line sent by remote SCP binary, line too short."); } int firstMsecBegin = line.indexOf(" ") + 1; if (firstMsecBegin == 0 || firstMsecBegin >= line.length()) { throw new RemoteScpException( "Malformed T line sent by remote SCP binary, line not enough data."); } int atimeBegin = line.indexOf(" ", firstMsecBegin + 1) + 1; if (atimeBegin == 0 || atimeBegin >= line.length()) { throw new RemoteScpException( "Malformed T line sent by remote SCP binary, line not enough data."); } int secondMsecBegin = line.indexOf(" ", atimeBegin + 1) + 1; if (secondMsecBegin == 0 || secondMsecBegin >= line.length()) { throw new RemoteScpException( "Malformed T line sent by remote SCP binary, line not enough data."); } try { modtime = Long.parseLong(line.substring(0, firstMsecBegin - 1)); firstMsec = Long.parseLong(line.substring(firstMsecBegin, atimeBegin - 1)); atime = Long.parseLong(line.substring(atimeBegin, secondMsecBegin - 1)); secondMsec = Long.parseLong(line.substring(secondMsecBegin)); } catch (NumberFormatException e) { throw new RemoteScpException( "Malformed C line sent by remote SCP binary, cannot parse file length."); } if (modtime < 0 || firstMsec < 0 || atime < 0 || secondMsec < 0) { throw new RemoteScpException( "Malformed C line sent by remote SCP binary, illegal file length."); } fileInfo.setLastModified(modtime); } private void sendFile(Channel channel, String localFile, String remoteName, String mode) throws IOException, RemoteScpException { byte[] buffer = new byte[BUFFER_SIZE]; OutputStream os = new BufferedOutputStream(channel.getOutputStream(), SEND_FILE_BUFFER_LENGTH); InputStream is = new BufferedInputStream(channel.getInputStream(), SEND_BYTES_BUFFER_LENGTH); try { if (channel.isConnected()) { channel.start(); } else { channel.connect(); } } catch (JSchException e1) { throw (IOException) new IOException("Channel connection problems").initCause(e1); } readResponse(is); File f = new File(localFile); long remain = f.length(); String cMode = mode; if (cMode == null) { cMode = "0600"; } String cline = "C" + cMode + " " + remain + " " + remoteName + "\n"; os.write(cline.getBytes()); os.flush(); readResponse(is); FileInputStream fis = null; try { fis = new FileInputStream(f); while (remain > 0) { int trans; if (remain > buffer.length) { trans = buffer.length; } else { trans = (int) remain; } if (fis.read(buffer, 0, trans) != trans) { throw new IOException("Cannot read enough from local file " + localFile); } os.write(buffer, 0, trans); remain -= trans; } fis.close(); } catch (IOException e) { if (fis != null) { fis.close(); } throw (e); } os.write(0); os.flush(); readResponse(is); os.write("E\n".getBytes()); os.flush(); } /** * Receive a file via scp and store it in a stream * * @param channel * ssh channel to use * @param file * to receive from remote * @param target * to store file into (if null, get only file info) * @return file information of the file we received * @throws IOException * in case of network or protocol trouble * @throws RemoteScpException * in case of problems on the target system (connection is fine) */ private FileInfo receiveStream(Channel channel, String file, OutputStream targetStream) throws IOException, RemoteScpException { byte[] buffer = new byte[BUFFER_SIZE]; OutputStream os = channel.getOutputStream(); InputStream is = channel.getInputStream(); try { if (channel.isConnected()) { channel.start(); } else { channel.connect(); } } catch (JSchException e1) { throw (IOException) new IOException("Channel connection problems").initCause(e1); } os.write(0x0); os.flush(); FileInfo fileInfo = new FileInfo(); while (true) { int c = is.read(); if (c < 0) { throw new RemoteScpException("Remote scp terminated unexpectedly."); } String line = receiveLine(is); if (c == 'T') { parseTLine(line, fileInfo); os.write(0x0); os.flush(); continue; } if ((c == 1) || (c == 2)) { throw new RemoteScpException("Remote SCP error: " + line); } if (c == 'C') { parseCLine(line, fileInfo); break; } throw new RemoteScpException("Remote SCP error: " + ((char) c) + line); } if (targetStream != null) { os.write(0x0); os.flush(); try { long remain = fileInfo.getLength(); while (remain > 0) { int trans; if (remain > buffer.length) { trans = buffer.length; } else { trans = (int) remain; } int thisTimeReceived = is.read(buffer, 0, trans); if (thisTimeReceived < 0) { throw new IOException("Remote scp terminated connection unexpectedly"); } targetStream.write(buffer, 0, thisTimeReceived); remain -= thisTimeReceived; } targetStream.close(); } catch (IOException e) { if (targetStream != null) { targetStream.close(); } throw (e); } readResponse(is); os.write(0x0); os.flush(); } return fileInfo; } /** * @return * @throws JSchException */ private ChannelExec getExecChannel() throws JSchException { ChannelExec channel; channel = (ChannelExec) session.openChannel("exec"); return channel; } /** * Copy a local file to a remote site, uses the specified mode when creating the file on the * remote side. * * @param localFile * Path and name of local file. Must be absolute. * @param remoteTargetDir * Remote target directory where the file has to end up (optional) * @param remoteTargetName * file name to use on the target system * @param mode * a four digit string (e.g., 0644, see "man chmod", "man open") * @throws IOException * in case of network problems * @throws RemoteScpException * in case of problems on the target system (connection ok) */ public void put(String localFile, String remoteTargetDir, String remoteTargetName, String mode) throws IOException, RemoteScpException { ChannelExec channel = null; if ((localFile == null) || (remoteTargetName == null)) { throw new IllegalArgumentException("Null argument."); } if (mode != null) { if (mode.length() != MODE_LENGTH) { throw new IllegalArgumentException("Invalid mode."); } for (int i = 0; i < mode.length(); i++) { if (!Character.isDigit(mode.charAt(i))) { throw new IllegalArgumentException("Invalid mode."); } } } String cmd = "scp -t "; if (mode != null) { cmd = cmd + "-p "; } if (remoteTargetDir != null && remoteTargetDir.length() > 0) { cmd = cmd + "-d " + remoteTargetDir; } try { channel = getExecChannel(); channel.setCommand(cmd); sendFile(channel, localFile, remoteTargetName, mode); channel.disconnect(); } catch (JSchException e) { if (channel != null) { channel.disconnect(); } throw (IOException) new IOException("Error during SCP transfer." + e.getMessage()) .initCause(e); } } /** * Download a file from the remote server to a local file. * * @param remoteFile * Path and name of the remote file. * @param localTarget * Local file where to store the data. Must be absolute. * @throws IOException * in case of network problems * @throws RemoteScpException * in case of problems on the target system (connection ok) */ public void get(String remoteFile, String localTarget) throws IOException, RemoteScpException { File f = new File(localTarget); FileOutputStream fop = new FileOutputStream(f); get(remoteFile, fop); } /** * Download a file from the remote server into an OutputStream * * @param remoteFile * Path and name of the remote file. * @param localTarget * OutputStream to store the data. * @throws IOException * in case of network problems * @throws RemoteScpException * in case of problems on the target system (connection ok) */ public void get(String remoteFile, OutputStream localTarget) throws IOException, RemoteScpException { ChannelExec channel = null; if ((remoteFile == null) || (localTarget == null)) { throw new IllegalArgumentException("Null argument."); } String cmd = "scp -p -f " + remoteFile; try { channel = getExecChannel(); channel.setCommand(cmd); receiveStream(channel, remoteFile, localTarget); channel.disconnect(); } catch (JSchException e) { if (channel != null) { channel.disconnect(); } throw (IOException) new IOException("Error during SCP transfer." + e.getMessage()) .initCause(e); } } /** * Initiates an SCP sequence but stops after getting fileinformation header * * @param remoteFile * to get information for * @return the file information got * @throws IOException * in case of network problems * @throws RemoteScpException * in case of problems on the target system (connection ok) */ public FileInfo getFileinfo(String remoteFile) throws IOException, RemoteScpException { ChannelExec channel = null; FileInfo fileInfo = null; if (remoteFile == null) { throw new IllegalArgumentException("Null argument."); } String cmd = "scp -p -f \"" + remoteFile + "\""; try { channel = getExecChannel(); channel.setCommand(cmd); fileInfo = receiveStream(channel, remoteFile, null); channel.disconnect(); } catch (JSchException e) { throw (IOException) new IOException("Error during SCP transfer." + e.getMessage()) .initCause(e); } finally { if (channel != null) { channel.disconnect(); } } return fileInfo; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/SshCache.java000066400000000000000000000352311226750426600263750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.event.IvyListener; import org.apache.ivy.core.event.resolve.EndResolveEvent; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Credentials; import org.apache.ivy.util.CredentialsUtil; import org.apache.ivy.util.Message; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.jcraft.jsch.UIKeyboardInteractive; import com.jcraft.jsch.UserInfo; import com.jcraft.jsch.agentproxy.AgentProxyException; import com.jcraft.jsch.agentproxy.Connector; import com.jcraft.jsch.agentproxy.ConnectorFactory; import com.jcraft.jsch.agentproxy.RemoteIdentityRepository; /** * a class to cache SSH Connections and Channel for the SSH Repository each session is defined by * connecting user / host / port two maps are used to find cache entries one map is using the above * keys, the other uses the session itself */ public final class SshCache { private static final int SSH_DEFAULT_PORT = 22; private SshCache() { }; private static SshCache instance = new SshCache(); public static SshCache getInstance() { return instance; } private class Entry { private Session session = null; private ChannelSftp channelSftp = null; private String host = null; private String user = null; private int port = SSH_DEFAULT_PORT; /** * @return the host */ public String getHost() { return host; } /** * @return the port */ public int getPort() { return port; } /** * @return the user */ public String getUser() { return user; } public Entry(Session newSession, String newUser, String newHost, int newPort) { session = newSession; host = newHost; user = newUser; port = newPort; IvyContext.getContext().getEventManager().addIvyListener(new IvyListener() { public void progress(IvyEvent event) { event.getSource().removeIvyListener(this); clearSession(session); } }, EndResolveEvent.NAME); } /** * attach an sftp channel to this cache entry * * @param newChannel * to attach */ public void setChannelSftp(ChannelSftp newChannel) { if (channelSftp != null && newChannel != null) { throw new IllegalStateException("Only one sftp channelSftp per session allowed"); } this.channelSftp = newChannel; } /** * @return the attached sftp channel */ public ChannelSftp getChannelSftp() { return channelSftp; } /** * @return the session */ private Session getSession() { return session; } /** * remove channelSftp and disconnect if necessary */ public void releaseChannelSftp() { if (channelSftp != null) { if (channelSftp.isConnected()) { Message.verbose(":: SFTP :: closing sftp connection from " + host + "..."); channelSftp.disconnect(); channelSftp = null; Message.verbose(":: SFTP :: sftp connection closed from " + host); } } } } /** * key is username / host / port * * @see SshCache.createCacheKey() for details */ private Map uriCacheMap = new HashMap(); /** * key is the session itself */ private Map sessionCacheMap = new HashMap(); /** * retrieves a session entry for a given hostname from the cache * * @param hostname * to retrieve session for * @return null or the existing entry */ private Entry getCacheEntry(String user, String host, int port) { return (Entry) uriCacheMap.get(createCacheKey(user, host, port)); } /** * Creates a cobined cache key from the given key parts * * @param user * name of the user * @param host * of the connection * @param port * of the connection * @return key for the cache */ private static String createCacheKey(String user, String host, int port) { String portToUse = "22"; if (port != -1 && port != SSH_DEFAULT_PORT) { portToUse = Integer.toString(port); } return user.toLowerCase(Locale.US).trim() + "@" + host.toLowerCase(Locale.US).trim() + ":" + portToUse; } /** * retrieves a session entry for a given session from the cache * * @param session * to retrieve cache entry for * @return null or the existing entry */ private Entry getCacheEntry(Session session) { return (Entry) sessionCacheMap.get(session); } /** * Sets a session to a given combined key into the cache If an old session object already * exists, close and remove it * * @param user * of the session * @param host * of the session * @param port * of the session * @param newSession * Session to save */ private void setSession(String user, String host, int port, Session newSession) { Entry entry = (Entry) uriCacheMap.get(createCacheKey(user, host, port)); Session oldSession = null; if (entry != null) { oldSession = entry.getSession(); } if (oldSession != null && !oldSession.equals(newSession) && oldSession.isConnected()) { entry.releaseChannelSftp(); String oldhost = oldSession.getHost(); Message.verbose(":: SSH :: closing ssh connection from " + oldhost + "..."); oldSession.disconnect(); Message.verbose(":: SSH :: ssh connection closed from " + oldhost); } if ((newSession == null) && (entry != null)) { uriCacheMap.remove(createCacheKey(user, host, port)); if (entry.getSession() != null) { sessionCacheMap.remove(entry.getSession()); } } else { Entry newEntry = new Entry(newSession, user, host, port); uriCacheMap.put(createCacheKey(user, host, port), newEntry); sessionCacheMap.put(newSession, newEntry); } } /** * discardes session entries from the cache * * @param session * to clear */ public void clearSession(Session session) { Entry entry = (Entry) sessionCacheMap.get(session); if (entry != null) { setSession(entry.getUser(), entry.getHost(), entry.getPort(), null); } } /** * retrieves an sftp channel from the cache * * @param session * to connect to * @return channelSftp or null if not successful (channel not existent or dead) */ public ChannelSftp getChannelSftp(Session session) throws IOException { ChannelSftp channel = null; Entry entry = getCacheEntry(session); if (entry != null) { channel = entry.getChannelSftp(); if (channel != null && !channel.isConnected()) { entry.releaseChannelSftp(); channel = null; } } return channel; } /** * attaches a channelSftp to an existing session cache entry * * @param session * to attach the channel to * @param channel * channel to attach */ public void attachChannelSftp(Session session, ChannelSftp channel) { Entry entry = getCacheEntry(session); if (entry == null) { throw new IllegalArgumentException("No entry for " + session + " in the cache"); } entry.setChannelSftp(channel); } /** * Attempts to connect to a local SSH agent (using either UNIX sockets or PuTTY's Pageant) * * @param jsch * Connection to be attached to an available local agent * @return true if connected to agent, false otherwise */ private boolean attemptAgentUse(JSch jsch) { try { Connector con = ConnectorFactory.getDefault().createConnector(); jsch.setIdentityRepository(new RemoteIdentityRepository(con)); return true; } catch (AgentProxyException e) { Message.verbose(":: SSH :: Failure connecting to agent :: " + e.toString()); return false; } } /** * Gets a session from the cache or establishes a new session if necessary * * @param host * to connect to * @param port * to use for session (-1 == use standard port) * @param username * for the session to use * @param userPassword * to use for authentication (optional) * @param pemFile * File to use for public key authentication * @param pemPassword * to use for accessing the pemFile (optional) * @param passFile * to store credentials * @param allowedAgentUse * Whether to communicate with an agent for authentication * @return session or null if not successful */ public Session getSession(String host, int port, String username, String userPassword, File pemFile, String pemPassword, File passFile, boolean allowedAgentUse) throws IOException { Checks.checkNotNull(host, "host"); Checks.checkNotNull(username, "user"); Entry entry = getCacheEntry(username, host, port); Session session = null; if (entry != null) { session = entry.getSession(); } if (session == null || !session.isConnected()) { Message.verbose(":: SSH :: connecting to " + host + "..."); try { JSch jsch = new JSch(); if (port != -1) { session = jsch.getSession(username, host, port); } else { session = jsch.getSession(username, host); } if (allowedAgentUse) { attemptAgentUse(jsch); } if (pemFile != null) { jsch.addIdentity(pemFile.getAbsolutePath(), pemPassword); } session.setUserInfo(new CfUserInfo(host, username, userPassword, pemFile, pemPassword, passFile)); session.setDaemonThread(true); Properties config = new Properties(); config.setProperty("PreferredAuthentications", "publickey,keyboard-interactive,password"); session.setConfig(config); session.connect(); Message.verbose(":: SSH :: connected to " + host + "!"); setSession(username, host, port, session); } catch (JSchException e) { if (passFile != null && passFile.exists()) { passFile.delete(); } IOException ex = new IOException(e.getMessage()); ex.initCause(e); throw ex; } } return session; } /** * feeds in password silently into JSch */ private static class CfUserInfo implements UserInfo, UIKeyboardInteractive { private String userPassword; private String pemPassword; private String userName; private final File pemFile; private final String host; private final File passfile; public CfUserInfo(String host, String userName, String userPassword, File pemFile, String pemPassword, File passfile) { this.userPassword = userPassword; this.pemPassword = pemPassword; this.host = host; this.passfile = passfile; this.userName = userName; this.pemFile = pemFile; } public void showMessage(String message) { Message.info(message); } public boolean promptYesNo(String message) { return true; } public boolean promptPassword(String message) { return true; } public boolean promptPassphrase(String message) { return true; } public String getPassword() { if (userPassword == null) { Credentials c = CredentialsUtil.promptCredentials(new Credentials(null, host, userName, userPassword), passfile); if (c != null) { userName = c.getUserName(); userPassword = c.getPasswd(); } } return userPassword; } public String getPassphrase() { if (pemPassword == null && pemFile != null) { Credentials c = CredentialsUtil.promptCredentials( new Credentials(null, pemFile.getAbsolutePath(), userName, pemPassword), passfile); if (c != null) { userName = c.getUserName(); pemPassword = c.getPasswd(); } } return pemPassword; } public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) { return new String[] {getPassword()}; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/SshRepository.java000066400000000000000000000371611226750426600275550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; /** * Ivy Repository based on SSH */ public class SshRepository extends AbstractSshBasedRepository { private static final int BUFFER_SIZE = 64 * 1024; private static final String ARGUMENT_PLACEHOLDER = "%arg"; private static final int POLL_SLEEP_TIME = 500; private char fileSeparator = '/'; private String listCommand = "ls -1"; private String existCommand = "ls"; private String createDirCommand = "mkdir"; private String publishPermissions = null; /** * create a new resource with lazy initializing */ public Resource getResource(String source) { Message.debug("SShRepository:getResource called: " + source); return new SshResource(this, source); } /** * Fetch the needed file information for a given file (size, last modification time) and report * it back in a SshResource * * @param source * ssh uri for the file to get info for * @return SshResource filled with the needed informations * @see org.apache.ivy.plugins.repository.Repository#getResource(java.lang.String) */ public SshResource resolveResource(String source) { Message.debug("SShRepository:resolveResource called: " + source); SshResource result = null; Session session = null; try { session = getSession(source); Scp myCopy = new Scp(session); Scp.FileInfo fileInfo = myCopy.getFileinfo(new URI(source).getPath()); result = new SshResource(this, source, true, fileInfo.getLength(), fileInfo.getLastModified()); } catch (IOException e) { if (session != null) { releaseSession(session, source); } result = new SshResource(); } catch (URISyntaxException e) { if (session != null) { releaseSession(session, source); } result = new SshResource(); } catch (RemoteScpException e) { result = new SshResource(); } Message.debug("SShRepository:resolveResource end."); return result; } /** * Reads out the output of a ssh session exec * * @param channel * Channel to read from * @param strStdout * StringBuffer that receives Session Stdout output * @param strStderr * StringBuffer that receives Session Stderr output * @throws IOException * in case of trouble with the network */ private void readSessionOutput(ChannelExec channel, StringBuffer strStdout, StringBuffer strStderr) throws IOException { InputStream stdout = channel.getInputStream(); InputStream stderr = channel.getErrStream(); try { channel.connect(); } catch (JSchException e1) { throw (IOException) new IOException("Channel connection problems").initCause(e1); } byte[] buffer = new byte[BUFFER_SIZE]; while (true) { int avail = 0; while ((avail = stdout.available()) > 0) { int len = stdout.read(buffer, 0, (avail > BUFFER_SIZE - 1 ? BUFFER_SIZE : avail)); strStdout.append(new String(buffer, 0, len)); } while ((avail = stderr.available()) > 0) { int len = stderr.read(buffer, 0, (avail > BUFFER_SIZE - 1 ? BUFFER_SIZE : avail)); strStderr.append(new String(buffer, 0, len)); } if (channel.isClosed()) { break; } try { Thread.sleep(POLL_SLEEP_TIME); } catch (Exception ee) { // ignored } } int avail = 0; while ((avail = stdout.available()) > 0) { int len = stdout.read(buffer, 0, (avail > BUFFER_SIZE - 1 ? BUFFER_SIZE : avail)); strStdout.append(new String(buffer, 0, len)); } while ((avail = stderr.available()) > 0) { int len = stderr.read(buffer, 0, (avail > BUFFER_SIZE - 1 ? BUFFER_SIZE : avail)); strStderr.append(new String(buffer, 0, len)); } } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Repository#list(java.lang.String) */ public List list(String parent) throws IOException { Message.debug("SShRepository:list called: " + parent); ArrayList result = new ArrayList(); Session session = null; ChannelExec channel = null; session = getSession(parent); channel = getExecChannel(session); URI parentUri = null; try { parentUri = new URI(parent); } catch (URISyntaxException e) { IOException ioe = new IOException("The uri '" + parent + "' is not valid!"); ioe.initCause(e); throw ioe; } String fullCmd = replaceArgument(listCommand, parentUri.getPath()); channel.setCommand(fullCmd); StringBuffer stdOut = new StringBuffer(); StringBuffer stdErr = new StringBuffer(); readSessionOutput(channel, stdOut, stdErr); if (channel.getExitStatus() != 0) { Message.error("Ssh ListCommand exited with status != 0"); Message.error(stdErr.toString()); return null; } else { BufferedReader br = new BufferedReader(new StringReader(stdOut.toString())); String line = null; while ((line = br.readLine()) != null) { result.add(line); } } return result; } /** * @param session * @return * @throws JSchException */ private ChannelExec getExecChannel(Session session) throws IOException { ChannelExec channel; try { channel = (ChannelExec) session.openChannel("exec"); } catch (JSchException e) { throw new IOException(); } return channel; } /** * Replace the argument placeholder with argument or append the argument if no placeholder is * present * * @param command * with argument placeholder or not * @param argument * @return replaced full command */ private String replaceArgument(String command, String argument) { String fullCmd; if (command.indexOf(ARGUMENT_PLACEHOLDER) == -1) { fullCmd = command + " " + argument; } else { fullCmd = command.replaceAll(ARGUMENT_PLACEHOLDER, argument); } return fullCmd; } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Repository#put(java.io.File, java.lang.String, boolean) */ public void put(File source, String destination, boolean overwrite) throws IOException { Message.debug("SShRepository:put called: " + destination); Session session = getSession(destination); URI destinationUri = null; try { destinationUri = new URI(destination); } catch (URISyntaxException e) { IOException ioe = new IOException("The uri '" + destination + "' is not valid!"); ioe.initCause(e); throw ioe; } try { String filePath = destinationUri.getPath(); int lastSep = filePath.lastIndexOf(fileSeparator); String path; String name; if (lastSep == -1) { name = filePath; path = null; } else { name = filePath.substring(lastSep + 1); path = filePath.substring(0, lastSep); } if (!overwrite) { if (checkExistence(filePath, session)) { throw new IOException("destination file exists and overwrite == false"); } } if (path != null) { makePath(path, session); } Scp myCopy = new Scp(session); myCopy.put(source.getCanonicalPath(), path, name, publishPermissions); } catch (IOException e) { if (session != null) { releaseSession(session, destination); } throw e; } catch (RemoteScpException e) { throw new IOException(e.getMessage()); } } /** * Tries to create a directory path on the target system * * @param path * to create * @param connnection * to use */ private void makePath(String path, Session session) throws IOException { ChannelExec channel = null; String trimmed = path; try { while (trimmed.length() > 0 && trimmed.charAt(trimmed.length() - 1) == fileSeparator) { trimmed = trimmed.substring(0, trimmed.length() - 1); } if (trimmed.length() == 0 || checkExistence(trimmed, session)) { return; } int nextSlash = trimmed.lastIndexOf(fileSeparator); if (nextSlash > 0) { String parent = trimmed.substring(0, nextSlash); makePath(parent, session); } channel = getExecChannel(session); String mkdir = replaceArgument(createDirCommand, trimmed); Message.debug("SShRepository: trying to create path: " + mkdir); channel.setCommand(mkdir); StringBuffer stdOut = new StringBuffer(); StringBuffer stdErr = new StringBuffer(); readSessionOutput(channel, stdOut, stdErr); } finally { if (channel != null) { channel.disconnect(); } } } /** * check for existence of file or dir on target system * * @param filePath * to the object to check * @param session * to use * @return true: object exists, false otherwise */ private boolean checkExistence(String filePath, Session session) throws IOException { Message.debug("SShRepository: checkExistence called: " + filePath); ChannelExec channel = null; channel = getExecChannel(session); String fullCmd = replaceArgument(existCommand, filePath); channel.setCommand(fullCmd); StringBuffer stdOut = new StringBuffer(); StringBuffer stdErr = new StringBuffer(); readSessionOutput(channel, stdOut, stdErr); return channel.getExitStatus() == 0; } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Repository#get(java.lang.String, java.io.File) */ public void get(String source, File destination) throws IOException { Message.debug("SShRepository:get called: " + source + " to " + destination.getCanonicalPath()); if (destination.getParentFile() != null) { destination.getParentFile().mkdirs(); } Session session = getSession(source); URI sourceUri = null; try { sourceUri = new URI(source); } catch (URISyntaxException e) { IOException ioe = new IOException("The uri '" + source + "' is not valid!"); ioe.initCause(e); throw ioe; } try { Scp myCopy = new Scp(session); myCopy.get(sourceUri.getPath(), destination.getCanonicalPath()); } catch (IOException e) { if (session != null) { releaseSession(session, source); } throw e; } catch (RemoteScpException e) { throw new IOException(e.getMessage()); } } /** * sets the list command to use for a directory listing listing must be only the filename and * each filename on a separate line * * @param cmd * to use. default is "ls -1" */ public void setListCommand(String cmd) { this.listCommand = cmd.trim(); } /** * @return the list command to use */ public String getListCommand() { return listCommand; } /** * @return the createDirCommand */ public String getCreateDirCommand() { return createDirCommand; } /** * @param createDirCommand * the createDirCommand to set */ public void setCreateDirCommand(String createDirCommand) { this.createDirCommand = createDirCommand; } /** * @return the existCommand */ public String getExistCommand() { return existCommand; } /** * @param existCommand * the existCommand to set */ public void setExistCommand(String existCommand) { this.existCommand = existCommand; } /** * The file separator is the separator to use on the target system On a unix system it is '/', * but I don't know, how this is solved on different ssh implementations. Using the default * might be fine * * @param fileSeparator * The fileSeparator to use. default '/' */ public void setFileSeparator(char fileSeparator) { this.fileSeparator = fileSeparator; } /** * A four digit string (e.g., 0644, see "man chmod", "man open") specifying the permissions of * the published files. */ public void setPublishPermissions(String permissions) { this.publishPermissions = permissions; } /** * return ssh as scheme use the Resolver type name here? would be nice if it would be static, so * we could use SshResolver.getTypeName() */ protected String getRepositoryScheme() { return "ssh"; } /** * Not really streaming...need to implement a proper streaming approach? * * @param resource * to stream * @return InputStream of the resource data */ public InputStream openStream(SshResource resource) throws IOException { Session session = getSession(resource.getName()); Scp scp = new Scp(session); ByteArrayOutputStream os = new ByteArrayOutputStream(); try { scp.get(resource.getName(), os); } catch (IOException e) { if (session != null) { releaseSession(session, resource.getName()); } throw e; } catch (RemoteScpException e) { throw new IOException(e.getMessage()); } return new ByteArrayInputStream(os.toByteArray()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/ssh/SshResource.java000066400000000000000000000070151226750426600271600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.ssh; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; /** * Resource for SSH Ivy Repository */ public class SshResource implements Resource { private boolean resolved = false; private String uri = null; private boolean bExists = false; private long len = 0; private long lastModified = 0; private SshRepository repository = null; public SshResource() { resolved = true; } public SshResource(SshRepository repository, String uri) { this.uri = uri; this.repository = repository; resolved = false; } public SshResource(SshRepository repository, String uri, boolean bExists, long len, long lastModified) { this.uri = uri; this.bExists = bExists; this.len = len; this.lastModified = lastModified; this.repository = repository; resolved = true; } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Resource#exists() */ public boolean exists() { if (!resolved) { resolve(); } return bExists; } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Resource#getContentLength() */ public long getContentLength() { if (!resolved) { resolve(); } return len; } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Resource#getLastModified() */ public long getLastModified() { if (!resolved) { resolve(); } return lastModified; } private void resolve() { Message.debug("SShResource: resolving " + uri); SshResource res = repository.resolveResource(uri); len = res.getContentLength(); lastModified = res.getLastModified(); bExists = res.exists(); resolved = true; Message.debug("SShResource: resolved " + this); } /* * (non-Javadoc) * * @see org.apache.ivy.repository.Resource#getName() */ public String getName() { return uri; } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("SshResource:"); buffer.append(uri); buffer.append(" ("); buffer.append(len); buffer.append(")]"); return buffer.toString(); } public boolean isLocal() { return false; } public Resource clone(String cloneName) { return new SshResource(repository, cloneName); } public InputStream openStream() throws IOException { return repository.openStream(this); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/url/000077500000000000000000000000001226750426600240525ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/url/ChainedRepository.java000066400000000000000000000100671226750426600303540ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.url; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.BasicResource; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; public class ChainedRepository extends AbstractRepository { private List/* Repository */repositories; public void setRepositories(List/* Repository */repositories) { this.repositories = repositories; } public Resource getResource(String source) throws IOException { Iterator it = repositories.iterator(); while (it.hasNext()) { Repository repository = (Repository) it.next(); logTry(repository); try { Resource r = repository.getResource(source); if (r != null && r.exists()) { logSuccess(repository); return r; } } catch (Exception e) { logFailed(repository, e); } } // resource that basically doesn't exists return new BasicResource(source, false, 0, 0, true); } public void get(String source, File destination) throws IOException { Iterator it = repositories.iterator(); while (it.hasNext()) { Repository repository = (Repository) it.next(); logTry(repository); boolean ok = false; try { repository.get(source, destination); ok = true; } catch (Exception e) { logFailed(repository, e); } if (ok) { logSuccess(repository); return; } } throw newIOEFail("copy " + source + " into " + destination); } public List list(String parent) throws IOException { Iterator it = repositories.iterator(); while (it.hasNext()) { Repository repository = (Repository) it.next(); logTry(repository); try { List list = repository.list(parent); if (list != null) { logSuccess(repository); return list; } } catch (Exception e) { logFailed(repository, e); } } throw newIOEFail("list contents in " + parent); } private void logTry(Repository repository) { Message.debug("Mirrored repository " + getName() + ": trying " + repository.getName()); } private void logFailed(Repository repository, Exception e) { Message.warn("Mirrored repository " + getName() + ": " + repository.getName() + " is not available", e); Message.warn("Trying the next one in the mirror list..."); } private void logSuccess(Repository repository) { Message.debug("Mirrored repository " + getName() + ": success with " + repository.getName()); } private IOException newIOEFail(String action) { return new IOException("Mirrored repository " + getName() + ": fail to " + action + " with every listed mirror"); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/url/URLRepository.java000066400000000000000000000121221226750426600274550ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.url; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.url.ApacheURLLister; public class URLRepository extends AbstractRepository { private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener(this); private Map resourcesCache = new HashMap(); public Resource getResource(String source) throws IOException { Resource res = (Resource) resourcesCache.get(source); if (res == null) { res = new URLResource(new URL(source)); resourcesCache.put(source, res); } return res; } public void get(String source, File destination) throws IOException { fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); try { Resource res = getResource(source); long totalLength = res.getContentLength(); if (totalLength > 0) { progress.setTotalLength(new Long(totalLength)); } FileUtil.copy(new URL(source), destination, progress); } catch (IOException ex) { fireTransferError(ex); throw ex; } catch (RuntimeException ex) { fireTransferError(ex); throw ex; } finally { progress.setTotalLength(null); } } public void put(File source, String destination, boolean overwrite) throws IOException { if (!overwrite && getResource(destination).exists()) { throw new IOException("destination file exists and overwrite == false"); } fireTransferInitiated(getResource(destination), TransferEvent.REQUEST_PUT); try { long totalLength = source.length(); if (totalLength > 0) { progress.setTotalLength(new Long(totalLength)); } FileUtil.copy(source, new URL(destination), progress); } catch (IOException ex) { fireTransferError(ex); throw ex; } catch (RuntimeException ex) { fireTransferError(ex); throw ex; } finally { progress.setTotalLength(null); } } private ApacheURLLister lister = new ApacheURLLister(); public List list(String parent) throws IOException { if (parent.startsWith("http")) { List urls = lister.listAll(new URL(parent)); if (urls != null) { List ret = new ArrayList(urls.size()); for (ListIterator iter = urls.listIterator(); iter.hasNext();) { URL url = (URL) iter.next(); ret.add(url.toExternalForm()); } return ret; } } else if (parent.startsWith("file")) { String path; try { URI uri = new URI(parent); if (uri.isOpaque()) { path = uri.getSchemeSpecificPart(); } else { path = uri.getPath(); } } catch (URISyntaxException e) { IOException ioe = new IOException("Couldn't list content of '" + parent + "'"); ioe.initCause(e); throw ioe; } File file = new File(path); if (file.exists() && file.isDirectory()) { String[] files = file.list(); List ret = new ArrayList(files.length); URL context = path.endsWith("/") ? new URL(parent) : new URL(parent + "/"); for (int i = 0; i < files.length; i++) { ret.add(new URL(context, files[i]).toExternalForm()); } return ret; } else { return Collections.EMPTY_LIST; } } return null; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/url/URLResource.java000066400000000000000000000062301226750426600270700ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.url; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import org.apache.ivy.plugins.repository.LocalizableResource; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.url.URLHandler.URLInfo; import org.apache.ivy.util.url.URLHandlerRegistry; public class URLResource implements LocalizableResource { private URL url; private boolean init = false; private long lastModified; private long contentLength; private boolean exists; public URLResource(URL url) { this.url = url; } public String getName() { return url.toExternalForm(); } public Resource clone(String cloneName) { try { return new URLResource(new URL(cloneName)); } catch (MalformedURLException e) { throw new IllegalArgumentException( "bad clone name provided: not suitable for an URLResource: " + cloneName); } } public long getLastModified() { if (!init) { init(); } return lastModified; } private void init() { URLInfo info = URLHandlerRegistry.getDefault().getURLInfo(url); contentLength = info.getContentLength(); lastModified = info.getLastModified(); exists = info.isReachable(); init = true; } public long getContentLength() { if (!init) { init(); } return contentLength; } public boolean exists() { if (!init) { init(); } return exists; } public URL getURL() { return url; } public String toString() { return getName(); } public boolean isLocal() { return url.getProtocol().equals("file"); } public InputStream openStream() throws IOException { return URLHandlerRegistry.getDefault().openStream(url); } public File getFile() { if (!isLocal()) { throw new IllegalStateException("Cannot get the local file for the not local resource " + url); } try { return new File(url.toURI()); } catch (URISyntaxException e) { return new File(url.getPath()); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vfs/000077500000000000000000000000001226750426600240465ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vfs/VfsRepository.java000066400000000000000000000207371226750426600275600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.vfs; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.vfs.FileContent; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileSystemException; import org.apache.commons.vfs.FileSystemManager; import org.apache.commons.vfs.FileType; import org.apache.commons.vfs.impl.StandardFileSystemManager; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.util.CopyProgressListener; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; /** * Implementation of a VFS repository */ public class VfsRepository extends AbstractRepository { /** * Name of the resource defining the Ivy VFS Repo configuration. */ private static final String IVY_VFS_CONFIG = "ivy_vfs.xml"; private StandardFileSystemManager manager = null; private final CopyProgressListener progress = new RepositoryCopyProgressListener(this); /** * Create a new Ivy VFS Repository Instance */ public VfsRepository() { } private FileSystemManager getVFSManager() throws IOException { synchronized (this) { if (manager == null) { manager = createVFSManager(); } } return manager; } private StandardFileSystemManager createVFSManager() throws IOException { StandardFileSystemManager result = null; try { /* * The DefaultFileSystemManager gets its configuration from the jakarta-vfs-common * implementation which includes the res and tmp schemes which are of no use to use * here. Using StandardFileSystemManager lets us specify which schemes to support as * well as providing a mechanism to change this support without recompilation. */ result = new StandardFileSystemManager() { protected void configurePlugins() throws FileSystemException { // disable automatic loading potential unsupported extensions } }; result.setConfiguration(getClass().getResource(IVY_VFS_CONFIG)); result.init(); // Generate and print a list of available schemes Message.verbose("Available VFS schemes..."); String[] schemes = result.getSchemes(); Arrays.sort(schemes); for (int i = 0; i < schemes.length; i++) { Message.verbose("VFS Supported Scheme: " + schemes[i]); } } catch (FileSystemException e) { /* * If our attempt to initialize a VFS Repository fails we log the failure but continue * on. Given that an Ivy instance may involve numerous different repository types, it * seems overly cautious to throw a runtime exception on the initialization failure of * just one repository type. */ Message.error("Unable to initialize VFS repository manager!"); Message.error(e.getLocalizedMessage()); IOException error = new IOException(e.getLocalizedMessage()); error.initCause(e); throw error; } return result; } protected void finalize() { if (manager != null) { manager.close(); manager = null; } } /** * Get a VfsResource * * @param source * a String identifying a VFS Resource * @throws IOException on failure * @see "Supported File Systems in the jakarta-commons-vfs documentation" */ public Resource getResource(String vfsURI) throws IOException { return new VfsResource(vfsURI, getVFSManager()); } /** * Transfer a VFS Resource from the repository to the local file system. * * @param srcVfsURI * a String identifying the VFS resource to be fetched * @param destination * a File identifying the destination file * @throws IOException on failure * @see "Supported File Systems in the jakarta-commons-vfs documentation" */ public void get(String srcVfsURI, File destination) throws IOException { VfsResource src = new VfsResource(srcVfsURI, getVFSManager()); fireTransferInitiated(src, TransferEvent.REQUEST_GET); try { FileContent content = src.getContent(); if (content == null) { throw new IllegalArgumentException("invalid vfs uri " + srcVfsURI + ": no content found"); } FileUtil.copy(content.getInputStream(), destination, progress); } catch (IOException ex) { fireTransferError(ex); throw ex; } catch (RuntimeException ex) { fireTransferError(ex); throw ex; } } /** * Return a listing of the contents of a parent directory. Listing is a set of strings * representing VFS URIs. * * @param vfsURI * providing identifying a VFS provided resource * @throws IOException * on failure. * @see "Supported File Systems in the jakarta-commons-vfs documentation" */ public List list(String vfsURI) throws IOException { ArrayList list = new ArrayList(); Message.debug("list called for URI" + vfsURI); FileObject resourceImpl = getVFSManager().resolveFile(vfsURI); Message.debug("resourceImpl=" + resourceImpl.toString()); Message.debug("resourceImpl.exists()" + resourceImpl.exists()); Message.debug("resourceImpl.getType()" + resourceImpl.getType()); Message.debug("FileType.FOLDER" + FileType.FOLDER); if ((resourceImpl != null) && resourceImpl.exists() && (resourceImpl.getType() == FileType.FOLDER)) { FileObject[] children = resourceImpl.getChildren(); for (int i = 0; i < children.length; i++) { FileObject child = children[i]; Message.debug("child " + i + child.getName().getURI()); list.add(VfsResource.normalize(child.getName().getURI())); } } return list; } /** * Transfer an Ivy resource to a VFS repository * * @param source * a File indentifying the local file to transfer to the repository * @param vfsURI * a String identifying the destination VFS Resource. * @param overwrite * whether to overwrite an existing resource. * @throws IOException on failure. * @see "Supported File Systems in the jakarta-commons-vfs documentation" */ public void put(File source, String vfsURI, boolean overwrite) throws IOException { VfsResource dest = new VfsResource(vfsURI, getVFSManager()); fireTransferInitiated(dest, TransferEvent.REQUEST_PUT); if (dest.physicallyExists() && !overwrite) { throw new IOException("Cannot copy. Destination file: " + dest.getName() + " exists and overwrite not set."); } if (dest.getContent() == null) { throw new IllegalArgumentException("invalid vfs uri " + vfsURI + " to put data to: resource has no content"); } FileUtil.copy(new FileInputStream(source), dest.getContent().getOutputStream(), progress); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vfs/VfsResource.java000066400000000000000000000143231226750426600271620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.vfs; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.apache.commons.vfs.FileContent; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileSystemException; import org.apache.commons.vfs.FileSystemManager; import org.apache.commons.vfs.FileType; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.VfsResolver; import org.apache.ivy.util.Message; /** * VFS implementation of the Resource interface */ public class VfsResource implements Resource { private String vfsURI; private FileSystemManager fsManager; private transient boolean init = false; private transient boolean exists; private transient long lastModified; private transient long contentLength; private transient FileContent content = null; private transient FileObject resourceImpl; // Constructor public VfsResource(String vfsURI, FileSystemManager fsManager) { this.vfsURI = vfsURI; this.fsManager = fsManager; this.init = false; } private void init() { if (!init) { try { resourceImpl = fsManager.resolveFile(vfsURI); content = resourceImpl.getContent(); exists = resourceImpl.exists(); lastModified = content.getLastModifiedTime(); contentLength = content.getSize(); } catch (FileSystemException e) { Message.debug(e); Message.verbose(e.getLocalizedMessage()); exists = false; lastModified = 0; contentLength = 0; } init = true; } } /** * Get a list of direct descendents of the given resource. Note that attempts to get a list of * children does not result in an error. Instead an error message is * logged and an empty ArrayList returned. * * @return A ArrayList of VFSResources */ public List getChildren() { init(); ArrayList list = new ArrayList(); try { if ((resourceImpl != null) && resourceImpl.exists() && (resourceImpl.getType() == FileType.FOLDER)) { FileObject[] children = resourceImpl.getChildren(); for (int i = 0; i < children.length; i++) { FileObject child = children[i]; list.add(normalize(child.getName().getURI())); } } } catch (IOException e) { Message.debug(e); Message.verbose(e.getLocalizedMessage()); } return list; } public FileContent getContent() { init(); return content; } /** * Get the name of the resource. * * @return a String representing the Resource URL. */ public String getName() { return normalize(vfsURI); } public Resource clone(String cloneName) { return new VfsResource(cloneName, fsManager); } /** * The VFS FileName getURI method seems to have a bug in it where file: URIs will have 4 forward * slashes instead of 3. * * @param vfsURI * @return a normalized String representing the VFS URI */ public static String normalize(String vfsURI) { if (vfsURI == null) { return ""; } if (vfsURI.startsWith("file:////")) { vfsURI = vfsURI.replaceFirst("////", "///"); } return vfsURI; } /** * Get the last modification time of the resource. * * @return a long indicating last modified time. */ public long getLastModified() { init(); return lastModified; } /** * Get the size of the resource * * @return a long representing the size of the resource (in bytes). */ public long getContentLength() { init(); return contentLength; } /** * Flag indicating whether a resource is available for querying * * @return true if the resource is available for querying, false * otherwise. */ public boolean exists() { init(); return exists; } /** * Return a flag indicating whether a provided VFS resource physically exists * * @return true if the resource physically exists, false otherwise. */ public boolean physicallyExists() { // TODO: there is no need for this method anymore, replace it by calling exists(); init(); try { return resourceImpl.exists(); // originally I only checked for a FileSystemException. I expanded it to // include all exceptions when I found it would throw a NPE exception when the query was // run on non-wellformed VFS URI. } catch (Exception e) { Message.verbose("Fail to check the existance of the resource " + getName(), e); return false; } } public String toString() { return VfsResolver.prepareForDisplay(getName()); } public boolean isLocal() { return getName().startsWith("file:"); } public InputStream openStream() throws IOException { return getContent().getInputStream(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vfs/ivy_vfs.xml000066400000000000000000000042061226750426600262570ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vsftp/000077500000000000000000000000001226750426600244125ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vsftp/VsftpRepository.java000066400000000000000000000640011226750426600304600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.vsftp; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyThread; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.event.IvyListener; import org.apache.ivy.core.event.resolve.EndResolveEvent; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.BasicResource; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.TransferEvent; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Message; /** * Repository using SecureCRT vsftp command line program to access an sftp repository This is * especially useful to leverage the gssapi authentication supported by SecureCRT. In caseswhere * usual sftp is enough, prefer the 100% java solution of sftp repository. This requires SecureCRT * to be in the PATH. Tested with SecureCRT 5.0.5 */ public class VsftpRepository extends AbstractRepository { private static final int LS_DATE_INDEX4 = 7; private static final int LS_DATE_INDEX3 = 6; private static final int LS_DATE_INDEX2 = 5; private static final int LS_DATE_INDEX1 = 4; private static final int LS_SIZE_INDEX = 3; private static final int LS_PARTS_NUMBER = 9; private static final int DISCONNECT_COMMAND_TIMEOUT = 300; private static final int REUSE_CONNECTION_SLEEP_TIME = 10; private static final int READER_ALIVE_SLEEP_TIME = 100; private static final int MAX_READER_ALIVE_ATTEMPT = 5; private static final int ERROR_SLEEP_TIME = 30; private static final int PROMPT_SLEEP_TIME = 50; private static final int MAX_READ_PROMPT_ATTEMPT = 5; private static final int GET_JOIN_MAX_TIME = 100; private static final int DEFAULT_REUSE_CONNECTION_TIME = 300000; // reuse connection during 5 minutes by default private static final int DEFAULT_READ_TIMEOUT = 30000; private static final String PROMPT = "vsftp> "; private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MMM dd, yyyy HH:mm", Locale.US); private String host; private String username; private String authentication = "gssapi"; private Reader in; private Reader err; private PrintWriter out; private volatile StringBuffer errors = new StringBuffer(); private long readTimeout = DEFAULT_READ_TIMEOUT; private long reuseConnection = DEFAULT_REUSE_CONNECTION_TIME; private volatile long lastCommand; private volatile boolean inCommand; private Process process; private Thread connectionCleaner; private Thread errorsReader; private volatile long errorsLastUpdateTime; private Ivy ivy = null; public Resource getResource(String source) throws IOException { initIvy(); return new VsftpResource(this, source); } private void initIvy() { ivy = IvyContext.getContext().getIvy(); } protected Resource getInitResource(String source) throws IOException { try { return lslToResource(source, sendCommand("ls -l " + source, true, true)); } catch (IOException ex) { cleanup(ex); throw ex; } finally { cleanup(); } } public void get(final String source, File destination) throws IOException { initIvy(); try { fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); File destDir = destination.getParentFile(); if (destDir != null) { sendCommand("lcd " + destDir.getAbsolutePath()); } if (destination.exists()) { destination.delete(); } int index = source.lastIndexOf('/'); String srcName = index == -1 ? source : source.substring(index + 1); final File to = destDir == null ? Checks.checkAbsolute(srcName, "source") : new File( destDir, srcName); final IOException[] ex = new IOException[1]; Thread get = new IvyThread() { public void run() { initContext(); try { sendCommand("get " + source, getExpectedDownloadMessage(source, to), 0); } catch (IOException e) { ex[0] = e; } } }; get.start(); long prevLength = 0; long lastUpdate = System.currentTimeMillis(); long timeout = readTimeout; while (get.isAlive()) { checkInterrupted(); long length = to.exists() ? to.length() : 0; if (length > prevLength) { fireTransferProgress(length - prevLength); lastUpdate = System.currentTimeMillis(); prevLength = length; } else { if (System.currentTimeMillis() - lastUpdate > timeout) { Message.verbose("download hang for more than " + timeout + "ms. Interrupting."); get.interrupt(); if (to.exists()) { to.delete(); } throw new IOException(source + " download timeout from " + getHost()); } } try { get.join(GET_JOIN_MAX_TIME); } catch (InterruptedException e) { if (to.exists()) { to.delete(); } return; } } if (ex[0] != null) { if (to.exists()) { to.delete(); } throw ex[0]; } to.renameTo(destination); fireTransferCompleted(destination.length()); } catch (IOException ex) { fireTransferError(ex); cleanup(ex); throw ex; } finally { cleanup(); } } public List list(String parent) throws IOException { initIvy(); try { if (!parent.endsWith("/")) { parent = parent + "/"; } String response = sendCommand("ls -l " + parent, true, true); if (response.startsWith("ls")) { return null; } String[] lines = response.split("\n"); List ret = new ArrayList(lines.length); for (int i = 0; i < lines.length; i++) { while (lines[i].endsWith("\r") || lines[i].endsWith("\n")) { lines[i] = lines[i].substring(0, lines[i].length() - 1); } if (lines[i].trim().length() != 0) { ret.add(parent + lines[i].substring(lines[i].lastIndexOf(' ') + 1)); } } return ret; } catch (IOException ex) { cleanup(ex); throw ex; } finally { cleanup(); } } public void put(File source, String destination, boolean overwrite) throws IOException { initIvy(); try { if (getResource(destination).exists()) { if (overwrite) { sendCommand("rm " + destination, getExpectedRemoveMessage(destination)); } else { return; } } int index = destination.lastIndexOf('/'); String destDir = null; if (index != -1) { destDir = destination.substring(0, index); mkdirs(destDir); sendCommand("cd " + destDir); } String to = destDir != null ? destDir + "/" + source.getName() : source.getName(); sendCommand("put " + source.getAbsolutePath(), getExpectedUploadMessage(source, to), 0); sendCommand("mv " + to + " " + destination); } catch (IOException ex) { cleanup(ex); throw ex; } finally { cleanup(); } } private void mkdirs(String destDir) throws IOException { if (dirExists(destDir)) { return; } if (destDir.endsWith("/")) { destDir = destDir.substring(0, destDir.length() - 1); } int index = destDir.lastIndexOf('/'); if (index != -1) { mkdirs(destDir.substring(0, index)); } sendCommand("mkdir " + destDir); } private boolean dirExists(String dir) throws IOException { return !sendCommand("ls " + dir, true).startsWith("ls: "); } protected String sendCommand(String command) throws IOException { return sendCommand(command, false, readTimeout); } protected void sendCommand(String command, Pattern expectedResponse) throws IOException { sendCommand(command, expectedResponse, readTimeout); } /** * The behaviour of vsftp with some commands is to log the resulting message on the error * stream, even if everything is ok. So it's quite difficult if there was an error or not. Hence * we compare the response with the expected message and deal with it. The problem is that this * is very specific to the version of vsftp used for the test, That's why expected messages are * obtained using overridable protected methods. */ protected void sendCommand(String command, Pattern expectedResponse, long timeout) throws IOException { String response = sendCommand(command, true, timeout); if (!expectedResponse.matcher(response).matches()) { Message.debug("invalid response from server:"); Message.debug("expected: '" + expectedResponse + "'"); Message.debug("was: '" + response + "'"); throw new IOException(response); } } protected String sendCommand(String command, boolean sendErrorAsResponse) throws IOException { return sendCommand(command, sendErrorAsResponse, readTimeout); } protected String sendCommand(String command, boolean sendErrorAsResponse, boolean single) throws IOException { return sendCommand(command, sendErrorAsResponse, single, readTimeout); } protected String sendCommand(String command, boolean sendErrorAsResponse, long timeout) throws IOException { return sendCommand(command, sendErrorAsResponse, false, timeout); } protected String sendCommand(String command, boolean sendErrorAsResponse, boolean single, long timeout) throws IOException { single = false; // use of alone commands does not work properly due to a long delay between // end of process and end of stream... checkInterrupted(); inCommand = true; errorsLastUpdateTime = 0; synchronized (this) { if (!single || in != null) { ensureConnectionOpened(); Message.debug("sending command '" + command + "' to " + getHost()); updateLastCommandTime(); out.println(command); out.flush(); } else { sendSingleCommand(command); } } try { return readResponse(sendErrorAsResponse, timeout); } finally { inCommand = false; if (single) { closeConnection(); } } } protected String readResponse(boolean sendErrorAsResponse) throws IOException { return readResponse(sendErrorAsResponse, readTimeout); } protected synchronized String readResponse(final boolean sendErrorAsResponse, long timeout) throws IOException { final StringBuffer response = new StringBuffer(); final IOException[] exc = new IOException[1]; final boolean[] done = new boolean[1]; Runnable r = new Runnable() { public void run() { synchronized (VsftpRepository.this) { try { int c; boolean getPrompt = false; // the reading is done in a for loop making five attempts to read the stream // if we do not reach the next prompt for (int attempts = 0; !getPrompt && attempts < MAX_READ_PROMPT_ATTEMPT; attempts++) { while ((c = in.read()) != -1) { attempts = 0; // we manage to read something, reset numer of // attempts response.append((char) c); if (response.length() >= PROMPT.length() && response.substring(response.length() - PROMPT.length(), response.length()).equals(PROMPT)) { response.setLength(response.length() - PROMPT.length()); getPrompt = true; break; } } if (!getPrompt) { try { Thread.sleep(PROMPT_SLEEP_TIME); } catch (InterruptedException e) { break; } } } if (getPrompt) { // wait enough for error stream to be fully read if (errorsLastUpdateTime == 0) { // no error written yet, but it may be pending... errorsLastUpdateTime = lastCommand; } while ((System.currentTimeMillis() - errorsLastUpdateTime) < PROMPT_SLEEP_TIME) { try { Thread.sleep(ERROR_SLEEP_TIME); } catch (InterruptedException e) { break; } } } if (errors.length() > 0) { if (sendErrorAsResponse) { response.append(errors); errors.setLength(0); } else { throw new IOException(chomp(errors).toString()); } } chomp(response); done[0] = true; } catch (IOException e) { exc[0] = e; } finally { VsftpRepository.this.notify(); } } } }; Thread reader = null; if (timeout == 0) { r.run(); } else { reader = new IvyThread(r); reader.start(); try { wait(timeout); } catch (InterruptedException e) { // nothing to do } } updateLastCommandTime(); if (exc[0] != null) { throw exc[0]; } else if (!done[0]) { if (reader != null && reader.isAlive()) { reader.interrupt(); for (int i = 0; i < MAX_READER_ALIVE_ATTEMPT && reader.isAlive(); i++) { try { Thread.sleep(READER_ALIVE_SLEEP_TIME); } catch (InterruptedException e) { break; } } if (reader.isAlive()) { reader.stop(); // no way to interrupt it non abruptly } } throw new IOException("connection timeout to " + getHost()); } else { if ("Not connected.".equals(response.toString())) { Message.info("vsftp connection to " + getHost() + " reset"); closeConnection(); throw new IOException("not connected to " + getHost()); } Message.debug("received response '" + response + "' from " + getHost()); return response.toString(); } } private synchronized void sendSingleCommand(String command) throws IOException { exec(getSingleCommand(command)); } protected synchronized void ensureConnectionOpened() throws IOException { if (in == null) { Message.verbose("connecting to " + getUsername() + "@" + getHost() + "... "); String connectionCommand = getConnectionCommand(); exec(connectionCommand); try { readResponse(false); // waits for first prompt if (reuseConnection > 0) { connectionCleaner = new IvyThread() { public void run() { initContext(); try { long sleep = REUSE_CONNECTION_SLEEP_TIME; while (in != null && sleep > 0) { sleep(sleep); sleep = reuseConnection - (System.currentTimeMillis() - lastCommand); if (inCommand) { sleep = sleep <= 0 ? reuseConnection : sleep; } } } catch (InterruptedException e) { // nothing to do } disconnect(); } }; connectionCleaner.start(); } if (ivy != null) { ivy.getEventManager().addIvyListener(new IvyListener() { public void progress(IvyEvent event) { disconnect(); event.getSource().removeIvyListener(this); } }, EndResolveEvent.NAME); } } catch (IOException ex) { closeConnection(); throw new IOException("impossible to connect to " + getUsername() + "@" + getHost() + " using " + getAuthentication() + ": " + ex.getMessage()); } Message.verbose("connected to " + getHost()); } } private void updateLastCommandTime() { lastCommand = System.currentTimeMillis(); } private void exec(String command) throws IOException { Message.debug("launching '" + command + "'"); process = Runtime.getRuntime().exec(command); in = new InputStreamReader(process.getInputStream()); err = new InputStreamReader(process.getErrorStream()); out = new PrintWriter(process.getOutputStream()); errorsReader = new IvyThread() { public void run() { initContext(); int c; try { // CheckStyle:InnerAssignment OFF while (err != null && (c = err.read()) != -1) { errors.append((char) c); errorsLastUpdateTime = System.currentTimeMillis(); } // CheckStyle:InnerAssignment ON } catch (IOException e) { // nothing to do } } }; errorsReader.start(); } private void checkInterrupted() { if (ivy != null) { ivy.checkInterrupted(); } } /** * Called whenever an api level method end */ private void cleanup(Exception ex) { if (ex.getMessage().equals("connection timeout to " + getHost())) { closeConnection(); } else { disconnect(); } } /** * Called whenever an api level method end */ private void cleanup() { if (reuseConnection == 0) { disconnect(); } } public synchronized void disconnect() { if (in != null) { Message.verbose("disconnecting from " + getHost() + "... "); try { sendCommand("exit", false, DISCONNECT_COMMAND_TIMEOUT); } catch (IOException e) { // nothing I can do } finally { closeConnection(); Message.verbose("disconnected of " + getHost()); } } } private synchronized void closeConnection() { if (connectionCleaner != null) { connectionCleaner.interrupt(); } if (errorsReader != null) { errorsReader.interrupt(); } try { process.destroy(); } catch (Exception ex) { // nothing I can do } try { in.close(); } catch (Exception e) { // nothing I can do } try { err.close(); } catch (Exception e) { // nothing I can do } try { out.close(); } catch (Exception e) { // nothing I can do } connectionCleaner = null; errorsReader = null; process = null; in = null; out = null; err = null; Message.debug("connection to " + getHost() + " closed"); } /** * Parses a ls -l line and transforms it in a resource * * @param file * @param responseLine * @return */ protected Resource lslToResource(String file, String responseLine) { if (responseLine == null || responseLine.startsWith("ls")) { return new BasicResource(file, false, 0, 0, false); } else { String[] parts = responseLine.split("\\s+"); if (parts.length != LS_PARTS_NUMBER) { Message.debug("unrecognized ls format: " + responseLine); return new BasicResource(file, false, 0, 0, false); } else { try { long contentLength = Long.parseLong(parts[LS_SIZE_INDEX]); String date = parts[LS_DATE_INDEX1] + " " + parts[LS_DATE_INDEX2] + " " + parts[LS_DATE_INDEX3] + " " + parts[LS_DATE_INDEX4]; return new BasicResource(file, true, contentLength, FORMAT.parse(date) .getTime(), false); } catch (Exception ex) { Message.warn("impossible to parse server response: " + responseLine, ex); return new BasicResource(file, false, 0, 0, false); } } } } protected String getSingleCommand(String command) { return "vsh -noprompt -auth " + authentication + " " + username + "@" + host + " " + command; } protected String getConnectionCommand() { return "vsftp -noprompt -auth " + authentication + " " + username + "@" + host; } protected Pattern getExpectedDownloadMessage(String source, File to) { return Pattern.compile("Downloading " + to.getName() + " from [^\\s]+"); } protected Pattern getExpectedRemoveMessage(String destination) { return Pattern.compile("Removing [^\\s]+"); } protected Pattern getExpectedUploadMessage(File source, String to) { return Pattern.compile("Uploading " + source.getName() + " to [^\\s]+"); } public String getAuthentication() { return authentication; } public void setAuthentication(String authentication) { this.authentication = authentication; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } private static StringBuffer chomp(StringBuffer str) { if (str == null || str.length() == 0) { return str; } while ("\n".equals(str.substring(str.length() - 1)) || "\r".equals(str.substring(str.length() - 1))) { str.setLength(str.length() - 1); } return str; } public String toString() { return getName() + " " + getUsername() + "@" + getHost() + " (" + getAuthentication() + ")"; } /** * Sets the reuse connection time. The same connection will be reused if the time here does not * last between two commands. O indicates that the connection should never be reused * * @param time */ public void setReuseConnection(long time) { this.reuseConnection = time; } public long getReadTimeout() { return readTimeout; } public void setReadTimeout(long readTimeout) { this.readTimeout = readTimeout; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/repository/vsftp/VsftpResource.java000066400000000000000000000035671226750426600301020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.repository.vsftp; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.plugins.repository.LazyResource; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; public class VsftpResource extends LazyResource { private VsftpRepository repository; public VsftpResource(VsftpRepository repository, String file) { super(file); this.repository = repository; } protected void init() { try { init(repository.getInitResource(getName())); } catch (IOException e) { Message.debug(e); Message.verbose(e.toString()); } } public InputStream openStream() throws IOException { throw new UnsupportedOperationException( "vsftp resource does not support openStream operation"); } public Resource clone(String cloneName) { try { return repository.getResource(cloneName); } catch (IOException e) { throw new RuntimeException(e); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/000077500000000000000000000000001226750426600226725ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/AbstractPatternsBasedResolver.java000066400000000000000000000331241226750426600315050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.settings.IvyPattern; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.plugins.resolver.util.ResourceMDParser; import org.apache.ivy.util.Message; /** * */ public abstract class AbstractPatternsBasedResolver extends BasicResolver { private List ivyPatterns = new ArrayList(); // List (String pattern) private List artifactPatterns = new ArrayList(); // List (String pattern) private boolean m2compatible = false; public AbstractPatternsBasedResolver() { } public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { ModuleRevisionId mrid = dd.getDependencyRevisionId(); if (isM2compatible()) { mrid = convertM2IdForResourceSearch(mrid); } return findResourceUsingPatterns(mrid, ivyPatterns, DefaultArtifact.newIvyArtifact(mrid, data.getDate()), getRMDParser(dd, data), data.getDate()); } public ResolvedResource findArtifactRef(Artifact artifact, Date date) { ModuleRevisionId mrid = artifact.getModuleRevisionId(); if (isM2compatible()) { mrid = convertM2IdForResourceSearch(mrid); } return findResourceUsingPatterns(mrid, artifactPatterns, artifact, getDefaultRMDParser(artifact.getModuleRevisionId().getModuleId()), date); } public ResolvedResource findResource(ResolvedResource[] rress, ResourceMDParser rmdparser, ModuleRevisionId mrid, Date date) { if (isM2compatible()) { // convert 'M2'-organisation back to 'Ivy'-organisation mrid = convertM2ResourceSearchIdToNormal(mrid); } return super.findResource(rress, rmdparser, mrid, date); } protected ResolvedResource findResourceUsingPatterns(ModuleRevisionId moduleRevision, List patternList, Artifact artifact, ResourceMDParser rmdparser, Date date) { List resolvedResources = new ArrayList(); Set foundRevisions = new HashSet(); boolean dynamic = getSettings().getVersionMatcher().isDynamic(moduleRevision); boolean stop = false; for (Iterator iter = patternList.iterator(); iter.hasNext() && !stop;) { String pattern = (String) iter.next(); ResolvedResource rres = findResourceUsingPattern(moduleRevision, pattern, artifact, rmdparser, date); if ((rres != null) && !foundRevisions.contains(rres.getRevision())) { // only add the first found ResolvedResource for each revision foundRevisions.add(rres.getRevision()); resolvedResources.add(rres); stop = !dynamic; // stop iterating if we are not searching a dynamic revision } } if (resolvedResources.size() > 1) { ResolvedResource[] rress = (ResolvedResource[]) resolvedResources .toArray(new ResolvedResource[resolvedResources.size()]); return findResource(rress, rmdparser, moduleRevision, date); } else if (resolvedResources.size() == 1) { return (ResolvedResource) resolvedResources.get(0); } else { return null; } } protected abstract ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, String pattern, Artifact artifact, ResourceMDParser rmdparser, Date date); protected Collection findNames(Map tokenValues, String token) { Collection names = new HashSet(); names.addAll(findIvyNames(tokenValues, token)); if (isAllownomd()) { names.addAll(findArtifactNames(tokenValues, token)); } return names; } protected Collection findIvyNames(Map tokenValues, String token) { Collection names = new HashSet(); tokenValues = new HashMap(tokenValues); tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy"); tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy"); tokenValues.put(IvyPatternHelper.EXT_KEY, "xml"); if (isM2compatible()) { convertM2TokenValuesForResourceSearch(tokenValues); } findTokenValues(names, getIvyPatterns(), tokenValues, token); filterNames(names); return names; } protected Collection findArtifactNames(Map tokenValues, String token) { Collection names = new HashSet(); tokenValues = new HashMap(tokenValues); tokenValues .put(IvyPatternHelper.ARTIFACT_KEY, tokenValues.get(IvyPatternHelper.MODULE_KEY)); tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar"); tokenValues.put(IvyPatternHelper.EXT_KEY, "jar"); if (isM2compatible()) { convertM2TokenValuesForResourceSearch(tokenValues); } findTokenValues(names, getArtifactPatterns(), tokenValues, token); filterNames(names); return names; } public Map[] listTokenValues(String[] tokens, Map criteria) { Set result = new LinkedHashSet(); // use ivy patterns List ivyPatterns = getIvyPatterns(); Map tokenValues = new HashMap(criteria); tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy"); tokenValues.put(IvyPatternHelper.EXT_KEY, getModuleDescriptorExtension()); if (isM2compatible()) { convertM2TokenValuesForResourceSearch(tokenValues); } for (Iterator it = ivyPatterns.iterator(); it.hasNext();) { String ivyPattern = (String) it.next(); result.addAll(resolveTokenValues(tokens, ivyPattern, tokenValues, false)); } if (isAllownomd()) { List artifactPatterns = getArtifactPatterns(); tokenValues = new HashMap(criteria); tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar"); tokenValues.put(IvyPatternHelper.EXT_KEY, "jar"); if (isM2compatible()) { convertM2TokenValuesForResourceSearch(tokenValues); } for (Iterator it = artifactPatterns.iterator(); it.hasNext();) { String artifactPattern = (String) it.next(); result.addAll(resolveTokenValues(tokens, artifactPattern, tokenValues, true)); } } return (Map[]) result.toArray(new Map[result.size()]); } protected String getModuleDescriptorExtension() { return "xml"; } private Set resolveTokenValues(String[] tokens, String pattern, Map criteria, boolean noMd) { Set result = new LinkedHashSet(); Set tokenSet = new HashSet(Arrays.asList(tokens)); Map tokenValues = new HashMap(); for (Iterator it = criteria.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Entry) it.next(); Object key = entry.getKey(); Object value = entry.getValue(); if (value instanceof String) { tokenValues.put(key, value); } } if (tokenSet.isEmpty()) { // no more tokens to resolve result.add(tokenValues); return result; } String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues); String token = IvyPatternHelper.getFirstToken(partiallyResolvedPattern); if ((token == null) && exist(partiallyResolvedPattern)) { // no more tokens to resolve result.add(tokenValues); return result; } tokenSet.remove(token); Matcher matcher = null; Object criteriaForToken = criteria.get(token); if (criteriaForToken instanceof Matcher) { matcher = (Matcher) criteriaForToken; } String[] values = listTokenValues(partiallyResolvedPattern, token); if (values == null) { return result; } List vals = new ArrayList(Arrays.asList(values)); filterNames(vals); for (Iterator it = vals.iterator(); it.hasNext();) { String value = (String) it.next(); if ((matcher != null) && !matcher.matches(value)) { continue; } tokenValues.put(token, value); String moreResolvedPattern = IvyPatternHelper.substituteTokens( partiallyResolvedPattern, tokenValues); Map newCriteria = new HashMap(criteria); newCriteria.put(token, value); if (noMd && "artifact".equals(token)) { newCriteria.put("module", value); } else if (noMd && "module".equals(token)) { newCriteria.put("artifact", value); } result.addAll(resolveTokenValues( (String[]) tokenSet.toArray(new String[tokenSet.size()]), moreResolvedPattern, newCriteria, noMd)); } return result; } protected abstract String[] listTokenValues(String pattern, String token); protected abstract boolean exist(String path); protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { // to be overridden by subclasses wanting to have listing features } /** * example of pattern : ~/Workspace/[module]/[module].ivy.xml * * @param pattern */ public void addIvyPattern(String pattern) { ivyPatterns.add(pattern); } public void addArtifactPattern(String pattern) { artifactPatterns.add(pattern); } public List getIvyPatterns() { return Collections.unmodifiableList(ivyPatterns); } public List getArtifactPatterns() { return Collections.unmodifiableList(artifactPatterns); } protected void setIvyPatterns(List patterns) { ivyPatterns = patterns; } protected void setArtifactPatterns(List patterns) { artifactPatterns = patterns; } /* * Methods respecting ivy conf method specifications */ public void addConfiguredIvy(IvyPattern p) { ivyPatterns.add(p.getPattern()); } public void addConfiguredArtifact(IvyPattern p) { artifactPatterns.add(p.getPattern()); } public void dumpSettings() { super.dumpSettings(); Message.debug("\t\tm2compatible: " + isM2compatible()); Message.debug("\t\tivy patterns:"); for (ListIterator iter = getIvyPatterns().listIterator(); iter.hasNext();) { String p = (String) iter.next(); Message.debug("\t\t\t" + p); } Message.debug("\t\tartifact patterns:"); for (ListIterator iter = getArtifactPatterns().listIterator(); iter.hasNext();) { String p = (String) iter.next(); Message.debug("\t\t\t" + p); } } public boolean isM2compatible() { return m2compatible; } public void setM2compatible(boolean compatible) { m2compatible = compatible; } protected ModuleRevisionId convertM2ResourceSearchIdToNormal(ModuleRevisionId mrid) { if (mrid.getOrganisation() == null || mrid.getOrganisation().indexOf('/') == -1) { return mrid; } return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('/', '.'), mrid.getName(), mrid.getBranch(), mrid.getRevision(), mrid.getQualifiedExtraAttributes()); } protected ModuleRevisionId convertM2IdForResourceSearch(ModuleRevisionId mrid) { if (mrid.getOrganisation() == null || mrid.getOrganisation().indexOf('.') == -1) { return mrid; } return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('.', '/'), mrid.getName(), mrid.getBranch(), mrid.getRevision(), mrid.getQualifiedExtraAttributes()); } protected String convertM2OrganizationForResourceSearch(String org) { return org.replace('.', '/'); } protected void convertM2TokenValuesForResourceSearch(Map tokenValues) { if (tokenValues.get(IvyPatternHelper.ORGANISATION_KEY) instanceof String) { tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, convertM2OrganizationForResourceSearch((String) tokenValues .get(IvyPatternHelper.ORGANISATION_KEY))); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java000066400000000000000000000542131226750426600270270ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Date; import java.util.Map; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.RelativeUrlResolver; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.CacheDownloadOptions; import org.apache.ivy.core.cache.CacheMetadataOptions; import org.apache.ivy.core.cache.DownloadListener; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.cache.ResolutionCacheManager; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.event.download.EndArtifactDownloadEvent; import org.apache.ivy.core.event.download.NeedArtifactEvent; import org.apache.ivy.core.event.download.StartArtifactDownloadEvent; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolveOptions; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.core.settings.Validatable; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.resolver.ChainResolver.ResolvedModuleRevisionArtifactInfo; import org.apache.ivy.plugins.resolver.util.HasLatestStrategy; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Message; /** * This abstract resolver only provides handling for resolver name */ public abstract class AbstractResolver implements DependencyResolver, HasLatestStrategy, Validatable { /** * True if parsed ivy files should be validated against xsd, false if they should not, null if * default behavior should be used */ private Boolean validate = null; private String name; private ResolverSettings settings; private EventManager eventManager = null; // may remain null /** * The latest strategy to use to find latest among several artifacts */ private LatestStrategy latestStrategy; private String latestStrategyName; /** * The namespace to which this resolver belongs */ private Namespace namespace; private String namespaceName; private String cacheManagerName; private RepositoryCacheManager repositoryCacheManager; // used to store default values for nested cache private String changingMatcherName; private String changingPattern; private Boolean checkmodified; public ResolverSettings getSettings() { return settings; } public ParserSettings getParserSettings() { return new ResolverParserSettings(); } public void setSettings(ResolverSettings ivy) { settings = ivy; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * this method should remove sensitive information from a location to be displayed in a log * * @param name * location * @return location with sensitive data replaced by stars */ public String hidePassword(String name) { return name; } protected boolean doValidate(ResolveData data) { if (validate != null) { return validate.booleanValue(); } else { return data.isValidate(); } } public boolean isValidate() { return validate == null ? true : validate.booleanValue(); } public void setValidate(boolean validate) { this.validate = Boolean.valueOf(validate); } protected void checkInterrupted() { IvyContext.getContext().getIvy().checkInterrupted(); } public void reportFailure() { Message.verbose("no failure report implemented by " + getName()); } public void reportFailure(Artifact art) { Message.verbose("no failure report implemented by " + getName()); } public String[] listTokenValues(String token, Map otherTokenValues) { return new String[0]; } public Map[] listTokenValues(String[] tokens, Map criteria) { return new Map[0]; } public OrganisationEntry[] listOrganisations() { return new OrganisationEntry[0]; } public ModuleEntry[] listModules(OrganisationEntry org) { return new ModuleEntry[0]; } public RevisionEntry[] listRevisions(ModuleEntry module) { return new RevisionEntry[0]; } public String toString() { return getName(); } public void dumpSettings() { Message.verbose("\t" + getName() + " [" + getTypeName() + "]"); Message.debug("\t\tcache: " + cacheManagerName); } public String getTypeName() { return getClass().getName(); } /** * Default implementation downloads the artifact without taking advantage of its location */ public ArtifactDownloadReport download(ArtifactOrigin artifact, DownloadOptions options) { DownloadReport r = download(new Artifact[] {artifact.getArtifact()}, options); return r.getArtifactReport(artifact.getArtifact()); } public boolean exists(Artifact artifact) { return locate(artifact) != null; } /** * Default implementation actually download the artifact Subclasses should overwrite this to * avoid the download */ public ArtifactOrigin locate(Artifact artifact) { DownloadReport dr = download(new Artifact[] {artifact}, new DownloadOptions()); if (dr == null) { /* * according to IVY-831, it seems that this actually happen sometime, while the contract * of DependencyResolver says that it should never return null */ throw new IllegalStateException("null download report returned by " + getName() + " (" + getClass().getName() + ")" + " when trying to download " + artifact); } ArtifactDownloadReport adr = dr.getArtifactReport(artifact); return adr.getDownloadStatus() == DownloadStatus.FAILED ? null : adr.getArtifactOrigin(); } public LatestStrategy getLatestStrategy() { if (latestStrategy == null) { initLatestStrategyFromSettings(); } return latestStrategy; } private void initLatestStrategyFromSettings() { if (getSettings() != null) { if (latestStrategyName != null && !"default".equals(latestStrategyName)) { latestStrategy = getSettings().getLatestStrategy(latestStrategyName); if (latestStrategy == null) { throw new IllegalStateException("unknown latest strategy '" + latestStrategyName + "'"); } } else { latestStrategy = getSettings().getDefaultLatestStrategy(); Message.debug(getName() + ": no latest strategy defined: using default"); } } else { throw new IllegalStateException("no ivy instance found: " + "impossible to get a latest strategy without ivy instance"); } } public void setLatestStrategy(LatestStrategy latestStrategy) { this.latestStrategy = latestStrategy; } public void setLatest(String strategyName) { latestStrategyName = strategyName; } public String getLatest() { if (latestStrategyName == null) { latestStrategyName = "default"; } return latestStrategyName; } public Namespace getNamespace() { if (namespace == null) { initNamespaceFromSettings(); } return namespace; } private void initNamespaceFromSettings() { if (getSettings() != null) { if (namespaceName != null) { namespace = getSettings().getNamespace(namespaceName); if (namespace == null) { throw new IllegalStateException("unknown namespace '" + namespaceName + "'"); } } else { namespace = getSettings().getSystemNamespace(); Message.debug(getName() + ": no namespace defined: using system"); } } else { Message.verbose(getName() + ": no namespace defined nor ivy instance: using system namespace"); namespace = Namespace.SYSTEM_NAMESPACE; } } public void setNamespace(String namespaceName) { this.namespaceName = namespaceName; } // Namespace conversion methods protected ModuleDescriptor toSystem(ModuleDescriptor md) { return NameSpaceHelper.toSystem(md, getNamespace()); } protected Artifact fromSystem(Artifact artifact) { return NameSpaceHelper.transform(artifact, getNamespace().getFromSystemTransformer()); } protected Artifact toSystem(Artifact artifact) { return NameSpaceHelper.transform(artifact, getNamespace().getToSystemTransformer()); } protected MetadataArtifactDownloadReport toSystem(MetadataArtifactDownloadReport report) { return NameSpaceHelper.transform(report, getNamespace().getToSystemTransformer()); } protected ResolvedModuleRevision toSystem(ResolvedModuleRevision rmr) { return NameSpaceHelper.toSystem(rmr, getNamespace()); } protected ModuleRevisionId toSystem(ModuleRevisionId resolvedMrid) { return getNamespace().getToSystemTransformer().transform(resolvedMrid); } protected DependencyDescriptor fromSystem(DependencyDescriptor dd) { return NameSpaceHelper.transform(dd, getNamespace().getFromSystemTransformer(), true); } protected DependencyDescriptor toSystem(DependencyDescriptor dd) { return NameSpaceHelper.transform(dd, getNamespace().getToSystemTransformer(), true); } protected IvyNode getSystemNode(ResolveData data, ModuleRevisionId resolvedMrid) { return data.getNode(toSystem(resolvedMrid)); } protected ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd, ResolveData data) { return findModuleInCache(dd, data, false); } protected ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd, ResolveData data, boolean anyResolver) { ResolvedModuleRevision rmr = getRepositoryCacheManager().findModuleInCache(dd, dd.getDependencyRevisionId(), getCacheOptions(data), anyResolver ? null : getName()); if (rmr == null) { return null; } if (data.getReport() != null && data.isBlacklisted(data.getReport().getConfiguration(), rmr.getId())) { Message.verbose("\t" + getName() + ": found revision in cache: " + rmr.getId() + " for " + dd + ", but it is blacklisted"); return null; } return rmr; } public void setChangingMatcher(String changingMatcherName) { this.changingMatcherName = changingMatcherName; } protected String getChangingMatcherName() { return changingMatcherName; } public void setChangingPattern(String changingPattern) { this.changingPattern = changingPattern; } protected String getChangingPattern() { return changingPattern; } public void setCheckmodified(boolean check) { checkmodified = Boolean.valueOf(check); } public RepositoryCacheManager getRepositoryCacheManager() { if (repositoryCacheManager == null) { initRepositoryCacheManagerFromSettings(); } return repositoryCacheManager; } private void initRepositoryCacheManagerFromSettings() { if (cacheManagerName == null) { repositoryCacheManager = settings.getDefaultRepositoryCacheManager(); if (repositoryCacheManager == null) { throw new IllegalStateException( "no default cache manager defined with current settings"); } } else { repositoryCacheManager = settings.getRepositoryCacheManager(cacheManagerName); if (repositoryCacheManager == null) { throw new IllegalStateException("unknown cache manager '" + cacheManagerName + "'. Available caches are " + Arrays.asList(settings.getRepositoryCacheManagers())); } } } public void setRepositoryCacheManager(RepositoryCacheManager repositoryCacheManager) { this.cacheManagerName = repositoryCacheManager.getName(); this.repositoryCacheManager = repositoryCacheManager; } public void setCache(String cacheName) { cacheManagerName = cacheName; } public void setEventManager(EventManager eventManager) { this.eventManager = eventManager; } public EventManager getEventManager() { return eventManager; } public void validate() { initRepositoryCacheManagerFromSettings(); initNamespaceFromSettings(); initLatestStrategyFromSettings(); } protected CacheMetadataOptions getCacheOptions(ResolveData data) { return (CacheMetadataOptions) new CacheMetadataOptions() .setChangingMatcherName(getChangingMatcherName()) .setChangingPattern(getChangingPattern()) .setCheckTTL(!data.getOptions().isUseCacheOnly()) .setCheckmodified( data.getOptions().isUseCacheOnly() ? Boolean.FALSE : checkmodified) .setValidate(doValidate(data)).setNamespace(getNamespace()) .setForce(data.getOptions().isRefresh()) .setListener(getDownloadListener(getDownloadOptions(data.getOptions()))); } protected CacheDownloadOptions getCacheDownloadOptions(DownloadOptions options) { CacheDownloadOptions cacheDownloadOptions = new CacheDownloadOptions(); cacheDownloadOptions.setListener(getDownloadListener(options)); return cacheDownloadOptions; } protected DownloadOptions getDownloadOptions(ResolveOptions options) { return (DownloadOptions) new DownloadOptions().setLog(options.getLog()); } public void abortPublishTransaction() throws IOException { /* Default implementation is a no-op */ } public void commitPublishTransaction() throws IOException { /* Default implementation is a no-op */ } public void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) throws IOException { /* Default implementation is a no-op */ } private DownloadListener getDownloadListener(final DownloadOptions options) { return new DownloadListener() { public void needArtifact(RepositoryCacheManager cache, Artifact artifact) { if (eventManager != null) { eventManager .fireIvyEvent(new NeedArtifactEvent(AbstractResolver.this, artifact)); } } public void startArtifactDownload(RepositoryCacheManager cache, ResolvedResource rres, Artifact artifact, ArtifactOrigin origin) { if (artifact.isMetadata() || LogOptions.LOG_QUIET.equals(options.getLog())) { Message.verbose("downloading " + rres.getResource() + " ..."); } else { Message.info("downloading " + rres.getResource() + " ..."); } if (eventManager != null) { eventManager.fireIvyEvent(new StartArtifactDownloadEvent(AbstractResolver.this, artifact, origin)); } } public void endArtifactDownload(RepositoryCacheManager cache, Artifact artifact, ArtifactDownloadReport adr, File archiveFile) { if (eventManager != null) { eventManager.fireIvyEvent(new EndArtifactDownloadEvent(AbstractResolver.this, artifact, adr, archiveFile)); } } }; } /** * Returns true if rmr1 is after rmr2, using the latest strategy to determine which is the * latest * * @param rmr1 * @param rmr2 * @return */ protected boolean isAfter(ResolvedModuleRevision rmr1, ResolvedModuleRevision rmr2, Date date) { ArtifactInfo[] ais = new ArtifactInfo[] {new ResolvedModuleRevisionArtifactInfo(rmr1), new ResolvedModuleRevisionArtifactInfo(rmr2)}; return getLatestStrategy().findLatest(ais, date) == ais[0]; } protected ResolvedModuleRevision checkLatest(DependencyDescriptor dd, ResolvedModuleRevision newModuleFound, ResolveData data) { Checks.checkNotNull(dd, "dd"); Checks.checkNotNull(data, "data"); // check if latest is asked and compare to return the most recent ResolvedModuleRevision previousModuleFound = data.getCurrentResolvedModuleRevision(); String newModuleDesc = describe(newModuleFound); Message.debug("\tchecking " + newModuleDesc + " against " + describe(previousModuleFound)); if (previousModuleFound == null) { Message.debug("\tmodule revision kept as first found: " + newModuleDesc); saveModuleRevisionIfNeeded(dd, newModuleFound); return newModuleFound; } else if (isAfter(newModuleFound, previousModuleFound, data.getDate())) { Message.debug("\tmodule revision kept as younger: " + newModuleDesc); saveModuleRevisionIfNeeded(dd, newModuleFound); return newModuleFound; } else if (!newModuleFound.getDescriptor().isDefault() && previousModuleFound.getDescriptor().isDefault()) { Message.debug("\tmodule revision kept as better (not default): " + newModuleDesc); saveModuleRevisionIfNeeded(dd, newModuleFound); return newModuleFound; } else { Message.debug("\tmodule revision discarded as older: " + newModuleDesc); return previousModuleFound; } } protected void saveModuleRevisionIfNeeded(DependencyDescriptor dd, ResolvedModuleRevision newModuleFound) { if (newModuleFound != null && getSettings().getVersionMatcher().isDynamic(dd.getDependencyRevisionId())) { getRepositoryCacheManager().saveResolvedRevision(dd.getDependencyRevisionId(), newModuleFound.getId().getRevision()); } } private String describe(ResolvedModuleRevision rmr) { if (rmr == null) { return "[none]"; } return rmr.getId() + (rmr.getDescriptor().isDefault() ? "[default]" : "") + " from " + rmr.getResolver().getName(); } private class ResolverParserSettings implements ParserSettings { public ConflictManager getConflictManager(String name) { return AbstractResolver.this.getSettings().getConflictManager(name); } public Namespace getContextNamespace() { return AbstractResolver.this.getNamespace(); } public String getDefaultBranch(ModuleId moduleId) { return AbstractResolver.this.getSettings().getDefaultBranch(moduleId); } public PatternMatcher getMatcher(String matcherName) { return AbstractResolver.this.getSettings().getMatcher(matcherName); } public Namespace getNamespace(String namespace) { return AbstractResolver.this.getSettings().getNamespace(namespace); } public RelativeUrlResolver getRelativeUrlResolver() { return AbstractResolver.this.getSettings().getRelativeUrlResolver(); } public ResolutionCacheManager getResolutionCacheManager() { return AbstractResolver.this.getSettings().getResolutionCacheManager(); } public DependencyResolver getResolver(ModuleRevisionId mRevId) { return AbstractResolver.this.getSettings().getResolver(mRevId); } public StatusManager getStatusManager() { return AbstractResolver.this.getSettings().getStatusManager(); } public File resolveFile(String filename) { return AbstractResolver.this.getSettings().resolveFile(filename); } public Map substitute(Map strings) { return AbstractResolver.this.getSettings().substitute(strings); } public String substitute(String value) { return AbstractResolver.this.getSettings().substitute(value); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/AbstractSshBasedResolver.java000066400000000000000000000127751226750426600304530ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.repository.ssh.AbstractSshBasedRepository; /** * Abstract base class for all resolvers using SSH All necessary connection parameters can be set * here via attributes. However all attributes defined in the pattern url of the resolver will have * higher priority and will overwrite the values given here. To specify connection parameters in the * pattern, you have to specify a full url and not just a path as pattern. e.g. * pattern="/path/to/my/repos/[artifact].[ext]" will use all connection parameters from this class * e.g. pattern="ssh://myserver.com/path/to/my/repos/[artifact].[ext]" will use all parameters from * this class with the exception of the host, which will be "myserver.com" e.g. * pattern="sftp://user:geheim@myserver.com:8022/path/to/my/repos/[artifact].[ext]" will use only * the keyFile and keyFilePassword from this class (if needed). Rest will come from the url. */ public abstract class AbstractSshBasedResolver extends RepositoryResolver { private boolean passfileSet = false; public AbstractSshBasedResolver() { super(); } private AbstractSshBasedRepository getSshBasedRepository() { return ((AbstractSshBasedRepository) getRepository()); } /** * Sets the location of the Public Key file to use for authentication * * @param filePath * full file path name */ public void setKeyFile(File filePath) { getSshBasedRepository().setKeyFile(filePath); } /** * Determines whether a local SSH agent may be used for authentication * * @param allowedAgentUse * true if an agent may be used if available */ public void setAllowedAgentUse(boolean allowedAgentUse) { getSshBasedRepository().setAllowedAgentUse(allowedAgentUse); } /** * Optional password file. If set the repository will use it as an encypted property file, to * load username and passwd entries, and to store them if the user choose to do so. Defaults to * user.dir/.ivy/[host].sftp.passwd, set it to null to disable this feature. */ public void setPassfile(File passfile) { getSshBasedRepository().setPassFile(passfile); passfileSet = true; } public void setSettings(IvySettings settings) { super.setSettings(settings); if (!passfileSet) { getSshBasedRepository().setPassFile( new File(settings.getDefaultIvyUserDir(), getSshBasedRepository().getHost() + ".ssh.passwd")); } } /** * Sets the password to authenticate the user if password based login is used if no password is * set and password based login is used, user will be prompted for it the password can also be * set by using a full url for the pattern, like * "sftp://user:password@myserver.com/path/to/repos/[artifact].[ext]" * * @param password * to use */ public void setUserPassword(String password) { getSshBasedRepository().setUserPassword(password); } /** * Sets the password to use for decrypting key file (if it is encrypted) if no password is set * and the keyfile is encrypted, the user will be prompted for the password if the keyfile is * passwordless, this parameter will be ignored if given * * @param password * to use */ public void setKeyFilePassword(String password) { getSshBasedRepository().setKeyFilePassword(password); } /** * sets the user to use for the ssh communication the user can also be set by using a full url * for the pattern, like "ssh://user@myserver.com/path/to/repos/[artifact].[ext]" * * @param user * on the target system */ public void setUser(String user) { getSshBasedRepository().setUser(user); } /** * sets the host to use for the ssh communication the host can also be set by using a full url * for the pattern, like "ssh://myserver.com/path/to/repos/[artifact].[ext]" * * @param host * of the target system */ public void setHost(String host) { getSshBasedRepository().setHost(host); } /** * sets the port to use for the ssh communication port 22 is default the port can also be set by * using a full url for the pattern, like * "sftp://myserver.com:8022/path/to/repos/[artifact].[ext]" * * @param port * of the target system */ public void setPort(int port) { getSshBasedRepository().setPort(port); } public abstract String getTypeName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java000066400000000000000000001433151226750426600263070ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.LogOptions; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.ModuleDescriptorWriter; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.report.MetadataArtifactDownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.plugins.repository.ArtifactResourceResolver; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.ResourceDownloader; import org.apache.ivy.plugins.repository.file.FileRepository; import org.apache.ivy.plugins.repository.file.FileResource; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.util.MDResolvedResource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.plugins.resolver.util.ResourceMDParser; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Checks; import org.apache.ivy.util.ChecksumHelper; import org.apache.ivy.util.HostUtil; import org.apache.ivy.util.Message; /** * */ public abstract class BasicResolver extends AbstractResolver { public static final String DESCRIPTOR_OPTIONAL = "optional"; public static final String DESCRIPTOR_REQUIRED = "required"; /** * Exception thrown internally in getDependency to indicate a dependency is unresolved. *

    * Due to the contract of getDependency, this exception is never thrown publicly, but rather * converted in a message (either error or verbose) and returning null *

    */ private static class UnresolvedDependencyException extends RuntimeException { private boolean error; /** * Dependency has not been resolved. This is not an error and won't log any message. */ public UnresolvedDependencyException() { this("", false); } /** * Dependency has not been resolved. This is an error and will log a message. */ public UnresolvedDependencyException(String message) { this(message, true); } /** * Dependency has not been resolved. The boolean tells if it is an error or not, a message * will be logged if non empty. */ public UnresolvedDependencyException(String message, boolean error) { super(message); this.error = error; } public boolean isError() { return error; } } public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); private String workspaceName; /** * True if the files resolved are dependent of the environment from which they have been * resolved, false otherwise. In general, relative paths are dependent of the environment, and * absolute paths including machine reference are not. */ private boolean envDependent = true; private List ivyattempts = new ArrayList(); private Map artattempts = new HashMap(); private boolean checkconsistency = true; private boolean allownomd = true; private boolean force = false; private String checksums = null; private URLRepository extartifactrep = new URLRepository(); // used only to download // external artifacts public BasicResolver() { workspaceName = HostUtil.getLocalHostName(); } public String getWorkspaceName() { return workspaceName; } public void setWorkspaceName(String workspaceName) { this.workspaceName = workspaceName; } public boolean isEnvDependent() { return envDependent; } public void setEnvDependent(boolean envDependent) { this.envDependent = envDependent; } public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { IvyContext context = IvyContext.pushNewCopyContext(); try { ResolvedModuleRevision mr = data.getCurrentResolvedModuleRevision(); if (mr != null) { if (shouldReturnResolvedModule(dd, mr)) { return mr; } } if (isForce()) { dd = dd.clone(ModuleRevisionId.newInstance(dd.getDependencyRevisionId(), "latest.integration")); } DependencyDescriptor systemDd = dd; DependencyDescriptor nsDd = fromSystem(dd); context.setDependencyDescriptor(systemDd); context.setResolveData(data); clearIvyAttempts(); clearArtifactAttempts(); ModuleRevisionId systemMrid = systemDd.getDependencyRevisionId(); ModuleRevisionId nsMrid = nsDd.getDependencyRevisionId(); checkRevision(systemMrid); boolean isDynamic = getAndCheckIsDynamic(systemMrid); // we first search for the dependency in cache ResolvedModuleRevision rmr = null; rmr = findModuleInCache(systemDd, data); if (rmr != null) { if (rmr.getDescriptor().isDefault() && rmr.getResolver() != this) { Message.verbose("\t" + getName() + ": found revision in cache: " + systemMrid + " (resolved by " + rmr.getResolver().getName() + "): but it's a default one, maybe we can find a better one"); } else if (isForce() && rmr.getResolver() != this) { Message.verbose("\t" + getName() + ": found revision in cache: " + systemMrid + " (resolved by " + rmr.getResolver().getName() + "): but we are in force mode, let's try to find one ourself"); } else { Message.verbose("\t" + getName() + ": revision in cache: " + systemMrid); return checkLatest(systemDd, checkForcedResolvedModuleRevision(rmr), data); } } if (data.getOptions().isUseCacheOnly()) { throw new UnresolvedDependencyException("\t" + getName() + " (useCacheOnly) : no ivy file found for " + systemMrid, false); } checkInterrupted(); ResolvedResource ivyRef = findIvyFileRef(nsDd, data); checkInterrupted(); // get module descriptor ModuleDescriptor nsMd; ModuleDescriptor systemMd = null; if (ivyRef == null) { if (!isAllownomd()) { throw new UnresolvedDependencyException("\t" + getName() + ": no ivy file found for " + systemMrid, false); } nsMd = DefaultModuleDescriptor.newDefaultInstance(nsMrid, nsDd.getAllDependencyArtifacts()); ResolvedResource artifactRef = findFirstArtifactRef(nsMd, nsDd, data); checkInterrupted(); if (artifactRef == null) { throw new UnresolvedDependencyException("\t" + getName() + ": no ivy file nor artifact found for " + systemMrid, false); } else { long lastModified = artifactRef.getLastModified(); if (lastModified != 0 && nsMd instanceof DefaultModuleDescriptor) { ((DefaultModuleDescriptor) nsMd).setLastModified(lastModified); } Message.verbose("\t" + getName() + ": no ivy file found for " + systemMrid + ": using default data"); if (isDynamic) { nsMd.setResolvedModuleRevisionId(ModuleRevisionId.newInstance(nsMrid, artifactRef.getRevision())); } systemMd = toSystem(nsMd); MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport( systemMd.getMetadataArtifact()); madr.setDownloadStatus(DownloadStatus.NO); madr.setSearched(true); rmr = new ResolvedModuleRevision(this, this, systemMd, madr, isForce()); getRepositoryCacheManager().cacheModuleDescriptor(this, artifactRef, toSystem(dd), systemMd.getAllArtifacts()[0], null, getCacheOptions(data)); } } else { if (ivyRef instanceof MDResolvedResource) { rmr = ((MDResolvedResource) ivyRef).getResolvedModuleRevision(); } if (rmr == null) { rmr = parse(ivyRef, systemDd, data); if (rmr == null) { throw new UnresolvedDependencyException(); } } if (!rmr.getReport().isDownloaded() && rmr.getReport().getLocalFile() != null) { return checkLatest(systemDd, checkForcedResolvedModuleRevision(rmr), data); } else { nsMd = rmr.getDescriptor(); // check descriptor data is in sync with resource revision and names systemMd = toSystem(nsMd); if (isCheckconsistency()) { checkDescriptorConsistency(systemMrid, systemMd, ivyRef); checkDescriptorConsistency(nsMrid, nsMd, ivyRef); } else { if (systemMd instanceof DefaultModuleDescriptor) { DefaultModuleDescriptor defaultMd = (DefaultModuleDescriptor) systemMd; ModuleRevisionId revision = getRevision(ivyRef, systemMrid, systemMd); defaultMd.setModuleRevisionId(revision); defaultMd.setResolvedModuleRevisionId(revision); } else { Message.warn("consistency disabled with instance of non DefaultModuleDescriptor..." + " module info can't be updated, so consistency check will be done"); checkDescriptorConsistency(nsMrid, nsMd, ivyRef); checkDescriptorConsistency(systemMrid, systemMd, ivyRef); } } rmr = new ResolvedModuleRevision(this, this, systemMd, toSystem(rmr.getReport()), isForce()); } } resolveAndCheckRevision(systemMd, systemMrid, ivyRef, isDynamic); resolveAndCheckPublicationDate(systemDd, systemMd, systemMrid, data); checkNotConvertedExclusionRule(systemMd, ivyRef, data); if (ivyRef == null || ivyRef.getResource() != null) { cacheModuleDescriptor(systemMd, systemMrid, ivyRef, rmr); } return checkLatest(systemDd, checkForcedResolvedModuleRevision(rmr), data); } catch (UnresolvedDependencyException ex) { if (ex.getMessage().length() > 0) { if (ex.isError()) { Message.error(ex.getMessage()); } else { Message.verbose(ex.getMessage()); } } return data.getCurrentResolvedModuleRevision(); } finally { IvyContext.popContext(); } } protected boolean shouldReturnResolvedModule(DependencyDescriptor dd, ResolvedModuleRevision mr) { // a resolved module revision has already been found by a prior dependency resolver // let's see if it should be returned and bypass this resolver ModuleRevisionId mrid = dd.getDependencyRevisionId(); boolean isDynamic = getSettings().getVersionMatcher().isDynamic(mrid); boolean shouldReturn = mr.isForce(); shouldReturn |= !isDynamic && !mr.getDescriptor().isDefault(); shouldReturn &= !isForce(); return shouldReturn; } private ResolvedModuleRevision checkForcedResolvedModuleRevision(ResolvedModuleRevision rmr) { if (rmr == null) { return null; } if (!isForce() || rmr.isForce()) { return rmr; } return new ResolvedModuleRevision(rmr.getResolver(), rmr.getArtifactResolver(), rmr.getDescriptor(), rmr.getReport(), true); } private void cacheModuleDescriptor(ModuleDescriptor systemMd, ModuleRevisionId systemMrid, ResolvedResource ivyRef, ResolvedModuleRevision rmr) { RepositoryCacheManager cacheManager = getRepositoryCacheManager(); final ModuleDescriptorParser parser = systemMd.getParser(); // the metadata artifact which was used to cache the original metadata file Artifact requestedMetadataArtifact = ivyRef == null ? systemMd.getMetadataArtifact() : parser.getMetadataArtifact( ModuleRevisionId.newInstance(systemMrid, systemMd.getRevision()), ivyRef.getResource()); cacheManager.originalToCachedModuleDescriptor(this, ivyRef, requestedMetadataArtifact, rmr, new ModuleDescriptorWriter() { public void write(ResolvedResource originalMdResource, ModuleDescriptor md, File src, File dest) throws IOException, ParseException { if (originalMdResource == null) { // a basic ivy file is written containing default data XmlModuleDescriptorWriter.write(md, dest); } else { // copy and update ivy file from source to cache parser.toIvyFile(new FileInputStream(src), originalMdResource.getResource(), dest, md); long repLastModified = originalMdResource.getLastModified(); if (repLastModified > 0) { dest.setLastModified(repLastModified); } } } }); } private void checkNotConvertedExclusionRule(ModuleDescriptor systemMd, ResolvedResource ivyRef, ResolveData data) { if (!getNamespace().equals(Namespace.SYSTEM_NAMESPACE) && !systemMd.isDefault() && data.getSettings().logNotConvertedExclusionRule() && systemMd instanceof DefaultModuleDescriptor) { DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) systemMd; if (dmd.isNamespaceUseful()) { Message.warn("the module descriptor " + ivyRef.getResource() + " has information which can't be converted into " + "the system namespace. " + "It will require the availability of the namespace '" + getNamespace().getName() + "' to be fully usable."); } } } private void resolveAndCheckPublicationDate(DependencyDescriptor systemDd, ModuleDescriptor systemMd, ModuleRevisionId systemMrid, ResolveData data) { // resolve and check publication date if (data.getDate() != null) { long pubDate = getPublicationDate(systemMd, systemDd, data); if (pubDate > data.getDate().getTime()) { throw new UnresolvedDependencyException("\t" + getName() + ": unacceptable publication date => was=" + new Date(pubDate) + " required=" + data.getDate()); } else if (pubDate == -1) { throw new UnresolvedDependencyException("\t" + getName() + ": impossible to guess publication date: artifact missing for " + systemMrid); } systemMd.setResolvedPublicationDate(new Date(pubDate)); } } protected void checkModuleDescriptorRevision(ModuleDescriptor systemMd, ModuleRevisionId systemMrid) { if (!getSettings().getVersionMatcher().accept(systemMrid, systemMd)) { throw new UnresolvedDependencyException("\t" + getName() + ": unacceptable revision => was=" + systemMd.getResolvedModuleRevisionId().getRevision() + " required=" + systemMrid.getRevision()); } } private boolean getAndCheckIsDynamic(ModuleRevisionId systemMrid) { boolean isDynamic = getSettings().getVersionMatcher().isDynamic(systemMrid); if (isDynamic && !acceptLatest()) { throw new UnresolvedDependencyException("dynamic revisions not handled by " + getClass().getName() + ". impossible to resolve " + systemMrid); } return isDynamic; } private void checkRevision(ModuleRevisionId systemMrid) { // check revision int index = systemMrid.getRevision().indexOf("@"); if (index != -1 && !systemMrid.getRevision().substring(index + 1).equals(workspaceName)) { throw new UnresolvedDependencyException("\t" + getName() + ": unhandled revision => " + systemMrid.getRevision()); } } private void resolveAndCheckRevision(ModuleDescriptor systemMd, ModuleRevisionId dependencyConstraint, ResolvedResource ivyRef, boolean isDynamic) { // we get the resolved module revision id from the descriptor: it may contain extra // attributes that were not included in the dependency constraint ModuleRevisionId resolvedMrid = systemMd.getResolvedModuleRevisionId(); if (resolvedMrid.getRevision() == null || resolvedMrid.getRevision().length() == 0 || resolvedMrid.getRevision().startsWith("working@")) { if (!isDynamic) { resolvedMrid = ModuleRevisionId.newInstance(resolvedMrid, dependencyConstraint.getRevision()); } else if (ivyRef == null) { resolvedMrid = systemMd.getMetadataArtifact().getModuleRevisionId(); } else if (ivyRef.getRevision() == null || ivyRef.getRevision().length() == 0) { resolvedMrid = ModuleRevisionId.newInstance(resolvedMrid, "working@" + getName()); } else { resolvedMrid = ModuleRevisionId.newInstance(resolvedMrid, ivyRef.getRevision()); } } if (isDynamic) { Message.verbose("\t\t[" + toSystem(resolvedMrid).getRevision() + "] " + dependencyConstraint.getModuleId()); } systemMd.setResolvedModuleRevisionId(resolvedMrid); checkModuleDescriptorRevision(systemMd, dependencyConstraint); } private ModuleRevisionId getRevision(ResolvedResource ivyRef, ModuleRevisionId askedMrid, ModuleDescriptor md) throws ParseException { Map allAttributes = new HashMap(); allAttributes.putAll(md.getQualifiedExtraAttributes()); allAttributes.putAll(askedMrid.getQualifiedExtraAttributes()); String revision = ivyRef.getRevision(); if (revision == null) { Message.debug("no revision found in reference for " + askedMrid); if (getSettings().getVersionMatcher().isDynamic(askedMrid)) { if (md.getModuleRevisionId().getRevision() == null) { revision = "working@" + getName(); } else { Message.debug("using " + askedMrid); revision = askedMrid.getRevision(); } } else { Message.debug("using " + askedMrid); revision = askedMrid.getRevision(); } } return ModuleRevisionId.newInstance(askedMrid.getOrganisation(), askedMrid.getName(), askedMrid.getBranch(), revision, allAttributes); } public ResolvedModuleRevision parse(final ResolvedResource mdRef, DependencyDescriptor dd, ResolveData data) throws ParseException { DependencyDescriptor nsDd = dd; dd = toSystem(nsDd); ModuleRevisionId mrid = dd.getDependencyRevisionId(); ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser( mdRef.getResource()); if (parser == null) { Message.warn("no module descriptor parser available for " + mdRef.getResource()); return null; } Message.verbose("\t" + getName() + ": found md file for " + mrid); Message.verbose("\t\t=> " + mdRef); Message.debug("\tparser = " + parser); ModuleRevisionId resolvedMrid = mrid; // first check if this dependency has not yet been resolved if (getSettings().getVersionMatcher().isDynamic(mrid)) { resolvedMrid = ModuleRevisionId.newInstance(mrid, mdRef.getRevision()); IvyNode node = data.getNode(resolvedMrid); if (node != null && node.getModuleRevision() != null) { // this revision has already be resolved : return it if (node.getDescriptor() != null && node.getDescriptor().isDefault()) { Message.verbose("\t" + getName() + ": found already resolved revision: " + resolvedMrid + ": but it's a default one, maybe we can find a better one"); } else { Message.verbose("\t" + getName() + ": revision already resolved: " + resolvedMrid); node.getModuleRevision().getReport().setSearched(true); return node.getModuleRevision(); } } } Artifact moduleArtifact = parser.getMetadataArtifact(resolvedMrid, mdRef.getResource()); return getRepositoryCacheManager().cacheModuleDescriptor(this, mdRef, dd, moduleArtifact, downloader, getCacheOptions(data)); } protected ResourceMDParser getRMDParser(final DependencyDescriptor dd, final ResolveData data) { return new ResourceMDParser() { public MDResolvedResource parse(Resource resource, String rev) { try { ResolvedModuleRevision rmr = BasicResolver.this.parse(new ResolvedResource( resource, rev), dd, data); if (rmr == null) { return null; } else { return new MDResolvedResource(resource, rev, rmr); } } catch (ParseException e) { Message.warn("Failed to parse the file '" + resource + "'", e); return null; } } }; } protected ResourceMDParser getDefaultRMDParser(final ModuleId mid) { return new ResourceMDParser() { public MDResolvedResource parse(Resource resource, String rev) { DefaultModuleDescriptor md = DefaultModuleDescriptor .newDefaultInstance(new ModuleRevisionId(mid, rev)); MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport( md.getMetadataArtifact()); madr.setDownloadStatus(DownloadStatus.NO); madr.setSearched(true); return new MDResolvedResource(resource, rev, new ResolvedModuleRevision( BasicResolver.this, BasicResolver.this, md, madr, isForce())); } }; } // private boolean isResolved(ResolveData data, ModuleRevisionId mrid) { // IvyNode node = getSystemNode(data, mrid); // return node != null && node.getModuleRevision() != null; // } // private void checkDescriptorConsistency(ModuleRevisionId mrid, ModuleDescriptor md, ResolvedResource ivyRef) throws ParseException { boolean ok = true; StringBuffer errors = new StringBuffer(); if (!mrid.getOrganisation().equals(md.getModuleRevisionId().getOrganisation())) { Message.error("\t" + getName() + ": bad organisation found in " + ivyRef.getResource() + ": expected='" + mrid.getOrganisation() + "' found='" + md.getModuleRevisionId().getOrganisation() + "'"); errors.append("bad organisation: expected='" + mrid.getOrganisation() + "' found='" + md.getModuleRevisionId().getOrganisation() + "'; "); ok = false; } if (!mrid.getName().equals(md.getModuleRevisionId().getName())) { Message.error("\t" + getName() + ": bad module name found in " + ivyRef.getResource() + ": expected='" + mrid.getName() + " found='" + md.getModuleRevisionId().getName() + "'"); errors.append("bad module name: expected='" + mrid.getName() + "' found='" + md.getModuleRevisionId().getName() + "'; "); ok = false; } if (mrid.getBranch() != null && !mrid.getBranch().equals(md.getModuleRevisionId().getBranch())) { Message.error("\t" + getName() + ": bad branch name found in " + ivyRef.getResource() + ": expected='" + mrid.getBranch() + " found='" + md.getModuleRevisionId().getBranch() + "'"); errors.append("bad branch name: expected='" + mrid.getBranch() + "' found='" + md.getModuleRevisionId().getBranch() + "'; "); ok = false; } if (ivyRef.getRevision() != null && !ivyRef.getRevision().startsWith("working@") && !mrid.getRevision().equals(md.getModuleRevisionId().getRevision())) { ModuleRevisionId expectedMrid = ModuleRevisionId.newInstance(mrid, mrid.getRevision()); if (!getSettings().getVersionMatcher().accept(expectedMrid, md)) { Message.error("\t" + getName() + ": bad revision found in " + ivyRef.getResource() + ": expected='" + ivyRef.getRevision() + " found='" + md.getModuleRevisionId().getRevision() + "'"); errors.append("bad revision: expected='" + ivyRef.getRevision() + "' found='" + md.getModuleRevisionId().getRevision() + "'; "); ok = false; } } if (!getSettings().getStatusManager().isStatus(md.getStatus())) { Message.error("\t" + getName() + ": bad status found in " + ivyRef.getResource() + ": '" + md.getStatus() + "'"); errors.append("bad status: '" + md.getStatus() + "'; "); ok = false; } for (Iterator it = mrid.getExtraAttributes().entrySet().iterator(); it.hasNext();) { Entry extra = (Entry) it.next(); if (extra.getValue() != null && !extra.getValue().equals(md.getExtraAttribute((String) extra.getKey()))) { String errorMsg = "bad " + extra.getKey() + " found in " + ivyRef.getResource() + ": expected='" + extra.getValue() + "' found='" + md.getExtraAttribute((String) extra.getKey()) + "'"; Message.error("\t" + getName() + ": " + errorMsg); errors.append(errorMsg + ";"); ok = false; } } if (!ok) { throw new ParseException("inconsistent module descriptor file found in '" + ivyRef.getResource() + "': " + errors, 0); } } /** * When the resolver has many choices, this function helps choosing one * * @param rress * the list of resolved resource which the resolver found to fit the requirement * @param rmdparser * the parser of module descriptor * @param mrid * the module being resolved * @param date * the current date * @return the selected resource */ public ResolvedResource findResource(ResolvedResource[] rress, ResourceMDParser rmdparser, ModuleRevisionId mrid, Date date) { String name = getName(); VersionMatcher versionMatcher = getSettings().getVersionMatcher(); ResolvedResource found = null; List sorted = getLatestStrategy().sort(rress); List rejected = new ArrayList(); List foundBlacklisted = new ArrayList(); IvyContext context = IvyContext.getContext(); for (ListIterator iter = sorted.listIterator(sorted.size()); iter.hasPrevious();) { ResolvedResource rres = (ResolvedResource) iter.previous(); // we start by filtering based on information already available, // even though we don't even know if the resource actually exist. // But checking for existence is most of the time more costly than checking // name, blacklisting and first level version matching if (filterNames(new ArrayList(Collections.singleton(rres.getRevision()))).isEmpty()) { Message.debug("\t" + name + ": filtered by name: " + rres); continue; } ModuleRevisionId foundMrid = ModuleRevisionId.newInstance(mrid, rres.getRevision()); ResolveData data = context.getResolveData(); if (data != null && data.getReport() != null && data.isBlacklisted(data.getReport().getConfiguration(), foundMrid)) { Message.debug("\t" + name + ": blacklisted: " + rres); rejected.add(rres.getRevision() + " (blacklisted)"); foundBlacklisted.add(foundMrid); continue; } if (!versionMatcher.accept(mrid, foundMrid)) { Message.debug("\t" + name + ": rejected by version matcher: " + rres); rejected.add(rres.getRevision()); continue; } if (rres.getResource() != null && !rres.getResource().exists()) { Message.debug("\t" + name + ": unreachable: " + rres + "; res=" + rres.getResource()); rejected.add(rres.getRevision() + " (unreachable)"); continue; } if ((date != null && rres.getLastModified() > date.getTime())) { Message.verbose("\t" + name + ": too young: " + rres); rejected.add(rres.getRevision() + " (" + rres.getLastModified() + ")"); continue; } if (versionMatcher.needModuleDescriptor(mrid, foundMrid)) { ResolvedResource r = rmdparser.parse(rres.getResource(), rres.getRevision()); if (r == null) { Message.debug("\t" + name + ": impossible to get module descriptor resource: " + rres); rejected.add(rres.getRevision() + " (no or bad MD)"); continue; } ModuleDescriptor md = ((MDResolvedResource) r).getResolvedModuleRevision() .getDescriptor(); if (md.isDefault()) { Message.debug("\t" + name + ": default md rejected by version matcher" + "requiring module descriptor: " + rres); rejected.add(rres.getRevision() + " (MD)"); continue; } else if (!versionMatcher.accept(mrid, md)) { Message.debug("\t" + name + ": md rejected by version matcher: " + rres); rejected.add(rres.getRevision() + " (MD)"); continue; } else { found = r; } } else { found = rres; } if (found != null) { break; } } if (found == null && !rejected.isEmpty()) { logAttempt(rejected.toString()); } if (found == null && !foundBlacklisted.isEmpty()) { // all acceptable versions have been blacklisted, this means that an unsolvable conflict // has been found DependencyDescriptor dd = context.getDependencyDescriptor(); IvyNode parentNode = context.getResolveData().getNode(dd.getParentRevisionId()); ConflictManager cm = parentNode.getConflictManager(mrid.getModuleId()); cm.handleAllBlacklistedRevisions(dd, foundBlacklisted); } return found; } /** * Filters names before returning them in the findXXXNames or findTokenValues method. *

    * Remember to call the super implementation when overriding this method. *

    * * @param names * the list to filter. * @return the filtered list */ protected Collection filterNames(Collection names) { getSettings().filterIgnore(names); return names; } protected void clearIvyAttempts() { ivyattempts.clear(); clearArtifactAttempts(); } protected void logIvyAttempt(String attempt) { ivyattempts.add(attempt); Message.verbose("\t\ttried " + attempt); } protected void logArtifactAttempt(Artifact art, String attempt) { List attempts = (List) artattempts.get(art); if (attempts == null) { attempts = new ArrayList(); artattempts.put(art, attempts); } attempts.add(attempt); Message.verbose("\t\ttried " + attempt); } protected void logAttempt(String attempt) { Artifact currentArtifact = (Artifact) IvyContext.getContext().get(getName() + ".artifact"); if (currentArtifact != null) { logArtifactAttempt(currentArtifact, attempt); } else { logIvyAttempt(attempt); } } public void reportFailure() { Message.warn("==== " + getName() + ": tried"); for (ListIterator iter = ivyattempts.listIterator(); iter.hasNext();) { String m = (String) iter.next(); Message.warn(" " + m); } for (Iterator iter = artattempts.keySet().iterator(); iter.hasNext();) { Artifact art = (Artifact) iter.next(); List attempts = (List) artattempts.get(art); if (attempts != null) { Message.warn(" -- artifact " + art + ":"); for (ListIterator iterator = attempts.listIterator(); iterator.hasNext();) { String m = (String) iterator.next(); Message.warn(" " + m); } } } } public void reportFailure(Artifact art) { Message.warn("==== " + getName() + ": tried"); List attempts = (List) artattempts.get(art); if (attempts != null) { for (ListIterator iter = attempts.listIterator(); iter.hasNext();) { String m = (String) iter.next(); Message.warn(" " + m); } } } protected boolean acceptLatest() { return true; } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { RepositoryCacheManager cacheManager = getRepositoryCacheManager(); clearArtifactAttempts(); DownloadReport dr = new DownloadReport(); for (int i = 0; i < artifacts.length; i++) { ArtifactDownloadReport adr = cacheManager.download(artifacts[i], artifactResourceResolver, downloader, getCacheDownloadOptions(options)); if (DownloadStatus.FAILED == adr.getDownloadStatus()) { if (!ArtifactDownloadReport.MISSING_ARTIFACT.equals(adr.getDownloadDetails())) { Message.warn("\t" + adr); } } else if (DownloadStatus.NO == adr.getDownloadStatus()) { Message.verbose("\t" + adr); } else if (LogOptions.LOG_QUIET.equals(options.getLog())) { Message.verbose("\t" + adr); } else { Message.info("\t" + adr); } dr.addArtifactReport(adr); checkInterrupted(); } return dr; } protected void clearArtifactAttempts() { artattempts.clear(); } public ArtifactDownloadReport download(final ArtifactOrigin origin, DownloadOptions options) { Checks.checkNotNull(origin, "origin"); return getRepositoryCacheManager().download(origin.getArtifact(), new ArtifactResourceResolver() { public ResolvedResource resolve(Artifact artifact) { try { Resource resource = getResource(origin.getLocation()); if (resource == null) { return null; } String revision = origin.getArtifact().getModuleRevisionId().getRevision(); return new ResolvedResource(resource, revision); } catch (IOException e) { Message.debug(e); return null; } } }, downloader, getCacheDownloadOptions(options)); } protected abstract Resource getResource(String source) throws IOException; public boolean exists(Artifact artifact) { ResolvedResource artifactRef = getArtifactRef(artifact, null); if (artifactRef != null) { return artifactRef.getResource().exists(); } return false; } public ArtifactOrigin locate(Artifact artifact) { ArtifactOrigin origin = getRepositoryCacheManager().getSavedArtifactOrigin( toSystem(artifact)); if (!ArtifactOrigin.isUnknown(origin)) { return origin; } ResolvedResource artifactRef = getArtifactRef(artifact, null); if (artifactRef != null && artifactRef.getResource().exists()) { return new ArtifactOrigin(artifact, artifactRef.getResource().isLocal(), artifactRef .getResource().getName()); } return null; } protected long getPublicationDate(ModuleDescriptor md, DependencyDescriptor dd, ResolveData data) { if (md.getPublicationDate() != null) { return md.getPublicationDate().getTime(); } ResolvedResource artifactRef = findFirstArtifactRef(md, dd, data); if (artifactRef != null) { return artifactRef.getLastModified(); } return -1; } public String toString() { return getName(); } public String[] listTokenValues(String token, Map otherTokenValues) { Collection ret = findNames(otherTokenValues, token); return (String[]) ret.toArray(new String[ret.size()]); } public OrganisationEntry[] listOrganisations() { Collection names = findNames(Collections.EMPTY_MAP, IvyPatternHelper.ORGANISATION_KEY); OrganisationEntry[] ret = new OrganisationEntry[names.size()]; int i = 0; for (Iterator iter = names.iterator(); iter.hasNext(); i++) { String org = (String) iter.next(); ret[i] = new OrganisationEntry(this, org); } return ret; } public ModuleEntry[] listModules(OrganisationEntry org) { Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); Collection names = findNames(tokenValues, IvyPatternHelper.MODULE_KEY); ModuleEntry[] ret = new ModuleEntry[names.size()]; int i = 0; for (Iterator iter = names.iterator(); iter.hasNext(); i++) { String name = (String) iter.next(); ret[i] = new ModuleEntry(org, name); } return ret; } public RevisionEntry[] listRevisions(ModuleEntry mod) { Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, mod.getOrganisation()); tokenValues.put(IvyPatternHelper.MODULE_KEY, mod.getModule()); Collection names = findNames(tokenValues, IvyPatternHelper.REVISION_KEY); RevisionEntry[] ret = new RevisionEntry[names.size()]; int i = 0; for (Iterator iter = names.iterator(); iter.hasNext(); i++) { String name = (String) iter.next(); ret[i] = new RevisionEntry(mod, name); } return ret; } protected abstract Collection findNames(Map tokenValues, String token); protected ResolvedResource findFirstArtifactRef(ModuleDescriptor md, DependencyDescriptor dd, ResolveData data) { ResolvedResource ret = null; String[] conf = md.getConfigurationsNames(); for (int i = 0; i < conf.length; i++) { Artifact[] artifacts = md.getArtifacts(conf[i]); for (int j = 0; j < artifacts.length; j++) { ret = getArtifactRef(artifacts[j], data.getDate()); if (ret != null) { return ret; } } } return null; } protected long getAndCheck(Resource resource, File dest) throws IOException { long size = get(resource, dest); String[] checksums = getChecksumAlgorithms(); boolean checked = false; for (int i = 0; i < checksums.length && !checked; i++) { checked = check(resource, dest, checksums[i]); } return size; } /** * Checks the given resource checksum if a checksum resource exists. * * @param resource * the resource to check * @param dest * the file where the resource has been downloaded * @param algorithm * the checksum algorithm to use * @return true if the checksum has been successfully checked, false if the checksum wasn't * available * @throws IOException * if a checksum exist but do not match the downloaded file checksum */ private boolean check(Resource resource, File dest, String algorithm) throws IOException { if (!ChecksumHelper.isKnownAlgorithm(algorithm)) { throw new IllegalArgumentException("Unknown checksum algorithm: " + algorithm); } Resource csRes = resource.clone(resource.getName() + "." + algorithm); if (csRes.exists()) { Message.debug(algorithm + " file found for " + resource + ": checking..."); File csFile = File.createTempFile("ivytmp", algorithm); try { get(csRes, csFile); try { ChecksumHelper.check(dest, csFile, algorithm); Message.verbose(algorithm + " OK for " + resource); return true; } catch (IOException ex) { dest.delete(); throw ex; } } finally { csFile.delete(); } } else { return false; } } protected ResolvedResource getArtifactRef(Artifact artifact, Date date) { IvyContext.getContext().set(getName() + ".artifact", artifact); try { ResolvedResource ret = findArtifactRef(artifact, date); if (ret == null && artifact.getUrl() != null) { URL url = artifact.getUrl(); Message.verbose("\tusing url for " + artifact + ": " + url); logArtifactAttempt(artifact, url.toExternalForm()); Resource resource; if ("file".equals(url.getProtocol())) { File f; try { f = new File(new URI(url.toExternalForm())); } catch (URISyntaxException e) { // unexpected, try to get the best of it f = new File(url.getPath()); } resource = new FileResource(new FileRepository(), f); } else { resource = new URLResource(url); } ret = new ResolvedResource(resource, artifact.getModuleRevisionId().getRevision()); } return ret; } finally { IvyContext.getContext().set(getName() + ".artifact", null); } } public ResolvedResource doFindArtifactRef(Artifact artifact, Date date) { return findArtifactRef(artifact, date); } protected abstract ResolvedResource findArtifactRef(Artifact artifact, Date date); protected abstract long get(Resource resource, File dest) throws IOException; public boolean isCheckconsistency() { return checkconsistency; } public void setCheckconsistency(boolean checkConsitency) { checkconsistency = checkConsitency; } public void setForce(boolean force) { this.force = force; } public boolean isForce() { return force; } public boolean isAllownomd() { return allownomd; } public void setAllownomd(boolean b) { Message.deprecated("allownomd is deprecated, please use descriptor=\"" + (b ? DESCRIPTOR_OPTIONAL : DESCRIPTOR_REQUIRED) + "\" instead"); allownomd = b; } /** * Sets the module descriptor presence rule. Should be one of {@link #DESCRIPTOR_REQUIRED} or * {@link #DESCRIPTOR_OPTIONAL}. * * @param descriptorRule * the descriptor rule to use with this resolver. */ public void setDescriptor(String descriptorRule) { if (DESCRIPTOR_REQUIRED.equals(descriptorRule)) { allownomd = false; } else if (DESCRIPTOR_OPTIONAL.equals(descriptorRule)) { allownomd = true; } else { throw new IllegalArgumentException("unknown descriptor rule '" + descriptorRule + "'. Allowed rules are: " + Arrays.asList(new String[] {DESCRIPTOR_REQUIRED, DESCRIPTOR_OPTIONAL})); } } public String[] getChecksumAlgorithms() { String csDef = checksums == null ? getSettings().getVariable("ivy.checksums") : checksums; if (csDef == null) { return new String[0]; } // csDef is a comma separated list of checksum algorithms to use with this resolver // we parse and return it as a String[] String[] checksums = csDef.split(","); List algos = new ArrayList(); for (int i = 0; i < checksums.length; i++) { String cs = checksums[i].trim(); if (!"".equals(cs) && !"none".equals(cs)) { algos.add(cs); } } return (String[]) algos.toArray(new String[algos.size()]); } public void setChecksums(String checksums) { this.checksums = checksums; } private final ArtifactResourceResolver artifactResourceResolver = new ArtifactResourceResolver() { public ResolvedResource resolve(Artifact artifact) { artifact = fromSystem(artifact); return getArtifactRef(artifact, null); } }; private final ResourceDownloader downloader = new ResourceDownloader() { public void download(Artifact artifact, Resource resource, File dest) throws IOException { if (dest.exists()) { dest.delete(); } File part = new File(dest.getAbsolutePath() + ".part"); if (resource.getName().equals(String.valueOf(artifact.getUrl()))) { if (part.getParentFile() != null) { part.getParentFile().mkdirs(); } extartifactrep.get(resource.getName(), part); } else { getAndCheck(resource, part); } if (!part.renameTo(dest)) { throw new IOException("impossible to move part file to definitive one: " + part + " -> " + dest); } } }; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java000066400000000000000000000170201226750426600262620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.DefaultRepositoryCacheManager; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.IvyNode; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.plugins.repository.file.FileResource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; public class CacheResolver extends FileSystemResolver { public CacheResolver() { } public CacheResolver(ResolverSettings settings) { setSettings(settings); setName("cache"); } public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { clearIvyAttempts(); ModuleRevisionId mrid = dd.getDependencyRevisionId(); // check revision ResolvedModuleRevision rmr = getRepositoryCacheManager().findModuleInCache(dd, mrid, getCacheOptions(data), null); if (rmr != null) { Message.verbose("\t" + getName() + ": revision in cache: " + mrid); return rmr; } else if (!getSettings().getVersionMatcher().isDynamic(mrid)) { Message.verbose("\t" + getName() + ": no ivy file in cache found for " + mrid); return null; } else { ensureConfigured(); ResolvedResource ivyRef = findIvyFileRef(dd, data); if (ivyRef != null) { Message.verbose("\t" + getName() + ": found ivy file in cache for " + mrid); Message.verbose("\t\t=> " + ivyRef); ModuleRevisionId resolvedMrid = ModuleRevisionId.newInstance(mrid, ivyRef.getRevision()); IvyNode node = data.getNode(resolvedMrid); if (node != null && node.getModuleRevision() != null) { // this revision has already be resolved : return it Message.verbose("\t" + getName() + ": revision already resolved: " + resolvedMrid); return node.getModuleRevision(); } rmr = getRepositoryCacheManager().findModuleInCache( dd.clone(ModuleRevisionId.newInstance(dd.getDependencyRevisionId(), ivyRef.getRevision())), dd.getDependencyRevisionId(), getCacheOptions(data), null); if (rmr != null) { Message.verbose("\t" + getName() + ": revision in cache: " + resolvedMrid); return rmr; } else { Message.error("\t" + getName() + ": inconsistent cache: clean it and resolve again"); return null; } } else { Message.verbose("\t" + getName() + ": no ivy file in cache found for " + mrid); return null; } } } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { ensureConfigured(); clearArtifactAttempts(); DownloadReport dr = new DownloadReport(); for (int i = 0; i < artifacts.length; i++) { final ArtifactDownloadReport adr = new ArtifactDownloadReport(artifacts[i]); dr.addArtifactReport(adr); ResolvedResource artifactRef = getArtifactRef(artifacts[i], null); if (artifactRef != null) { Message.verbose("\t[NOT REQUIRED] " + artifacts[i]); ArtifactOrigin origin = new ArtifactOrigin(artifacts[i], true, artifactRef .getResource().getName()); File archiveFile = ((FileResource) artifactRef.getResource()).getFile(); adr.setDownloadStatus(DownloadStatus.NO); adr.setSize(archiveFile.length()); adr.setArtifactOrigin(origin); adr.setLocalFile(archiveFile); } else { adr.setDownloadStatus(DownloadStatus.FAILED); } } return dr; } public boolean exists(Artifact artifact) { ensureConfigured(); return super.exists(artifact); } public ArtifactOrigin locate(Artifact artifact) { ensureConfigured(); return super.locate(artifact); } public void publish(Artifact artifact, File src, boolean overwrite) throws IOException { ensureConfigured(); super.publish(artifact, src, overwrite); } public OrganisationEntry[] listOrganisations() { ensureConfigured(); return super.listOrganisations(); } public ModuleEntry[] listModules(OrganisationEntry org) { ensureConfigured(); return super.listModules(org); } public RevisionEntry[] listRevisions(ModuleEntry module) { ensureConfigured(); return super.listRevisions(module); } public void dumpSettings() { Message.verbose("\t" + getName() + " [cache]"); } private void ensureConfigured() { if (getIvyPatterns().isEmpty()) { setIvyPatterns(new ArrayList()); setArtifactPatterns(new ArrayList()); RepositoryCacheManager[] caches = getSettings().getRepositoryCacheManagers(); for (int i = 0; i < caches.length; i++) { if (caches[i] instanceof DefaultRepositoryCacheManager) { DefaultRepositoryCacheManager c = (DefaultRepositoryCacheManager) caches[i]; addIvyPattern(c.getBasedir().getAbsolutePath() + "/" + c.getIvyPattern()); addArtifactPattern(c.getBasedir().getAbsolutePath() + "/" + c.getArtifactPattern()); } else { Message.verbose(caches[i] + ": cache implementation is not a DefaultRepositoryCacheManager:" + " unable to configure cache resolver with it"); } } } } public String getTypeName() { return "cache"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java000066400000000000000000000313061226750426600263040ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.resolver.util.HasLatestStrategy; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; import org.apache.ivy.util.StringUtils; /** * */ public class ChainResolver extends AbstractResolver { public static class ResolvedModuleRevisionArtifactInfo implements ArtifactInfo { private ResolvedModuleRevision rmr; public ResolvedModuleRevisionArtifactInfo(ResolvedModuleRevision rmr) { this.rmr = rmr; } public String getRevision() { return rmr.getId().getRevision(); } public long getLastModified() { return rmr.getPublicationDate().getTime(); } } private boolean returnFirst = false; private List chain = new ArrayList(); private boolean dual; public void add(DependencyResolver resolver) { chain.add(resolver); } public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { data = new ResolveData(data, doValidate(data)); List errors = new ArrayList(); ResolvedModuleRevision resolved = data.getCurrentResolvedModuleRevision(); ResolvedModuleRevision mr = resolved; if (mr == null) { Message.verbose(getName() + ": Checking cache for: " + dd); mr = findModuleInCache(dd, data, true); if (mr != null) { Message.verbose(getName() + ": module revision found in cache: " + mr.getId()); mr = forcedRevision(mr); } } for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); LatestStrategy oldLatest = setLatestIfRequired(resolver, getLatestStrategy()); try { ResolvedModuleRevision previouslyResolved = mr; data.setCurrentResolvedModuleRevision(previouslyResolved); mr = resolver.getDependency(dd, data); if (mr != previouslyResolved && isReturnFirst()) { mr = forcedRevision(mr); } } catch (Exception ex) { Message.verbose("problem occurred while resolving " + dd + " with " + resolver, ex); errors.add(ex); } finally { if (oldLatest != null) { setLatest(resolver, oldLatest); } } checkInterrupted(); } if (mr == null && !errors.isEmpty()) { if (errors.size() == 1) { Exception ex = (Exception) errors.get(0); if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else if (ex instanceof ParseException) { throw (ParseException) ex; } else { throw new RuntimeException(ex.toString(), ex); } } else { StringBuffer err = new StringBuffer(); for (Iterator iter = errors.iterator(); iter.hasNext();) { Exception ex = (Exception) iter.next(); err.append("\t").append(StringUtils.getErrorMessage(ex)).append("\n"); } err.setLength(err.length() - 1); throw new RuntimeException("several problems occurred while resolving " + dd + ":\n" + err); } } if (resolved == mr) { // nothing has actually been resolved here, we don't need to touch the returned rmr return resolved; } return resolvedRevision(mr); } private ResolvedModuleRevision resolvedRevision(ResolvedModuleRevision mr) { if (isDual() && mr != null) { return new ResolvedModuleRevision(mr.getResolver(), this, mr.getDescriptor(), mr.getReport(), mr.isForce()); } else { return mr; } } private ResolvedModuleRevision forcedRevision(ResolvedModuleRevision rmr) { if (rmr == null) { return null; } return new ResolvedModuleRevision(rmr.getResolver(), rmr.getArtifactResolver(), rmr.getDescriptor(), rmr.getReport(), true); } private LatestStrategy setLatestIfRequired(DependencyResolver resolver, LatestStrategy latestStrategy) { String latestName = getLatestStrategyName(resolver); if (latestName != null && !"default".equals(latestName)) { LatestStrategy oldLatest = getLatest(resolver); setLatest(resolver, latestStrategy); return oldLatest; } else { return null; } } public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); ResolvedResource result = resolver.findIvyFileRef(dd, data); if (result != null) { return result; } } return null; } public Map[] listTokenValues(String[] tokens, Map criteria) { Set result = new HashSet(); for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); Map[] temp = resolver.listTokenValues(tokens, new HashMap(criteria)); result.addAll(Arrays.asList(temp)); } return (Map[]) result.toArray(new Map[result.size()]); } public void reportFailure() { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); resolver.reportFailure(); } } public void reportFailure(Artifact art) { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); resolver.reportFailure(art); } } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { List artifactsToDownload = new ArrayList(Arrays.asList(artifacts)); DownloadReport report = new DownloadReport(); for (Iterator iter = chain.iterator(); iter.hasNext() && !artifactsToDownload.isEmpty();) { DependencyResolver resolver = (DependencyResolver) iter.next(); DownloadReport r = resolver.download( (Artifact[]) artifactsToDownload.toArray(new Artifact[artifactsToDownload.size()]), options); ArtifactDownloadReport[] adr = r.getArtifactsReports(); for (int i = 0; i < adr.length; i++) { if (adr[i].getDownloadStatus() != DownloadStatus.FAILED) { artifactsToDownload.remove(adr[i].getArtifact()); report.addArtifactReport(adr[i]); } } } for (Iterator iter = artifactsToDownload.iterator(); iter.hasNext();) { Artifact art = (Artifact) iter.next(); ArtifactDownloadReport adr = new ArtifactDownloadReport(art); adr.setDownloadStatus(DownloadStatus.FAILED); report.addArtifactReport(adr); } return report; } public List getResolvers() { return chain; } public void publish(Artifact artifact, File src, boolean overwrite) throws IOException { getFirstResolver().publish(artifact, src, overwrite); } public void abortPublishTransaction() throws IOException { getFirstResolver().abortPublishTransaction(); } public void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) throws IOException { getFirstResolver().beginPublishTransaction(module, overwrite); } public void commitPublishTransaction() throws IOException { getFirstResolver().commitPublishTransaction(); } private DependencyResolver getFirstResolver() { if (chain.isEmpty()) { throw new IllegalStateException("invalid chain resolver with no sub resolver"); } return ((DependencyResolver) chain.get(0)); } public boolean isReturnFirst() { return returnFirst; } public void setReturnFirst(boolean returnFirst) { this.returnFirst = returnFirst; } public void dumpSettings() { Message.verbose("\t" + getName() + " [chain] " + chain); Message.debug("\t\treturn first: " + isReturnFirst()); Message.debug("\t\tdual: " + isDual()); for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver r = (DependencyResolver) iter.next(); Message.debug("\t\t-> " + r.getName()); } } public boolean exists(Artifact artifact) { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); if (resolver.exists(artifact)) { return true; } } return false; } public ArtifactOrigin locate(Artifact artifact) { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); ArtifactOrigin origin = resolver.locate(artifact); if (!ArtifactOrigin.isUnknown(origin)) { return origin; } } return ArtifactOrigin.unkwnown(artifact); } public ArtifactDownloadReport download(ArtifactOrigin artifact, DownloadOptions options) { for (Iterator iter = chain.iterator(); iter.hasNext();) { DependencyResolver resolver = (DependencyResolver) iter.next(); ArtifactDownloadReport adr = resolver.download(artifact, options); if (adr.getDownloadStatus() != DownloadStatus.FAILED) { return adr; } } ArtifactDownloadReport adr = new ArtifactDownloadReport(artifact.getArtifact()); adr.setDownloadStatus(DownloadStatus.FAILED); return adr; } private static void setLatest(DependencyResolver resolver, LatestStrategy latest) { if (resolver instanceof HasLatestStrategy) { HasLatestStrategy r = (HasLatestStrategy) resolver; r.setLatestStrategy(latest); } } private static LatestStrategy getLatest(DependencyResolver resolver) { if (resolver instanceof HasLatestStrategy) { HasLatestStrategy r = (HasLatestStrategy) resolver; return r.getLatestStrategy(); } return null; } private static String getLatestStrategyName(DependencyResolver resolver) { if (resolver instanceof HasLatestStrategy) { HasLatestStrategy r = (HasLatestStrategy) resolver; return r.getLatest(); } return null; } public void setDual(boolean b) { dual = b; } public boolean isDual() { return dual; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java000066400000000000000000000176601226750426600273470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.Map; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.resolver.util.ResolvedResource; /** * */ public interface DependencyResolver { String getName(); /** * Should only be used by configurator * * @param name * the new name of the resolver */ void setName(String name); /** * Resolve a module by id, getting its module descriptor and resolving the revision if it's a * latest one (i.e. a revision uniquely identifying the revision of a module in the current * environment - If this revision is not able to identify uniquely the revision of the module * outside of the current environment, then the resolved revision must begin by ##) * * @throws ParseException */ ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException; /** * Finds the module descriptor for the specified DependencyDescriptor. If this resolver * can't find the module descriptor, null is returned. * * @param dd * the dependency descriptor * @param data * the resolve data * @return the module descriptor, or null */ ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data); /** * Download artifacts with specified DownloadOptions. *

    * The resolver will always make a best effort, and do not stop when an artifact is not * available. It rather continue to attempt to download other requested artifacts, and report * what has been done in the returned DownloadReport. *

    *

    * The returned DownloadReport is never null, and always contain an * {@link ArtifactDownloadReport} for each requested Artifact. *

    * * @param artifacts * an array of artifacts to download. Must not be null. * @param options * options to apply for this download. Must not be null. * @return a DownloadReport with details about each Artifact download. */ DownloadReport download(Artifact[] artifacts, DownloadOptions options); /** * Download an artifact according to the given DownloadOptions. *

    * This methods is an alternative to {@link #download(Artifact[], DownloadOptions)}, which * locates and downloads a set of artifacts. This method uses an {@link ArtifactOrigin}, and as * such is only used to materialize an already located Artifact. *

    * * @param artifact * the location of the artifact to download. Must not be null. * @param options * options to apply for this download. Must not be null. * @return a report detailing how the download has gone, is never null. */ ArtifactDownloadReport download(ArtifactOrigin artifact, DownloadOptions options); /** * Returns true if the given artifact can be located by this resolver and actually * exist. * * @param artifact * the artifact which should be tested. * @return true if the given artifact can be located by this resolver and actually * exist. */ boolean exists(Artifact artifact); /** * Locates the given artifact and returns its location if it can be located by this resolver and * if it actually exists, or null in other cases. * * @param artifact * the artifact which should be located * @return the artifact location, or null if it can't be located by this resolver * or doesn't exist. */ ArtifactOrigin locate(Artifact artifact); void publish(Artifact artifact, File src, boolean overwrite) throws IOException; void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) throws IOException; void abortPublishTransaction() throws IOException; void commitPublishTransaction() throws IOException; /** * Reports last resolve failure as Messages */ void reportFailure(); /** * Reports last artifact download failure as Messages * * @param art */ void reportFailure(Artifact art); // listing methods, enable to know what is available from this resolver // the listing methods must only list entries directly // available from them, no recursion is needed as long as sub resolvers // are registered in ivy too. /** * List all the values the given token can take if other tokens are set as described in the * otherTokenValues map. For instance, if token = "revision" and the map contains * "organisation"->"foo" "module"->"bar" The results will be the list of revisions of the module * bar from the org foo. *

    * Note that listing does not take into account namespaces, and return raw information without * any namespace transformation. The caller is responsible for calling namespace transformation * with the Namespace returned by {@link #getNamespace()}. *

    */ String[] listTokenValues(String token, Map otherTokenValues); /** * Same as {@link #listTokenValues(String, Map)} but more generic. * * @param tokens * the tokens of the query * @param criteria * the token which have values * @return the list of token values (Map[]), must not be null */ Map[] listTokenValues(String[] tokens, Map criteria); OrganisationEntry[] listOrganisations(); ModuleEntry[] listModules(OrganisationEntry org); RevisionEntry[] listRevisions(ModuleEntry module); /** * Returns the namespace associated with this resolver. * * @return the namespace associated with this resolver. */ Namespace getNamespace(); void dumpSettings(); void setSettings(ResolverSettings settings); /** * Returns the {@link RepositoryCacheManager} used to manage the repository cache associated * with this dependency resolver. * * @return the {@link RepositoryCacheManager} used to manage the repository cache associated * with this dependency resolver. */ RepositoryCacheManager getRepositoryCacheManager(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/DualResolver.java000066400000000000000000000203051226750426600261440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.Arrays; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; /** * DualResolver is used to resolve dependencies with one dependency revolver, called ivy resolver, * and then download artifacts found in the resolved dependencies from a second dependency resolver, * called artifact resolver. It is especially useful with resolvers using repository where there is * a lot of artifact, but no ivy file, like the maven ibiblio repository. If no ivy file is found by * the ivy resolver, the artifact resolver is used to check if there is artifact corresponding to * the request (with default ivy file). For artifact download, however, only the artifact resolver * is used. Exactly two resolvers should be added to this resolver for it to work properly. The * first resolver added if the ivy resolver, the second is the artifact one. */ public class DualResolver extends AbstractResolver { public static final String DESCRIPTOR_OPTIONAL = "optional"; public static final String DESCRIPTOR_REQUIRED = "required"; private DependencyResolver ivyResolver; private DependencyResolver artifactResolver; private boolean allownomd = true; public void add(DependencyResolver resolver) { if (ivyResolver == null) { ivyResolver = resolver; } else if (artifactResolver == null) { artifactResolver = resolver; } else { throw new IllegalStateException( "exactly two resolvers must be added: ivy(1) and artifact(2) one"); } } public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { if (ivyResolver == null || artifactResolver == null) { throw new IllegalStateException( "exactly two resolvers must be added: ivy(1) and artifact(2) one"); } ResolvedModuleRevision resolved = data.getCurrentResolvedModuleRevision(); data = new ResolveData(data, doValidate(data)); final ResolvedModuleRevision mr = ivyResolver.getDependency(dd, data); if (mr == null) { checkInterrupted(); if (isAllownomd()) { Message.verbose("ivy resolver didn't find " + dd + ": trying with artifact resolver"); return artifactResolver.getDependency(dd, data); } else { return null; } } else { if (mr == resolved) { // nothing has actually been resolved here, we don't need to touch the returned rmr return mr; } return new ResolvedModuleRevision(mr.getResolver(), this, mr.getDescriptor(), mr.getReport(), mr.isForce()); } } public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { return ivyResolver.findIvyFileRef(dd, data); } public void reportFailure() { ivyResolver.reportFailure(); artifactResolver.reportFailure(); } public void reportFailure(Artifact art) { ivyResolver.reportFailure(art); artifactResolver.reportFailure(art); } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { return artifactResolver.download(artifacts, options); } public DependencyResolver getArtifactResolver() { return artifactResolver; } public void setArtifactResolver(DependencyResolver artifactResolver) { this.artifactResolver = artifactResolver; } public DependencyResolver getIvyResolver() { return ivyResolver; } public void setIvyResolver(DependencyResolver ivyResolver) { this.ivyResolver = ivyResolver; } public void publish(Artifact artifact, File src, boolean overwrite) throws IOException { if ("ivy".equals(artifact.getType())) { ivyResolver.publish(artifact, src, overwrite); } else { artifactResolver.publish(artifact, src, overwrite); } } public void abortPublishTransaction() throws IOException { ivyResolver.abortPublishTransaction(); artifactResolver.abortPublishTransaction(); } public void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) throws IOException { ivyResolver.beginPublishTransaction(module, overwrite); artifactResolver.beginPublishTransaction(module, overwrite); } public void commitPublishTransaction() throws IOException { ivyResolver.commitPublishTransaction(); artifactResolver.commitPublishTransaction(); } public void dumpSettings() { if (ivyResolver == null || artifactResolver == null) { throw new IllegalStateException( "exactly two resolvers must be added: ivy(1) and artifact(2) one"); } Message.verbose("\t" + getName() + " [dual " + ivyResolver.getName() + " " + artifactResolver.getName() + "]"); } public boolean exists(Artifact artifact) { if (artifact.isMetadata()) { return ivyResolver.exists(artifact); } else { return artifactResolver.exists(artifact); } } public ArtifactOrigin locate(Artifact artifact) { if (artifact.isMetadata()) { return ivyResolver.locate(artifact); } else { return artifactResolver.locate(artifact); } } public ArtifactDownloadReport download(ArtifactOrigin artifact, DownloadOptions options) { if (artifact.getArtifact().isMetadata()) { return ivyResolver.download(artifact, options); } else { return artifactResolver.download(artifact, options); } } public boolean isAllownomd() { return allownomd; } public void setAllownomd(boolean allownomd) { Message.deprecated("allownomd is deprecated, please use descriptor=\"" + (allownomd ? DESCRIPTOR_OPTIONAL : DESCRIPTOR_REQUIRED) + "\" instead"); this.allownomd = allownomd; } /** * Sets the module descriptor presence rule. Should be one of {@link #DESCRIPTOR_REQUIRED} or * {@link #DESCRIPTOR_OPTIONAL}. * * @param descriptorRule * the descriptor rule to use with this resolver. */ public void setDescriptor(String descriptorRule) { if (DESCRIPTOR_REQUIRED.equals(descriptorRule)) { allownomd = false; } else if (DESCRIPTOR_OPTIONAL.equals(descriptorRule)) { allownomd = true; } else { throw new IllegalArgumentException("unknown descriptor rule '" + descriptorRule + "'. Allowed rules are: " + Arrays.asList(new String[] {DESCRIPTOR_REQUIRED, DESCRIPTOR_OPTIONAL})); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java000066400000000000000000000300731226750426600273460ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvyPattern; import org.apache.ivy.plugins.repository.file.FileRepository; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Message; /** */ public class FileSystemResolver extends RepositoryResolver { private static final String TRANSACTION_DESTINATION_SUFFIX = ".part"; private static final Pattern TRANSACTION_PATTERN = Pattern .compile("(.*[/\\\\]\\[revision\\])([/\\\\].+)"); /** * Transactional mode. * * auto: use transaction if possible, only log verbose message if not true: always use * transaction, fail if not supported false: never use transactions */ private String transactional = "auto"; // one of 'auto', 'true' or 'false' /** * When set indicates if this resolver supports transaction */ private Boolean supportTransaction; /** * The pattern leading to the directory where files are published before being moved at the end * of a transaction */ private String baseTransactionPattern; /** * Map between actual patterns and patterns used during the transaction to put files in a * temporary directory */ private Map/* */fullTransactionPatterns = new HashMap(); /** * Location where files are published during the transaction */ private File transactionTempDir; /** * Location where files should end up at the end of the transaction */ private File transactionDestDir; public FileSystemResolver() { setRepository(new FileRepository()); } public String getTypeName() { return "file"; } public boolean isLocal() { return getFileRepository().isLocal(); } public void setLocal(boolean local) { getFileRepository().setLocal(local); } private FileRepository getFileRepository() { return (FileRepository) getRepository(); } protected String getDestination(String pattern, Artifact artifact, ModuleRevisionId mrid) { if (supportTransaction() && isTransactionStarted()) { String destPattern = (String) fullTransactionPatterns.get(pattern); if (destPattern == null) { throw new IllegalArgumentException( "unsupported pattern for publish destination pattern: " + pattern + ". supported patterns: " + fullTransactionPatterns.keySet()); } return IvyPatternHelper.substitute(destPattern, mrid, artifact); } else { return super.getDestination(pattern, artifact, mrid); } } private boolean isTransactionStarted() { return transactionTempDir != null; } public void abortPublishTransaction() throws IOException { if (supportTransaction()) { if (isTransactionStarted()) { try { getFileRepository().delete(transactionTempDir); Message.info("\tpublish aborted: deleted " + transactionTempDir); } finally { closeTransaction(); } } else { Message.info("\tpublish aborted: nothing was started"); } } } public void commitPublishTransaction() throws IOException { if (supportTransaction()) { if (!isTransactionStarted()) { throw new IllegalStateException("no current transaction!"); } if (transactionDestDir.exists()) { throw new IOException( "impossible to commit transaction: transaction destination directory " + "already exists: " + transactionDestDir + "\npossible cause: usage of identifying tokens after the revision token"); } try { getFileRepository().move(transactionTempDir, transactionDestDir); Message.info("\tpublish commited: moved " + transactionTempDir + " \n\t\tto " + transactionDestDir); } catch (IOException ex) { IOException commitEx; try { getFileRepository().delete(transactionTempDir); commitEx = new IOException("publish transaction commit error for " + transactionDestDir + ": rolled back"); } catch (IOException deleteEx) { commitEx = new IOException("publish transaction commit error for " + transactionDestDir + ": rollback impossible either, " + "please remove " + transactionTempDir + " manually"); } commitEx.initCause(ex); throw commitEx; } finally { closeTransaction(); } } } public void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) throws IOException { if (supportTransaction()) { if (isTransactionStarted()) { throw new IllegalStateException("a transaction is already started and not closed!"); } if (overwrite) { unsupportedTransaction("overwrite transaction not supported yet"); } else { initTransaction(module); if (transactionDestDir.exists()) { unsupportedTransaction("transaction destination directory already exists: " + transactionDestDir + "\npossible cause: usage of identifying tokens after the revision token"); closeTransaction(); } else { Message.verbose("\tstarting transaction: publish during transaction will be done in \n\t\t" + transactionTempDir + "\n\tand on commit moved to \n\t\t" + transactionDestDir); } } } } protected Collection filterNames(Collection values) { if (supportTransaction()) { values = super.filterNames(values); for (Iterator iterator = values.iterator(); iterator.hasNext();) { String v = (String) iterator.next(); if (v.endsWith(TRANSACTION_DESTINATION_SUFFIX)) { iterator.remove(); } } return values; } else { return super.filterNames(values); } } public boolean supportTransaction() { if ("false".equals(transactional)) { return false; } checkSupportTransaction(); return supportTransaction.booleanValue(); } private void closeTransaction() { transactionTempDir = null; transactionDestDir = null; } private void checkSupportTransaction() { if (supportTransaction == null) { supportTransaction = Boolean.FALSE; List ivyPatterns = getIvyPatterns(); List artifactPatterns = getArtifactPatterns(); if (ivyPatterns.size() > 0) { String pattern = (String) ivyPatterns.get(0); Matcher m = TRANSACTION_PATTERN.matcher(pattern); if (!m.matches()) { unsupportedTransaction("ivy pattern does not use revision as a directory"); return; } else { baseTransactionPattern = m.group(1); fullTransactionPatterns.put(pattern, m.group(1) + TRANSACTION_DESTINATION_SUFFIX + m.group(2)); } } if (artifactPatterns.size() > 0) { String pattern = (String) artifactPatterns.get(0); Matcher m = TRANSACTION_PATTERN.matcher(pattern); if (!m.matches()) { unsupportedTransaction("artifact pattern does not use revision as a directory"); return; } else if (baseTransactionPattern != null) { if (!baseTransactionPattern.equals(m.group(1))) { unsupportedTransaction("ivy pattern and artifact pattern " + "do not use the same directory for revision"); return; } else { fullTransactionPatterns.put(pattern, m.group(1) + TRANSACTION_DESTINATION_SUFFIX + m.group(2)); } } else { baseTransactionPattern = m.group(1); fullTransactionPatterns.put(pattern, m.group(1) + TRANSACTION_DESTINATION_SUFFIX + m.group(2)); } } supportTransaction = Boolean.TRUE; } } private void unsupportedTransaction(String msg) { String fullMsg = getName() + " do not support transaction. " + msg; if ("true".equals(transactional)) { throw new IllegalStateException(fullMsg + ". Set transactional attribute to 'auto' or 'false' or fix the problem."); } else { Message.verbose(fullMsg); supportTransaction = Boolean.FALSE; } } private void initTransaction(ModuleRevisionId module) { ModuleRevisionId mrid = module; if (isM2compatible()) { mrid = convertM2IdForResourceSearch(module); } transactionTempDir = Checks.checkAbsolute( IvyPatternHelper.substitute( baseTransactionPattern, ModuleRevisionId.newInstance(mrid, mrid.getRevision() + TRANSACTION_DESTINATION_SUFFIX)), "baseTransactionPattern"); transactionDestDir = Checks.checkAbsolute( IvyPatternHelper.substitute(baseTransactionPattern, mrid), "baseTransactionPattern"); } public String getTransactional() { return transactional; } public void setTransactional(String transactional) { this.transactional = transactional; } public void addConfiguredIvy(IvyPattern p) { File file = Checks.checkAbsolute(p.getPattern(), "ivy pattern"); p.setPattern(file.getAbsolutePath()); super.addConfiguredIvy(p); } public void addIvyPattern(String pattern) { File file = Checks.checkAbsolute(pattern, "ivy pattern"); super.addIvyPattern(file.getAbsolutePath()); } public void addConfiguredArtifact(IvyPattern p) { File file = Checks.checkAbsolute(p.getPattern(), "artifact pattern"); p.setPattern(file.getAbsolutePath()); super.addConfiguredArtifact(p); } public void addArtifactPattern(String pattern) { File file = Checks.checkAbsolute(pattern, "artifact pattern"); super.addArtifactPattern(file.getAbsolutePath()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/IBiblioResolver.java000066400000000000000000000540221226750426600265730ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.ContextualSAXHandler; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.xml.sax.SAXException; /** * IBiblioResolver is a resolver which can be used to resolve dependencies found in the ibiblio * maven repository, or similar repositories. *

    * For more flexibility with url and patterns, see * {@link org.apache.ivy.plugins.resolver.URLResolver}. */ public class IBiblioResolver extends URLResolver { private static final String M2_PER_MODULE_PATTERN = "[revision]/[artifact]-[revision](-[classifier]).[ext]"; private static final String M2_PATTERN = "[organisation]/[module]/" + M2_PER_MODULE_PATTERN; public static final String DEFAULT_PATTERN = "[module]/[type]s/[artifact]-[revision].[ext]"; public static final String DEFAULT_ROOT = "http://www.ibiblio.org/maven/"; public static final String DEFAULT_M2_ROOT = "http://repo1.maven.org/maven2/"; private String root = null; private String pattern = null; // use poms if m2 compatible is true private boolean usepoms = true; // use maven-metadata.xml is exists to list revisions private boolean useMavenMetadata = true; public IBiblioResolver() { // SNAPSHOT revisions are changing revisions setChangingMatcher(PatternMatcher.REGEXP); setChangingPattern(".*-SNAPSHOT"); } public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { if (isM2compatible() && isUsepoms()) { ModuleRevisionId mrid = dd.getDependencyRevisionId(); mrid = convertM2IdForResourceSearch(mrid); ResolvedResource rres = null; if (dd.getDependencyRevisionId().getRevision().endsWith("SNAPSHOT")) { rres = findSnapshotDescriptor(dd, data, mrid); if (rres != null) { return rres; } } rres = findResourceUsingPatterns(mrid, getIvyPatterns(), DefaultArtifact.newPomArtifact(mrid, data.getDate()), getRMDParser(dd, data), data.getDate()); return rres; } else { return null; } } public ResolvedResource findArtifactRef(Artifact artifact, Date date) { ensureConfigured(getSettings()); ModuleRevisionId mrid = artifact.getModuleRevisionId(); if (isM2compatible()) { mrid = convertM2IdForResourceSearch(mrid); } ResolvedResource rres = null; if (artifact.getId().getRevision().endsWith("SNAPSHOT") && isM2compatible()) { rres = findSnapshotArtifact(artifact, date, mrid); if (rres != null) { return rres; } } return findResourceUsingPatterns(mrid, getArtifactPatterns(), artifact, getDefaultRMDParser(artifact.getModuleRevisionId().getModuleId()), date); } private ResolvedResource findSnapshotArtifact(Artifact artifact, Date date, ModuleRevisionId mrid) { String rev = findSnapshotVersion(mrid); if (rev != null) { // replace the revision token in file name with the resolved revision String pattern = getWholePattern().replaceFirst("\\-\\[revision\\]", "-" + rev); return findResourceUsingPattern(mrid, pattern, artifact, getDefaultRMDParser(artifact .getModuleRevisionId().getModuleId()), date); } return null; } private ResolvedResource findSnapshotDescriptor(DependencyDescriptor dd, ResolveData data, ModuleRevisionId mrid) { String rev = findSnapshotVersion(mrid); if (rev != null) { // here it would be nice to be able to store the resolved snapshot version, to avoid // having to follow the same process to download artifacts Message.verbose("[" + rev + "] " + mrid); // replace the revision token in file name with the resolved revision String pattern = getWholePattern().replaceFirst("\\-\\[revision\\]", "-" + rev); return findResourceUsingPattern(mrid, pattern, DefaultArtifact.newPomArtifact(mrid, data.getDate()), getRMDParser(dd, data), data.getDate()); } return null; } private String findSnapshotVersion(ModuleRevisionId mrid) { if (!isM2compatible()) { return null; } if (shouldUseMavenMetadata(getWholePattern())) { InputStream metadataStream = null; try { String metadataLocation = IvyPatternHelper.substitute(root + "[organisation]/[module]/[revision]/maven-metadata.xml", mrid); Resource metadata = getRepository().getResource(metadataLocation); if (metadata.exists()) { metadataStream = metadata.openStream(); final StringBuffer timestamp = new StringBuffer(); final StringBuffer buildNumer = new StringBuffer(); XMLHelper.parse(metadataStream, null, new ContextualSAXHandler() { public void endElement(String uri, String localName, String qName) throws SAXException { if ("metadata/versioning/snapshot/timestamp".equals(getContext())) { timestamp.append(getText()); } if ("metadata/versioning/snapshot/buildNumber".equals(getContext())) { buildNumer.append(getText()); } super.endElement(uri, localName, qName); } }, null); if (timestamp.length() > 0) { // we have found a timestamp, so this is a snapshot unique version String rev = mrid.getRevision(); rev = rev.substring(0, rev.length() - "SNAPSHOT".length()); rev = rev + timestamp.toString() + "-" + buildNumer.toString(); return rev; } } else { Message.verbose("\tmaven-metadata not available: " + metadata); } } catch (IOException e) { Message.verbose("impossible to access maven metadata file, ignored", e); } catch (SAXException e) { Message.verbose("impossible to parse maven metadata file, ignored", e); } catch (ParserConfigurationException e) { Message.verbose("impossible to parse maven metadata file, ignored", e); } finally { if (metadataStream != null) { try { metadataStream.close(); } catch (IOException e) { // ignored } } } } return null; } public void setM2compatible(boolean m2compatible) { super.setM2compatible(m2compatible); if (m2compatible) { if (root == null) { root = DEFAULT_M2_ROOT; } if (pattern == null) { pattern = M2_PATTERN; } updateWholePattern(); } } public void ensureConfigured(ResolverSettings settings) { if (settings != null && (root == null || pattern == null)) { if (root == null) { String root = settings.getVariable("ivy.ibiblio.default.artifact.root"); if (root != null) { this.root = root; } else { settings.configureRepositories(true); this.root = settings.getVariable("ivy.ibiblio.default.artifact.root"); } } if (pattern == null) { String pattern = settings.getVariable("ivy.ibiblio.default.artifact.pattern"); if (pattern != null) { this.pattern = pattern; } else { settings.configureRepositories(false); this.pattern = settings.getVariable("ivy.ibiblio.default.artifact.pattern"); } } updateWholePattern(); } } protected String getModuleDescriptorExtension() { return "pom"; } private String getWholePattern() { return root + pattern; } public String getPattern() { return pattern; } public void setPattern(String pattern) { if (pattern == null) { throw new NullPointerException("pattern must not be null"); } this.pattern = pattern; ensureConfigured(getSettings()); updateWholePattern(); } public String getRoot() { return root; } /** * Sets the root of the maven like repository. The maven like repository is necessarily an http * repository. * * @param root * the root of the maven like repository * @throws IllegalArgumentException * if root does not start with "http://" */ public void setRoot(String root) { if (root == null) { throw new NullPointerException("root must not be null"); } if (!root.endsWith("/")) { this.root = root + "/"; } else { this.root = root; } ensureConfigured(getSettings()); updateWholePattern(); } private void updateWholePattern() { if (isM2compatible() && isUsepoms()) { setIvyPatterns(Collections.singletonList(getWholePattern())); } else { setIvyPatterns(Collections.EMPTY_LIST); } setArtifactPatterns(Collections.singletonList(getWholePattern())); } public void publish(Artifact artifact, File src) { throw new UnsupportedOperationException("publish not supported by IBiblioResolver"); } // we do not allow to list organisations on ibiblio, nor modules in ibiblio 1 public String[] listTokenValues(String token, Map otherTokenValues) { if (IvyPatternHelper.ORGANISATION_KEY.equals(token)) { return new String[0]; } if (IvyPatternHelper.MODULE_KEY.equals(token) && !isM2compatible()) { return new String[0]; } ensureConfigured(getSettings()); return super.listTokenValues(token, otherTokenValues); } protected String[] listTokenValues(String pattern, String token) { if (IvyPatternHelper.ORGANISATION_KEY.equals(token)) { return new String[0]; } if (IvyPatternHelper.MODULE_KEY.equals(token) && !isM2compatible()) { return new String[0]; } ensureConfigured(getSettings()); // let's see if we should use maven metadata for this listing... if (IvyPatternHelper.REVISION_KEY.equals(token) && shouldUseMavenMetadata(getWholePattern())) { // now we must use metadata if available /* * we substitute tokens with ext token only in the m2 per module pattern, to match has * has been done in the given pattern */ String partiallyResolvedM2PerModulePattern = IvyPatternHelper.substituteTokens( M2_PER_MODULE_PATTERN, Collections.singletonMap(IvyPatternHelper.EXT_KEY, "pom")); if (pattern.endsWith(partiallyResolvedM2PerModulePattern)) { /* * the given pattern already contain resolved org and module, we just have to * replace the per module pattern at the end by 'maven-metadata.xml' to have the * maven metadata file location */ String metadataLocation = pattern.substring(0, pattern.lastIndexOf(partiallyResolvedM2PerModulePattern)) + "maven-metadata.xml"; List revs = listRevisionsWithMavenMetadata(getRepository(), metadataLocation); if (revs != null) { return (String[]) revs.toArray(new String[revs.size()]); } } else { /* * this is probably because the given pattern has been substituted with jar ext, if * this resolver has optional module descriptors. But since we have to use maven * metadata, we don't care about this case, maven metadata has already been used * when looking for revisions with the pattern substituted with ext=xml for the * "ivy" pattern. */ return new String[0]; } } return super.listTokenValues(pattern, token); } public OrganisationEntry[] listOrganisations() { return new OrganisationEntry[0]; } public ModuleEntry[] listModules(OrganisationEntry org) { if (isM2compatible()) { ensureConfigured(getSettings()); return super.listModules(org); } return new ModuleEntry[0]; } public RevisionEntry[] listRevisions(ModuleEntry mod) { ensureConfigured(getSettings()); return super.listRevisions(mod); } protected ResolvedResource[] listResources(Repository repository, ModuleRevisionId mrid, String pattern, Artifact artifact) { if (shouldUseMavenMetadata(pattern)) { List revs = listRevisionsWithMavenMetadata(repository, mrid.getModuleId() .getAttributes()); if (revs != null) { Message.debug("\tfound revs: " + revs); List rres = new ArrayList(); for (Iterator iter = revs.iterator(); iter.hasNext();) { String rev = (String) iter.next(); ModuleRevisionId historicalMrid = ModuleRevisionId.newInstance(mrid, rev); String patternForRev = pattern; if (rev.endsWith("SNAPSHOT")) { String snapshotVersion = findSnapshotVersion(historicalMrid); if (snapshotVersion != null) { patternForRev = pattern.replaceFirst("\\-\\[revision\\]", "-" + snapshotVersion); } } String resolvedPattern = IvyPatternHelper.substitute(patternForRev, historicalMrid, artifact); try { Resource res = repository.getResource(resolvedPattern); if (res != null) { // we do not test if the resource actually exist here, it would cause // a lot of checks which are not always necessary depending on the usage // which is done of the returned ResolvedResource array rres.add(new ResolvedResource(res, rev)); } } catch (IOException e) { Message.warn( "impossible to get resource from name listed by maven-metadata.xml:" + rres, e); } } return (ResolvedResource[]) rres.toArray(new ResolvedResource[rres.size()]); } else { // maven metadata not available or something went wrong, // use default listing capability return super.listResources(repository, mrid, pattern, artifact); } } else { return super.listResources(repository, mrid, pattern, artifact); } } private List listRevisionsWithMavenMetadata(Repository repository, Map tokenValues) { String metadataLocation = IvyPatternHelper.substituteTokens(root + "[organisation]/[module]/maven-metadata.xml", tokenValues); return listRevisionsWithMavenMetadata(repository, metadataLocation); } private List listRevisionsWithMavenMetadata(Repository repository, String metadataLocation) { List revs = null; InputStream metadataStream = null; try { Resource metadata = repository.getResource(metadataLocation); if (metadata.exists()) { Message.verbose("\tlisting revisions from maven-metadata: " + metadata); final List metadataRevs = new ArrayList(); metadataStream = metadata.openStream(); XMLHelper.parse(metadataStream, null, new ContextualSAXHandler() { public void endElement(String uri, String localName, String qName) throws SAXException { if ("metadata/versioning/versions/version".equals(getContext())) { metadataRevs.add(getText().trim()); } super.endElement(uri, localName, qName); } }, null); revs = metadataRevs; } else { Message.verbose("\tmaven-metadata not available: " + metadata); } } catch (IOException e) { Message.verbose("impossible to access maven metadata file, ignored", e); } catch (SAXException e) { Message.verbose("impossible to parse maven metadata file, ignored", e); } catch (ParserConfigurationException e) { Message.verbose("impossible to parse maven metadata file, ignored", e); } finally { if (metadataStream != null) { try { metadataStream.close(); } catch (IOException e) { // ignored } } } return revs; } protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { if (IvyPatternHelper.REVISION_KEY.equals(token)) { if (shouldUseMavenMetadata(getWholePattern())) { List revs = listRevisionsWithMavenMetadata(getRepository(), tokenValues); if (revs != null) { names.addAll(filterNames(revs)); return; } } } super.findTokenValues(names, patterns, tokenValues, token); } private boolean shouldUseMavenMetadata(String pattern) { return isUseMavenMetadata() && isM2compatible() && pattern.endsWith(M2_PATTERN); } public String getTypeName() { return "ibiblio"; } // override some methods to ensure configuration public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { ensureConfigured(data.getSettings()); return super.getDependency(dd, data); } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { ensureConfigured(getSettings()); return super.download(artifacts, options); } public boolean exists(Artifact artifact) { ensureConfigured(getSettings()); return super.exists(artifact); } public ArtifactOrigin locate(Artifact artifact) { ensureConfigured(getSettings()); return super.locate(artifact); } public List getArtifactPatterns() { ensureConfigured(getSettings()); return super.getArtifactPatterns(); } public boolean isUsepoms() { return usepoms; } public void setUsepoms(boolean usepoms) { this.usepoms = usepoms; updateWholePattern(); } public boolean isUseMavenMetadata() { return useMavenMetadata; } public void setUseMavenMetadata(boolean useMavenMetadata) { this.useMavenMetadata = useMavenMetadata; } public void dumpSettings() { ensureConfigured(getSettings()); super.dumpSettings(); Message.debug("\t\troot: " + getRoot()); Message.debug("\t\tpattern: " + getPattern()); Message.debug("\t\tusepoms: " + usepoms); Message.debug("\t\tuseMavenMetadata: " + useMavenMetadata); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/IvyRepResolver.java000066400000000000000000000254401226750426600265020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.cache.ArtifactOrigin; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.core.resolve.ResolveData; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.search.ModuleEntry; import org.apache.ivy.core.search.OrganisationEntry; import org.apache.ivy.core.search.RevisionEntry; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * IvyRepResolver is a resolver which can be used to resolve dependencies found in the ivy official * repository for ivy files and ibiblio maven repository for the artifacts, or similar repositories. * For more flexibility with url and patterns, see * {@link org.apache.ivy.plugins.resolver.URLResolver}. */ public class IvyRepResolver extends URLResolver { public static final String DEFAULT_IVYPATTERN = "[organisation]/[module]/ivy-[revision].xml"; public static final String DEFAULT_IVYROOT = "http://ivyrep.jayasoft.org/"; private String ivyroot = null; private String ivypattern = null; private String artroot = null; private String artpattern = null; public IvyRepResolver() { } private void ensureArtifactConfigured(ResolverSettings settings) { if (settings != null && (artroot == null || artpattern == null)) { if (artroot == null) { String root = settings.getVariable("ivy.ivyrep.default.artifact.root"); if (root != null) { artroot = root; } else { settings.configureRepositories(true); artroot = settings.getVariable("ivy.ivyrep.default.artifact.root"); } } if (artpattern == null) { String pattern = settings.getVariable("ivy.ivyrep.default.artifact.pattern"); if (pattern != null) { artpattern = pattern; } else { settings.configureRepositories(false); artpattern = settings.getVariable("ivy.ivyrep.default.artifact.pattern"); } } updateWholeArtPattern(); } } private void ensureIvyConfigured(ResolverSettings settings) { if (settings != null && (ivyroot == null || ivypattern == null)) { if (ivyroot == null) { String root = settings.getVariable("ivy.ivyrep.default.ivy.root"); if (root != null) { ivyroot = root; } else { throw new IllegalStateException("ivyroot is mandatory on IvyRepResolver. " + "Make sure to set it in your settings, before setting ivypattern " + "if you wish to set ivypattern too."); } } if (ivypattern == null) { String pattern = settings.getVariable("ivy.ivyrep.default.ivy.pattern"); if (pattern != null) { ivypattern = pattern; } else { settings.configureRepositories(false); ivypattern = settings.getVariable("ivy.ivyrep.default.ivy.pattern"); } } updateWholeIvyPattern(); } } private String getWholeIvyPattern() { if (ivyroot == null || ivypattern == null) { return null; } return ivyroot + ivypattern; } private String getWholeArtPattern() { return artroot + artpattern; } public String getIvypattern() { return ivypattern; } public void setIvypattern(String pattern) { if (pattern == null) { throw new NullPointerException("pattern must not be null"); } ivypattern = pattern; ensureIvyConfigured(getSettings()); updateWholeIvyPattern(); } public String getIvyroot() { return ivyroot; } /** * Sets the root of the maven like repository. The maven like repository is necessarily an http * repository. * * @param root * the root of the maven like repository * @throws IllegalArgumentException * if root does not start with "http://" */ public void setIvyroot(String root) { if (root == null) { throw new NullPointerException("root must not be null"); } if (!root.endsWith("/")) { ivyroot = root + "/"; } else { ivyroot = root; } ensureIvyConfigured(getSettings()); updateWholeIvyPattern(); } public void setM2compatible(boolean m2compatible) { if (m2compatible) { throw new IllegalArgumentException( "ivyrep does not support maven2 compatibility. " + "Please use ibiblio resolver instead, or even url or filesystem resolvers for" + " more specific needs."); } } private void updateWholeIvyPattern() { setIvyPatterns(Collections.singletonList(getWholeIvyPattern())); } private void updateWholeArtPattern() { setArtifactPatterns(Collections.singletonList(getWholeArtPattern())); } public void publish(Artifact artifact, File src) { throw new UnsupportedOperationException("publish not supported by IBiblioResolver"); } public String getArtroot() { return artroot; } public String getArtpattern() { return artpattern; } public void setArtpattern(String pattern) { if (pattern == null) { throw new NullPointerException("pattern must not be null"); } artpattern = pattern; ensureArtifactConfigured(getSettings()); updateWholeArtPattern(); } public void setArtroot(String root) { if (root == null) { throw new NullPointerException("root must not be null"); } if (!root.endsWith("/")) { artroot = root + "/"; } else { artroot = root; } ensureArtifactConfigured(getSettings()); updateWholeArtPattern(); } public OrganisationEntry[] listOrganisations() { ensureIvyConfigured(getSettings()); try { URL content = new URL(ivyroot + "content.xml"); final List ret = new ArrayList(); XMLHelper.parse(content, null, new DefaultHandler() { public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes) throws SAXException { if ("organisation".equals(qName)) { String org = attributes.getValue("name"); if (org != null) { ret.add(new OrganisationEntry(IvyRepResolver.this, org)); } } } }); return (OrganisationEntry[]) ret.toArray(new OrganisationEntry[ret.size()]); } catch (MalformedURLException e) { // ??? } catch (Exception e) { Message.warn("unable to parse content.xml file on ivyrep", e); } return super.listOrganisations(); } // overwrite parent to use only ivy patterns (and not artifact ones, cause ibiblio is too slow // to answer) public ModuleEntry[] listModules(OrganisationEntry org) { ensureIvyConfigured(getSettings()); Map tokenValues = new HashMap(); tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); Collection names = findIvyNames(tokenValues, IvyPatternHelper.MODULE_KEY); ModuleEntry[] ret = new ModuleEntry[names.size()]; int i = 0; for (Iterator iter = names.iterator(); iter.hasNext(); i++) { String name = (String) iter.next(); ret[i] = new ModuleEntry(org, name); } return ret; } public RevisionEntry[] listRevisions(ModuleEntry mod) { ensureIvyConfigured(getSettings()); ensureArtifactConfigured(getSettings()); return super.listRevisions(mod); } public String getTypeName() { return "ivyrep"; } // override some methods to ensure configuration public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { ensureIvyConfigured(data.getSettings()); return super.getDependency(dd, data); } public ResolvedResource findArtifactRef(Artifact artifact, Date date) { ensureArtifactConfigured(getSettings()); return super.findArtifactRef(artifact, date); } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { ensureArtifactConfigured(getSettings()); return super.download(artifacts, options); } public boolean exists(Artifact artifact) { ensureArtifactConfigured(getSettings()); return super.exists(artifact); } public ArtifactOrigin locate(Artifact artifact) { ensureArtifactConfigured(getSettings()); return super.locate(artifact); } public List getIvyPatterns() { ensureIvyConfigured(getSettings()); return super.getIvyPatterns(); } public List getArtifactPatterns() { ensureArtifactConfigured(getSettings()); return super.getArtifactPatterns(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/JarResolver.java000066400000000000000000000072501226750426600257770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.jar.JarFile; import org.apache.ivy.core.cache.CacheResourceOptions; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.core.report.DownloadStatus; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.repository.jar.JarRepository; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; public class JarResolver extends RepositoryResolver { private URL url; public JarResolver() { setRepository(new JarRepository()); } public String getTypeName() { return "jar"; } public void setFile(String jarFile) { setJarFile(new File(jarFile)); } public void setUrl(String jarUrl) { try { url = new URL(jarUrl); } catch (MalformedURLException e) { throw new RuntimeException("the jar repository " + getName() + " has an malformed url : " + jarUrl + " (" + e.getMessage() + ")"); } } public JarRepository getJarRepository() { return (JarRepository) super.getRepository(); } private void setJarFile(File jarLocalFile) { JarFile jar; try { jar = new JarFile(jarLocalFile); } catch (IOException e) { throw new RuntimeException("the jar repository " + getName() + " could not be read (" + e.getMessage() + ")", e); } getJarRepository().setJarFile(jar); } public void setSettings(ResolverSettings settings) { super.setSettings(settings); // let's resolve the url if (url != null) { ArtifactDownloadReport report; EventManager eventManager = getEventManager(); try { if (eventManager != null) { getRepository().addTransferListener(eventManager); } Resource jarResource = new URLResource(url); CacheResourceOptions options = new CacheResourceOptions(); report = getRepositoryCacheManager().downloadRepositoryResource(jarResource, "jarrepository", "jar", "jar", options, new URLRepository()); } finally { if (eventManager != null) { getRepository().removeTransferListener(eventManager); } } if (report.getDownloadStatus() == DownloadStatus.FAILED) { throw new RuntimeException("The jar file " + url.toExternalForm() + " could not be downloaded (" + report.getDownloadDetails() + ")"); } setJarFile(report.getLocalFile()); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/MirroredURLResolver.java000066400000000000000000000102051226750426600274230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.ivy.core.cache.CacheResourceOptions; import org.apache.ivy.core.report.ArtifactDownloadReport; import org.apache.ivy.osgi.repo.RelativeURLRepository; import org.apache.ivy.plugins.repository.url.ChainedRepository; import org.apache.ivy.plugins.repository.url.URLRepository; import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.util.Message; public class MirroredURLResolver extends RepositoryResolver { private URL mirrorListUrl; public MirroredURLResolver() { setRepository(new ChainedRepository()); } public void setMirrorListUrl(URL mirrorListUrl) { this.mirrorListUrl = mirrorListUrl; } private void setupMirrors() { File mirrorListFile = downloadMirrorList(); List mirrorBaseUrls; try { mirrorBaseUrls = readMirrorList(mirrorListFile); } catch (IOException e) { throw new IllegalStateException("The mirror list could not be read from " + mirrorListUrl + " (" + e.getMessage() + ")"); } List/* */repositories = new ArrayList(); Iterator it = mirrorBaseUrls.iterator(); while (it.hasNext()) { String baseUrl = (String) it.next(); URL url = null; try { url = new URL(baseUrl); } catch (MalformedURLException e) { Message.warn("In the mirror list from " + mirrorListUrl + ", an incorrect url has been found and will then not be used: " + baseUrl); } if (url != null) { RelativeURLRepository repo = new RelativeURLRepository(url); repositories.add(repo); } } ((ChainedRepository) getRepository()).setRepositories(repositories); } private File downloadMirrorList() { URLRepository urlRepository = new URLRepository(); if (getEventManager() != null) { urlRepository.addTransferListener(getEventManager()); } URLResource mirrorResource = new URLResource(mirrorListUrl); CacheResourceOptions options = new CacheResourceOptions(); ArtifactDownloadReport report = getRepositoryCacheManager().downloadRepositoryResource( mirrorResource, "mirrorlist", "text", "txt", options, urlRepository); return report.getLocalFile(); } private List/* */readMirrorList(File mirrorListFile) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream( mirrorListFile))); List/* */list = new ArrayList(); try { String line = in.readLine(); while (line != null) { list.add(line); line = in.readLine(); } } finally { in.close(); } return list; } public String getTypeName() { return "mirroredurl"; } public void validate() { super.validate(); setupMirrors(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java000066400000000000000000000340161226750426600274420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.event.EventManager; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.DownloadReport; import org.apache.ivy.core.resolve.DownloadOptions; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry; import org.apache.ivy.plugins.repository.AbstractRepository; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.plugins.resolver.util.ResolverHelper; import org.apache.ivy.plugins.resolver.util.ResourceMDParser; import org.apache.ivy.plugins.signer.SignatureGenerator; import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.ChecksumHelper; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; /** * */ public class RepositoryResolver extends AbstractPatternsBasedResolver { private Repository repository; private Boolean alwaysCheckExactRevision = null; private String signerName = null; public RepositoryResolver() { } public Repository getRepository() { return repository; } public void setRepository(Repository repository) { this.repository = repository; } public void setName(String name) { super.setName(name); if (repository instanceof AbstractRepository) { ((AbstractRepository) repository).setName(name); } } public void setSigner(String signerName) { this.signerName = signerName; } protected ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, String pattern, Artifact artifact, ResourceMDParser rmdparser, Date date) { String name = getName(); VersionMatcher versionMatcher = getSettings().getVersionMatcher(); try { if (!versionMatcher.isDynamic(mrid) || isAlwaysCheckExactRevision()) { String resourceName = IvyPatternHelper.substitute(pattern, mrid, artifact); Message.debug("\t trying " + resourceName); logAttempt(resourceName); Resource res = repository.getResource(resourceName); boolean reachable = res.exists(); if (reachable) { String revision; if (pattern.indexOf(IvyPatternHelper.REVISION_KEY) == -1) { if ("ivy".equals(artifact.getType()) || "pom".equals(artifact.getType())) { // we can't determine the revision from the pattern, get it // from the moduledescriptor itself File temp = File.createTempFile("ivy", artifact.getExt()); temp.deleteOnExit(); repository.get(res.getName(), temp); ModuleDescriptorParser parser = ModuleDescriptorParserRegistry .getInstance().getParser(res); ModuleDescriptor md = parser.parseDescriptor(getParserSettings(), temp .toURI().toURL(), res, false); revision = md.getRevision(); if ((revision == null) || (revision.length() == 0)) { revision = "working@" + name; } } else { revision = "working@" + name; } } else { revision = mrid.getRevision(); } return new ResolvedResource(res, revision); } else if (versionMatcher.isDynamic(mrid)) { return findDynamicResourceUsingPattern(rmdparser, mrid, pattern, artifact, date); } else { Message.debug("\t" + name + ": resource not reachable for " + mrid + ": res=" + res); return null; } } else { return findDynamicResourceUsingPattern(rmdparser, mrid, pattern, artifact, date); } } catch (IOException ex) { throw new RuntimeException(name + ": unable to get resource for " + mrid + ": res=" + IvyPatternHelper.substitute(pattern, mrid, artifact) + ": " + ex, ex); } catch (ParseException ex) { throw new RuntimeException(name + ": unable to get resource for " + mrid + ": res=" + IvyPatternHelper.substitute(pattern, mrid, artifact) + ": " + ex, ex); } } private ResolvedResource findDynamicResourceUsingPattern(ResourceMDParser rmdparser, ModuleRevisionId mrid, String pattern, Artifact artifact, Date date) { String name = getName(); logAttempt(IvyPatternHelper.substitute( pattern, ModuleRevisionId.newInstance(mrid, IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY)), artifact)); ResolvedResource[] rress = listResources(repository, mrid, pattern, artifact); if (rress == null) { Message.debug("\t" + name + ": unable to list resources for " + mrid + ": pattern=" + pattern); return null; } else { ResolvedResource found = findResource(rress, rmdparser, mrid, date); if (found == null) { Message.debug("\t" + name + ": no resource found for " + mrid + ": pattern=" + pattern); } return found; } } protected Resource getResource(String source) throws IOException { return repository.getResource(source); } /** * List all revisions as resolved resources for the given artifact in the given repository using * the given pattern, and using the given mrid except its revision. * * @param repository * the repository in which revisions should be located * @param mrid * the module revision id to look for (except revision) * @param pattern * the pattern to use to locate the revisions * @param artifact * the artifact to find * @return an array of ResolvedResource, all pointing to a different revision of the given * Artifact. */ protected ResolvedResource[] listResources(Repository repository, ModuleRevisionId mrid, String pattern, Artifact artifact) { return ResolverHelper.findAll(repository, mrid, pattern, artifact); } protected long get(Resource resource, File dest) throws IOException { Message.verbose("\t" + getName() + ": downloading " + resource.getName()); Message.debug("\t\tto " + dest); if (dest.getParentFile() != null) { dest.getParentFile().mkdirs(); } repository.get(resource.getName(), dest); return dest.length(); } public void publish(Artifact artifact, File src, boolean overwrite) throws IOException { String destPattern; if ("ivy".equals(artifact.getType()) && !getIvyPatterns().isEmpty()) { destPattern = (String) getIvyPatterns().get(0); } else if (!getArtifactPatterns().isEmpty()) { destPattern = (String) getArtifactPatterns().get(0); } else { throw new IllegalStateException("impossible to publish " + artifact + " using " + this + ": no artifact pattern defined"); } // Check for m2 compatibility ModuleRevisionId mrid = artifact.getModuleRevisionId(); if (isM2compatible()) { mrid = convertM2IdForResourceSearch(mrid); } String dest = getDestination(destPattern, artifact, mrid); put(artifact, src, dest, overwrite); Message.info("\tpublished " + artifact.getName() + " to " + hidePassword(repository.standardize(dest))); } protected String getDestination(String pattern, Artifact artifact, ModuleRevisionId mrid) { return IvyPatternHelper.substitute(pattern, mrid, artifact); } protected void put(Artifact artifact, File src, String dest, boolean overwrite) throws IOException { // verify the checksum algorithms before uploading artifacts! String[] checksums = getChecksumAlgorithms(); for (int i = 0; i < checksums.length; i++) { if (!ChecksumHelper.isKnownAlgorithm(checksums[i])) { throw new IllegalArgumentException("Unknown checksum algorithm: " + checksums[i]); } } repository.put(artifact, src, dest, overwrite); for (int i = 0; i < checksums.length; i++) { putChecksum(artifact, src, dest, overwrite, checksums[i]); } if (signerName != null) { putSignature(artifact, src, dest, overwrite); } } protected void putChecksum(Artifact artifact, File src, String dest, boolean overwrite, String algorithm) throws IOException { File csFile = File.createTempFile("ivytemp", algorithm); try { FileUtil.copy(new ByteArrayInputStream(ChecksumHelper.computeAsString(src, algorithm) .getBytes()), csFile, null); repository.put( DefaultArtifact.cloneWithAnotherTypeAndExt(artifact, algorithm, artifact.getExt() + "." + algorithm), csFile, dest + "." + algorithm, overwrite); } finally { csFile.delete(); } } protected void putSignature(Artifact artifact, File src, String dest, boolean overwrite) throws IOException { SignatureGenerator gen = getSettings().getSignatureGenerator(signerName); if (gen == null) { throw new IllegalArgumentException("Couldn't sign the artifacts! " + "Unknown signer name: '" + signerName + "'"); } File tempFile = File.createTempFile("ivytemp", gen.getExtension()); try { gen.sign(src, tempFile); repository.put( DefaultArtifact.cloneWithAnotherTypeAndExt(artifact, gen.getExtension(), artifact.getExt() + "." + gen.getExtension()), tempFile, dest + "." + gen.getExtension(), overwrite); } finally { tempFile.delete(); } } public DownloadReport download(Artifact[] artifacts, DownloadOptions options) { EventManager eventManager = getEventManager(); try { if (eventManager != null) { repository.addTransferListener(eventManager); } return super.download(artifacts, options); } finally { if (eventManager != null) { repository.removeTransferListener(eventManager); } } } protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { for (Iterator iter = patterns.iterator(); iter.hasNext();) { String pattern = (String) iter.next(); String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues); String[] values = ResolverHelper.listTokenValues(repository, partiallyResolvedPattern, token); if (values != null) { names.addAll(filterNames(new ArrayList(Arrays.asList(values)))); } } } protected String[] listTokenValues(String pattern, String token) { return ResolverHelper.listTokenValues(repository, pattern, token); } protected boolean exist(String path) { try { Resource resource = repository.getResource(path); return resource.exists(); } catch (IOException e) { Message.debug(e); return false; } } public String getTypeName() { return "repository"; } public void dumpSettings() { super.dumpSettings(); Message.debug("\t\trepository: " + getRepository()); } public void setSettings(ResolverSettings settings) { super.setSettings(settings); if (settings != null) { if (alwaysCheckExactRevision == null) { alwaysCheckExactRevision = Boolean.valueOf(settings .getVariable("ivy.default.always.check.exact.revision")); } } } public boolean isAlwaysCheckExactRevision() { return alwaysCheckExactRevision == null ? true : alwaysCheckExactRevision.booleanValue(); } public void setAlwaysCheckExactRevision(boolean alwaysCheckExactRevision) { this.alwaysCheckExactRevision = Boolean.valueOf(alwaysCheckExactRevision); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java000066400000000000000000000037101226750426600270600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.util.Collection; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.plugins.latest.LatestStrategy; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.signer.SignatureGenerator; import org.apache.ivy.plugins.version.VersionMatcher; public interface ResolverSettings extends ParserSettings { LatestStrategy getLatestStrategy(String latestStrategyName); LatestStrategy getDefaultLatestStrategy(); RepositoryCacheManager getRepositoryCacheManager(String name); RepositoryCacheManager getDefaultRepositoryCacheManager(); RepositoryCacheManager[] getRepositoryCacheManagers(); Namespace getNamespace(String namespaceName); Namespace getSystemNamespace(); String getVariable(String string); void configureRepositories(boolean b); VersionMatcher getVersionMatcher(); String getResolveMode(ModuleId moduleId); void filterIgnore(Collection names); SignatureGenerator getSignatureGenerator(String name); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/SFTPResolver.java000066400000000000000000000030551226750426600260360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import org.apache.ivy.plugins.repository.sftp.SFTPRepository; /** * This resolver is able to work with any sftp server. It supports listing and publishing. The * server host should absolutely be set using setHost. basedir defaults to . port default to 22 * username and password will be prompted using a dialog box if not set. So if you are in an * headless environment, provide username and password. */ public class SFTPResolver extends AbstractSshBasedResolver { public SFTPResolver() { setRepository(new SFTPRepository()); } public String getTypeName() { return "sftp"; } public SFTPRepository getSFTPRepository() { return (SFTPRepository) getRepository(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/SshResolver.java000066400000000000000000000072051226750426600260200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import org.apache.ivy.plugins.repository.ssh.SshRepository; /** * Resolver for SSH resolver for ivy */ public class SshResolver extends AbstractSshBasedResolver { public SshResolver() { setRepository(new SshRepository()); } /** * A four digit string (e.g., 0644, see "man chmod", "man open") specifying the permissions of * the published files. */ public void setPublishPermissions(String permissions) { ((SshRepository) getRepository()).setPublishPermissions(permissions); } /** * sets the path separator used on the target system. Not sure if this is used or if '/' is used * on all implementation. default is to use '/' * * @param sep * file separator to use on the target system */ public void setFileSeparator(String sep) { if (sep == null || sep.length() != 1) { throw new IllegalArgumentException( "File Separator has to be a single character and not " + sep); } ((SshRepository) getRepository()).setFileSeparator(sep.trim().charAt(0)); } /** * set the command to get a directory listing the command has to be a shell command working on * the target system and has to produce a listing of filenames, with each filename on a new line * the term %arg can be used in the command to substitue the path to be listed (e.g. * "ls -1 %arg | grep -v CVS" to get a listing without CVS directory) if %arg is not part of the * command, the path will be appended to the command default is: "ls -1" */ public void setListCommand(String cmd) { ((SshRepository) getRepository()).setListCommand(cmd); } /** * set the command to check for existence of a file the command has to be a shell command * working on the target system and has to create an exit status of 0 for an existent file and * <> 0 for a non existing file given as argument the term %arg can be used in the command to * substitue the path to be listed if %arg is not part of the command, the path will be appended * to the command default is: "ls" */ public void setExistCommand(String cmd) { ((SshRepository) getRepository()).setExistCommand(cmd); } /** * set the command to create a directory on the target system the command has to be a shell * command working on the target system and has to create a directory with the given argument * the term %arg can be used in the command to substitue the path to be listed if %arg is not * part of the command, the path will be appended to the command default is: "mkdir" */ public void setCreateDirCommand(String cmd) { ((SshRepository) getRepository()).setExistCommand(cmd); } public String getTypeName() { return "ssh"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/URLResolver.java000066400000000000000000000023631226750426600257250ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import org.apache.ivy.plugins.repository.url.URLRepository; /** * This resolver is able to work with any URLs, it handles latest revisions with file and http urls * only, and it does not handle publishing */ public class URLResolver extends RepositoryResolver { public URLResolver() { setRepository(new URLRepository()); } public String getTypeName() { return "url"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/VfsResolver.java000066400000000000000000000040561226750426600260220ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.plugins.repository.vfs.VfsRepository; /** * */ public class VfsResolver extends RepositoryResolver { private static final Pattern URL_PATTERN = Pattern.compile("[a-z]*://(.+):(.+)@.*"); private static final int PASSWORD_GROUP = 2; public VfsResolver() { setRepository(new VfsRepository()); } public String getTypeName() { return "vfs"; } public String hidePassword(String name) { return prepareForDisplay(name); } public static String prepareForDisplay(String name) { StringBuffer s = new StringBuffer(name); Matcher m = URL_PATTERN.matcher(s); if (m.matches()) { final String password = m.group(PASSWORD_GROUP); final int passwordposi = s.indexOf(password); StringBuffer stars = new StringBuffer(password); for (int posi = 0; posi < password.length(); posi++) { stars.setCharAt(posi, '*'); } String replacement = stars.toString(); s = s.replace(passwordposi, passwordposi + password.length(), replacement); } return s.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/VsftpResolver.java000066400000000000000000000044401226750426600263630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver; import org.apache.ivy.plugins.repository.vsftp.VsftpRepository; /** * This resolver uses SecureCRT vsft to access an sftp server. It supports listing and publishing. * The server host should absolutely be set using setHost, so does the username. */ public class VsftpResolver extends RepositoryResolver { public VsftpResolver() { setRepository(new VsftpRepository()); } public String getTypeName() { return "vsftp"; } public VsftpRepository getVsftpRepository() { return (VsftpRepository) getRepository(); } public void disconnect() { getVsftpRepository().disconnect(); } public String getAuthentication() { return getVsftpRepository().getAuthentication(); } public String getHost() { return getVsftpRepository().getHost(); } public String getUsername() { return getVsftpRepository().getUsername(); } public void setAuthentication(String authentication) { getVsftpRepository().setAuthentication(authentication); } public void setHost(String host) { getVsftpRepository().setHost(host); } public void setUsername(String username) { getVsftpRepository().setUsername(username); } public void setReuseConnection(long time) { getVsftpRepository().setReuseConnection(time); } public void setReadTimeout(long readTimeout) { getVsftpRepository().setReadTimeout(readTimeout); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/000077500000000000000000000000001226750426600244475ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/BuiltFileResource.java000066400000000000000000000046021226750426600307030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.packager; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.plugins.repository.Resource; /** * Represents an artifact built by a {@link PackagerResolver}. */ public class BuiltFileResource implements Resource { /** * Where the build file should put built artifacts (relative to the build directory). Value is: * * {@value} */ public static final String BUILT_ARTIFACT_PATTERN = "artifacts/[type]s/[artifact].[ext]"; private final File file; public BuiltFileResource(File file) { this.file = file; } public BuiltFileResource(File dir, Artifact artifact) { this(new File(dir, IvyPatternHelper.substitute(BUILT_ARTIFACT_PATTERN, artifact))); } public String getName() { return file.toURI().toString(); } public Resource clone(String name) { return new BuiltFileResource(new File(name)); } public long getLastModified() { return file.lastModified(); } public long getContentLength() { return file.length(); } public boolean exists() { return file.exists(); } public String toString() { return getName(); } public File getFile() { return file; } public boolean isLocal() { return false; } public InputStream openStream() throws IOException { return new FileInputStream(file); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/PackagerCacheEntry.java000066400000000000000000000204441226750426600310010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.packager; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildLogger; import org.apache.tools.ant.DefaultLogger; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; /** * Represents one entry in the cache of a {@link PackagerResolver}. */ public class PackagerCacheEntry { private final ModuleRevisionId mr; private final File dir; private final File resourceCache; private final String resourceURL; private final boolean validate; private final boolean preserve; private final boolean restricted; private final boolean verbose; private final boolean quiet; private boolean built; // CheckStyle:ParameterNumber OFF public PackagerCacheEntry(ModuleRevisionId mr, File rootDir, File resourceCache, String resourceURL, boolean validate, boolean preserve, boolean restricted, boolean verbose, boolean quiet) { this.mr = mr; this.dir = getSubdir(rootDir, this.mr); this.resourceCache = resourceCache; this.resourceURL = resourceURL; this.validate = validate; this.preserve = preserve; this.restricted = restricted; this.verbose = verbose; this.quiet = quiet; } // CheckStyle:ParameterNumber ON /** * Attempt to build this entry. * * @param packagerResource * packager metadata resource * @param properties * a map of properties to pass to the child Ant build responsible for dependency * packaging * * @throws IllegalStateException * if this entry has already been built */ public synchronized void build(Resource packagerResource, Map properties) throws IOException { // Sanity check if (this.built) { throw new IllegalStateException("build in directory `" + this.dir + "' already completed"); } // Remove work directory if it exists (e.g. left over from last time) if (this.dir.exists()) { if (!cleanup()) { throw new IOException("can't remove directory `" + this.dir + "'"); } } // Create work directory if (!this.dir.mkdirs()) { throw new IOException("can't create directory `" + this.dir + "'"); } // Write out packager XML InputStream packagerXML = packagerResource.openStream(); saveFile("packager.xml", packagerXML); // Write packager XSLT saveFile("packager.xsl"); // Write packager XSD saveFile("packager-1.0.xsd"); // Write master Ant build file saveFile("build.xml"); // Execute the Ant build file Project project = new Project(); project.init(); project.setUserProperty("ant.file", new File(dir, "build.xml").getAbsolutePath()); ProjectHelper.configureProject(project, new File(dir, "build.xml")); project.setBaseDir(dir); // Configure logging verbosity BuildLogger logger = new DefaultLogger(); logger.setMessageOutputLevel(this.verbose ? Project.MSG_VERBOSE : this.quiet ? Project.MSG_WARN : Project.MSG_INFO); logger.setOutputPrintStream(System.out); logger.setErrorPrintStream(System.err); project.addBuildListener(logger); // Set properties project.setUserProperty("ivy.packager.organisation", "" + this.mr.getModuleId().getOrganisation()); project.setUserProperty("ivy.packager.module", "" + this.mr.getModuleId().getName()); project.setUserProperty("ivy.packager.revision", "" + this.mr.getRevision()); project.setUserProperty("ivy.packager.branch", "" + this.mr.getBranch()); if (this.resourceCache != null) { project.setUserProperty("ivy.packager.resourceCache", "" + this.resourceCache.getCanonicalPath()); } if (this.resourceURL != null) { project.setUserProperty("ivy.packager.resourceURL", "" + getResourceURL()); } if (this.validate) { project.setUserProperty("ivy.packager.validate", "true"); } project.setUserProperty("ivy.packager.restricted", "" + this.restricted); project.setUserProperty("ivy.packager.quiet", String.valueOf(quiet)); if (properties != null) { for (Iterator it = properties.entrySet().iterator(); it.hasNext();) { Entry entry = (Entry) it.next(); project.setUserProperty((String) entry.getKey(), (String) entry.getValue()); } } // Execute task Message.verbose("performing packager resolver build in " + this.dir); try { project.executeTarget("build"); this.built = true; } catch (BuildException e) { Message.verbose("packager resolver build failed: " + e); throw e; } } /** * Has this entry been successfully built? */ public synchronized boolean isBuilt() { return this.built; } /** * Get a built artifact. * * @throws IllegalStateException * if this entry's built has not (yet) completed successfully */ public ResolvedResource getBuiltArtifact(Artifact artifact) { if (!this.built) { throw new IllegalStateException("build in directory `" + this.dir + "' has not yet successfully completed"); } return new ResolvedResource(new BuiltFileResource(this.dir, artifact), this.mr.getRevision()); } public synchronized boolean cleanup() { this.built = false; return FileUtil.forceDelete(this.dir); } protected void saveFile(String name, InputStream input) throws IOException { FileUtil.copy(input, new File(this.dir, name), null); } protected void saveFile(String name) throws IOException { InputStream input = getClass().getResourceAsStream(name); if (input == null) { throw new IOException("can't find resource `" + name + "'"); } saveFile(name, input); } // @Override protected void finalize() throws Throwable { try { if (!this.preserve) { cleanup(); } } finally { super.finalize(); } } private String getResourceURL() { String baseURL = IvyPatternHelper.substitute(resourceURL, mr.getOrganisation(), mr.getName(), mr.getRevision(), null, null, null, null, mr.getQualifiedExtraAttributes(), null); int slash = baseURL.lastIndexOf('/'); if (slash != -1) { baseURL = baseURL.substring(0, slash + 1); } return baseURL; } private static File getSubdir(File rootDir, ModuleRevisionId mr) { return new File(rootDir, mr.getOrganisation() + File.separatorChar + mr.getName() + File.separatorChar + mr.getRevision()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/PackagerResolver.java000066400000000000000000000172541226750426600305620ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.packager; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.resolver.URLResolver; import org.apache.ivy.plugins.resolver.util.ResolvedResource; import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; /** * Resolver that performs a "build" operation to resolve artifacts. * *

    * The resolver is configured with a base URL, from which the "ivy.xml" and "packager.xml" files are * resolved. The latter file contains instructions describing how to build the actual artifacts. */ public class PackagerResolver extends URLResolver { private static final String PACKAGER_ARTIFACT_NAME = "packager"; private static final String PACKAGER_ARTIFACT_TYPE = "packager"; private static final String PACKAGER_ARTIFACT_EXT = "xml"; private final HashMap/* */packagerCache = new HashMap(); private File buildRoot; private File resourceCache; private String resourceURL; private Map/* */properties = new LinkedHashMap(); private boolean validate = true; private boolean preserve; private boolean restricted = true; private boolean verbose; private boolean quiet; public PackagerResolver() { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { clearCache(); } }); } protected synchronized void clearCache() { if (this.preserve) { return; } for (Iterator i = packagerCache.values().iterator(); i.hasNext();) { PackagerCacheEntry entry = (PackagerCacheEntry) i.next(); entry.cleanup(); } packagerCache.clear(); if (this.buildRoot != null) { FileUtil.forceDelete(this.buildRoot); } } /** * Set root directory under which builds take place. */ public void setBuildRoot(File buildRoot) { this.buildRoot = buildRoot; } /** * Returns root directory under which builds take place. */ public File getBuildRoot() { return buildRoot; } /** * Set resource cache directory. */ public void setResourceCache(File resourceCache) { this.resourceCache = resourceCache; } /** * Get resource cache directory. */ public File getResourceCache() { return resourceCache; } /** * Set base resource override URL pattern. */ public void setResourceURL(String resourceURL) { this.resourceURL = resourceURL; } /** * Set pattern for locating "packager.xml" files. */ public void setPackagerPattern(String pattern) { ArrayList list = new ArrayList(); list.add(pattern); setArtifactPatterns(list); } /** * Set whether to preserve build directories. Default is false. */ public void setPreserveBuildDirectories(boolean preserve) { this.preserve = preserve; } /** * Set whether to enable restricted mode. Default is true. */ public void setRestricted(boolean restricted) { this.restricted = restricted; } /** * Set whether to run ant with the -verbose flag. Default is false. */ public void setVerbose(boolean verbose) { this.verbose = verbose; } /** * Set whether to run ant with the -quiet flag. Default is false. */ public void setQuiet(boolean quiet) { this.quiet = quiet; } /** * Set whether to validate downloaded packager.xml files. Default is true. */ public void setValidate(boolean validate) { this.validate = validate; } public void setAllownomd(boolean b) { Message.error("allownomd not supported by resolver " + this); } public void setDescriptor(String rule) { if (DESCRIPTOR_OPTIONAL.equals(rule)) { Message.error("descriptor=\"" + DESCRIPTOR_OPTIONAL + "\" not supported by resolver " + this); return; } super.setDescriptor(rule); } /** * Sets a property to be passed to the child Ant build responsible for packaging the dependency. * * @param propertyKey * the property to pass * @param propertyValue * the value of the property to pass */ public void setProperty(String propertyKey, String propertyValue) { properties.put(propertyKey, propertyValue); } // @Override public void validate() { super.validate(); if (this.buildRoot == null) { throw new IllegalStateException("no buildRoot specified"); } if (getArtifactPatterns().size() == 0) { throw new IllegalStateException("no packager pattern specified"); } } // @Override public synchronized ResolvedResource findArtifactRef(Artifact artifact, Date date) { // For our special packager.xml file, defer to superclass if (PACKAGER_ARTIFACT_NAME.equals(artifact.getName()) && PACKAGER_ARTIFACT_TYPE.equals(artifact.getType()) && PACKAGER_ARTIFACT_EXT.equals(artifact.getExt())) { return super.findArtifactRef(artifact, date); } // Check the cache ModuleRevisionId mr = artifact.getModuleRevisionId(); PackagerCacheEntry entry = (PackagerCacheEntry) packagerCache.get(mr); // Ignore invalid entries if (entry != null && !entry.isBuilt()) { packagerCache.remove(mr); entry.cleanup(); entry = null; } // Build the artifacts (if not done already) if (entry == null) { ResolvedResource packager = findArtifactRef(new DefaultArtifact(mr, null, PACKAGER_ARTIFACT_NAME, PACKAGER_ARTIFACT_TYPE, PACKAGER_ARTIFACT_EXT), date); if (packager == null) { return null; } entry = new PackagerCacheEntry(mr, this.buildRoot, this.resourceCache, this.resourceURL, this.validate, this.preserve, this.restricted, this.verbose, this.quiet); try { entry.build(packager.getResource(), properties); } catch (IOException e) { throw new RuntimeException("can't build artifact " + artifact, e); } packagerCache.put(mr, entry); } // Return reference to desired artifact return entry.getBuiltArtifact(artifact); } public String getTypeName() { return "packager"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/build.xml000066400000000000000000000047651226750426600263040ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/packager-1.0.xsd000066400000000000000000000115551226750426600272470ustar00rootroot00000000000000 ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/packager/packager.xsl000066400000000000000000000546621226750426600267710ustar00rootroot00000000000000 GENERATED FILE - DO NOT EDIT build tag <> not allowed in restricted mode ${ivy.packager.resourceCache} using resource cache: ${ivy.packager.resourceCache} archive gzip bzip2 jar war zip tar tar.gz tar.gz tar.bz2 ignoring unexpected XML node <> ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/000077500000000000000000000000001226750426600236475ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/ApacheHttpURLLister.java000066400000000000000000000025321226750426600303030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import java.io.IOException; import java.net.URL; import java.util.List; import org.apache.ivy.util.url.ApacheURLLister; public class ApacheHttpURLLister implements URLLister { private ApacheURLLister lister = new ApacheURLLister(); public boolean accept(String pattern) { return pattern.startsWith("http"); } public List listAll(URL url) throws IOException { return lister.listAll(url); } public String toString() { return "apache http lister"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/FileURLLister.java000066400000000000000000000043621226750426600271440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class FileURLLister implements URLLister { private File basedir; public FileURLLister() { this(null); } public FileURLLister(File baseDir) { this.basedir = baseDir; } public boolean accept(String pattern) { return pattern.startsWith("file"); } public List listAll(URL url) throws IOException { String path; try { path = new File(new URI(url.toExternalForm())).getPath(); } catch (URISyntaxException e) { // unexpected try to get the best of it path = url.getPath(); } File file = basedir == null ? new File(path) : new File(basedir, path); if (file.exists() && file.isDirectory()) { String[] files = file.list(); List ret = new ArrayList(files.length); URL context = url.getPath().endsWith("/") ? url : new URL(url.toExternalForm() + "/"); for (int i = 0; i < files.length; i++) { ret.add(new URL(context, files[i])); } return ret; } else { return Collections.EMPTY_LIST; } } public String toString() { return "file lister"; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/HasLatestStrategy.java000066400000000000000000000021171226750426600301260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import org.apache.ivy.plugins.latest.LatestStrategy; public interface HasLatestStrategy { public LatestStrategy getLatestStrategy(); public void setLatestStrategy(LatestStrategy latestStrategy); public String getLatest(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/MDResolvedResource.java000066400000000000000000000024361226750426600302330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.plugins.repository.Resource; public class MDResolvedResource extends ResolvedResource { private ResolvedModuleRevision rmr; public MDResolvedResource(Resource res, String rev, ResolvedModuleRevision rmr) { super(res, rev); this.rmr = rmr; } public ResolvedModuleRevision getResolvedModuleRevision() { return rmr; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/ResolvedResource.java000066400000000000000000000027071226750426600300130ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.repository.Resource; public class ResolvedResource implements ArtifactInfo { private Resource res; private String rev; public ResolvedResource(Resource res, String rev) { this.res = res; this.rev = rev; } public String getRevision() { return rev; } public Resource getResource() { return res; } public String toString() { return res + " (" + rev + ")"; } public long getLastModified() { return getResource().getLastModified(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/ResolverHelper.java000066400000000000000000000370271226750426600274640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.repository.Repository; import org.apache.ivy.plugins.repository.Resource; import org.apache.ivy.util.Message; public final class ResolverHelper { private ResolverHelper() { } // lists all the values a token can take in a pattern, as listed by a given url lister public static String[] listTokenValues(Repository rep, String pattern, String token) { String fileSep = rep.getFileSeparator(); pattern = rep.standardize(pattern); String tokenString = IvyPatternHelper.getTokenString(token); int index = pattern.indexOf(tokenString); if (index == -1) { Message.verbose("unable to list " + token + " in " + pattern + ": token not found in pattern"); return null; } if (((pattern.length() <= index + tokenString.length()) || fileSep.equals(pattern .substring(index + tokenString.length(), index + tokenString.length() + 1))) && (index == 0 || fileSep.equals(pattern.substring(index - 1, index)))) { // the searched token is a whole name String root = pattern.substring(0, index); return listAll(rep, root); } else { int slashIndex = pattern.substring(0, index).lastIndexOf(fileSep); String root = slashIndex == -1 ? "" : pattern.substring(0, slashIndex); try { Message.debug("\tusing " + rep + " to list all in " + root); List all = rep.list(root); if (all != null) { Message.debug("\t\tfound " + all.size() + " urls"); List ret = new ArrayList(all.size()); int endNameIndex = pattern.indexOf(fileSep, slashIndex + 1); String namePattern; if (endNameIndex != -1) { namePattern = pattern.substring(slashIndex + 1, endNameIndex); } else { namePattern = pattern.substring(slashIndex + 1); } namePattern = namePattern.replaceAll("\\.", "\\\\."); namePattern = IvyPatternHelper.substituteToken(namePattern, token, "(.+)"); Pattern p = Pattern.compile(namePattern); for (Iterator iter = all.iterator(); iter.hasNext();) { String path = (String) iter.next(); Matcher m = p.matcher(path.substring(root.length() + 1)); if (m.matches()) { String value = m.group(1); ret.add(value); } } Message.debug("\t\t" + ret.size() + " matched " + pattern); return (String[]) ret.toArray(new String[ret.size()]); } else { return null; } } catch (IOException e) { Message.verbose("problem while listing resources in " + root + " with " + rep, e); return null; } catch (Exception e) { Message.warn("problem while listing resources in " + root + " with " + rep, e); return null; } } } public static String[] listAll(Repository rep, String parent) { try { String fileSep = rep.getFileSeparator(); Message.debug("\tusing " + rep + " to list all in " + parent); List all = rep.list(parent); if (all != null) { Message.debug("\t\tfound " + all.size() + " resources"); List names = new ArrayList(all.size()); for (Iterator iter = all.iterator(); iter.hasNext();) { String path = (String) iter.next(); if (path.endsWith(fileSep)) { path = path.substring(0, path.length() - 1); } int slashIndex = path.lastIndexOf(fileSep); names.add(path.substring(slashIndex + 1)); } return (String[]) names.toArray(new String[names.size()]); } else { Message.debug("\t\tno resources found"); return null; } } catch (IOException e) { Message.verbose("problem while listing resources in " + parent + " with " + rep, e); return null; } catch (Exception e) { Message.warn("problem while listing resources in " + parent + " with " + rep, e); return null; } } public static ResolvedResource[] findAll(Repository rep, ModuleRevisionId mrid, String pattern, Artifact artifact) { // substitute all but revision String partiallyResolvedPattern = IvyPatternHelper.substitute( pattern, ModuleRevisionId.newInstance(mrid, IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY)), artifact); Message.debug("\tlisting all in " + partiallyResolvedPattern); String[] revs = listTokenValues(rep, partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY); if (revs != null) { Message.debug("\tfound revs: " + Arrays.asList(revs)); List ret = new ArrayList(revs.length); for (int i = 0; i < revs.length; i++) { String rres = IvyPatternHelper.substituteToken(partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY, revs[i]); try { Resource res = rep.getResource(rres); if (res != null) { // we do not test if the resource actually exist here, it would cause // a lot of checks which are not always necessary depending on the usage // which is done of the returned ResolvedResource array ret.add(new ResolvedResource(res, revs[i])); } } catch (IOException e) { Message.warn("impossible to get resource from name listed by repository: " + rres, e); } } if (revs.length != ret.size()) { Message.debug("\tfound resolved res: " + ret); } return (ResolvedResource[]) ret.toArray(new ResolvedResource[ret.size()]); } else if (partiallyResolvedPattern.indexOf("[" + IvyPatternHelper.REVISION_KEY + "]") == -1) { // the partially resolved pattern is completely resolved, check the resource try { Resource res = rep.getResource(partiallyResolvedPattern); if (res.exists()) { Message.debug("\tonly one resource found without real listing: " + "using and defining it as working@" + rep.getName() + " revision: " + res.getName()); return new ResolvedResource[] {new ResolvedResource(res, "working@" + rep.getName())}; } } catch (IOException e) { Message.debug("\timpossible to get resource from name listed by repository: " + partiallyResolvedPattern, e); } Message.debug("\tno revision found"); } return null; } // public static ResolvedResource[] findAll(Repository rep, ModuleRevisionId mrid, String // pattern, Artifact artifact, VersionMatcher versionMatcher, ResourceMDParser mdParser) { // // substitute all but revision // String partiallyResolvedPattern = IvyPatternHelper.substitute(pattern, new // ModuleRevisionId(mrid.getModuleId(), // IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY), mrid.getExtraAttributes()), // artifact); // Message.debug("\tlisting all in "+partiallyResolvedPattern); // // String[] revs = listTokenValues(rep, partiallyResolvedPattern, // IvyPatternHelper.REVISION_KEY); // if (revs != null) { // Message.debug("\tfound revs: "+Arrays.asList(revs)); // List ret = new ArrayList(revs.length); // String rres = null; // for (int i = 0; i < revs.length; i++) { // ModuleRevisionId foundMrid = new ModuleRevisionId(mrid.getModuleId(), revs[i], // mrid.getExtraAttributes()); // if (versionMatcher.accept(mrid, foundMrid)) { // rres = IvyPatternHelper.substituteToken(partiallyResolvedPattern, // IvyPatternHelper.REVISION_KEY, revs[i]); // try { // ResolvedResource resolvedResource; // if (versionMatcher.needModuleDescriptor(mrid, foundMrid)) { // resolvedResource = mdParser.parse(rep.getResource(rres), revs[i]); // if (!versionMatcher.accept(mrid, // ((MDResolvedResource)resolvedResource).getResolvedModuleRevision().getDescriptor())) { // continue; // } // } else { // resolvedResource = new ResolvedResource(rep.getResource(rres), revs[i]); // } // ret.add(resolvedResource); // } catch (IOException e) { // Message.warn("impossible to get resource from name listed by repository: "+rres+": // "+e.getMessage()); // } // } // } // if (revs.length != ret.size()) { // Message.debug("\tfound resolved res: "+ret); // } // return (ResolvedResource[])ret.toArray(new ResolvedResource[ret.size()]); // } else { // // maybe the partially resolved pattern is completely resolved ? // try { // Resource res = rep.getResource(partiallyResolvedPattern); // if (res.exists()) { // Message.debug("\tonly one resource found without real listing: using and defining it as // working@"+rep.getName()+" revision: "+res.getName()); // return new ResolvedResource[] {new ResolvedResource(res, "working@"+rep.getName())}; // } // } catch (IOException e) { // Message.debug("\timpossible to get resource from name listed by repository: // "+partiallyResolvedPattern+": "+e.getMessage()); // } // Message.debug("\tno revision found"); // } // return null; // } // lists all the values a token can take in a pattern, as listed by a given url lister public static String[] listTokenValues(URLLister lister, String pattern, String token) { pattern = standardize(pattern); if (lister.accept(pattern)) { String tokenString = IvyPatternHelper.getTokenString(token); int index = pattern.indexOf(tokenString); if (index == -1) { Message.verbose("unable to list " + token + " in " + pattern + ": token not found in pattern"); return null; } if (((pattern.length() <= index + tokenString.length()) || "/".equals(pattern .substring(index + tokenString.length(), index + tokenString.length() + 1))) && (index == 0 || "/".equals(pattern.substring(index - 1, index)))) { // the searched token is a whole name String root = pattern.substring(0, index); try { return listAll(lister, new URL(root)); } catch (MalformedURLException e) { Message.warn("malformed url from pattern root: " + root + ": " + e.getMessage()); return null; } } else { int slashIndex = pattern.substring(0, index).lastIndexOf('/'); String root = slashIndex == -1 ? "" : pattern.substring(0, slashIndex); try { Message.debug("\tusing " + lister + " to list all in " + root); List all = lister.listAll(new URL(root)); Message.debug("\t\tfound " + all.size() + " urls"); List ret = new ArrayList(all.size()); int endNameIndex = pattern.indexOf('/', slashIndex + 1); String namePattern; if (endNameIndex != -1) { namePattern = pattern.substring(slashIndex + 1, endNameIndex); } else { namePattern = pattern.substring(slashIndex + 1); } String acceptNamePattern = ".*" + IvyPatternHelper.substituteToken(namePattern, token, "([^/]+)") + ".*"; Pattern p = Pattern.compile(acceptNamePattern.toString()); for (Iterator iter = all.iterator(); iter.hasNext();) { URL url = (URL) iter.next(); String path = standardize(url.getPath()); Matcher m = p.matcher(path); if (m.matches()) { String value = m.group(1); ret.add(value); } } Message.debug("\t\t" + ret.size() + " matched " + pattern); return (String[]) ret.toArray(new String[ret.size()]); } catch (Exception e) { Message.warn("problem while listing files in " + root, e); return null; } } } return null; } private static String standardize(String path) { return path.replace('\\', '/'); } public static String[] listAll(URLLister lister, URL root) { try { if (lister.accept(root.toExternalForm())) { Message.debug("\tusing " + lister + " to list all in " + root); List all = lister.listAll(root); Message.debug("\t\tfound " + all.size() + " urls"); List names = new ArrayList(all.size()); for (Iterator iter = all.iterator(); iter.hasNext();) { URL dir = (URL) iter.next(); String path = dir.getPath(); if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } int slashIndex = path.lastIndexOf('/'); names.add(path.substring(slashIndex + 1)); } return (String[]) names.toArray(new String[names.size()]); } return null; } catch (Exception e) { Message.warn("problem while listing directories in " + root, e); return null; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/ResourceMDParser.java000066400000000000000000000026711226750426600277050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import org.apache.ivy.plugins.repository.Resource; public interface ResourceMDParser { /** * Parses the module descriptor designed by the given resource. * * @param resource * the resource at which the module descriptor is located * @param rev * the revision at which the module descriptor should be * @return the parsed module descriptor as a {@link MDResolvedResource}, or null if * parsing has failed or if the resource is not available. */ MDResolvedResource parse(Resource resource, String rev); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/resolver/util/URLLister.java000066400000000000000000000023171226750426600263420ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.resolver.util; import java.io.IOException; import java.net.URL; import java.util.List; public interface URLLister { /** * Indicates if this lister is able to list urls with the given pattern. In general, only * protocol is used. * * @param pattern * @return */ boolean accept(String pattern); List listAll(URL url) throws IOException; } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/signer/000077500000000000000000000000001226750426600223205ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java000066400000000000000000000020371226750426600267750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.signer; import java.io.File; import java.io.IOException; public interface SignatureGenerator { String getName(); void sign(File src, File dest) throws IOException; String getExtension(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/signer/bouncycastle/000077500000000000000000000000001226750426600250135ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java000066400000000000000000000136111226750426600326610ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.signer.bouncycastle; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Security; import java.security.SignatureException; import java.util.Iterator; import org.apache.ivy.plugins.signer.SignatureGenerator; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.BCPGOutputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPUtil; public class OpenPGPSignatureGenerator implements SignatureGenerator { private static final long MASK = 0xFFFFFFFFL; static { Security.addProvider(new BouncyCastleProvider()); } private String name; private String secring; private String password; private String keyId; private PGPSecretKey pgpSec; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getExtension() { return "asc"; } public void setPassword(String password) { this.password = password; } public void setSecring(String secring) { this.secring = secring; } public void setKeyId(String keyId) { if (!"auto".equals(keyId)) { this.keyId = keyId; } } public void sign(File src, File dest) throws IOException { OutputStream out = null; InputStream in = null; InputStream keyIn = null; try { if (secring == null) { secring = System.getProperty("user.home") + "/.gnupg/secring.gpg"; } if (pgpSec == null) { keyIn = new FileInputStream(secring); pgpSec = readSecretKey(keyIn); } PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(password.toCharArray(), BouncyCastleProvider.PROVIDER_NAME); PGPSignatureGenerator sGen = new PGPSignatureGenerator(pgpSec.getPublicKey() .getAlgorithm(), PGPUtil.SHA1, BouncyCastleProvider.PROVIDER_NAME); sGen.initSign(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); in = new FileInputStream(src); out = new BCPGOutputStream(new ArmoredOutputStream(new FileOutputStream(dest))); int ch = 0; while ((ch = in.read()) >= 0) { sGen.update((byte) ch); } sGen.generate().encode(out); } catch (SignatureException e) { IOException ioexc = new IOException(); ioexc.initCause(e); throw ioexc; } catch (PGPException e) { IOException ioexc = new IOException(); ioexc.initCause(e); throw ioexc; } catch (NoSuchAlgorithmException e) { IOException ioexc = new IOException(); ioexc.initCause(e); throw ioexc; } catch (NoSuchProviderException e) { IOException ioexc = new IOException(); ioexc.initCause(e); throw ioexc; } finally { if (out != null) { try { out.close(); } catch (IOException e) { } } if (in != null) { try { in.close(); } catch (IOException e) { } } if (keyIn != null) { try { keyIn.close(); } catch (IOException e) { } } } } private PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException { in = PGPUtil.getDecoderStream(in); PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in); PGPSecretKey key = null; for (Iterator it = pgpSec.getKeyRings(); key == null && it.hasNext();) { PGPSecretKeyRing kRing = (PGPSecretKeyRing) it.next(); for (Iterator it2 = kRing.getSecretKeys(); key == null && it2.hasNext();) { PGPSecretKey k = (PGPSecretKey) it2.next(); if ((keyId == null) && k.isSigningKey()) { key = k; } if ((keyId != null) && (Long.valueOf(keyId, 16).longValue() == (k.getKeyID() & MASK))) { key = k; } } } if (key == null) { throw new IllegalArgumentException("Can't find encryption key" + (keyId != null ? " '" + keyId + "' " : " ") + "in key ring."); } return key; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/trigger/000077500000000000000000000000001226750426600224745ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/trigger/AbstractTrigger.java000066400000000000000000000047671226750426600264440ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.trigger; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.event.IvyEventFilter; import org.apache.ivy.core.event.IvyListener; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.util.filter.Filter; /** * Base class for easy trigger implementation. This base class takes of the event filtering part, * the only method to implement in subclasses is {@link IvyListener#progress(IvyEvent)} which should * do whatever the trigger needs to do when the event occurs. This method will only be called when * an event matching the trigger filter occurs. * * @since 1.4 */ public abstract class AbstractTrigger implements Trigger { private Filter filter; private String event; private String expression; private String matcher = PatternMatcher.EXACT; public Filter getEventFilter() { if (filter == null) { filter = createFilter(); } return filter; } private Filter createFilter() { return new IvyEventFilter(getEvent(), getFilter(), getPatternMatcher()); } private PatternMatcher getPatternMatcher() { return IvyContext.getContext().getSettings().getMatcher(matcher); } public String getEvent() { return event; } public void setEvent(String event) { this.event = event; } public String getFilter() { return expression; } public void setFilter(String filterExpression) { expression = filterExpression; } public String getMatcher() { return matcher; } public void setMatcher(String matcher) { this.matcher = matcher; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/trigger/LogTrigger.java000066400000000000000000000100761226750426600254100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.trigger; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.event.IvyEvent; import org.apache.ivy.core.resolve.ResolveProcessException; import org.apache.ivy.util.Message; /** * A trigger performing logging. *

    * The implementation is widely inspired by Ant Echo task. *

    */ public class LogTrigger extends AbstractTrigger { private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private String message = ""; private File file = null; private boolean append = true; /** encoding; set to null or empty means 'default' */ private String encoding = ""; public void progress(IvyEvent event) { log(IvyPatternHelper.substituteVariables(message, event.getAttributes())); } /** * Logs the given message. * * @param message * the message to log */ protected void log(String message) { if (file == null) { Message.info(message); } else { Writer out = null; try { // we add a line separator here for consistency with Message.info which creates a // new line each time. // we use the system dependent line separator to ease reading the log file message += LINE_SEPARATOR; String filename = file.getAbsolutePath(); if (encoding == null || encoding.length() == 0) { out = new FileWriter(filename, append); } else { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, append), encoding)); } out.write(message, 0, message.length()); } catch (IOException e) { throw new ResolveProcessException(e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { throw new ResolveProcessException(e); } } } } } /** * Message to write. * * @param msg * Sets the value for the message variable. */ public void setMessage(String msg) { this.message = msg; } /** * File to write to. * * @param file * the file to write to, if not set, echo to standard Ivy logging */ public void setFile(File file) { this.file = file; } /** * If true, append to existing file. * * @param append * if true, append to existing file, default is false. */ public void setAppend(boolean append) { this.append = append; } /** * Declare the encoding to use when outputting to a file; Use "" for the platform's default * encoding. * * @param encoding * the character encoding to use. */ public void setEncoding(String encoding) { this.encoding = encoding; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/trigger/Trigger.java000066400000000000000000000020011226750426600247330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.trigger; import org.apache.ivy.core.event.IvyListener; import org.apache.ivy.util.filter.Filter; public interface Trigger extends IvyListener { Filter getEventFilter(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/000077500000000000000000000000001226750426600225165ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/AbstractVersionMatcher.java000066400000000000000000000046211226750426600300010ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Comparator; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; import org.apache.ivy.util.Checks; public abstract class AbstractVersionMatcher implements VersionMatcher, IvySettingsAware { private String name; private IvySettings settings; public AbstractVersionMatcher() { } public AbstractVersionMatcher(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean needModuleDescriptor(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { return false; } public boolean accept(ModuleRevisionId askedMrid, ModuleDescriptor foundMD) { return accept(askedMrid, foundMD.getResolvedModuleRevisionId()); } /** * This method should be overriden in most cases, because it uses the default contract to return * 1 when it's not possible to know which revision is greater. */ public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator) { return 0; } public String toString() { return getName(); } public IvySettings getSettings() { return settings; } public void setSettings(IvySettings settings) { Checks.checkNotNull(settings, "settings"); this.settings = settings; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/ChainVersionMatcher.java000066400000000000000000000136271226750426600272660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.IvySettingsAware; import org.apache.ivy.util.Checks; /** * An implementation of {@link VersionMatcher} chaining several version matchers, and implemeting * the {@link VersionMatcher} interface by returning results from the first matcher in the chain * accepting the version. */ public class ChainVersionMatcher extends AbstractVersionMatcher { /** * The list of version matchers in the chain. This list will be queried in order, so the last * matcher will be used only if no other matcher accept the revision before. */ private List/* */matchers = new LinkedList(); /** * Unique Constructor. */ public ChainVersionMatcher() { super("chain"); } /** * Adds a {@link VersionMatcher} to the chain. * * @param matcher * the version matcher to add. Must not be null */ public void add(VersionMatcher matcher) { Checks.checkNotNull(matcher, "matcher"); matchers.add(0, matcher); if (getSettings() != null && matcher instanceof IvySettingsAware) { ((IvySettingsAware) matcher).setSettings(getSettings()); } } /** * Sets the settings this matcher will use, and set to the matcher in the chain which implements * {@link IvySettingsAware}. * * @param settings * the settings to use in the whole chain. Must not be null. */ public void setSettings(IvySettings settings) { super.setSettings(settings); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (matcher instanceof IvySettingsAware) { ((IvySettingsAware) matcher).setSettings(settings); } } } /** * Returns the list of matchers in the chain. *

    * The list is returned as an unmodifiable view on the actual list of matchers, and will thus * reflect futher changes made in the chain. * * @return the list of matchers in the chain. Is never null. */ public List getMatchers() { return Collections.unmodifiableList(matchers); } public boolean isDynamic(ModuleRevisionId askedMrid) { Checks.checkNotNull(askedMrid, "askedMrid"); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (matcher.isDynamic(askedMrid)) { return true; } } return false; } public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator) { Checks.checkNotNull(askedMrid, "askedMrid"); Checks.checkNotNull(foundMrid, "foundMrid"); Checks.checkNotNull(staticComparator, "staticComparator"); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (matcher.isDynamic(askedMrid)) { return matcher.compare(askedMrid, foundMrid, staticComparator); } } throw new IllegalArgumentException( "impossible to compare revisions: askedMrid is not dynamic: " + askedMrid); } public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { Checks.checkNotNull(askedMrid, "askedMrid"); Checks.checkNotNull(foundMrid, "foundMrid"); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (!iter.hasNext() || matcher.isDynamic(askedMrid)) { return matcher.accept(askedMrid, foundMrid); } } return false; } public boolean needModuleDescriptor(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { Checks.checkNotNull(askedMrid, "askedMrid"); Checks.checkNotNull(foundMrid, "foundMrid"); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (!iter.hasNext() || matcher.isDynamic(askedMrid)) { return matcher.needModuleDescriptor(askedMrid, foundMrid); } } return false; } public boolean accept(ModuleRevisionId askedMrid, ModuleDescriptor foundMD) { Checks.checkNotNull(askedMrid, "askedMrid"); Checks.checkNotNull(foundMD, "foundMD"); for (Iterator iter = matchers.iterator(); iter.hasNext();) { VersionMatcher matcher = (VersionMatcher) iter.next(); if (!iter.hasNext() || matcher.isDynamic(askedMrid)) { return matcher.accept(askedMrid, foundMD); } } return false; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/ExactVersionMatcher.java000066400000000000000000000024231226750426600273000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import org.apache.ivy.core.module.id.ModuleRevisionId; public class ExactVersionMatcher extends AbstractVersionMatcher { public ExactVersionMatcher() { super("exact"); } public boolean isDynamic(ModuleRevisionId askedMrid) { return false; } public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { return askedMrid.getRevision().equals(foundMrid.getRevision()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/LatestVersionMatcher.java000066400000000000000000000050411226750426600274670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Comparator; import java.util.List; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.module.status.Status; import org.apache.ivy.core.module.status.StatusManager; public class LatestVersionMatcher extends AbstractVersionMatcher { public LatestVersionMatcher() { super("latest"); } public boolean isDynamic(ModuleRevisionId askedMrid) { return askedMrid.getRevision().startsWith("latest."); } public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { return true; } public boolean needModuleDescriptor(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { List statuses = StatusManager.getCurrent().getStatuses(); Status lowest = (Status) statuses.get(statuses.size() - 1); String latestLowest = "latest." + lowest.getName(); return !latestLowest.equals(askedMrid.getRevision()); } public boolean accept(ModuleRevisionId askedMrid, ModuleDescriptor foundMD) { String askedStatus = askedMrid.getRevision().substring("latest.".length()); return StatusManager.getCurrent().getPriority(askedStatus) >= StatusManager.getCurrent() .getPriority(foundMD.getStatus()); } /** * If we don't need a module descriptor we can consider the dynamic revision to be greater. If * we need a module descriptor then we can't know which one is greater and return 0. */ public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator) { return needModuleDescriptor(askedMrid, foundMrid) ? 0 : 1; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/Match.java000066400000000000000000000073161226750426600244240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.apache.ivy.core.IvyContext; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.matcher.Matcher; import org.apache.ivy.plugins.matcher.PatternMatcher; /** * */ public class Match { private String revision; private String pattern; private String args; private String matcher; public String getArgs() { return args; } public void setArgs(String args) { this.args = args; } public String getMatcher() { return matcher; } public void setMatcher(String matcher) { this.matcher = matcher; } public String getPattern() { return pattern; } public void setPattern(String pattern) { this.pattern = pattern; } public String getRevision() { return revision; } public void setRevision(String revision) { this.revision = revision; } public Matcher getPatternMatcher(ModuleRevisionId askedMrid) { String revision = askedMrid.getRevision(); String[] args = split(getArgs()); String[] argValues = getRevisionArgs(revision); if (args.length != argValues.length) { return new NoMatchMatcher(); } Map variables = new HashMap(); for (int i = 0; i < args.length; i++) { variables.put(args[i], argValues[i]); } String pattern = getPattern(); pattern = IvyPatternHelper.substituteVariables(pattern, variables); PatternMatcher pMatcher = IvyContext.getContext().getSettings().getMatcher(matcher); return pMatcher.getMatcher(pattern); } private String[] getRevisionArgs(String revision) { int bracketStartIndex = revision.indexOf('('); if (bracketStartIndex == -1) { return new String[0]; } int bracketEndIndex = revision.indexOf(')'); if (bracketEndIndex <= (bracketStartIndex + 1)) { return new String[0]; } String args = revision.substring(bracketStartIndex + 1, bracketEndIndex); return split(args); } private static String[] split(String string) { if (string == null) { return new String[0]; } StringTokenizer tokenizer = new StringTokenizer(string, ", "); List tokens = new ArrayList(); while (tokenizer.hasMoreTokens()) { tokens.add(tokenizer.nextToken()); } return (String[]) tokens.toArray(new String[tokens.size()]); } private static class NoMatchMatcher implements Matcher { public boolean isExact() { return false; } public boolean matches(String str) { return false; } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/PatternVersionMatcher.java000066400000000000000000000060661226750426600276600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.matcher.Matcher; /** * */ public class PatternVersionMatcher extends AbstractVersionMatcher { private List matches = new ArrayList(); private Map revisionMatches = new HashMap(); // revision -> list of Match instances private boolean init = false; public void addMatch(Match match) { matches.add(match); } private void init() { if (!init) { for (Iterator it = matches.iterator(); it.hasNext();) { Match match = (Match) it.next(); List revMatches = (List) revisionMatches.get(match.getRevision()); if (revMatches == null) { revMatches = new ArrayList(); revisionMatches.put(match.getRevision(), revMatches); } revMatches.add(match); } init = true; } } /** * {@inheritDoc} */ public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { init(); boolean accept = false; String revision = askedMrid.getRevision(); int bracketIndex = revision.indexOf('('); if (bracketIndex > 0) { revision = revision.substring(0, bracketIndex); } List revMatches = (List) revisionMatches.get(revision); if (revMatches != null) { Iterator it = revMatches.iterator(); while (!accept && it.hasNext()) { Match match = (Match) it.next(); Matcher matcher = match.getPatternMatcher(askedMrid); accept = matcher.matches(foundMrid.getRevision()); } } return accept; } /** * {@inheritDoc} */ public boolean isDynamic(ModuleRevisionId askedMrid) { init(); String revision = askedMrid.getRevision(); int bracketIndex = revision.indexOf('('); if (bracketIndex > 0) { revision = revision.substring(0, bracketIndex); } return revisionMatches.containsKey(revision); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/SubVersionMatcher.java000066400000000000000000000034241226750426600267670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Comparator; import org.apache.ivy.core.module.id.ModuleRevisionId; public class SubVersionMatcher extends AbstractVersionMatcher { public SubVersionMatcher() { super("sub-version"); } public boolean isDynamic(ModuleRevisionId askedMrid) { return askedMrid.getRevision().endsWith("+"); } public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { String prefix = askedMrid.getRevision().substring(0, askedMrid.getRevision().length() - 1); return foundMrid.getRevision().startsWith(prefix); } public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator) { if (foundMrid.getRevision().startsWith( askedMrid.getRevision().substring(0, askedMrid.getRevision().length() - 1))) { return 1; } return staticComparator.compare(askedMrid, foundMrid); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/VersionMatcher.java000066400000000000000000000113661226750426600263210ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Comparator; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; /** * This interface defines a version matcher, i.e. a class able to tell if the revision asked by a * module for a dependency is dynamic (i.e. need to find all revisions to find the good one among * them) and if a found revision matches the asked one. *

    * Two ways of matching are possible: *

      *
    • based on the module revision only (known as ModuleRevisionId)
    • *
    • based on the parsed module descriptor
    • *
    * The second being much more time consuming than the first, the version matcher should tell if it * needs such parsing or not using the * {@link #needModuleDescriptor(ModuleRevisionId, ModuleRevisionId)} method. Anyway, the first way * is always used, and if a revision is not accepted using the first method, the module descriptor * won't be parsed. Therefore if a version matcher uses only module descriptors to accept a revision * or not it should always return true to * {@link #needModuleDescriptor(ModuleRevisionId, ModuleRevisionId)} and * {@link #accept(ModuleRevisionId, ModuleDescriptor)}. */ public interface VersionMatcher { /** * Indicates if the given asked ModuleRevisionId should be considered as dynamic for the current * VersionMatcher or not. * * @param askedMrid * the dependency module revision id as asked by a module * @return true if this revision is considered as a dynamic one, false otherwise */ public boolean isDynamic(ModuleRevisionId askedMrid); /** * Indicates if this version matcher considers that the module revision found matches the asked * one. * * @param askedMrid * @param foundMrid * @return */ public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid); /** * Indicates if this VersionMatcher needs module descriptors to determine if a module revision * matches the asked one. Note that returning true in this method may imply big performance * issues. * * @return */ public boolean needModuleDescriptor(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid); /** * Indicates if this version matcher considers that the module found matches the asked one. This * method can be called even needModuleDescriptor(ModuleRevisionId askedMrid, ModuleRevisionId * foundMrid) returns false, so it is required to implement it in any case, a usual default * implementation being: return accept(askedMrid, foundMD.getResolvedModuleRevisionId()); * * @param askedMrid * @param foundMD * @return */ public boolean accept(ModuleRevisionId askedMrid, ModuleDescriptor foundMD); /** * Compares a dynamic revision (askedMrid) with a static one (foundMrid) to indicate which one * should be considered the greater. If there is not enough information to know which one is the * greater, the dynamic one should be considered greater and this method should return 0. This * method should never be called with a askdeMrid for which isDynamic returns false. * * @param askedMrid * the dynamic revision to compare * @param foundMrid * the static revision to compare * @param staticComparator * a comparator which can be used to compare static revisions * @return 0 if it's not possible to know which one is greater, greater than 0 if askedMrid * should be considered greater, lower than 0 if it can't be consider greater */ public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator); /** * Returns the version matcher name identifying this version matcher * * @return the version matcher name identifying this version matcher */ public String getName(); } ivy-2.4.0-rc1/src/java/org/apache/ivy/plugins/version/VersionRangeMatcher.java000066400000000000000000000234431226750426600272750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.plugins.version; import java.util.Comparator; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.latest.LatestStrategy; /** * Matches version ranges: [1.0,2.0] matches all versions greater or equal to 1.0 and lower or equal * to 2.0 [1.0,2.0[ matches all versions greater or equal to 1.0 and lower than 2.0 ]1.0,2.0] * matches all versions greater than 1.0 and lower or equal to 2.0 ]1.0,2.0[ matches all versions * greater than 1.0 and lower than 2.0 [1.0,) matches all versions greater or equal to 1.0 ]1.0,) * matches all versions greater than 1.0 (,2.0] matches all versions lower or equal to 2.0 (,2.0[ * matches all versions lower than 2.0 This class uses a latest strategy to compare revisions. If * none is set, it uses the default one of the ivy instance set through setIvy(). If neither a * latest strategy nor a ivy instance is set, an IllegalStateException will be thrown when calling * accept(). Note that it can't work with latest time strategy, cause no time is known for the * limits of the range. Therefore only purely revision based LatestStrategy can be used. */ public class VersionRangeMatcher extends AbstractVersionMatcher { // todo: check these constants private static final String OPEN_INC = "["; private static final String OPEN_EXC = "]"; private static final String OPEN_EXC_MAVEN = "("; private static final String CLOSE_INC = "]"; private static final String CLOSE_EXC = "["; private static final String CLOSE_EXC_MAVEN = ")"; private static final String LOWER_INFINITE = "("; private static final String UPPER_INFINITE = ")"; private static final String SEPARATOR = ","; // following patterns are built upon constants above and should not be modified private static final String OPEN_INC_PATTERN = "\\" + OPEN_INC; private static final String OPEN_EXC_PATTERN = "\\" + OPEN_EXC + "\\" + OPEN_EXC_MAVEN; private static final String CLOSE_INC_PATTERN = "\\" + CLOSE_INC; private static final String CLOSE_EXC_PATTERN = "\\" + CLOSE_EXC + "\\" + CLOSE_EXC_MAVEN; private static final String LI_PATTERN = "\\" + LOWER_INFINITE; private static final String UI_PATTERN = "\\" + UPPER_INFINITE; private static final String SEP_PATTERN = "\\s*\\" + SEPARATOR + "\\s*"; private static final String OPEN_PATTERN = "[" + OPEN_INC_PATTERN + OPEN_EXC_PATTERN + "]"; private static final String CLOSE_PATTERN = "[" + CLOSE_INC_PATTERN + CLOSE_EXC_PATTERN + "]"; private static final String ANY_NON_SPECIAL_PATTERN = "[^\\s" + SEPARATOR + OPEN_INC_PATTERN + OPEN_EXC_PATTERN + CLOSE_INC_PATTERN + CLOSE_EXC_PATTERN + LI_PATTERN + UI_PATTERN + "]"; private static final String FINITE_PATTERN = OPEN_PATTERN + "\\s*(" + ANY_NON_SPECIAL_PATTERN + "+)" + SEP_PATTERN + "(" + ANY_NON_SPECIAL_PATTERN + "+)\\s*" + CLOSE_PATTERN; private static final String LOWER_INFINITE_PATTERN = LI_PATTERN + SEP_PATTERN + "(" + ANY_NON_SPECIAL_PATTERN + "+)\\s*" + CLOSE_PATTERN; private static final String UPPER_INFINITE_PATTERN = OPEN_PATTERN + "\\s*(" + ANY_NON_SPECIAL_PATTERN + "+)" + SEP_PATTERN + UI_PATTERN; private static final Pattern FINITE_RANGE = Pattern.compile(FINITE_PATTERN); private static final Pattern LOWER_INFINITE_RANGE = Pattern.compile(LOWER_INFINITE_PATTERN); private static final Pattern UPPER_INFINITE_RANGE = Pattern.compile(UPPER_INFINITE_PATTERN); private static final Pattern ALL_RANGE = Pattern.compile(FINITE_PATTERN + "|" + LOWER_INFINITE_PATTERN + "|" + UPPER_INFINITE_PATTERN); private final class MRIDArtifactInfo implements ArtifactInfo { private ModuleRevisionId mrid; public MRIDArtifactInfo(ModuleRevisionId id) { mrid = id; } public long getLastModified() { return 0; } public String getRevision() { return mrid.getRevision(); } } private final Comparator comparator = new Comparator() { public int compare(Object o1, Object o2) { if (o1.equals(o2)) { return 0; } ArtifactInfo art1 = new MRIDArtifactInfo((ModuleRevisionId) o1); ArtifactInfo art2 = new MRIDArtifactInfo((ModuleRevisionId) o2); ArtifactInfo art = getLatestStrategy() .findLatest(new ArtifactInfo[] {art1, art2}, null); return art == art1 ? -1 : 1; } }; private LatestStrategy latestStrategy; private String latestStrategyName = "default"; public VersionRangeMatcher() { super("version-range"); } public VersionRangeMatcher(String name) { super(name); } public VersionRangeMatcher(String name, LatestStrategy strategy) { super(name); this.latestStrategy = strategy; } public boolean isDynamic(ModuleRevisionId askedMrid) { String revision = askedMrid.getRevision(); return ALL_RANGE.matcher(revision).matches(); } public boolean accept(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid) { String revision = askedMrid.getRevision(); Matcher m; m = FINITE_RANGE.matcher(revision); if (m.matches()) { String lower = m.group(1); String upper = m.group(2); return isUpper(askedMrid, lower, foundMrid, revision.startsWith(OPEN_INC)) && isLower(askedMrid, upper, foundMrid, revision.endsWith(CLOSE_INC)); } m = LOWER_INFINITE_RANGE.matcher(revision); if (m.matches()) { String upper = m.group(1); return isLower(askedMrid, upper, foundMrid, revision.endsWith(CLOSE_INC)); } m = UPPER_INFINITE_RANGE.matcher(revision); if (m.matches()) { String lower = m.group(1); return isUpper(askedMrid, lower, foundMrid, revision.startsWith(OPEN_INC)); } return false; } private boolean isLower(ModuleRevisionId askedMrid, String revision, ModuleRevisionId foundMrid, boolean inclusive) { ModuleRevisionId mRevId = ModuleRevisionId.newInstance(askedMrid, revision); int result = comparator.compare(mRevId, foundMrid); return result <= (inclusive ? 0 : -1); } private boolean isUpper(ModuleRevisionId askedMrid, String revision, ModuleRevisionId foundMrid, boolean inclusive) { ModuleRevisionId mRevId = ModuleRevisionId.newInstance(askedMrid, revision); int result = comparator.compare(mRevId, foundMrid); return result >= (inclusive ? 0 : 1); } public int compare(ModuleRevisionId askedMrid, ModuleRevisionId foundMrid, Comparator staticComparator) { String revision = askedMrid.getRevision(); Matcher m; m = UPPER_INFINITE_RANGE.matcher(revision); if (m.matches()) { // no upper limit, the dynamic revision can always be considered greater return 1; } String upper; m = FINITE_RANGE.matcher(revision); if (m.matches()) { upper = m.group(2); } else { m = LOWER_INFINITE_RANGE.matcher(revision); if (m.matches()) { upper = m.group(1); } else { throw new IllegalArgumentException( "impossible to compare: askedMrid is not a dynamic revision: " + askedMrid); } } int c = staticComparator.compare(ModuleRevisionId.newInstance(askedMrid, upper), foundMrid); // if the comparison consider them equal, we must return -1, because we can't consider the // dynamic revision to be greater. Otherwise we can safeely return the result of the static // comparison return c == 0 ? -1 : c; } public LatestStrategy getLatestStrategy() { if (latestStrategy == null) { if (getSettings() == null) { throw new IllegalStateException( "no ivy instance nor latest strategy configured in version range matcher " + this); } if (latestStrategyName == null) { throw new IllegalStateException( "null latest strategy defined in version range matcher " + this); } latestStrategy = getSettings().getLatestStrategy(latestStrategyName); if (latestStrategy == null) { throw new IllegalStateException("unknown latest strategy '" + latestStrategyName + "' configured in version range matcher " + this); } } return latestStrategy; } public void setLatestStrategy(LatestStrategy latestStrategy) { this.latestStrategy = latestStrategy; } public void setLatest(String latestStrategyName) { this.latestStrategyName = latestStrategyName; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/000077500000000000000000000000001226750426600205105ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/000077500000000000000000000000001226750426600223265ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/DependencyAnalyser.java000066400000000000000000000017751226750426600267600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.tools.analyser; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; public interface DependencyAnalyser { public ModuleDescriptor[] analyze(JarModule[] modules); } ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/JarJarDependencyAnalyser.java000066400000000000000000000100211226750426600300320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.tools.analyser; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.util.Message; public class JarJarDependencyAnalyser implements DependencyAnalyser { private File jarjarjarLocation; public JarJarDependencyAnalyser(File jarjarjarLocation) { this.jarjarjarLocation = jarjarjarLocation; } public ModuleDescriptor[] analyze(JarModule[] modules) { StringBuffer jarjarCmd = new StringBuffer("java -jar \"").append( jarjarjarLocation.getAbsolutePath()).append("\" --find --level=jar "); Map jarModulesMap = new HashMap(); Map mds = new HashMap(); for (int i = 0; i < modules.length; i++) { jarModulesMap.put(modules[i].getJar().getAbsolutePath(), modules[i]); DefaultModuleDescriptor md = DefaultModuleDescriptor.newBasicInstance( modules[i].getMrid(), new Date(modules[i].getJar().lastModified())); mds.put(modules[i].getMrid(), md); jarjarCmd.append("\"").append(modules[i].getJar().getAbsolutePath()).append("\""); if (i + 1 < modules.length) { jarjarCmd.append(File.pathSeparator); } } Message.verbose("jarjar command: " + jarjarCmd); try { Process p = Runtime.getRuntime().exec(jarjarCmd.toString()); BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; while ((line = r.readLine()) != null) { String[] deps = line.split(" -> "); JarModule module = (JarModule) jarModulesMap.get(deps[0]); JarModule dependency = (JarModule) jarModulesMap.get(deps[1]); if (module.getMrid().getModuleId().equals(dependency.getMrid().getModuleId())) { continue; } Message.verbose(module.getMrid() + " depends on " + dependency.getMrid()); DefaultModuleDescriptor md = (DefaultModuleDescriptor) mds.get(module.getMrid()); DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, dependency.getMrid(), false, false, true); dd.addDependencyConfiguration(ModuleDescriptor.DEFAULT_CONFIGURATION, ModuleDescriptor.DEFAULT_CONFIGURATION); md.addDependency(dd); } } catch (IOException e) { Message.debug(e); } return (ModuleDescriptor[]) mds.values().toArray(new ModuleDescriptor[mds.values().size()]); } public static void main(String[] args) { JarJarDependencyAnalyser a = new JarJarDependencyAnalyser(new File( "D:/temp/test2/jarjar-0.7.jar")); a.analyze(new JarModuleFinder( "D:/temp/test2/ivyrep/[organisation]/[module]/[revision]/[artifact].[ext]") .findJarModules()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/JarModule.java000066400000000000000000000024571226750426600250630ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.tools.analyser; import java.io.File; import org.apache.ivy.core.module.id.ModuleRevisionId; public class JarModule { private ModuleRevisionId mrid; private File jar; public JarModule(ModuleRevisionId mrid, File jar) { this.mrid = mrid; this.jar = jar; } public File getJar() { return jar; } public ModuleRevisionId getMrid() { return mrid; } public String toString() { return jar + " " + mrid; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/JarModuleFinder.java000066400000000000000000000063701226750426600262110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.tools.analyser; import java.io.File; import java.util.ArrayList; import java.util.List; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.plugins.resolver.util.FileURLLister; import org.apache.ivy.plugins.resolver.util.ResolverHelper; import org.apache.ivy.plugins.resolver.util.URLLister; import org.apache.ivy.util.Message; public class JarModuleFinder { private String pattern; private String filePattern; public JarModuleFinder(String pattern) { this.pattern = "file:///" + pattern; this.filePattern = pattern; } public JarModule[] findJarModules() { List ret = new ArrayList(); URLLister lister = new FileURLLister(); try { String[] orgs = ResolverHelper.listTokenValues(lister, pattern, "organisation"); for (int i = 0; i < orgs.length; i++) { String orgPattern = IvyPatternHelper.substituteToken(pattern, IvyPatternHelper.ORGANISATION_KEY, orgs[i]); String[] modules = ResolverHelper.listTokenValues(lister, orgPattern, "module"); for (int j = 0; j < modules.length; j++) { String modPattern = IvyPatternHelper.substituteToken(orgPattern, IvyPatternHelper.MODULE_KEY, modules[j]); String[] revs = ResolverHelper.listTokenValues(lister, modPattern, "revision"); for (int k = 0; k < revs.length; k++) { File jar = new File(IvyPatternHelper.substitute(filePattern, orgs[i], modules[j], revs[k], modules[j], "jar", "jar")); if (jar.exists()) { ret.add(new JarModule(ModuleRevisionId.newInstance(orgs[i], modules[j], revs[k]), jar)); } } } } } catch (Exception e) { Message.debug(e); // TODO: handle exception } return (JarModule[]) ret.toArray(new JarModule[ret.size()]); } public static void main(String[] args) { JarModule[] mods = new JarModuleFinder( "D:/temp/test2/ivyrep/[organisation]/[module]/[revision]/[artifact].[ext]") .findJarModules(); for (int i = 0; i < mods.length; i++) { System.out.println(mods[i]); } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/tools/analyser/RepositoryAnalyser.java000066400000000000000000000046361226750426600270600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.tools.analyser; import java.io.File; import java.io.IOException; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.DefaultArtifact; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter; import org.apache.ivy.util.Message; public class RepositoryAnalyser { public void analyse(String pattern, DependencyAnalyser depAnalyser) { JarModuleFinder finder = new JarModuleFinder(pattern); ModuleDescriptor[] mds = depAnalyser.analyze(finder.findJarModules()); Message.info("found " + mds.length + " modules"); for (int i = 0; i < mds.length; i++) { File ivyFile = new File(IvyPatternHelper.substitute( pattern, DefaultArtifact.newIvyArtifact(mds[i].getModuleRevisionId(), mds[i].getPublicationDate()))); try { Message.info("generating " + ivyFile); XmlModuleDescriptorWriter.write(mds[i], ivyFile); } catch (IOException e) { Message.debug(e); } } } public static void main(String[] args) { if (args.length != 2) { System.out .println("usage: ivyanalyser path/to/jarjar.jar absolute-ivy-repository-pattern"); return; } String jarjarLocation = args[0]; String pattern = args[1]; JarJarDependencyAnalyser a = new JarJarDependencyAnalyser(new File(jarjarLocation)); new RepositoryAnalyser().analyse(pattern, a); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/000077500000000000000000000000001226750426600203255ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/util/AbstractMessageLogger.java000066400000000000000000000113701226750426600254020ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.ArrayList; import java.util.List; /** * An abstract base class to ease {@link MessageLogger} implementation. */ public abstract class AbstractMessageLogger implements MessageLogger { private List problems = new ArrayList(); private List warns = new ArrayList(); private List errors = new ArrayList(); private boolean showProgress = true; /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#debug(java.lang.String) */ public void debug(String msg) { log(msg, Message.MSG_DEBUG); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#verbose(java.lang.String) */ public void verbose(String msg) { log(msg, Message.MSG_VERBOSE); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#deprecated(java.lang.String) */ public void deprecated(String msg) { log("DEPRECATED: " + msg, Message.MSG_WARN); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#info(java.lang.String) */ public void info(String msg) { log(msg, Message.MSG_INFO); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#info(java.lang.String) */ public void rawinfo(String msg) { rawlog(msg, Message.MSG_INFO); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#warn(java.lang.String) */ public void warn(String msg) { log("WARN: " + msg, Message.MSG_VERBOSE); problems.add("WARN: " + msg); getWarns().add(msg); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#error(java.lang.String) */ public void error(String msg) { // log in verbose mode because message is appended as a problem, and will be // logged at the end at error level log("ERROR: " + msg, Message.MSG_VERBOSE); problems.add("\tERROR: " + msg); getErrors().add(msg); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#getProblems() */ public List getProblems() { return problems; } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#sumupProblems() */ public void sumupProblems() { MessageLoggerHelper.sumupProblems(this); clearProblems(); } public void clearProblems() { problems.clear(); warns.clear(); errors.clear(); } public List getErrors() { return errors; } public List getWarns() { return warns; } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#progress() */ public void progress() { if (showProgress) { doProgress(); } } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#endProgress() */ public void endProgress() { endProgress(""); } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#endProgress(java.lang.String) */ public void endProgress(String msg) { if (showProgress) { doEndProgress(msg); } } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#isShowProgress() */ public boolean isShowProgress() { return showProgress; } /* * (non-Javadoc) * * @see org.apache.ivy.util.MessageLogger#setShowProgress(boolean) */ public void setShowProgress(boolean progress) { showProgress = progress; } /** * Indicates a progression for a long running task */ protected abstract void doProgress(); /** * Indicates the end of a long running task * * @param msg * the message associated with long running task end. */ protected abstract void doEndProgress(String msg); } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/Checks.java000066400000000000000000000041611226750426600223720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.File; /** * Utility class used to perform some checks. */ public final class Checks { private Checks() { } /** * Checks that an object is not null, and throw an exception if the object is null. * * @param o * the object to check * @param objectName * the name of the object to check. This name will be used in the exception message. * @throws IllegalArgumentException * if the object is null */ public static void checkNotNull(Object o, String objectName) { if (o == null) { throw new IllegalArgumentException(objectName + " must not be null"); } } public static File checkAbsolute(File f, String fileName) { checkNotNull(f, fileName); if (!f.isAbsolute()) { throw new IllegalArgumentException(fileName + " must be absolute: " + f.getPath()); } return FileUtil.normalize(f.getPath()); } public static File checkAbsolute(String path, String fileName) { checkNotNull(path, fileName); File f = new File(path); if (!f.isAbsolute()) { throw new IllegalArgumentException(fileName + " must be absolute: " + path); } return FileUtil.normalize(f.getPath()); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/ChecksumHelper.java000066400000000000000000000141311226750426600240720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Locale; import java.util.Map; public final class ChecksumHelper { private static final int BUFFER_SIZE = 2048; private static Map algorithms = new HashMap(); static { algorithms.put("md5", "MD5"); algorithms.put("sha1", "SHA-1"); } /** * Checks the checksum of the given file against the given checksumFile, and throws an * IOException if the checksum is not compliant * * @param dest * the file to test * @param checksumFile * the file containing the expected checksum * @param algorithm * the checksum algorithm to use * @throws IOException * if an IO problem occur whle reading files or if the checksum is not compliant */ public static void check(File dest, File checksumFile, String algorithm) throws IOException { String csFileContent = FileUtil .readEntirely(new BufferedReader(new FileReader(checksumFile))).trim() .toLowerCase(Locale.US); String expected; if (csFileContent.indexOf(' ') > -1 && (csFileContent.startsWith("md") || csFileContent.startsWith("sha"))) { int lastSpaceIndex = csFileContent.lastIndexOf(' '); expected = csFileContent.substring(lastSpaceIndex + 1); } else { int spaceIndex = csFileContent.indexOf(' '); if (spaceIndex != -1) { expected = csFileContent.substring(0, spaceIndex); // IVY-1155: support some strange formats like this one: // http://repo2.maven.org/maven2/org/apache/pdfbox/fontbox/0.8.0-incubator/fontbox-0.8.0-incubator.jar.md5 if (expected.endsWith(":")) { StringBuffer result = new StringBuffer(); char[] chars = csFileContent.substring(spaceIndex + 1).toCharArray(); for (int i = 0; i < chars.length; i++) { if (!Character.isWhitespace(chars[i])) { result.append(chars[i]); } } expected = result.toString(); } } else { expected = csFileContent; } } String computed = computeAsString(dest, algorithm).trim().toLowerCase(Locale.US); if (!expected.equals(computed)) { throw new IOException("invalid " + algorithm + ": expected=" + expected + " computed=" + computed); } } public static String computeAsString(File f, String algorithm) throws IOException { return byteArrayToHexString(compute(f, algorithm)); } private static byte[] compute(File f, String algorithm) throws IOException { InputStream is = new FileInputStream(f); try { MessageDigest md = getMessageDigest(algorithm); md.reset(); byte[] buf = new byte[BUFFER_SIZE]; int len = 0; while ((len = is.read(buf)) != -1) { md.update(buf, 0, len); } return md.digest(); } finally { is.close(); } } public static boolean isKnownAlgorithm(String algorithm) { return algorithms.containsKey(algorithm); } private static MessageDigest getMessageDigest(String algorithm) { String mdAlgorithm = (String) algorithms.get(algorithm); if (mdAlgorithm == null) { throw new IllegalArgumentException("unknown algorithm " + algorithm); } try { return MessageDigest.getInstance(mdAlgorithm); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("unknown algorithm " + algorithm); } } // byte to hex string converter private static final char[] CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * Convert a byte[] array to readable string format. This makes the "hex" readable! * * @return result String buffer in String format * @param in * byte[] buffer to convert to string format */ public static String byteArrayToHexString(byte[] in) { byte ch = 0x00; if (in == null || in.length <= 0) { return null; } StringBuffer out = new StringBuffer(in.length * 2); // CheckStyle:MagicNumber OFF for (int i = 0; i < in.length; i++) { ch = (byte) (in[i] & 0xF0); // Strip off high nibble ch = (byte) (ch >>> 4); // shift the bits down ch = (byte) (ch & 0x0F); // must do this is high order bit is on! out.append(CHARS[ch]); // convert the nibble to a String Character ch = (byte) (in[i] & 0x0F); // Strip off low nibble out.append(CHARS[ch]); // convert the nibble to a String Character } // CheckStyle:MagicNumber ON return out.toString(); } private ChecksumHelper() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/CollectionUtils.java000066400000000000000000000022111226750426600243000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class CollectionUtils { public static List toList(Iterator iterator) { List list = new ArrayList(); while (iterator.hasNext()) { list.add(iterator.next()); } return list; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/ConfigurationUtils.java000066400000000000000000000070771226750426600250330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.Configuration.Visibility; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; /** * Class containing several utility methods for working with configurations. */ public final class ConfigurationUtils { /** * Private constructor to avoid instantiation of this class. */ private ConfigurationUtils() { } /** * Replace the wildcards in the given configuration array, by the name of the given * ModuleDescriptor * * The supported wildcards are: *
      *
    • * : all configurations
    • *
    • *(public) : all public configurations
    • *
    • *(private) : all private configurations
    • *
    * If the given array of configurations is null, all configurations from the given * module descriptor are returned, including if this array is empty. * * @param confs * the configurations, can contain wildcards * @param md * the configurations where the wildcards are replaced * @return */ public static String[] replaceWildcards(String[] confs, ModuleDescriptor md) { if (confs == null) { return md.getConfigurationsNames(); } Set result = new LinkedHashSet(); Set excluded = new LinkedHashSet(); for (int i = 0; i < confs.length; i++) { if ("*".equals(confs[i])) { result.addAll(Arrays.asList(md.getConfigurationsNames())); } else if ("*(public)".equals(confs[i])) { Configuration[] all = md.getConfigurations(); for (int j = 0; j < all.length; j++) { if (all[j].getVisibility().equals(Visibility.PUBLIC)) { result.add(all[j].getName()); } } } else if ("*(private)".equals(confs[i])) { Configuration[] all = md.getConfigurations(); for (int j = 0; j < all.length; j++) { if (all[j].getVisibility().equals(Visibility.PRIVATE)) { result.add(all[j].getName()); } } } else if (confs[i].startsWith("!")) { excluded.add(confs[i].substring(1)); } else { result.add(confs[i]); } } for (Iterator iter = excluded.iterator(); iter.hasNext();) { result.remove(iter.next()); } return (String[]) result.toArray(new String[result.size()]); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/Configurator.java000066400000000000000000000666011226750426600236430ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Stack; import org.apache.ivy.core.IvyPatternHelper; /** * Ant 1.6.1 like Configurator *

    * This configurator is used to configure elements (initialised with setRoot) using the behaviour * defined by ant for its tasks. *

    * Example (based on Ant * Example): * *

     * Configurator conf = new Configurator();
     * conf.typeDef("buildpath", "Sample$BuildPath");
     * conf.typeDef("xinterface", "Sample$XInterface");
     * Sample.MyFileSelector mfs = new Sample.MyFileSelector();
     * conf.setRoot(mfs);
     * conf.startCreateChild("buildpath");
     * conf.setAttribute("path", ".");
     * conf.setAttribute("url", "abc");
     * conf.startCreateChild("xinterface");
     * conf.setAttribute("count", "4");
     * conf.endCreateChild(); // xinterface
     * conf.endCreateChild(); // buildpath
     * 
    */ public class Configurator { public static class Macro { private MacroDef macrodef; private Map attValues = new HashMap(); private Map macroRecords = new HashMap(); public Macro(MacroDef def) { macrodef = def; } public void defineAttribute(String attributeName, String value) { if (macrodef.getAttribute(attributeName) == null) { throw new IllegalArgumentException("undeclared attribute " + attributeName + " on macro " + macrodef.getName()); } attValues.put(attributeName, value); } public MacroRecord recordCreateChild(String name) { MacroRecord macroRecord = new MacroRecord(name); List records = (List) macroRecords.get(name); if (records == null) { records = new ArrayList(); macroRecords.put(name, records); } records.add(macroRecord); return macroRecord; } public Object play(Configurator conf) { return macrodef.play(conf, attValues, macroRecords); } } public static class Attribute { private String name; private String defaultValue; public String getDefault() { return defaultValue; } public void setDefault(String default1) { defaultValue = default1; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public static class Element { private String name; private boolean optional = false; public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isOptional() { return optional; } public void setOptional(boolean optional) { this.optional = optional; } } public static class MacroRecord { private String name; private Map attributes = new LinkedHashMap(); private List children = new ArrayList(); private Object object; public MacroRecord(String name) { this.name = name; } public String getName() { return name; } public void recordAttribute(String name, String value) { attributes.put(name, value); } public MacroRecord recordChild(String name) { MacroRecord child = new MacroRecord(name); children.add(child); return child; } public MacroRecord recordChild(String name, Object object) { MacroRecord child = recordChild(name); child.object = object; return child; } public Map getAttributes() { return attributes; } public List getChildren() { return children; } public Object getObject() { return object; } } public static class MacroDef { private String name; private Map attributes = new HashMap(); private Map elements = new HashMap(); private MacroRecord macroRecord; public MacroDef(String macroName) { name = macroName; } public Attribute getAttribute(String attributeName) { return (Attribute) attributes.get(attributeName); } public Object play(Configurator conf, Map attValues, Map macroRecords) { for (Iterator iter = attributes.values().iterator(); iter.hasNext();) { Attribute att = (Attribute) iter.next(); String val = (String) attValues.get(att.getName()); if (val == null) { if (att.getDefault() == null) { throw new IllegalArgumentException("attribute " + att.getName() + " is required in " + getName()); } else { attValues.put(att.getName(), att.getDefault()); } } } return play(conf, macroRecord, attValues, macroRecords); } private Object play(Configurator conf, MacroRecord macroRecord, Map attValues, Map childrenRecords) { if (macroRecord.getObject() != null) { // this is a recorded reference, we can add the referenced object directly conf.addChild(macroRecord.getName(), macroRecord.getObject()); conf.endCreateChild(); return macroRecord.getObject(); } conf.startCreateChild(macroRecord.getName()); Map attributes = macroRecord.getAttributes(); for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { String attName = (String) iter.next(); String attValue = replaceParam((String) attributes.get(attName), attValues); conf.setAttribute(attName, attValue); } for (Iterator iter = macroRecord.getChildren().iterator(); iter.hasNext();) { MacroRecord child = (MacroRecord) iter.next(); Element elt = (Element) elements.get(child.getName()); if (elt != null) { List elements = (List) childrenRecords.get(child.getName()); if (elements != null) { for (Iterator iterator = elements.iterator(); iterator.hasNext();) { MacroRecord element = (MacroRecord) iterator.next(); for (Iterator it2 = element.getChildren().iterator(); it2.hasNext();) { MacroRecord r = (MacroRecord) it2.next(); play(conf, r, attValues, Collections.EMPTY_MAP); } } } else if (!elt.isOptional()) { throw new IllegalArgumentException( "non optional element is not specified: " + elt.getName() + " in macro " + getName()); } continue; } play(conf, child, attValues, childrenRecords); } return conf.endCreateChild(); } private String replaceParam(String string, Map attValues) { return IvyPatternHelper.substituteParams(string, attValues); } public String getName() { return name; } public void addConfiguredAttribute(Attribute att) { attributes.put(att.getName(), att); } public void addConfiguredElement(Element elt) { elements.put(elt.getName(), elt); } public Macro createMacro() { return new Macro(this); } public void addAttribute(String attName, String attDefaultValue) { Attribute att = new Attribute(); att.setName(attName); att.setDefault(attDefaultValue); addConfiguredAttribute(att); } public void addElement(String elementName, boolean optional) { Element elt = new Element(); elt.setName(elementName); elt.setOptional(optional); addConfiguredElement(elt); } public MacroRecord recordCreateChild(String name) { macroRecord = new MacroRecord(name); return macroRecord; } } private static class ObjectDescriptor { private Object obj; private String objName; private Map createMethods = new HashMap(); private Map addMethods = new HashMap(); private Map addConfiguredMethods = new HashMap(); private Map setMethods = new HashMap(); private Map typeAddMethods = new HashMap(); private Map typeAddConfiguredMethods = new HashMap(); public ObjectDescriptor(Object object, String objName) { obj = object; this.objName = objName; Method[] methods = object.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (m.getName().startsWith("create") && m.getParameterTypes().length == 0 && !Void.TYPE.equals(m.getReturnType())) { String name = StringUtils .uncapitalize(m.getName().substring("create".length())); if (name.length() == 0) { continue; } addCreateMethod(name, m); } else if (m.getName().startsWith("addConfigured") && m.getParameterTypes().length == 1 && Void.TYPE.equals(m.getReturnType())) { String name = StringUtils.uncapitalize(m.getName().substring( "addConfigured".length())); if (name.length() == 0) { addAddConfiguredMethod(m); } addAddConfiguredMethod(name, m); } else if (m.getName().startsWith("add") && !m.getName().startsWith("addConfigured") && m.getParameterTypes().length == 1 && Void.TYPE.equals(m.getReturnType())) { String name = StringUtils.uncapitalize(m.getName().substring("add".length())); if (name.length() == 0) { addAddMethod(m); } addAddMethod(name, m); } else if (m.getName().startsWith("set") && m.getParameterTypes().length == 1 && Void.TYPE.equals(m.getReturnType())) { String name = StringUtils.uncapitalize(m.getName().substring("set".length())); if (name.length() == 0) { continue; } addSetMethod(name, m); } } } public void addCreateMethod(String name, Method m) { createMethods.put(name, m); } public void addAddMethod(String name, Method m) { addMethods.put(name, m); } public void addAddConfiguredMethod(String name, Method m) { addConfiguredMethods.put(name, m); } private void addAddMethod(Method m) { typeAddMethods.put(m.getParameterTypes()[0], m); } private void addAddConfiguredMethod(Method m) { typeAddConfiguredMethods.put(m.getParameterTypes()[0], m); } public void addSetMethod(String name, Method m) { Method current = (Method) setMethods.get(name); if (current != null && current.getParameterTypes()[0] == String.class) { // setter methods with String attribute take precedence return; } setMethods.put(name, m); } public Object getObject() { return obj; } public Method getCreateMethod(String name) { return (Method) createMethods.get(name); } public Method getAddMethod(String name) { return (Method) addMethods.get(name); } public Method getAddConfiguredMethod(String name) { return (Method) addConfiguredMethods.get(name); } public Method getAddMethod(Class type) { return getTypeMatchingMethod(type, typeAddMethods); } public Method getAddConfiguredMethod(Class type) { return getTypeMatchingMethod(type, typeAddConfiguredMethods); } private Method getTypeMatchingMethod(Class type, Map typeMethods) { Method m = (Method) typeMethods.get(type); if (m != null) { return m; } for (Iterator iter = typeMethods.keySet().iterator(); iter.hasNext();) { Class clss = (Class) iter.next(); if (clss.isAssignableFrom(type)) { return (Method) typeMethods.get(clss); } } return null; } public Method getSetMethod(String name) { return (Method) setMethods.get(name); } public String getObjectName() { return objName; } } private FileResolver fileResolver = FileResolver.DEFAULT; private Map typedefs = new HashMap(); private Map macrodefs = new HashMap(); // stack in which the top is current configured object descriptor private Stack objectStack = new Stack(); private static final List TRUE_VALUES = Arrays.asList(new String[] {"true", "yes", "on"}); public void typeDef(String name, String className) throws ClassNotFoundException { typeDef(name, Class.forName(className)); } public void typeDef(String name, Class clazz) { typedefs.put(name, clazz); } public void setRoot(Object root) { if (root == null) { throw new NullPointerException(); } objectStack.clear(); setCurrent(root, null); } public void clear() { objectStack.clear(); } private void setCurrent(Object object, String name) { objectStack.push(new ObjectDescriptor(object, name)); } public Object startCreateChild(String name) { if (objectStack.isEmpty()) { throw new IllegalStateException("set root before creating child"); } ObjectDescriptor parentOD = (ObjectDescriptor) objectStack.peek(); Object parent = parentOD.getObject(); if (parent instanceof MacroDef) { if (!"attribute".equals(name) && !"element".equals(name)) { MacroRecord record = ((MacroDef) parent).recordCreateChild(name); setCurrent(record, name); return record; } } if (parent instanceof Macro) { MacroRecord record = ((Macro) parent).recordCreateChild(name); setCurrent(record, name); return record; } if (parent instanceof MacroRecord) { MacroRecord record = ((MacroRecord) parent).recordChild(name); setCurrent(record, name); return record; } Object child = null; MacroDef macrodef = (MacroDef) macrodefs.get(name); if (macrodef != null) { Macro macro = macrodef.createMacro(); setCurrent(macro, name); return macro; } Class childClass = (Class) typedefs.get(name); Method addChild = null; try { if (childClass != null) { return addChild(parentOD, childClass, name, null); } else { addChild = parentOD.getCreateMethod(name); if (addChild != null) { child = addChild.invoke(parent, new Object[0]); setCurrent(child, name); return child; } addChild = parentOD.getAddMethod(name); if (addChild != null) { childClass = addChild.getParameterTypes()[0]; child = childClass.newInstance(); addChild.invoke(parent, new Object[] {child}); setCurrent(child, name); return child; } addChild = parentOD.getAddConfiguredMethod(name); if (addChild != null) { childClass = addChild.getParameterTypes()[0]; if (Map.class == childClass) { child = new HashMap(); } else { child = childClass.newInstance(); } setCurrent(child, name); return child; } } } catch (InstantiationException ex) { throw new IllegalArgumentException("no default constructor on " + childClass + " for adding " + name + " on " + parent.getClass()); } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException("bad method found for " + name + " on " + parent.getClass()); iae.initCause(ex); throw iae; } throw new IllegalArgumentException("no appropriate method found for adding " + name + " on " + parent.getClass()); } public void addChild(String name, Object child) { if (objectStack.isEmpty()) { throw new IllegalStateException("set root before creating child"); } ObjectDescriptor parentOD = (ObjectDescriptor) objectStack.peek(); try { addChild(parentOD, child.getClass(), name, child); } catch (InstantiationException ex) { throw new IllegalArgumentException("no default constructor on " + child.getClass() + " for adding " + name + " on " + parentOD.getObject().getClass()); } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException("bad method found for " + name + " on " + parentOD.getObject().getClass()); iae.initCause(ex); throw iae; } } private Object addChild(ObjectDescriptor parentOD, Class childClass, String name, Object child) throws InstantiationException, IllegalAccessException, InvocationTargetException { Object parent = parentOD.getObject(); if (parent instanceof MacroRecord) { MacroRecord record = (MacroRecord) parent; MacroRecord recordChild = record.recordChild(name, child); setCurrent(recordChild, name); return recordChild; } Method addChild = parentOD.getAddMethod(childClass); if (addChild != null) { if (child == null) { child = childClass.newInstance(); } addChild.invoke(parent, new Object[] {child}); setCurrent(child, name); return child; } addChild = parentOD.getAddConfiguredMethod(childClass); if (addChild != null) { if (child == null) { if (Map.class == childClass) { child = new HashMap(); } else { child = childClass.newInstance(); } } setCurrent(child, name); return child; } throw new IllegalArgumentException("no appropriate method found for adding " + name + " on " + parent.getClass()); } public boolean isTopLevelMacroRecord() { if (objectStack.isEmpty()) { return false; } ObjectDescriptor od = (ObjectDescriptor) objectStack.peek(); return (od.getObject() instanceof MacroDef); } public void setAttribute(String attributeName, String value) { if (objectStack.isEmpty()) { throw new IllegalStateException("set root before setting attribute"); } ObjectDescriptor od = (ObjectDescriptor) objectStack.peek(); if (od.getObject() instanceof Macro) { ((Macro) od.getObject()).defineAttribute(attributeName, value); return; } if (od.getObject() instanceof MacroRecord) { ((MacroRecord) od.getObject()).recordAttribute(attributeName, value); return; } Method m = od.getSetMethod(attributeName); if (m == null) { if (od.getObject() instanceof Map) { ((Map) od.getObject()).put(attributeName, value); return; } throw new IllegalArgumentException("no set method found for " + attributeName + " on " + od.getObject().getClass()); } Object convertedValue = null; Class paramClass = m.getParameterTypes()[0]; try { if (paramClass.equals(String.class)) { convertedValue = value; } else if (paramClass.equals(Boolean.class) || paramClass.equals(boolean.class)) { convertedValue = Boolean.valueOf(TRUE_VALUES.contains(value)); } else if (paramClass.equals(Character.class) || paramClass.equals(char.class)) { convertedValue = new Character(value.length() > 0 ? value.charAt(0) : ' '); } else if (paramClass.equals(Short.class) || paramClass.equals(short.class)) { convertedValue = Short.valueOf(value); } else if (paramClass.equals(Integer.class) || paramClass.equals(int.class)) { convertedValue = Integer.valueOf(value); } else if (paramClass.equals(Long.class) || paramClass.equals(long.class)) { convertedValue = Long.valueOf(value); } else if (paramClass.equals(Class.class)) { convertedValue = Class.forName(value); } else if (paramClass.equals(File.class)) { convertedValue = fileResolver.resolveFile(value, od.getObjectName() + "." + attributeName); } else { convertedValue = paramClass.getConstructor(new Class[] {String.class}).newInstance( new Object[] {value}); } } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException("impossible to convert " + value + " to " + paramClass + " for setting " + attributeName + " on " + od.getObject().getClass() + ": " + ex.getMessage()); iae.initCause(ex); throw iae; } try { m.invoke(od.getObject(), new Object[] {convertedValue}); } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException("impossible to set " + attributeName + " to " + convertedValue + " on " + od.getObject().getClass()); iae.initCause(ex); throw iae; } } public void addText(String text) { if (objectStack.isEmpty()) { throw new IllegalStateException("set root before adding text"); } ObjectDescriptor od = (ObjectDescriptor) objectStack.peek(); try { od.getObject().getClass().getMethod("addText", new Class[] {String.class}) .invoke(od.getObject(), new Object[] {text}); } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException( "impossible to add text on " + od.getObject().getClass()); iae.initCause(ex); throw iae; } } /** * @return the finished child */ public Object endCreateChild() { if (objectStack.isEmpty()) { throw new IllegalStateException("set root before ending child"); } ObjectDescriptor od = (ObjectDescriptor) objectStack.pop(); if (objectStack.isEmpty()) { objectStack.push(od); // back to previous state throw new IllegalStateException("cannot end root"); } if (od.getObject() instanceof Macro) { return ((Macro) od.getObject()).play(this); } ObjectDescriptor parentOD = (ObjectDescriptor) objectStack.peek(); String name = od.getObjectName(); Class childClass = (Class) typedefs.get(name); Method m = null; if (childClass != null) { m = parentOD.getAddConfiguredMethod(childClass); } else { m = parentOD.getAddConfiguredMethod(name); } try { if (m != null) { m.invoke(parentOD.getObject(), new Object[] {od.getObject()}); } return od.getObject(); } catch (Exception ex) { IllegalArgumentException iae = new IllegalArgumentException( "impossible to add configured child for " + name + " on " + parentOD.getObject().getClass() + ": " + StringUtils.getErrorMessage(ex)); iae.initCause(ex); throw iae; } } public Object getCurrent() { return objectStack.isEmpty() ? null : ((ObjectDescriptor) objectStack.peek()).getObject(); } public int getDepth() { return objectStack.size(); } public MacroDef startMacroDef(String macroName) { MacroDef macroDef = new MacroDef(macroName); setCurrent(macroDef, macroName); return macroDef; } public void addMacroAttribute(String attName, String attDefaultValue) { ((MacroDef) getCurrent()).addAttribute(attName, attDefaultValue); } public void addMacroElement(String elementName, boolean optional) { ((MacroDef) getCurrent()).addElement(elementName, optional); } public void endMacroDef() { addConfiguredMacrodef(((MacroDef) getCurrent())); objectStack.pop(); } public void addConfiguredMacrodef(MacroDef macrodef) { macrodefs.put(macrodef.getName(), macrodef); } public Class getTypeDef(String name) { return (Class) typedefs.get(name); } public FileResolver getFileResolver() { return fileResolver; } public void setFileResolver(FileResolver fileResolver) { Checks.checkNotNull(fileResolver, "fileResolver"); this.fileResolver = fileResolver; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/ContextualSAXHandler.java000066400000000000000000000041011226750426600251640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.Iterator; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class ContextualSAXHandler extends DefaultHandler { private Stack contextStack = new Stack(); private StringBuffer buffer = new StringBuffer(); public void characters(char[] ch, int start, int length) throws SAXException { buffer.append(ch, start, length); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { contextStack.push(qName); buffer.setLength(0); } public void endElement(String uri, String localName, String qName) throws SAXException { contextStack.pop(); buffer.setLength(0); } protected String getContext() { StringBuffer buf = new StringBuffer(); for (Iterator iter = contextStack.iterator(); iter.hasNext();) { String ctx = (String) iter.next(); buf.append(ctx).append("/"); } if (buf.length() > 0) { buf.setLength(buf.length() - 1); } return buf.toString(); } protected String getText() { return buffer.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/CopyProgressEvent.java000066400000000000000000000032231226750426600246310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; /** * Event reporting a stream copy progression */ public class CopyProgressEvent { private long totalReadBytes; private byte[] buffer; private int readBytes; public CopyProgressEvent() { } public CopyProgressEvent(byte[] buffer, int read, long total) { update(buffer, read, total); } public CopyProgressEvent(byte[] buffer, long total) { update(buffer, 0, total); } protected CopyProgressEvent update(byte[] buffer, int read, long total) { this.buffer = buffer; this.readBytes = read; this.totalReadBytes = total; return this; } public long getTotalReadBytes() { return totalReadBytes; } public byte[] getBuffer() { return buffer; } public int getReadBytes() { return readBytes; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/CopyProgressListener.java000066400000000000000000000020271226750426600253360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; /** * Listen to copy progression */ public interface CopyProgressListener { void start(CopyProgressEvent evt); void progress(CopyProgressEvent evt); void end(CopyProgressEvent evt); } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/Credentials.java000066400000000000000000000050641226750426600234320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; /** * */ public class Credentials { private String realm; private String host; private String userName; private String passwd; public Credentials(String realm, String host, String userName, String passwd) { this.realm = realm; this.host = host; this.userName = userName; this.passwd = passwd; } public String getHost() { return host; } public String getPasswd() { return passwd; } public String getRealm() { return realm; } public String getUserName() { return userName; } public static String buildKey(String realm, String host) { if (realm == null || "".equals(realm.trim())) { return host; } else { return realm + "@" + host; } } /** * Return a string that can be used for debug purpose. It contains only stars for each password * character. */ public String toString() { return getKey() + " " + getUserName() + "/" + getPasswdAsStars(); } private String getPasswdAsStars() { if (passwd == null) { return null; } StringBuffer sb = new StringBuffer(); for (int i = passwd.length(); i > 0; i--) { sb.append('*'); } return sb.toString(); } public boolean equals(Object o) { if (o == null) { return false; } if (o instanceof Credentials) { Credentials c = (Credentials) o; return getKey().equals(c.getKey()); } return false; } public int hashCode() { return getKey().hashCode(); } public String getKey() { return buildKey(realm, host); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/CredentialsUtil.java000066400000000000000000000137661226750426600243000ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import org.apache.ivy.Ivy; public final class CredentialsUtil { private static final class CredentialPanel extends JPanel { private static final int FIELD_LENGTH = 20; private JTextField userNameField = new JTextField(FIELD_LENGTH); private JTextField passwordField = new JPasswordField(FIELD_LENGTH); private JCheckBox rememberDataCB = new JCheckBox("remember my information"); CredentialPanel(Credentials credentials, File passfile) { GridBagLayout layout = new GridBagLayout(); setLayout(layout); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(2, 2, 2, 2); c.gridx = 1; c.gridheight = 1; c.gridwidth = 2; String prompt = credentials.getRealm() != null ? "Enter username and password for \"" + credentials.getRealm() + "\" at " + credentials.getHost() : "Enter username and password for " + credentials.getHost(); add(new JLabel(prompt), c); c.gridy = 1; c.gridwidth = 1; add(new JLabel("username: "), c); c.gridx = 2; add(userNameField, c); c.gridx = 1; c.gridy++; if (credentials.getUserName() != null) { userNameField.setText(credentials.getUserName()); } if (credentials.getPasswd() == null) { add(new JLabel("passwd: "), c); c.gridx = 2; add(passwordField, c); c.gridx = 1; c.gridy++; } else { passwordField.setText(credentials.getPasswd()); } if (passfile != null) { c.gridwidth = 2; add(rememberDataCB, c); c.gridy++; } c.gridwidth = 2; add(new JLabel(), c); // spacer } } public static Credentials promptCredentials(Credentials c, File passfile) { c = loadPassfile(c, passfile); if (c.getUserName() != null && c.getPasswd() != null) { return c; } CredentialPanel credentialPanel = new CredentialPanel(c, passfile); if (JOptionPane.showOptionDialog(null, credentialPanel, c.getHost() + " credentials", JOptionPane.OK_CANCEL_OPTION, 0, new ImageIcon(Ivy.class.getResource("logo.png")), null, new Integer(JOptionPane.OK_OPTION)) == JOptionPane.OK_OPTION) { String username = credentialPanel.userNameField.getText(); String passwd = credentialPanel.passwordField.getText(); if (credentialPanel.rememberDataCB.isSelected()) { Properties props = new EncrytedProperties(); props.setProperty("username", username); props.setProperty("passwd", passwd); FileOutputStream fos = null; try { fos = new FileOutputStream(passfile); props.store(fos, ""); } catch (Exception e) { Message.warn("error occurred while saving password file " + passfile, e); } finally { if (fos != null) { try { fos.close(); } catch (Exception e) { // ignored } } } } c = new Credentials(c.getRealm(), c.getHost(), username, passwd); } return c; } public static Credentials loadPassfile(Credentials c, File passfile) { if (passfile != null && passfile.exists()) { Properties props = new EncrytedProperties(); FileInputStream fis = null; try { fis = new FileInputStream(passfile); props.load(fis); String username = c.getUserName(); String passwd = c.getPasswd(); if (username == null) { username = props.getProperty("username"); } if (passwd == null) { passwd = props.getProperty("passwd"); } return new Credentials(c.getRealm(), c.getHost(), username, passwd); } catch (IOException e) { Message.warn("error occurred while loading password file " + passfile, e); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // ignored } } } } return c; } private CredentialsUtil() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/DateUtil.java000066400000000000000000000027171226750426600227120ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateUtil { private DateUtil() { // Utility class } public static final String DATE_FORMAT_PATTERN = "yyyyMMddHHmmss"; public static String format(Date date) { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_PATTERN); return format.format(date); } public static Date parse(String date) throws ParseException { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_PATTERN); return format.parse(date); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/DefaultMessageLogger.java000066400000000000000000000027311226750426600252240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; public class DefaultMessageLogger extends AbstractMessageLogger { private int level = Message.MSG_INFO; /** * @param level */ public DefaultMessageLogger(int level) { this.level = level; } public void log(String msg, int level) { if (level <= this.level) { System.out.println(msg); } } public void rawlog(String msg, int level) { log(msg, level); } public void doProgress() { System.out.print("."); } public void doEndProgress(String msg) { System.out.println(msg); } public int getLevel() { return level; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/EncrytedProperties.java000066400000000000000000000046341226750426600250310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Properties; /** * An implementation of Properties which stores the values encrypted. The use is transparent from * the user point of view (use as any Properties instance), except that get, put and putAll do not * handle encryption/decryption. This means that get returns the encrypted value, while put and * putAll puts given values without encrypting them. It this thus recommended to void using them, * use setProperty and getProperty instead. */ public class EncrytedProperties extends Properties { public EncrytedProperties() { super(); } public synchronized Object setProperty(String key, String value) { return StringUtils.decrypt((String) super.setProperty(key, StringUtils.encrypt(value))); } public String getProperty(String key) { return StringUtils.decrypt(super.getProperty(key)); } public String getProperty(String key, String defaultValue) { return StringUtils.decrypt(super.getProperty(key, StringUtils.encrypt(defaultValue))); } public boolean containsValue(Object value) { return super.containsValue(StringUtils.encrypt((String) value)); } public synchronized boolean contains(Object value) { return super.contains(StringUtils.encrypt((String) value)); } public Collection values() { List ret = new ArrayList(super.values()); for (int i = 0; i < ret.size(); i++) { ret.set(i, StringUtils.decrypt((String) ret.get(i))); } return ret; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/FileResolver.java000066400000000000000000000031611226750426600235720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.File; public interface FileResolver { public static final FileResolver DEFAULT = new FileResolver() { public File resolveFile(String path, String filename) { return new File(path); } }; /** * Return the canonical form of a path, or raise an {@link IllegalArgumentException} if the path * is not valid for this {@link FileResolver}. *

    * * @param path * The path of the file to resolve. Must not be null. * @param fileName * The name of the file to resolve. This is used only for exception message if any. * Must not be null. * * @return the resolved File. * */ File resolveFile(String path, String filename); } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/FileUtil.java000066400000000000000000000545341226750426600227200ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Stack; import java.util.StringTokenizer; import java.util.regex.Pattern; import org.apache.ivy.util.url.URLHandlerRegistry; /** * Utility class used to deal with file related operations, like copy, full reading, symlink, ... */ public final class FileUtil { private FileUtil() { // Utility class } // according to tests by users, 64kB seems to be a good value for the buffer used during copy // further improvements could be obtained using NIO API private static final int BUFFER_SIZE = 64 * 1024; private static final byte[] EMPTY_BUFFER = new byte[0]; private static final Pattern ALLOWED_PATH_PATTERN = Pattern.compile("[\\w-./\\\\:~ %\\(\\)]+"); public static void symlinkInMass(Map/* */destToSrcMap, boolean overwrite) throws IOException { // This pattern could be more forgiving if somebody wanted it to be... // ...but this should satisfy 99+% of all needs, without letting unsafe operations be done. // If you paths is not supported, you then skip this mass option. // NOTE: A space inside the path is allowed (I can't control other programmers who like them // in their working directory names)... // but trailing spaces on file names will be checked otherwise and refused. try { StringBuffer sb = new StringBuffer(); Iterator keyItr = destToSrcMap.entrySet().iterator(); while (keyItr.hasNext()) { Entry/* */entry = (Entry) keyItr.next(); File destFile = (File) entry.getKey(); File srcFile = (File) entry.getValue(); if (!ALLOWED_PATH_PATTERN.matcher(srcFile.getAbsolutePath()).matches()) { throw new IOException("Unsafe file to 'mass' symlink: '" + srcFile.getAbsolutePath() + "'"); } if (!ALLOWED_PATH_PATTERN.matcher(destFile.getAbsolutePath()).matches()) { throw new IOException("Unsafe file to 'mass' symlink to: '" + destFile.getAbsolutePath() + "'"); } // Add to our buffer of commands sb.append("ln -s -f \"" + srcFile.getAbsolutePath() + "\" \"" + destFile.getAbsolutePath() + "\";"); if (keyItr.hasNext()) { sb.append("\n"); } } String commands = sb.toString(); // Run the buffer of commands we have built. Runtime runtime = Runtime.getRuntime(); Message.verbose("executing \"sh\" of:\n\t" + commands.replaceAll("\n", "\n\t")); Process process = runtime.exec("sh"); OutputStream os = process.getOutputStream(); os.write(commands.getBytes("UTF-8")); os.flush(); os.close(); if (process.waitFor() != 0) { InputStream errorStream = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(isr); StringBuffer error = new StringBuffer(); String line; while ((line = br.readLine()) != null) { error.append(line); error.append('\n'); } throw new IOException("error running ln commands with 'sh':\n" + error); } } catch (InterruptedException x) { Thread.currentThread().interrupt(); } } public static void symlink(File src, File dest, CopyProgressListener l, boolean overwrite) throws IOException { if (!prepareCopy(src, dest, overwrite)) { return; } try { Runtime runtime = Runtime.getRuntime(); Message.verbose("executing 'ln -s -f " + src.getAbsolutePath() + " " + dest.getPath() + "'"); Process process = runtime.exec(new String[] {"ln", "-s", "-f", src.getAbsolutePath(), dest.getPath()}); if (process.waitFor() != 0) { InputStream errorStream = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(errorStream); BufferedReader br = new BufferedReader(isr); StringBuffer error = new StringBuffer(); String line; while ((line = br.readLine()) != null) { error.append(line); error.append('\n'); } throw new IOException("error symlinking " + src + " to " + dest + ":\n" + error); } // check if the creation of the symbolic link was successful if (!dest.exists()) { throw new IOException("error symlinking: " + dest + " doesn't exists"); } // check if the result is a true symbolic link if (dest.getAbsolutePath().equals(dest.getCanonicalPath())) { dest.delete(); // just make sure we do delete the invalid symlink! throw new IOException("error symlinking: " + dest + " isn't a symlink"); } } catch (IOException e) { Message.verbose("symlink failed; falling back to copy", e); copy(src, dest, l, overwrite); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } } public static boolean copy(File src, File dest, CopyProgressListener l) throws IOException { return copy(src, dest, l, false); } public static boolean prepareCopy(File src, File dest, boolean overwrite) throws IOException { if (src.isDirectory()) { if (dest.exists()) { if (!dest.isDirectory()) { throw new IOException("impossible to copy: destination is not a directory: " + dest); } } else { dest.mkdirs(); } return true; } // else it is a file copy if (dest.exists()) { if (!dest.isFile()) { throw new IOException("impossible to copy: destination is not a file: " + dest); } if (overwrite) { if (!dest.canWrite()) { dest.delete(); } // if dest is writable, the copy will overwrite it without requiring a delete } else { Message.verbose(dest + " already exists, nothing done"); return false; } } if (dest.getParentFile() != null) { dest.getParentFile().mkdirs(); } return true; } public static boolean copy(File src, File dest, CopyProgressListener l, boolean overwrite) throws IOException { if (!prepareCopy(src, dest, overwrite)) { return false; } if (src.isDirectory()) { return deepCopy(src, dest, l, overwrite); } // else it is a file copy copy(new FileInputStream(src), dest, l); long srcLen = src.length(); long destLen = dest.length(); if (srcLen != destLen) { dest.delete(); throw new IOException("size of source file " + src.toString() + "(" + srcLen + ") differs from size of dest file " + dest.toString() + "(" + destLen + ") - please retry"); } dest.setLastModified(src.lastModified()); return true; } public static boolean deepCopy(File src, File dest, CopyProgressListener l, boolean overwrite) throws IOException { // the list of files which already exist in the destination folder List/* */existingChild = Collections.EMPTY_LIST; if (dest.exists()) { if (!dest.isDirectory()) { // not expected type, remove dest.delete(); // and create a folder dest.mkdirs(); dest.setLastModified(src.lastModified()); } else { // existing folder, gather existing children File[] children = dest.listFiles(); if (children != null) { existingChild = Arrays.asList(children); } } } else { dest.mkdirs(); dest.setLastModified(src.lastModified()); } // copy files one by one File[] toCopy = src.listFiles(); if (toCopy != null) { for (int i = 0; i < toCopy.length; i++) { // compute the destination file File childDest = new File(dest, toCopy[i].getName()); // if file existing, 'mark' it as taken care of existingChild.remove(childDest); if (toCopy[i].isDirectory()) { deepCopy(toCopy[i], childDest, l, overwrite); } else { copy(toCopy[i], childDest, l, overwrite); } } } // some file exist in the destination but not in the source: delete them for (int i = 0; i < existingChild.size(); i++) { forceDelete((File) existingChild.get(i)); } return true; } public static void copy(URL src, File dest, CopyProgressListener l) throws IOException { URLHandlerRegistry.getDefault().download(src, dest, l); } public static void copy(File src, URL dest, CopyProgressListener l) throws IOException { URLHandlerRegistry.getDefault().upload(src, dest, l); } public static void copy(InputStream src, File dest, CopyProgressListener l) throws IOException { if (dest.getParentFile() != null) { dest.getParentFile().mkdirs(); } copy(src, new FileOutputStream(dest), l); } public static void copy(InputStream src, OutputStream dest, CopyProgressListener l) throws IOException { copy(src, dest, l, true); } public static void copy(InputStream src, OutputStream dest, CopyProgressListener l, boolean autoClose) throws IOException { CopyProgressEvent evt = null; if (l != null) { evt = new CopyProgressEvent(); } try { byte[] buffer = new byte[BUFFER_SIZE]; int c; long total = 0; if (l != null) { l.start(evt); } while ((c = src.read(buffer)) != -1) { if (Thread.currentThread().isInterrupted()) { throw new IOException("transfer interrupted"); } dest.write(buffer, 0, c); total += c; if (l != null) { l.progress(evt.update(buffer, c, total)); } } if (l != null) { evt.update(EMPTY_BUFFER, 0, total); } try { dest.flush(); } catch (IOException ex) { // ignore } // close the streams if (autoClose) { src.close(); dest.close(); } } finally { if (autoClose) { try { src.close(); } catch (IOException ex) { // ignore } try { dest.close(); } catch (IOException ex) { // ignore } } } if (l != null) { l.end(evt); } } /** * Reads the whole BufferedReader line by line, using \n as line separator for each line. *

    * Note that this method will add a final \n to the last line even though there is no new line * character at the end of last line in the original reader. *

    *

    * The BufferedReader is closed when this method returns. *

    * * @param in * the {@link BufferedReader} to read from * @return a String with the whole content read from the {@link BufferedReader} * @throws IOException * if an IO problems occur during reading */ public static String readEntirely(BufferedReader in) throws IOException { try { StringBuffer buf = new StringBuffer(); String line = in.readLine(); while (line != null) { buf.append(line + "\n"); line = in.readLine(); } return buf.toString(); } finally { in.close(); } } /** * Reads the entire content of the file and returns it as a String. * * @param f * the file to read from * @return a String with the file content * @throws IOException * if an IO problems occurs during reading */ public static String readEntirely(File f) throws IOException { return readEntirely(new FileInputStream(f)); } /** * Reads the entire content of the {@link InputStream} and returns it as a String. *

    * The input stream is closed when this method returns. *

    * * @param is * the {@link InputStream} to read from * @return a String with the input stream content * @throws IOException * if an IO problems occurs during reading */ public static String readEntirely(InputStream is) throws IOException { try { StringBuffer sb = new StringBuffer(); byte[] buffer = new byte[BUFFER_SIZE]; int c; while ((c = is.read(buffer)) != -1) { sb.append(new String(buffer, 0, c)); } return sb.toString(); } finally { is.close(); } } public static String concat(String dir, String file) { return dir + "/" + file; } /** * Recursively delete file * * @param file * the file to delete * @return true if the deletion completed successfully (ie if the file does not exist on the * filesystem after this call), false if a deletion was not performed successfully. */ public static boolean forceDelete(File file) { if (!file.exists()) { return true; } if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { if (!forceDelete(files[i])) { return false; } } } } return file.delete(); } /** * Returns a list of Files composed of all directories being parent of file and child of root + * file and root themselves. Example: getPathFiles(new File("test"), new * File("test/dir1/dir2/file.txt")) => {new File("test/dir1"), new File("test/dir1/dir2"), new * File("test/dir1/dir2/file.txt") } Note that if root is not an ancester of file, or if root is * null, all directories from the file system root will be returned. */ public static List getPathFiles(File root, File file) { List ret = new ArrayList(); while (file != null && !file.getAbsolutePath().equals(root.getAbsolutePath())) { ret.add(file); file = file.getParentFile(); } if (root != null) { ret.add(root); } Collections.reverse(ret); return ret; } /** * Returns a collection of all Files being contained in the given directory, recursively, * including directories. * * @param dir * The directory from which all files, including files in subdirectory) are * extracted. * @param ignore * a Collection of filenames which must be excluded from listing * @return A collectoin containing all the files of the given directory and it's subdirectories. */ public static Collection listAll(File dir, Collection ignore) { return listAll(dir, new ArrayList(), ignore); } private static Collection listAll(File file, Collection list, Collection ignore) { if (ignore.contains(file.getName())) { return list; } if (file.exists()) { list.add(file); } if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { listAll(files[i], list, ignore); } } return list; } public static File resolveFile(File file, String filename) { File result = new File(filename); if (!result.isAbsolute()) { result = new File(file, filename); } return normalize(result.getPath()); } // //////////////////////////////////////////// // The following code comes from Ant FileUtils // //////////////////////////////////////////// /** * "Normalize" the given absolute path. * *

    * This includes: *

      *
    • Uppercase the drive letter if there is one.
    • *
    • Remove redundant slashes after the drive spec.
    • *
    • Resolve all ./, .\, ../ and ..\ sequences.
    • *
    • DOS style paths that start with a drive letter will have \ as the separator.
    • *
    * Unlike {@link File#getCanonicalPath()} this method specifically does not resolve symbolic * links. * * @param path * the path to be normalized. * @return the normalized version of the path. * * @throws java.lang.NullPointerException * if path is null. */ public static File normalize(final String path) { Stack s = new Stack(); String[] dissect = dissect(path); s.push(dissect[0]); StringTokenizer tok = new StringTokenizer(dissect[1], File.separator); while (tok.hasMoreTokens()) { String thisToken = tok.nextToken(); if (".".equals(thisToken)) { continue; } if ("..".equals(thisToken)) { if (s.size() < 2) { // Cannot resolve it, so skip it. return new File(path); } s.pop(); } else { // plain component s.push(thisToken); } } StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.size(); i++) { if (i > 1) { // not before the filesystem root and not after it, since root // already contains one sb.append(File.separatorChar); } sb.append(s.elementAt(i)); } return new File(sb.toString()); } /** * Dissect the specified absolute path. * * @param path * the path to dissect. * @return String[] {root, remaining path}. * @throws java.lang.NullPointerException * if path is null. * @since Ant 1.7 */ private static String[] dissect(String path) { char sep = File.separatorChar; path = path.replace('/', sep).replace('\\', sep); // // make sure we are dealing with an absolute path // if (!isAbsolutePath(path)) { // throw new BuildException(path + " is not an absolute path"); // } String root = null; int colon = path.indexOf(':'); if (colon > 0) { // && (ON_DOS || ON_NETWARE)) { int next = colon + 1; root = path.substring(0, next); char[] ca = path.toCharArray(); root += sep; // remove the initial separator; the root has it. next = (ca[next] == sep) ? next + 1 : next; StringBuffer sbPath = new StringBuffer(); // Eliminate consecutive slashes after the drive spec: for (int i = next; i < ca.length; i++) { if (ca[i] != sep || ca[i - 1] != sep) { sbPath.append(ca[i]); } } path = sbPath.toString(); } else if (path.length() > 1 && path.charAt(1) == sep) { // UNC drive int nextsep = path.indexOf(sep, 2); nextsep = path.indexOf(sep, nextsep + 1); root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; path = path.substring(root.length()); } else { root = File.separator; path = path.substring(1); } return new String[] {root, path}; } /** * Get the length of the file, or the sum of the children lengths if it is a directory * * @param file * @return */ public static long getFileLength(File file) { long l = 0; if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { l += getFileLength(files[i]); } } } else { l = file.length(); } return l; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/HexEncoder.java000066400000000000000000000027301226750426600232160ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; /** * Simple encoder of byte arrays into String array using only the hexadecimal alphabet */ public class HexEncoder { private static final char[] ALPHABET = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; public static String encode(byte[] packet) { StringBuffer chars = new StringBuffer(16); for (int i = 0; i < packet.length; i++) { int highBits = (packet[i] & 0xF0) >> 4; int lowBits = packet[i] & 0x0F; chars.append(ALPHABET[highBits]); chars.append(ALPHABET[lowBits]); } return chars.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/HostUtil.java000066400000000000000000000033171226750426600227470ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.net.InetAddress; import java.net.UnknownHostException; /** * This class contains basic helper methods for the Host. * */ public final class HostUtil { private static String localHostName = null; /** * This default constructor is to hide this class from initialization through other classes. */ private HostUtil() { } /** * This method returns the name of the current Host, if this name cannot be determined, * localhost will be returned. * * @return The name of the current "local" Host. */ public static String getLocalHostName() { if (localHostName == null) { try { localHostName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { localHostName = "localhost"; } } return localHostName; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/MemoryUtil.java000066400000000000000000000060501226750426600232770ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; /** * Memory related utilities. */ public final class MemoryUtil { private static final int SAMPLING_SIZE = 100; private static final int SLEEP_TIME = 100; private MemoryUtil() { } /** * Returns the approximate size of a default instance of the given class. * * @param clazz * the class to evaluate. * @return the estimated size of instance, in bytes. */ public static long sizeOf(Class clazz) { long size = 0; Object[] objects = new Object[SAMPLING_SIZE]; try { clazz.newInstance(); long startingMemoryUse = getUsedMemory(); for (int i = 0; i < objects.length; i++) { objects[i] = clazz.newInstance(); } long endingMemoryUse = getUsedMemory(); float approxSize = (endingMemoryUse - startingMemoryUse) / (float) objects.length; size = Math.round(approxSize); } catch (Exception e) { Message.warn("Couldn't instantiate " + clazz, e); } return size; } /** * Returns the currently used memory, after calling garbage collector and waiting enough to get * maximal chance it is actually called. But since {@link Runtime#gc()} is only advisory, * results returned by this method should be treated as rough approximation only. * * @return the currently used memory, in bytes. */ public static long getUsedMemory() { gc(); long totalMemory = Runtime.getRuntime().totalMemory(); gc(); long freeMemory = Runtime.getRuntime().freeMemory(); long usedMemory = totalMemory - freeMemory; return usedMemory; } private static void gc() { try { System.gc(); Thread.sleep(SLEEP_TIME); System.runFinalization(); Thread.sleep(SLEEP_TIME); System.gc(); Thread.sleep(SLEEP_TIME); System.runFinalization(); Thread.sleep(SLEEP_TIME); } catch (Exception e) { Message.debug(e); } } public static void main(String[] args) throws ClassNotFoundException { System.out.println(sizeOf(Class.forName(args[0]))); } }ivy-2.4.0-rc1/src/java/org/apache/ivy/util/Message.java000066400000000000000000000137371226750426600225670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.List; import org.apache.ivy.Ivy; import org.apache.ivy.core.IvyContext; /** * Logging utility class. *

    * This class provides static methods for easy access to the current logger in {@link IvyContext}. *

    *

    * To configure logging, you should use the methods provided by the {@link MessageLoggerEngine} * associated with the {@link Ivy} engine. *

    */ public final class Message { // messages level copied from ant project, to avoid dependency on ant /** Message priority of "error". */ public static final int MSG_ERR = 0; /** Message priority of "warning". */ public static final int MSG_WARN = 1; /** Message priority of "information". */ public static final int MSG_INFO = 2; /** Message priority of "verbose". */ public static final int MSG_VERBOSE = 3; /** Message priority of "debug". */ public static final int MSG_DEBUG = 4; private static boolean showedInfo = false; private static MessageLogger defaultLogger = new DefaultMessageLogger(Message.MSG_INFO); /** * Returns the current default logger. * * @return the current default logger; is never null. */ public static MessageLogger getDefaultLogger() { return defaultLogger; } /** * Change the default logger used when no other logger is currently configured * * @param logger * the new default logger, must not be null */ public static void setDefaultLogger(MessageLogger logger) { Checks.checkNotNull(logger, "logger"); defaultLogger = logger; } private static MessageLogger getLogger() { return IvyContext.getContext().getMessageLogger(); } public static void showInfo() { if (!showedInfo) { info(":: Apache Ivy " + Ivy.getIvyVersion() + " - " + Ivy.getIvyDate() + " :: " + Ivy.getIvyHomeURL() + " ::"); showedInfo = true; } } public static void debug(String msg) { getLogger().debug(msg); } public static void verbose(String msg) { getLogger().verbose(msg); } public static void info(String msg) { getLogger().info(msg); } public static void rawinfo(String msg) { getLogger().rawinfo(msg); } public static void deprecated(String msg) { getLogger().deprecated(msg); } public static void warn(String msg) { getLogger().warn(msg); } public static void error(String msg) { getLogger().error(msg); } public static void log(int logLevel, String msg) { switch (logLevel) { case MSG_DEBUG: debug(msg); break; case MSG_VERBOSE: verbose(msg); break; case MSG_INFO: info(msg); break; case MSG_WARN: warn(msg); break; case MSG_ERR: error(msg); break; default: throw new IllegalArgumentException("Unknown log level " + logLevel); } } public static List getProblems() { return getLogger().getProblems(); } public static void sumupProblems() { getLogger().sumupProblems(); } public static void progress() { getLogger().progress(); } public static void endProgress() { getLogger().endProgress(); } public static void endProgress(String msg) { getLogger().endProgress(msg); } public static boolean isShowProgress() { return getLogger().isShowProgress(); } public static void setShowProgress(boolean progress) { getLogger().setShowProgress(progress); } private Message() { } public static void debug(String message, Throwable t) { if (t == null) { debug(message); } else { debug(message + " (" + t.getClass().getName() + ": " + t.getMessage() + ")"); debug(t); } } public static void verbose(String message, Throwable t) { if (t == null) { verbose(message); } else { verbose(message + " (" + t.getClass().getName() + ": " + t.getMessage() + ")"); debug(t); } } public static void info(String message, Throwable t) { if (t == null) { info(message); } else { info(message + " (" + t.getClass().getName() + ": " + t.getMessage() + ")"); debug(t); } } public static void warn(String message, Throwable t) { if (t == null) { warn(message); } else { warn(message + " (" + t.getClass().getName() + ": " + t.getMessage() + ")"); debug(t); } } public static void error(String message, Throwable t) { if (t == null) { error(message); } else { error(message + " (" + t.getClass().getName() + ": " + t.getMessage() + ")"); debug(t); } } public static void debug(Throwable t) { debug(StringUtils.getStackTrace(t)); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/MessageLogger.java000066400000000000000000000065241226750426600237230ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.List; /** * A MessageLogger is used to log messages. *

    * Where the messages are logged is depending on the implementation. *

    *

    * This interface provides both level specific methods ({@link #info(String)}, {@link #warn(String)} * , ...) and generic methods ({@link #log(String, int)}, {@link #rawlog(String, int)}). Note that * calling level specific methods is usually not equivalent to calling the generic method with the * corresponding level. Indeed, for warn and error level, the implementation will actually log the * message at a lower level (usually {@link Message#MSG_VERBOSE}) and log the message at the actual * level only when {@link #sumupProblems()} is called. *

    * * @see Message */ public interface MessageLogger { /** * Logs a message at the given level. *

    * level constants are defined in the {@link Message} class. *

    * * @param msg * the message to log * @param level * the level at which the message should be logged. * @see Message#MSG_DEBUG * @see Message#MSG_VERBOSE * @see Message#MSG_INFO * @see Message#MSG_WARN * @see Message#MSG_ERROR */ public abstract void log(String msg, int level); /** * Same as {@link #log(String, int)}, but without adding any contextual information to the * message. * * @param msg * the message to log * @param level * the level at which the message should be logged. */ public abstract void rawlog(String msg, int level); public abstract void debug(String msg); public abstract void verbose(String msg); public abstract void deprecated(String msg); public abstract void info(String msg); public abstract void rawinfo(String msg); public abstract void warn(String msg); public abstract void error(String msg); public abstract List getProblems(); public abstract List getWarns(); public abstract List getErrors(); /** * Clears the list of problems, warns and errors. */ public abstract void clearProblems(); /** * Sumup all problems encountered so far, and clear them. */ public abstract void sumupProblems(); public abstract void progress(); public abstract void endProgress(); public abstract void endProgress(String msg); public abstract boolean isShowProgress(); public abstract void setShowProgress(boolean progress); }ivy-2.4.0-rc1/src/java/org/apache/ivy/util/MessageLoggerEngine.java000066400000000000000000000133471226750426600250520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; /** * A {@link MessageLogger} implementation delegating the work to the current top logger on a stack. *

    * When the logger stack is empty, it delegates the work to a default logger, which by default is * the {@link Message#getDefaultLogger()}. *

    *

    * {@link #pushLogger(MessageLogger)} should be called to delegate to a new logger, and * {@link #popLogger()} should be called when the context of this logger is finished. *

    */ public class MessageLoggerEngine implements MessageLogger { private final ThreadLocal/* > */loggerStacks = new ThreadLocal(); private MessageLogger defaultLogger = null; private List problems = new ArrayList(); private List warns = new ArrayList(); private List errors = new ArrayList(); private Stack getLoggerStack() { Stack stack = (Stack) loggerStacks.get(); if (stack == null) { stack = new Stack(); loggerStacks.set(stack); } return stack; } public MessageLoggerEngine() { } /** * Sets the logger used when the stack is empty. * * @param defaultLogger * the logger to use when the stack is empty. */ public void setDefaultLogger(MessageLogger defaultLogger) { this.defaultLogger = defaultLogger; } /** * Push a logger on the stack. * * @param logger * the logger to push. Must not be null. */ public void pushLogger(MessageLogger logger) { Checks.checkNotNull(logger, "logger"); getLoggerStack().push(logger); } /** * Pops a logger from the logger stack. *

    * Does nothing if the logger stack is empty *

    */ public void popLogger() { if (!getLoggerStack().isEmpty()) { getLoggerStack().pop(); } } /** * Returns the current logger, or the default one if there is no logger in the stack * * @return the current logger, or the default one if there is no logger in the stack */ public MessageLogger peekLogger() { if (getLoggerStack().isEmpty()) { return getDefaultLogger(); } return (MessageLogger) getLoggerStack().peek(); } private MessageLogger getDefaultLogger() { // we don't store the logger returned by Message.getDefaultLogger() to always stay in sync // as long as our default logger has not been set explicitly with setDefaultLogger() return defaultLogger == null ? Message.getDefaultLogger() : defaultLogger; } // consolidated methods public void warn(String msg) { peekLogger().warn(msg); problems.add("WARN: " + msg); warns.add(msg); } public void error(String msg) { peekLogger().error(msg); problems.add("\tERROR: " + msg); errors.add(msg); } public List getErrors() { return errors; } public List getProblems() { return problems; } public List getWarns() { return warns; } public void sumupProblems() { MessageLoggerHelper.sumupProblems(this); clearProblems(); } public void clearProblems() { getDefaultLogger().clearProblems(); for (Iterator iter = getLoggerStack().iterator(); iter.hasNext();) { MessageLogger l = (MessageLogger) iter.next(); l.clearProblems(); } problems.clear(); errors.clear(); warns.clear(); } public void setShowProgress(boolean progress) { getDefaultLogger().setShowProgress(progress); // updates all loggers in the stack for (Iterator iter = getLoggerStack().iterator(); iter.hasNext();) { MessageLogger l = (MessageLogger) iter.next(); l.setShowProgress(progress); } } public boolean isShowProgress() { // testing the default logger is enough, all loggers should be in sync return getDefaultLogger().isShowProgress(); } // delegation methods public void debug(String msg) { peekLogger().debug(msg); } public void deprecated(String msg) { peekLogger().deprecated(msg); } public void endProgress() { peekLogger().endProgress(); } public void endProgress(String msg) { peekLogger().endProgress(msg); } public void info(String msg) { peekLogger().info(msg); } public void rawinfo(String msg) { peekLogger().rawinfo(msg); } public void log(String msg, int level) { peekLogger().log(msg, level); } public void progress() { peekLogger().progress(); } public void rawlog(String msg, int level) { peekLogger().rawlog(msg, level); } public void verbose(String msg) { peekLogger().verbose(msg); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/MessageLoggerHelper.java000066400000000000000000000043501226750426600250560ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.util.Iterator; import java.util.List; public final class MessageLoggerHelper { public static void sumupProblems(MessageLogger logger) { List myProblems = logger.getProblems(); if (myProblems.size() > 0) { List myWarns = logger.getWarns(); List myErrors = logger.getErrors(); logger.info(""); // new line on info to isolate error summary if (!myErrors.isEmpty()) { logger.log(":: problems summary ::", Message.MSG_ERR); } else { logger.log(":: problems summary ::", Message.MSG_WARN); } if (myWarns.size() > 0) { logger.log(":::: WARNINGS", Message.MSG_WARN); for (Iterator iter = myWarns.iterator(); iter.hasNext();) { String msg = (String) iter.next(); logger.log("\t" + msg + "\n", Message.MSG_WARN); } } if (myErrors.size() > 0) { logger.log(":::: ERRORS", Message.MSG_ERR); for (Iterator iter = myErrors.iterator(); iter.hasNext();) { String msg = (String) iter.next(); logger.log("\t" + msg + "\n", Message.MSG_ERR); } } logger.info("\n:: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS"); } } private MessageLoggerHelper() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/PropertiesFile.java000066400000000000000000000045171226750426600241330ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; /** * A simple Properties extension easing the loading and saving of data */ public class PropertiesFile extends Properties { private File file; private String header; public PropertiesFile(File file, String header) { this.file = file; this.header = header; if (file.exists()) { FileInputStream fis = null; try { fis = new FileInputStream(file); load(fis); } catch (Exception ex) { Message.warn("exception occurred while reading properties file " + file, ex); } try { if (fis != null) { fis.close(); } } catch (IOException e) { // ignored } } } public void save() { FileOutputStream fos = null; try { if (file.getParentFile() != null && !file.getParentFile().exists()) { file.getParentFile().mkdirs(); } fos = new FileOutputStream(file); store(fos, header); } catch (Exception ex) { Message.warn("exception occurred while writing properties file " + file, ex); } try { if (fos != null) { fos.close(); } } catch (IOException e) { // ignored } } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/StringUtils.java000066400000000000000000000163521226750426600234660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.util.Locale; /** * Convenient class used only for uncapitalization Usually use commons lang but here we do not want * to have such a dependency for only one feature */ public final class StringUtils { private StringUtils() { // Utility class } public static String uncapitalize(String string) { if (string == null || string.length() == 0) { return string; } if (string.length() == 1) { return string.toLowerCase(Locale.US); } return string.substring(0, 1).toLowerCase(Locale.US) + string.substring(1); } /** * Returns the error message associated with the given Throwable. The error message returned * will try to be as precise as possible, handling cases where e.getMessage() is not meaningful, * like {@link NullPointerException} for instance. * * @param t * the throwable to get the error message from * @return the error message of the given exception */ public static String getErrorMessage(Throwable t) { if (t == null) { return ""; } if (t instanceof InvocationTargetException) { InvocationTargetException ex = (InvocationTargetException) t; t = ex.getTargetException(); } String errMsg = t instanceof RuntimeException ? t.getMessage() : t.toString(); if (errMsg == null || errMsg.length() == 0 || "null".equals(errMsg)) { errMsg = t.getClass().getName() + " at " + t.getStackTrace()[0].toString(); } return errMsg; } /** * Returns the exception stack trace as a String. * * @param e * the exception to get the stack trace from. * @return the exception stack trace */ public static String getStackTrace(Throwable e) { if (e == null) { return ""; } StringWriter sw = new StringWriter(); PrintWriter printWriter = new PrintWriter(sw, true); e.printStackTrace(printWriter); return sw.getBuffer().toString(); } /** * Joins the given object array in one string, each separated by the given separator. * * Example: * *
         * join(new String[] {"one", "two", "three"}, ", ") -> "one, two, three"
         * 
    * * @param objs * The array of objects (toString() is used). * @param sep * The separator to use. * @return The concatinated string. */ public static String join(Object[] objs, String sep) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < objs.length; i++) { buf.append(objs[i]).append(sep); } if (objs.length > 0) { buf.setLength(buf.length() - sep.length()); // delete sep } return buf.toString(); } // basic string codec (same algo as CVS passfile, inspired by ant CVSPass class /** Array contain char conversion data */ private static final char[] SHIFTS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 114, 120, 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 111, 52, 75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, 41, 57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50, 42, 123, 91, 35, 125, 55, 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, 36, 121, 117, 104, 101, 100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 58, 113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223, 225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, 199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, 226, 193, 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, 161, 179, 160, 212, 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, 192, 159, 244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, 227, 231, 219, 169, 175, 156, 206, 198, 129, 164, 150, 210, 154, 177, 134, 127, 182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, 243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152}; /** * Encrypt the given string in a way which anybody having access to this method algorithm can * easily decrypt. This is useful only to avoid clear string storage in a file for example, but * shouldn't be considered as a real mean of security. This only works with simple characters * (char < 256). * * @param str * the string to encrypt * @return the encrypted version of the string */ public static final String encrypt(String str) { if (str == null) { return null; } StringBuffer buf = new StringBuffer(); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c >= SHIFTS.length) { throw new IllegalArgumentException( "encrypt method can only be used with simple characters. '" + c + "' not allowed"); } buf.append(SHIFTS[c]); } return buf.toString(); } /** * Decrypts a string encrypted with encrypt. * * @param str * the encrypted string to decrypt * @return The decrypted string. */ public static final String decrypt(String str) { if (str == null) { return null; } StringBuffer buf = new StringBuffer(); for (int i = 0; i < str.length(); i++) { buf.append(decrypt(str.charAt(i))); } return buf.toString(); } private static char decrypt(char c) { for (char i = 0; i < SHIFTS.length; i++) { if (SHIFTS[i] == c) { return i; } } throw new IllegalArgumentException("Impossible to decrypt '" + c + "'. Unhandled character."); } public static String repeat(String str, int count) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < count; i++) { sb.append(str); } return sb.toString(); } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/XMLHelper.java000066400000000000000000000221431226750426600227720ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.ivy.util.url.URLHandlerRegistry; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; public abstract class XMLHelper { static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; static final String XERCES_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; static final String XML_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; private static boolean canUseSchemaValidation = true; private static Boolean canDisableExternalDtds = null; private static SAXParser newSAXParser(URL schema, InputStream schemaStream, boolean loadExternalDtds) throws ParserConfigurationException, SAXException { SAXParserFactory parserFactory = SAXParserFactory.newInstance(); parserFactory.setNamespaceAware(true); parserFactory.setValidating(canUseSchemaValidation && (schema != null)); if (!loadExternalDtds && canDisableExternalDtds(parserFactory)) { parserFactory.setFeature(XERCES_LOAD_EXTERNAL_DTD, false); } SAXParser parser = parserFactory.newSAXParser(); if (canUseSchemaValidation && (schema != null)) { try { parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); parser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream); } catch (SAXNotRecognizedException ex) { Message.warn("problem while setting JAXP validating property on SAXParser... " + "XML validation will not be done", ex); canUseSchemaValidation = false; parserFactory.setValidating(false); parser = parserFactory.newSAXParser(); } } parser.getXMLReader().setFeature(XML_NAMESPACE_PREFIXES, true); return parser; } private static boolean canDisableExternalDtds(SAXParserFactory parserFactory) { if (canDisableExternalDtds == null) { try { parserFactory.getFeature(XERCES_LOAD_EXTERNAL_DTD); canDisableExternalDtds = Boolean.TRUE; } catch (Exception ex) { canDisableExternalDtds = Boolean.FALSE; } } return canDisableExternalDtds.booleanValue(); } /** * Convert an URL to a valid systemId according to RFC 2396. */ public static String toSystemId(URL url) { try { return new URI(url.toExternalForm()).toASCIIString(); } catch (URISyntaxException e) { return url.toExternalForm(); } } // IMPORTANT: validation errors are only notified to the given handler, and // do not cause exception // implement warning error and fatalError methods in handler to be informed // of validation errors public static void parse(URL xmlURL, URL schema, DefaultHandler handler) throws SAXException, IOException, ParserConfigurationException { parse(xmlURL, schema, handler, null); } public static void parse(URL xmlURL, URL schema, DefaultHandler handler, LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException { InputStream xmlStream = URLHandlerRegistry.getDefault().openStream(xmlURL); try { InputSource inSrc = new InputSource(xmlStream); inSrc.setSystemId(toSystemId(xmlURL)); parse(inSrc, schema, handler, lHandler); } finally { try { xmlStream.close(); } catch (IOException e) { // ignored } } } public static void parse(InputStream xmlStream, URL schema, DefaultHandler handler, LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException { parse(new InputSource(xmlStream), schema, handler, lHandler); } public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler, LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException { parse(xmlStream, schema, handler, lHandler, true); } public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler, LexicalHandler lHandler, boolean loadExternalDtds) throws SAXException, IOException, ParserConfigurationException { InputStream schemaStream = null; try { if (schema != null) { schemaStream = URLHandlerRegistry.getDefault().openStream(schema); } SAXParser parser = XMLHelper.newSAXParser(schema, schemaStream, loadExternalDtds); if (lHandler != null) { try { parser.setProperty("http://xml.org/sax/properties/lexical-handler", lHandler); } catch (SAXException ex) { Message.warn("problem while setting the lexical handler property on SAXParser", ex); // continue without the lexical handler } } parser.parse(xmlStream, handler); } finally { if (schemaStream != null) { try { schemaStream.close(); } catch (IOException ex) { // ignored } } } } public static boolean canUseSchemaValidation() { return canUseSchemaValidation; } /** * Escapes invalid XML characters in the given character data using XML entities. For the * moment, only the following characters are being escaped: (<), (&), (') and ("). * * Remark: we don't escape the (>) character to keep the readability of the configuration * mapping! The XML spec only requires that the (&) and (<) characters are being escaped inside * character data. * * @param text * the character data to escape * @return the escaped character data */ public static String escape(String text) { if (text == null) { return null; } StringBuffer result = new StringBuffer(text.length()); char[] chars = text.toCharArray(); for (int i = 0; i < chars.length; i++) { switch (chars[i]) { case '&': result.append("&"); break; case '<': result.append("<"); break; case '\'': result.append("'"); break; case '\"': result.append("""); break; default: result.append(chars[i]); } } return result.toString(); } public static Document parseToDom(InputSource source, EntityResolver entityResolver) throws IOException, SAXException { DocumentBuilder docBuilder = getDocBuilder(entityResolver); return docBuilder.parse(source); } public static DocumentBuilder getDocBuilder(EntityResolver entityResolver) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); DocumentBuilder docBuilder = factory.newDocumentBuilder(); if (entityResolver != null) { docBuilder.setEntityResolver(entityResolver); } return docBuilder; } catch (ParserConfigurationException e) { throw new RuntimeException(e); } } private XMLHelper() { } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/cli/000077500000000000000000000000001226750426600210745ustar00rootroot00000000000000ivy-2.4.0-rc1/src/java/org/apache/ivy/util/cli/CommandLine.java000066400000000000000000000035151226750426600241310ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util.cli; import java.util.HashMap; import java.util.Map; public class CommandLine { private Map/* */optionValues = new HashMap(); private String[] leftOverArgs; void addOptionValues(String option, String[] values) { optionValues.put(option, values); } void setLeftOverArgs(String[] args) { leftOverArgs = args; } public boolean hasOption(String option) { return optionValues.containsKey(option); } public String getOptionValue(String option) { String[] values = getOptionValues(option); return values == null || values.length == 0 ? null : values[0]; } public String getOptionValue(String option, String defaultValue) { String value = getOptionValue(option); return value == null ? defaultValue : value; } public String[] getOptionValues(String option) { return (String[]) optionValues.get(option); } public String[] getLeftOverArgs() { return leftOverArgs; } } ivy-2.4.0-rc1/src/java/org/apache/ivy/util/cli/CommandLineParser.java000066400000000000000000000124331226750426600253050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.ivy.util.cli; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.util.StringUtils; public class CommandLineParser { private static final int MIN_DESC_WIDTH = 40; private static final int MAX_SPEC_WIDTH = 30; private Map/* */options = new LinkedHashMap(); private Map/* > */categories = new LinkedHashMap(); public CommandLineParser() { } public CommandLineParser addCategory(String category) { categories.put(category, new ArrayList()); return this; } public CommandLineParser addOption(Option option) { options.put(option.getName(), option); if (!categories.isEmpty()) { ((List) categories.values().toArray()[categories.values().size() - 1]).add(option); } return this; } public CommandLine parse(String[] args) throws ParseException { CommandLine line = new CommandLine(); int index = args.length; ListIterator iterator = Arrays.asList(args).listIterator(); while (iterator.hasNext()) { String arg = (String) iterator.next(); if ("--".equals(arg)) { // skip this argument and stop looping index = iterator.nextIndex(); break; } if (!arg.startsWith("-")) { index = iterator.previousIndex(); break; } Option option = (Option) options.get(arg.substring(1)); if (option == null) { throw new ParseException("Unrecognized option: " + arg); } line.addOptionValues(arg.substring(1), option.parse(iterator)); } // left over args String[] leftOverArgs = new String[args.length - index]; System.arraycopy(args, index, leftOverArgs, 0, leftOverArgs.length); line.setLeftOverArgs(leftOverArgs); return line; } public void printHelp(PrintWriter pw, int width, String command, boolean showDeprecated) { pw.println("usage: " + command); // compute the largest option spec int specWidth = 0; for (Iterator iterator = options.values().iterator(); iterator.hasNext();) { Option option = (Option) iterator.next(); if (option.isDeprecated() && !showDeprecated) { continue; } specWidth = Math.min(MAX_SPEC_WIDTH, Math.max(specWidth, option.getSpec().length())); } // print options help for (Iterator iterator = categories.entrySet().iterator(); iterator.hasNext();) { Entry entry = (Entry) iterator.next(); String category = (String) entry.getKey(); pw.println("==== " + category); List/*