From e071abe7a020d0c04fcf57f4a0d810d3f108a92f Mon Sep 17 00:00:00 2001 From: Petr Gotthard Date: Tue, 22 Dec 2015 03:39:39 -0800 Subject: [PATCH] Make sure we use patched gen_smtp. Plus update erlang.mk --- Makefile | 18 ++---- build.config | 2 +- erlang.mk | 126 ++++++++++++++++++++--------------------- rabbitmq-components.mk | 109 +++++++++++++++++++---------------- 4 files changed, 130 insertions(+), 125 deletions(-) diff --git a/Makefile b/Makefile index 8edd115..553b131 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PROJECT = rabbitmq_email -DEPS = rabbit amqp_client gen_smtp +DEPS = amqp_client gen_smtp ifeq ($(EICONV),1) DEPS += eiconv endif @@ -11,17 +11,9 @@ DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk NO_AUTOPATCH += gen_smtp eiconv -PACKAGES += gen_smtp -pkg_gen_smtp_name = gen_smtp -pkg_gen_smtp_fetch = git -pkg_gen_smtp_repo = https://github.com/gotthardp/gen_smtp.git -pkg_gen_smtp_commit = master - -PACKAGES += eiconv -pkg_eiconv_name = eiconv -pkg_eiconv_fetch = git -pkg_eiconv_repo = https://github.com/zotonic/eiconv.git -pkg_eiconv_commit = master +# use the patched gen_smtp from my fork +dep_gen_smtp = git https://github.com/gotthardp/gen_smtp.git master +dep_eiconv = git https://github.com/zotonic/eiconv.git master # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be # reviewed and merged. @@ -44,5 +36,7 @@ test/data/samples.zip: WITH_BROKER_TEST_COMMANDS := \ eunit:test(rabbit_email_tests,[verbose,{report,{eunit_surefire,[{dir,\"test\"}]}}]) +#WITH_BROKER_TEST_MAKEVARS := \ +# RABBITMQ_CONFIG_FILE=$(CURDIR)/test/rabbit-test # end of file diff --git a/build.config b/build.config index c3e50c0..1856861 100644 --- a/build.config +++ b/build.config @@ -10,6 +10,7 @@ core/index core/deps # Plugins that must run before Erlang code gets compiled. +plugins/erlydtl plugins/protobuffs # Core modules, continued. @@ -28,7 +29,6 @@ plugins/ct plugins/dialyzer # plugins/edoc plugins/elvis -plugins/erlydtl plugins/escript # plugins/eunit plugins/relx diff --git a/erlang.mk b/erlang.mk index ebce286..47f3b33 100644 --- a/erlang.mk +++ b/erlang.mk @@ -16,7 +16,7 @@ ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) -ERLANG_MK_VERSION = 2.0.0-pre.2-16-ga6d6bfe-dirty +ERLANG_MK_VERSION = 2.0.0-pre.2-16-gb52203c-dirty # Core configuration. @@ -4656,6 +4656,67 @@ $(foreach p,$(DEP_PLUGINS),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/plugins.mk,$p)))) +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +ebin/$(PROJECT).app:: $(DTL_FILES) + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?,-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/))) +endif + # Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5965,67 +6026,6 @@ elvis: $(ELVIS) $(ELVIS_CONFIG) distclean-elvis: $(gen_verbose) rm -rf $(ELVIS) -# Copyright (c) 2013-2015, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# Configuration. - -DTL_FULL_PATH ?= -DTL_PATH ?= templates/ -DTL_SUFFIX ?= _dtl - -# Verbosity. - -dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); -dtl_verbose = $(dtl_verbose_$(V)) - -# Core targets. - -define erlydtl_compile.erl - [begin - Module0 = case "$(strip $(DTL_FULL_PATH))" of - "" -> - filename:basename(F, ".dtl"); - _ -> - "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), - re:replace(F2, "/", "_", [{return, list}, global]) - end, - Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), - case erlydtl:compile(F, Module, [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of - ok -> ok; - {ok, _} -> ok - end - end || F <- string:tokens("$(1)", " ")], - halt(). -endef - -ifneq ($(wildcard src/),) - -DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) - -ifdef DTL_FULL_PATH -BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) -else -BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) -endif - -ifneq ($(words $(DTL_FILES)),0) -# Rebuild everything when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) - @mkdir -p $(ERLANG_MK_TMP) - @if test -f $@; then \ - touch $(DTL_FILES); \ - fi - @touch $@ - -ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl -endif - -ebin/$(PROJECT).app:: $(DTL_FILES) - $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?,-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/))) -endif - # Copyright (c) 2014 Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6468,7 +6468,7 @@ $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(verbose) :> $@ else LIST_DIRS = $(ALL_DEPS_DIRS) -LIST_DEPS = $(DEPS) +LIST_DEPS = $(BUILD_DEPS) $(DEPS) $(ERLANG_MK_RECURSIVE_DEPS_LIST): fetch-deps diff --git a/rabbitmq-components.mk b/rabbitmq-components.mk index 8c5d09e..eed26fd 100644 --- a/rabbitmq-components.mk +++ b/rabbitmq-components.mk @@ -26,54 +26,58 @@ endif # topic branch or fallback to `stable` or `master` whichever was the # base of the topic branch. -dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) -dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) -dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) -dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live -dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) -dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) - -dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) - -# FIXME: As of 2015-11-20, we depend on Ranch 1.2.0, but erlang.mk +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk # defaults to Ranch 1.1.0. All projects depending indirectly on Ranch # needs to add "ranch" as a BUILD_DEPS. The list of projects needing # this workaround are: # o rabbitmq-web-stomp -dep_ranch = git https://github.com/ninenines/ranch 1.2.0 +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 RABBITMQ_COMPONENTS = amqp_client \ rabbit \ @@ -83,6 +87,7 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_auth_backend_http \ rabbitmq_auth_backend_ldap \ rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ rabbitmq_clusterer \ rabbitmq_codegen \ rabbitmq_consistent_hash_exchange \ @@ -96,10 +101,13 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_management \ rabbitmq_management_agent \ rabbitmq_management_exchange \ + rabbitmq_management_themes \ rabbitmq_management_visualiser \ rabbitmq_message_timestamp \ rabbitmq_metronome \ rabbitmq_mqtt \ + rabbitmq_recent_history_exchange \ + rabbitmq_rtopic_exchange \ rabbitmq_sharding \ rabbitmq_shovel \ rabbitmq_shovel_management \ @@ -120,9 +128,9 @@ NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) ifeq ($(origin current_rmq_ref),undefined) ifneq ($(wildcard .git),) -current_rmq_ref := $(shell \ - git describe --tags --exact-match 2>/dev/null || \ - git symbolic-ref -q --short HEAD) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) else current_rmq_ref := master endif @@ -167,7 +175,7 @@ RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_ # default to the upstream Git repository. ifneq ($(wildcard .git),) git_origin_fetch_url := $(shell git config remote.origin.url) -git_origin_push_url := $(shell git config remote.origin.pushurl) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) else @@ -198,8 +206,10 @@ define dep_fetch_git_rmq fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ fi; \ cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ @@ -208,7 +218,8 @@ define dep_fetch_git_rmq ) \ (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ 1>&2 && false) ) && \ - git remote set-url --push origin "$$$$push_url" + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") endef # --------------------------------------------------------------------