| summaryrefslogtreecommitdiff | 
diff options
| -rw-r--r-- | src/battlemap/mk/yaws.mk | 3 | ||||
| -rw-r--r-- | src/battlemap/src/handler.erl | 2 | ||||
| -rw-r--r-- | src/battlemap/src/query/character_turn.erl | 12 | ||||
| -rw-r--r-- | src/battlemap/src/shim/database_shim.erl | 66 | ||||
| -rw-r--r-- | src/battlemap/src/struct/character_turn_update.erl | 6 | ||||
| -rw-r--r-- | src/battlemap/src/struct/db_query.erl | 55 | ||||
| -rw-r--r-- | src/db/include/db_query.hrl | 10 | ||||
| -rw-r--r-- | src/db/src/logic/storage_access.erl | 34 | ||||
| -rw-r--r-- | src/db/src/struct/db_item.erl | 8 | ||||
| -rw-r--r-- | src/db/src/struct/db_model.erl | 4 | ||||
| -rw-r--r-- | src/db/src/struct/db_query.erl | 29 | 
11 files changed, 118 insertions, 111 deletions
| diff --git a/src/battlemap/mk/yaws.mk b/src/battlemap/mk/yaws.mk index eb120c1..a68edf2 100644 --- a/src/battlemap/mk/yaws.mk +++ b/src/battlemap/mk/yaws.mk @@ -5,6 +5,7 @@ YAWS_CONF ?= ${CURDIR}/yaws.conf  YAWS_API_HEADER ?= /my/src/yaws/include/yaws_api.hrl  YAWS ?= yaws +YAWS_OPTS ?= -name battlemap_node -erlarg "-connect_all false"  ################################################################################  ## MAKEFILE MAGIC ############################################################## @@ -19,7 +20,7 @@ YAWS_API_HEADER ?= /my/src/yaws/include/yaws_api.hrl  ## TARGET RULES ################################################################  ################################################################################  yaws_run: build $(WWW_DIR) $(LOG_DIR) -	$(YAWS) --conf $(YAWS_CONF) +	$(YAWS) --conf $(YAWS_CONF) $(YAWS_OPTS)  ################################################################################  ## INTERNAL RULES ############################################################## diff --git a/src/battlemap/src/handler.erl b/src/battlemap/src/handler.erl index 0ecc8be..1b79b69 100644 --- a/src/battlemap/src/handler.erl +++ b/src/battlemap/src/handler.erl @@ -18,6 +18,6 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  start (_YawsParams) ->     {ok, Pid} = timed_caches_manager:start(), -   database_shim:generate_db(Pid), +   database_shim:generate_db(),     timed_caches_manager:new_cache(Pid, battle_db, none),     ok. diff --git a/src/battlemap/src/query/character_turn.erl b/src/battlemap/src/query/character_turn.erl index a4b69a2..a10cda7 100644 --- a/src/battlemap/src/query/character_turn.erl +++ b/src/battlemap/src/query/character_turn.erl @@ -177,18 +177,12 @@ update_data (Data, Request) ->  send_to_database (Update, Request) ->     PlayerID = character_turn_request:get_player_id(Request),     BattleID = character_turn_request:get_battle_id(Request), -   Data = character_turn_update:get_data(Update), -   Battle = character_turn_data:get_battle(Data), +   Ops = character_turn_update:get_db(Update), +   Query = db_query:new(battle_db, BattleID, {user, PlayerID}, Ops),     % TODO: send queries to an actual DB... -   database_shim:commit -   ( -      battle_db, -      PlayerID, -      BattleID, -      Battle -   ), +   database_shim:commit(Query),     ok. diff --git a/src/battlemap/src/shim/database_shim.erl b/src/battlemap/src/shim/database_shim.erl index cc653ad..c64105d 100644 --- a/src/battlemap/src/shim/database_shim.erl +++ b/src/battlemap/src/shim/database_shim.erl @@ -10,36 +10,17 @@  -export  (     [ -      generate_db/1, +      generate_db/0,        fetch/2, -      commit/4 +      commit/1     ]  ).  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec create_db (pid()) -> 'ok'. -create_db (_Heir) -> -   ets:new -   ( -      db_shim, -      [ -         set, -         public, -         named_table, -         {keypos, 1}, -         {read_concurrency, true} -      ] -   ), -   io:format("~ndb_shim ets created.~n"), -   ok. - --spec add_to_db (any(), any()) -> 'ok'. -add_to_db (ID, Val) -> -   io:format("~nadd to db_shim: ~p.~n", [{ID, Val}]), -   ets:insert(db_shim, {ID, Val}), -   ok. +get_db_node () -> +   list_to_atom("db_node@" ++ net_adm:localhost()).  -spec generate_random_characters     ( @@ -122,13 +103,8 @@ generate_random_characters  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec generate_db (pid()) -> 'ok'. -generate_db (Heir) -> -   Pid = self(), -   spawn(fun () -> create_db(Heir), Pid ! ok, receive ok -> ok end end), -   receive -      ok -> ok -   end, +-spec generate_db () -> 'ok'. +generate_db () ->     BattlemapWidth = roll:between(16, 64),     BattlemapHeight = roll:between(16, 64),     Battlemap = battlemap:random(0, BattlemapWidth, BattlemapHeight), @@ -136,16 +112,26 @@ generate_db (Heir) ->     PlayersAsList = [player:new(<<"0">>), player:new(<<"1">>)],     Battle = battle:new(<<"0">>, PlayersAsList, Battlemap, Characters), -   add_to_db({battle_db, <<"0">>}, Battle). +   {atomic, ok} = +      rpc:call +      ( +         get_db_node(), +         storage_access, +         insert, +         [battle_db, <<"0">>, any, Battle] +      ), + +   ok. --spec fetch (atom(), any()) -> ({'ok', any()} | 'nothing'). +-spec fetch (atom(), any()) -> ({'ok', any()} | 'not_found').  fetch (DB, ObjectID) -> -   io:format("~ndb_shim lookup: ~p.~n", [{DB, ObjectID}]), -   case ets:lookup(db_shim, {DB, ObjectID}) of -      [{_Key, Value}] -> {ok, Value}; -      [] -> nothing -   end. +   {atomic, Reply} = +      rpc:call(get_db_node(), storage_access, read, [DB, ObjectID]), +   io:format("~ndb_shim:fetch(~p) -> ~p.~n", [{DB, ObjectID}, Reply]), +   Reply. --spec commit (atom(), any(), any(), any()) -> 'ok'. -commit (DB, _Owner, ObjectID, Value) -> -   add_to_db({DB, ObjectID}, Value). +-spec commit (db_query:type()) -> 'ok'. +commit (Query) -> +   {atomic, ok} = rpc:call(get_db_node(), storage_access, query, [Query]), +   io:format("~ndb_shim:commit(~p) -> ok.~n", [Query]), +   ok. diff --git a/src/battlemap/src/struct/character_turn_update.erl b/src/battlemap/src/struct/character_turn_update.erl index a3aa819..07cb562 100644 --- a/src/battlemap/src/struct/character_turn_update.erl +++ b/src/battlemap/src/struct/character_turn_update.erl @@ -9,7 +9,7 @@     {        data :: character_turn_data:type(),        timeline :: list(any()), -      db :: list(db_query:type()) +      db :: list(db_query:op())     }  ). @@ -57,7 +57,7 @@ get_data (Update) -> Update#type.data.  -spec get_timeline (type()) -> list(any()).  get_timeline (Update) -> Update#type.timeline. --spec get_db (type()) -> list(any()). +-spec get_db (type()) -> list(db_query:op()).  get_db (Update) -> Update#type.db.  -spec set_data (character_turn_data:type(), type()) -> type(). @@ -68,6 +68,6 @@ set_data (Data, Update) ->  add_to_timeline (Item, Update) ->     Update#type{ timeline = [turn_result:encode(Item)|Update#type.timeline] }. --spec add_to_db (db_query:type(), type()) -> type(). +-spec add_to_db (db_query:op(), type()) -> type().  add_to_db (Item, Update) ->     Update#type{ db = [Item|Update#type.db] }. diff --git a/src/battlemap/src/struct/db_query.erl b/src/battlemap/src/struct/db_query.erl index bf4b0f3..5d1e8d2 100644 --- a/src/battlemap/src/struct/db_query.erl +++ b/src/battlemap/src/struct/db_query.erl @@ -3,45 +3,20 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% --record -( -   set_field, -   { -      field :: non_neg_integer(), -      value :: any() -   } -). +-include("../../../db/include/db_query.hrl"). --record -( -   add_to_field, -   { -      field :: non_neg_integer(), -      values :: list(any()) -   } -). - --record -( -   update_indexed, -   { -      field :: non_neg_integer(), -      ix :: non_neg_integer(), -      update :: list(type()) -   } -). - --opaque type() :: (#update_indexed{} | #set_field{} | #add_to_field{}). +-opaque op() :: db_query_op(). +-opaque type() :: db_query().  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export_type([type/0]). +-export_type([type/0, op/0]).  -export  (     [ +      new/4,        set_field/2,        add_to_field/2,        update_indexed/3 @@ -55,11 +30,21 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec set_field (non_neg_integer(), any()) -> type(). +-spec new (atom(), any(), db_user:user(), list(op())) -> type(). +new (DBName, ObjectID, User, Ops) -> +   #db_query +   { +      db = DBName, +      id = ObjectID, +      user = User, +      ops = Ops +   }. + +-spec set_field (non_neg_integer(), any()) -> op().  set_field (Field, Value) ->     #set_field { field = Field, value = Value }. --spec add_to_field (non_neg_integer(), list(any())) -> type(). +-spec add_to_field (non_neg_integer(), list(any())) -> op().  add_to_field (Field, Values) ->     #add_to_field { field = Field, values = Values }. @@ -67,8 +52,8 @@ add_to_field (Field, Values) ->     (        non_neg_integer(),        non_neg_integer(), -      list(type()) +      list(op())     ) -   -> type(). +   -> op().  update_indexed (Field, IX, Updates) -> -   #update_indexed { field = Field, ix = IX, update = Updates}. +   #update_indexed { field = Field, ix = IX, ops = Updates}. diff --git a/src/db/include/db_query.hrl b/src/db/include/db_query.hrl index ac7745a..7e5a5b0 100644 --- a/src/db/include/db_query.hrl +++ b/src/db/include/db_query.hrl @@ -40,6 +40,14 @@  -record  ( +   set_val, +   { +      val :: any() +   } +). + +-record +(     db_query,     {        db :: atom(), @@ -50,6 +58,6 @@  ).  -type db_query_op() :: (#set_field{} | #add_to_field{} | #update_indexed{}). --type db_query_master_op() :: (db_query_op() | #set_perm{}). +-type db_query_master_op() :: (db_query_op() | #set_perm{} | #set_val{}).  -type db_query() :: #db_query{}. diff --git a/src/db/src/logic/storage_access.erl b/src/db/src/logic/storage_access.erl index c58f26d..437294f 100644 --- a/src/db/src/logic/storage_access.erl +++ b/src/db/src/logic/storage_access.erl @@ -3,7 +3,6 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --record(regval, {id, owner, val}).  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -13,34 +12,43 @@     [        read/2,        insert/4, -      update/3 +      query/1     ]  ).  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  get_value ([]) -> not_found; -get_value ([Regval]) -> {ok, Regval}. +get_value ([Regval]) -> {ok, db_item:get_value(Regval)}. -get_value(DB, ID) -> get_value(mnesia:read(DB, ID)). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -read (DB, ID) -> +read_transaction (DB, ID) ->     get_value(mnesia:read(DB, ID)). -insert (DB, ID, Owner, Value) -> -   StoredItem = #regval{ id = ID, owner = Owner, val = Value }, +insert_transaction (DB, ID, Perm, Value) -> +   StoredItem = db_item:new(ID, Perm, Value),     % FIXME: handle return value, mnesia:write -> (transaction abort | ok).     % FIXME: is this an atomic OP? Is the lock freed afterwards?     mnesia:write(DB, StoredItem, sticky_write),     ok. -update (DB, ID, Query) -> -   {ok, Item} = get_value(DB, ID), +query_transaction (Query) -> +   DB = db_query:get_database(Query), +   ID = db_query:get_entry_id(Query), +   [Item] = mnesia:read(DB, ID),     {ok, UpdatedItem} = db_query:apply_to(Query, Item),     % FIXME: handle return value, mnesia:write -> (transaction abort | ok).     % FIXME: is this an atomic OP? Is the lock freed afterwards?     mnesia:write(DB, UpdatedItem, sticky_write),     ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +read (DB, ID) -> +   mnesia:transaction(fun read_transaction/2, [DB, ID]). + +insert (DB, ID, Perm, Value) -> +   mnesia:transaction(fun insert_transaction/4, [DB, ID, Perm, Value]). + +query (Query) -> +   mnesia:transaction(fun query_transaction/1, [Query]). diff --git a/src/db/src/struct/db_item.erl b/src/db/src/struct/db_item.erl index 6ec79d0..0ce7630 100644 --- a/src/db/src/struct/db_item.erl +++ b/src/db/src/struct/db_item.erl @@ -24,7 +24,9 @@        set_permission/2,        set_value/2, -      get_id_field/0 +      get_id_field/0, +      get_record_info/0, +      get_record_name/0     ]  ). @@ -62,3 +64,7 @@ set_value (Value, Item) -> Item#db_item{ val = Value }.  -spec get_id_field () -> non_neg_integer().  get_id_field () -> #db_item.id. +get_record_info () -> record_info(fields, db_item). + +get_record_name () -> db_item. + diff --git a/src/db/src/struct/db_model.erl b/src/db/src/struct/db_model.erl index 0f8c872..1b21629 100644 --- a/src/db/src/struct/db_model.erl +++ b/src/db/src/struct/db_model.erl @@ -3,7 +3,6 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --include("../../include/db_item.hrl").  -record  ( @@ -61,7 +60,8 @@ start (Model) ->     (        DBName,        [ -         {attributes, record_info(fields, db_item)}, +         {record_name, db_item:get_record_name()}, +         {attributes, db_item:get_record_info()},           {disc_copies, [node()|Neighbors]},           {disc_only_copies, []},           {ram_copies, []}, diff --git a/src/db/src/struct/db_query.erl b/src/db/src/struct/db_query.erl index 18d0a12..f8ad310 100644 --- a/src/db/src/struct/db_query.erl +++ b/src/db/src/struct/db_query.erl @@ -8,6 +8,13 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      get_database/1, +      get_entry_id/1 +   ] +).  -export([apply_to/2]).  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -25,7 +32,8 @@ apply_update_indexed (Op, Elem) ->     IndexedFieldValue = element(FieldNumber, Elem),     ArrayValue = array:get(IX, IndexedFieldValue),     UpdatedArrayValue = lists:foldl(fun apply_op_to/2, ArrayValue, Ops), -   UpdatedIndexedFieldValue = array:set(IX, UpdatedArrayValue), +   UpdatedIndexedFieldValue = +      array:set(IX, UpdatedArrayValue, IndexedFieldValue),     setelement(FieldNumber, Elem, UpdatedIndexedFieldValue). @@ -52,11 +60,11 @@ apply_set_field (Op, Elem) ->     setelement(FieldNumber, Elem, NewValue).  -spec apply_op_to (db_query_op(), any()) -> any(). -apply_op_to (Op, Elem) when is_record(Elem, set_field) -> +apply_op_to (Op, Elem) when is_record(Op, set_field) ->     apply_set_field(Op, Elem); -apply_op_to (Op, Elem) when is_record(Elem, add_to_field) -> +apply_op_to (Op, Elem) when is_record(Op, add_to_field) ->     apply_add_to_field(Op, Elem); -apply_op_to (Op, Elem) when is_record(Elem, update_indexed) -> +apply_op_to (Op, Elem) when is_record(Op, update_indexed) ->     apply_update_indexed(Op, Elem).  -spec apply_master_op_to @@ -69,6 +77,10 @@ apply_master_op_to (MOp, Elem) when is_record(MOp, set_perm) ->     NewPerm = MOp#set_perm.perm,     db_item:set_perm(NewPerm, Elem); +apply_master_op_to (MOp, Elem) when is_record(MOp, set_val) -> +   NewVal = MOp#set_val.val, + +   db_item:set_value(NewVal, Elem);  apply_master_op_to (MOp, Elem) ->     OldValue = db_item:get_value(Elem),     NewValue = apply_op_to(MOp, OldValue), @@ -78,6 +90,12 @@ apply_master_op_to (MOp, Elem) ->  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec get_database (db_query()) -> atom(). +get_database (#db_query{ db = Result }) -> Result. + +-spec get_entry_id (db_query()) -> any(). +get_entry_id (#db_query{ id = Result }) -> Result. +  -spec apply_to     (        db_query(), @@ -86,5 +104,6 @@ apply_master_op_to (MOp, Elem) ->     -> ({'ok', db_item:type()} | 'error').  apply_to (DBQuery, DBItem) ->     true = db_user:can_access(db_item:get_permission(DBItem), get_user(DBQuery)), -   {ok, apply_master_op_to(DBQuery, DBItem)}. +   MOps = DBQuery#db_query.ops, +   {ok, lists:foldl(fun apply_master_op_to/2, DBItem, MOps)}. | 


