Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

487 rader
19 KiB

10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
10 år sedan
  1. -module(rebar_compile_SUITE).
  2. -export([suite/0,
  3. init_per_suite/1,
  4. end_per_suite/1,
  5. init_per_testcase/2,
  6. end_per_testcase/2,
  7. all/0,
  8. build_basic_app/1,
  9. build_release_apps/1,
  10. build_checkout_apps/1,
  11. build_checkout_deps/1,
  12. build_all_srcdirs/1,
  13. recompile_when_hrl_changes/1,
  14. recompile_when_opts_change/1,
  15. dont_recompile_when_opts_dont_change/1,
  16. dont_recompile_yrl_or_xrl/1,
  17. deps_in_path/1,
  18. delete_beam_if_source_deleted/1,
  19. checkout_priority/1,
  20. highest_version_of_pkg_dep/1,
  21. parse_transform_test/1,
  22. erl_first_files_test/1]).
  23. -include_lib("common_test/include/ct.hrl").
  24. -include_lib("eunit/include/eunit.hrl").
  25. -include_lib("kernel/include/file.hrl").
  26. suite() ->
  27. [].
  28. init_per_suite(Config) ->
  29. Config.
  30. end_per_suite(_Config) ->
  31. ok.
  32. init_per_testcase(_, Config) ->
  33. rebar_test_utils:init_rebar_state(Config).
  34. end_per_testcase(_, _Config) ->
  35. catch meck:unload().
  36. all() ->
  37. [build_basic_app, build_release_apps,
  38. build_checkout_apps, build_checkout_deps,
  39. build_all_srcdirs, recompile_when_hrl_changes,
  40. recompile_when_opts_change, dont_recompile_when_opts_dont_change,
  41. dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted,
  42. deps_in_path, checkout_priority, highest_version_of_pkg_dep,
  43. parse_transform_test, erl_first_files_test].
  44. build_basic_app(Config) ->
  45. AppDir = ?config(apps, Config),
  46. Name = rebar_test_utils:create_random_name("app1_"),
  47. Vsn = rebar_test_utils:create_random_vsn(),
  48. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  49. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}).
  50. build_release_apps(Config) ->
  51. AppDir = ?config(apps, Config),
  52. Name1 = rebar_test_utils:create_random_name("relapp1_"),
  53. Vsn1 = rebar_test_utils:create_random_vsn(),
  54. rebar_test_utils:create_app(filename:join([AppDir,Name1]), Name1, Vsn1, [kernel, stdlib]),
  55. Name2 = rebar_test_utils:create_random_name("relapp2_"),
  56. Vsn2 = rebar_test_utils:create_random_vsn(),
  57. rebar_test_utils:create_app(filename:join([AppDir,Name2]), Name2, Vsn2, [kernel, stdlib]),
  58. rebar_test_utils:run_and_check(
  59. Config, [], ["compile"],
  60. {ok, [{app, Name1}, {app, Name2}]}
  61. ).
  62. build_checkout_apps(Config) ->
  63. AppDir = ?config(apps, Config),
  64. CheckoutsDir = ?config(checkouts, Config),
  65. Name1 = rebar_test_utils:create_random_name("checkapp1_"),
  66. Vsn1 = rebar_test_utils:create_random_vsn(),
  67. rebar_test_utils:create_app(filename:join([AppDir,Name1]), Name1, Vsn1, [kernel, stdlib]),
  68. Name2 = rebar_test_utils:create_random_name("checkapp2_"),
  69. Vsn2 = rebar_test_utils:create_random_vsn(),
  70. rebar_test_utils:create_app(filename:join([CheckoutsDir,Name2]), Name2, Vsn2, [kernel, stdlib]),
  71. rebar_test_utils:run_and_check(
  72. Config, [], ["compile"],
  73. {ok, [{app, Name1}, {checkout, Name2}]}
  74. ).
  75. build_checkout_deps(Config) ->
  76. AppDir = ?config(apps, Config),
  77. CheckoutsDir = ?config(checkouts, Config),
  78. DepsDir = filename:join([AppDir, "_build", "default", "lib"]),
  79. Name1 = rebar_test_utils:create_random_name("checkapp1_"),
  80. Vsn1 = rebar_test_utils:create_random_vsn(),
  81. rebar_test_utils:create_app(filename:join([AppDir,Name1]), Name1, Vsn1, [kernel, stdlib]),
  82. Name2 = rebar_test_utils:create_random_name("checkapp2_"),
  83. Vsn2 = rebar_test_utils:create_random_vsn(),
  84. rebar_test_utils:create_app(filename:join([CheckoutsDir,Name2]), Name2, Vsn2, [kernel, stdlib]),
  85. rebar_test_utils:create_app(filename:join([DepsDir,Name2]), Name2, Vsn1, [kernel, stdlib]),
  86. Deps = [{list_to_atom(Name2), Vsn2, {git, "", ""}}],
  87. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, Deps}])),
  88. {ok, State} = rebar_test_utils:run_and_check(
  89. Config, RebarConfig, ["compile"],
  90. {ok, [{app, Name1}, {checkout, Name2}]}
  91. ),
  92. code:add_paths(rebar_state:code_paths(State, all_deps)),
  93. ok = application:load(list_to_atom(Name2)),
  94. Loaded = application:loaded_applications(),
  95. {_, _, Vsn2} = lists:keyfind(list_to_atom(Name2), 1, Loaded).
  96. build_all_srcdirs(Config) ->
  97. AppDir = ?config(apps, Config),
  98. RebarConfig = [{erl_opts, [{src_dirs, ["src", "extra"]}]}],
  99. Name = rebar_test_utils:create_random_name("app1_"),
  100. Vsn = rebar_test_utils:create_random_vsn(),
  101. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  102. ExtraSrc = <<"-module(extra_src).\n"
  103. "-export([ok/0]).\n"
  104. "ok() -> ok.\n">>,
  105. ok = filelib:ensure_dir(filename:join([AppDir, "extra", "dummy"])),
  106. ok = file:write_file(filename:join([AppDir, "extra", "extra_src.erl"]), ExtraSrc),
  107. rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
  108. %% check a beam corresponding to the src in the extra src_dir exists in ebin
  109. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  110. true = filelib:is_file(filename:join([EbinDir, "extra_src.beam"])),
  111. %% check the extra src_dir was linked into the _build dir
  112. true = filelib:is_dir(filename:join([AppDir, "_build", "default", "lib", Name, "extra"])).
  113. recompile_when_hrl_changes(Config) ->
  114. AppDir = ?config(apps, Config),
  115. Name = rebar_test_utils:create_random_name("app1_"),
  116. Vsn = rebar_test_utils:create_random_vsn(),
  117. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  118. ExtraSrc = <<"-module(test_header_include).\n"
  119. "-export([main/0]).\n"
  120. "-include(\"test_header_include.hrl\").\n"
  121. "main() -> ?SOME_DEFINE.\n">>,
  122. ExtraHeader = <<"-define(SOME_DEFINE, true).\n">>,
  123. HeaderFile = filename:join([AppDir, "src", "test_header_include.hrl"]),
  124. ok = file:write_file(filename:join([AppDir, "src", "test_header_include.erl"]), ExtraSrc),
  125. ok = file:write_file(HeaderFile, ExtraHeader),
  126. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  127. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  128. {ok, Files} = file:list_dir(EbinDir),
  129. ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  130. || F <- Files, filename:extension(F) == ".beam"],
  131. timer:sleep(1000),
  132. rebar_file_utils:touch(HeaderFile),
  133. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  134. {ok, NewFiles} = file:list_dir(EbinDir),
  135. NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  136. || F <- NewFiles, filename:extension(F) == ".beam"],
  137. ?assert(ModTime =/= NewModTime).
  138. recompile_when_opts_change(Config) ->
  139. AppDir = ?config(apps, Config),
  140. Name = rebar_test_utils:create_random_name("app1_"),
  141. Vsn = rebar_test_utils:create_random_vsn(),
  142. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  143. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  144. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  145. {ok, Files} = file:list_dir(EbinDir),
  146. ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  147. || F <- Files, filename:extension(F) == ".beam"],
  148. timer:sleep(1000),
  149. rebar_test_utils:create_config(AppDir, [{erl_opts, [{d, some_define}]}]),
  150. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  151. {ok, NewFiles} = file:list_dir(EbinDir),
  152. NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  153. || F <- NewFiles, filename:extension(F) == ".beam"],
  154. ?assert(ModTime =/= NewModTime).
  155. dont_recompile_when_opts_dont_change(Config) ->
  156. AppDir = ?config(apps, Config),
  157. Name = rebar_test_utils:create_random_name("app1_"),
  158. Vsn = rebar_test_utils:create_random_vsn(),
  159. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  160. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  161. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  162. {ok, Files} = file:list_dir(EbinDir),
  163. ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  164. || F <- Files, filename:extension(F) == ".beam"],
  165. timer:sleep(1000),
  166. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  167. {ok, NewFiles} = file:list_dir(EbinDir),
  168. NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
  169. || F <- NewFiles, filename:extension(F) == ".beam"],
  170. ?assert(ModTime == NewModTime).
  171. dont_recompile_yrl_or_xrl(Config) ->
  172. AppDir = ?config(apps, Config),
  173. Name = rebar_test_utils:create_random_name("app1_"),
  174. Vsn = rebar_test_utils:create_random_vsn(),
  175. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  176. Xrl = filename:join([AppDir, "src", "not_a_real_xrl_" ++ Name ++ ".xrl"]),
  177. ok = filelib:ensure_dir(Xrl),
  178. XrlBody =
  179. "Definitions."
  180. "\n\n"
  181. "D = [0-9]"
  182. "\n\n"
  183. "Rules."
  184. "\n\n"
  185. "{D}+ :"
  186. " {token,{integer,TokenLine,list_to_integer(TokenChars)}}."
  187. "\n\n"
  188. "{D}+\\.{D}+((E|e)(\\+|\\-)?{D}+)? :"
  189. " {token,{float,TokenLine,list_to_float(TokenChars)}}."
  190. "\n\n"
  191. "Erlang code.",
  192. ok = ec_file:write(Xrl, XrlBody),
  193. XrlBeam = filename:join([AppDir, "ebin", filename:basename(Xrl, ".xrl") ++ ".beam"]),
  194. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  195. ModTime = filelib:last_modified(XrlBeam),
  196. timer:sleep(1000),
  197. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  198. NewModTime = filelib:last_modified(XrlBeam),
  199. ?assert(ModTime == NewModTime).
  200. delete_beam_if_source_deleted(Config) ->
  201. AppDir = ?config(apps, Config),
  202. Name = rebar_test_utils:create_random_name("app1_"),
  203. Vsn = rebar_test_utils:create_random_vsn(),
  204. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  205. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  206. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  207. _SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
  208. ?assert(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))),
  209. file:delete(filename:join([AppDir, "src", "not_a_real_src_" ++ Name ++ ".erl"])),
  210. rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
  211. ?assertNot(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))).
  212. deps_in_path(Config) ->
  213. AppDir = ?config(apps, Config),
  214. StartPaths = code:get_path(),
  215. Name = rebar_test_utils:create_random_name("app1_"),
  216. Vsn = rebar_test_utils:create_random_vsn(),
  217. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  218. DepName = rebar_test_utils:create_random_name("dep1_"),
  219. PkgName = rebar_test_utils:create_random_name("pkg1_"),
  220. mock_git_resource:mock([]),
  221. mock_pkg_resource:mock([
  222. {pkgdeps, [{{iolist_to_binary(PkgName), iolist_to_binary(Vsn)}, []}]}
  223. ]),
  224. RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [
  225. {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}},
  226. {list_to_atom(PkgName), Vsn}
  227. ]}]),
  228. {ok, RConf} = file:consult(RConfFile),
  229. %% Make sure apps we look for are not visible
  230. %% Hope not to find src name
  231. ?assertEqual([], [Path || Path <- code:get_path(),
  232. {match, _} <- [re:run(Path, DepName)]]),
  233. %% Hope not to find pkg name in there
  234. ?assertEqual([], [Path || Path <- code:get_path(),
  235. {match, _} <- [re:run(Path, PkgName)]]),
  236. %% Build things
  237. {ok, State} = rebar_test_utils:run_and_check(
  238. Config, RConf, ["compile"],
  239. {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
  240. ),
  241. code:add_paths(rebar_state:code_paths(State, all_deps)),
  242. %% Find src name in there
  243. ?assertNotEqual([], [Path || Path <- code:get_path(),
  244. {match, _} <- [re:run(Path, DepName)]]),
  245. %% find pkg name in there
  246. ?assertNotEqual([], [Path || Path <- code:get_path(),
  247. {match, _} <- [re:run(Path, PkgName)]]),
  248. code:set_path(StartPaths),
  249. %% Make sure apps we look for are not visible again
  250. %% Hope not to find src name
  251. ?assertEqual([], [Path || Path <- code:get_path(),
  252. {match, _} <- [re:run(Path, DepName)]]),
  253. %% Hope not to find pkg name in there
  254. ?assertEqual([], [Path || Path <- code:get_path(),
  255. {match, _} <- [re:run(Path, PkgName)]]),
  256. %% Rebuild
  257. {ok, State1} = rebar_test_utils:run_and_check(
  258. Config, RConf, ["compile"],
  259. {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
  260. ),
  261. %% Find src name in there
  262. code:add_paths(rebar_state:code_paths(State1, all_deps)),
  263. ?assertNotEqual([], [Path || Path <- code:get_path(),
  264. {match, _} <- [re:run(Path, DepName)]]),
  265. %% find pkg name in there
  266. ?assertNotEqual([], [Path || Path <- code:get_path(),
  267. {match, _} <- [re:run(Path, PkgName)]]).
  268. checkout_priority(Config) ->
  269. AppDir = ?config(apps, Config),
  270. CheckoutsDir = ?config(checkouts, Config),
  271. StartPaths = code:get_path(),
  272. Name = rebar_test_utils:create_random_name("app1_"),
  273. Vsn = rebar_test_utils:create_random_vsn(),
  274. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  275. DepName = rebar_test_utils:create_random_name("dep1_"),
  276. PkgName = rebar_test_utils:create_random_name("pkg1_"),
  277. mock_git_resource:mock([]),
  278. mock_pkg_resource:mock([
  279. {pkgdeps, [{{iolist_to_binary(PkgName), iolist_to_binary(Vsn)}, []}]}
  280. ]),
  281. RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [
  282. {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}},
  283. {list_to_atom(PkgName), Vsn}
  284. ]}]),
  285. {ok, RConf} = file:consult(RConfFile),
  286. %% Build with deps.
  287. rebar_test_utils:run_and_check(
  288. Config, RConf, ["compile"],
  289. {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]}
  290. ),
  291. %% Build two checkout apps similar to dependencies to be fetched,
  292. %% but on a different version
  293. Vsn2 = rebar_test_utils:create_random_vsn(),
  294. rebar_test_utils:create_app(filename:join([CheckoutsDir,DepName]), DepName, Vsn2, [kernel, stdlib]),
  295. rebar_test_utils:create_app(filename:join([CheckoutsDir,PkgName]), PkgName, Vsn2, [kernel, stdlib]),
  296. %% Rebuild and make sure the checkout apps are in path
  297. code:set_path(StartPaths),
  298. {ok, State} = rebar_test_utils:run_and_check(
  299. Config, RConf, ["compile"],
  300. {ok, [{app, Name}, {checkout, DepName}, {checkout, PkgName}]}
  301. ),
  302. code:add_paths(rebar_state:code_paths(State, all_deps)),
  303. [DepPath] = [Path || Path <- code:get_path(),
  304. {match, _} <- [re:run(Path, DepName)]],
  305. [PkgPath] = [Path || Path <- code:get_path(),
  306. {match, _} <- [re:run(Path, PkgName)]],
  307. {ok, [DepApp]} = file:consult(filename:join([DepPath, DepName ++ ".app"])),
  308. {ok, [PkgApp]} = file:consult(filename:join([PkgPath, PkgName ++ ".app"])),
  309. {application, _, DepProps} = DepApp,
  310. {application, _, PkgProps} = PkgApp,
  311. ?assertEqual(Vsn2, proplists:get_value(vsn, DepProps)),
  312. ?assertEqual(Vsn2, proplists:get_value(vsn, PkgProps)).
  313. highest_version_of_pkg_dep(Config) ->
  314. AppDir = ?config(apps, Config),
  315. Name = rebar_test_utils:create_random_name("app1_"),
  316. Vsn = rebar_test_utils:create_random_vsn(),
  317. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  318. PkgName = rebar_test_utils:create_random_name("pkg1_"),
  319. mock_git_resource:mock([]),
  320. mock_pkg_resource:mock([
  321. {pkgdeps, [{{iolist_to_binary(PkgName), <<"0.1.0">>}, []},
  322. {{iolist_to_binary(PkgName), <<"0.0.1">>}, []},
  323. {{iolist_to_binary(PkgName), <<"0.1.3">>}, []},
  324. {{iolist_to_binary(PkgName), <<"0.1.1">>}, []}]}
  325. ]),
  326. RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [list_to_atom(PkgName)]}]),
  327. {ok, RConf} = file:consult(RConfFile),
  328. %% Build with deps.
  329. rebar_test_utils:run_and_check(
  330. Config, RConf, ["compile"],
  331. {ok, [{app, Name}, {dep, PkgName, <<"0.1.3">>}]}
  332. ).
  333. parse_transform_test(Config) ->
  334. AppDir = ?config(apps, Config),
  335. RebarConfig = [{erl_opts, [{parse_transform, pascal}]}],
  336. Name = rebar_test_utils:create_random_name("app1_"),
  337. Vsn = rebar_test_utils:create_random_vsn(),
  338. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  339. ExtraSrc = <<"-module(pascal). "
  340. "-export([parse_transform/2]). "
  341. "parse_transform(Forms, _Options) -> "
  342. "Forms.">>,
  343. ok = file:write_file(filename:join([AppDir, "src", "pascal.erl"]), ExtraSrc),
  344. rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
  345. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  346. true = filelib:is_file(filename:join([EbinDir, "pascal.beam"])).
  347. erl_first_files_test(Config) ->
  348. AppDir = ?config(apps, Config),
  349. RebarConfig = [{erl_opts, [{parse_transform, mark_time}]},
  350. {erl_first_files, ["src/mark_time.erl",
  351. "src/b.erl",
  352. "src/d.erl",
  353. "src/a.erl"]}],
  354. Name = rebar_test_utils:create_random_name("app1_"),
  355. Vsn = rebar_test_utils:create_random_vsn(),
  356. rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
  357. rebar_test_utils:write_src_file(AppDir, "a.erl"),
  358. rebar_test_utils:write_src_file(AppDir, "b.erl"),
  359. rebar_test_utils:write_src_file(AppDir, "d.erl"),
  360. rebar_test_utils:write_src_file(AppDir, "e.erl"),
  361. ExtraSrc = <<"-module(mark_time). "
  362. "-export([parse_transform/2]). "
  363. "parse_transform([Form={attribute,_,module,Mod}|Forms], Options) -> "
  364. " [Form, {attribute,1,number, os:timestamp()} | Forms];"
  365. "parse_transform([Form|Forms], Options) -> "
  366. " [Form | parse_transform(Forms, Options)].">>,
  367. ok = file:write_file(filename:join([AppDir, "src", "mark_time.erl"]), ExtraSrc),
  368. rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
  369. EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
  370. true = filelib:is_file(filename:join([EbinDir, "mark_time.beam"])),
  371. code:load_abs(filename:join([EbinDir, "a"])),
  372. code:load_abs(filename:join([EbinDir, "b"])),
  373. code:load_abs(filename:join([EbinDir, "d"])),
  374. code:load_abs(filename:join([EbinDir, "e"])),
  375. A = proplists:get_value(number, a:module_info(attributes)),
  376. B = proplists:get_value(number, b:module_info(attributes)),
  377. D = proplists:get_value(number, d:module_info(attributes)),
  378. E = proplists:get_value(number, e:module_info(attributes)),
  379. ?assertEqual([B,D,A,E], lists:sort([A,B,D,E])).