anchor.diff:  			throw(rating_failed)
   	end.
   %% @hidden
  -rate4(Protocol, Subscriber, Price, Validity, Flag, [], ReserveAmount, SessionAttributes) ->
  -	rate5(Protocol, Subscriber, Price, Validity, Flag, ReserveAmount, SessionAttributes);
  -rate4(Protocol, #subscriber{buckets = Buckets, enabled = Enabled} = Subscriber,
  -		#price{units = Type, size = Size, amount = Amount} = Price, Validity, Flag,
  -		DebitAmount, ReserveAmount, SessionAttributes) ->
  -	try
  -		{Type, Used} = lists:keyfind(Type, 1, DebitAmount),
  -		case charge(Type, Used, true, Buckets) of
  -			{R1, _C1, NB1} when R1 > 0 ->
  -				purchase(Type, Amount, Size, R1, Validity, true, NB1);
  -			{R1, C1, NB1} ->
  -				{R1, C1, NB1}
  -		end
  -	of
  -		{RemainingCharge, _Charged, NewBuckets}
  -				when Enabled == false; RemainingCharge > 0 ->
  -			rate6(Subscriber#subscriber{buckets = NewBuckets}, Flag,
  -					RemainingCharge, ReserveAmount, SessionAttributes);
  -		{_RemainingCharge, _Charged, NewBuckets} ->
  -			rate5(Protocol, Subscriber#subscriber{buckets = NewBuckets},
  -					Price, Validity, Flag, ReserveAmount, SessionAttributes)
  -	catch
  -		_:_ ->
  -			throw(price_not_found)
  -	end.
  -%% @hidden
  -rate5(radius, Subscriber, _Price, _Validity, final,
  -		_ReserveAmount, SessionAttributes) ->
  -	rate6(Subscriber, final, 0, 0, SessionAttributes);
  -rate5(radius, Subscriber, #price{units = Units, size = Size,
  -		amount = Amount, char_value_use = CharValueUse}, Validity, Flag,
  -		ReserveAmount, SessionAttributes) ->
  -	CharName = case Units of
  -		seconds ->
  -			"radiusReserveTime";
  -		octets ->
  -			"radiusReserveBytes"
  +rate4(_Protocol, #subscriber{enabled = false} = Subscriber, _Price,
  +		_Validity, initial, _DebitAmounts, _ReserveAmounts,
  +		SessionAttributes) ->
  +erlang:display({?MODULE, ?LINE, disabled}),
  +	rate6(Subscriber, initial, 0, 0, 0, 0, SessionAttributes);
  +rate4(radius, Subscriber, Price, Validity,
  +		initial, [], [], SessionAttributes) ->
  +erlang:display({?MODULE, ?LINE, SessionAttributes}),
  +	rate5(Subscriber, Price, Validity, initial,
  +			0, get_reserve(Price), SessionAttributes);
  +rate4(radius, Subscriber, #price{units = Units} = Price, Validity,
  +		interim, [], ReserveAmounts, SessionAttributes) ->
  +	ReserveAmount = case lists:keyfind(Units, 1, ReserveAmounts) of
  +		{_, ReserveUnits} ->
  +			ReserveUnits + get_reserve(Price);
  +		false ->
  +			get_reserve(Price)
   	end,
  -	Reserve = case lists:keyfind(Units, 1, ReserveAmount) of
  -		{_, R} ->
  -			R;
  +	rate5(Subscriber, Price, Validity, interim,
  +			0, ReserveAmount, SessionAttributes);
  +rate4(_Protocol, Subscriber, #price{units = Units} = Price, Validity,
  +		Flag, DebitAmounts, ReserveAmounts, SessionAttributes) ->
  +	DebitAmount = case lists:keyfind(Units, 1, DebitAmounts) of
  +		{_, DebitUnits} ->
  +			DebitUnits;
   		false ->
   			0
   	end,
  -	RadiusReserve = case lists:keyfind(CharName,
  -			#char_value_use.name, CharValueUse) of
  -		#char_value_use{values = [#char_value{value = Value}]} ->
  -			Reserve + Value;
  -		false ->
  -			Reserve
  +	ReserveAmount = case lists:keyfind(Units, 1, ReserveAmounts) of
  +		{_, ReserveUnits} ->
  +			ReserveUnits;
  +		false ->
  +			0
   	end,
  -	case RadiusReserve of
  -		0 ->
  -			rate6(Subscriber, Flag, 0, 0, SessionAttributes);
  -		_ ->
  -			rate5(Subscriber, Units, Amount, Size, RadiusReserve,
  -					Validity, Flag, SessionAttributes)
  +erlang:display({?MODULE, ?LINE, Subscriber, DebitAmount, ReserveAmount, Units}),
  +	rate5(Subscriber, Price, Validity, Flag,
  +			DebitAmount, ReserveAmount, SessionAttributes).
  +%% @hidden
  +rate5(#subscriber{buckets = Buckets1} = Subscriber,
  +		#price{units = Units, size = UnitSize, amount = UnitPrice},
  +		_Validity, initial, 0, ReserveAmount, SessionAttributes) ->
  +	SessionId = get_session_id(SessionAttributes),
  +	case reserve_session(Units, ReserveAmount, SessionId, Buckets1) of
  +		{ReserveAmount, Buckets2} ->
  +			rate6(Subscriber#subscriber{buckets = Buckets2},
  +					initial, 0, 0, ReserveAmount, ReserveAmount,
  +					SessionAttributes);
  +		{UnitsReserved, Buckets2} ->
  +			PriceReserveUnits = (ReserveAmount - UnitsReserved),
  +			{UnitReserve, PriceReserve} = price_units(PriceReserveUnits,
  +					UnitSize, UnitPrice),
  +			case reserve_session(cents, PriceReserve, SessionId, Buckets2) of
  +				{PriceReserve, Buckets3} ->
  +					rate6(Subscriber#subscriber{buckets = Buckets3},
  +							initial, 0, 0, ReserveAmount,
  +							UnitsReserved + UnitReserve, SessionAttributes);
  +				{PriceReserved, Buckets3} ->
  +					rate6(Subscriber#subscriber{buckets = Buckets3},
  +							initial, 0, 0, ReserveAmount,
  +							UnitsReserved + (PriceReserved div UnitPrice),
  +							SessionAttributes)
  +			end
   	end;
  -rate5(diameter, Subscriber, _Price, _Validity, Flag, [], SessionAttributes) ->
  -	rate6(Subscriber, Flag, 0, 0, SessionAttributes);
  -rate5(diameter, Subscriber, #price{units = Type, size = Size, amount = Amount},
  -		Validity, Flag, ReserveAmount, SessionAttributes) ->
  -	{Type, Reserve} = lists:keyfind(Type, 1, ReserveAmount),
  -	rate5(Subscriber, Type, Amount, Size, Reserve, Validity, Flag, SessionAttributes).
  -%% @hidden
  -rate5(#subscriber{buckets = Buckets} = Subscriber,
  -		Type, Price, Size, ReserveAmount, Validity, Flag, SessionAttributes) ->
  -	try
  -		case charge(Type, ReserveAmount, false, Buckets) of
  -			{R1, C1, NB1} when R1 > 0 ->
  -				{R2, C2, NB2} = purchase(Type, Price, Size, R1, Validity, false, NB1),
  -				{R2, C1 + C2, NB2};
  -			{R1, C1, NB1} ->
  -				{R1, C1, NB1}
  -		end
  -	of
  -		{0, ReservedAmount, NewBuckets} ->
  -			rate6(Subscriber#subscriber{buckets = NewBuckets},
  -					Flag, 0, ReservedAmount, SessionAttributes);
  -		{RemainingCharge, ReservedAmount, _NewBuckets} ->
  -			rate6(Subscriber, Flag, RemainingCharge,
  -				ReservedAmount, SessionAttributes)
  -	catch
  -		_:_ ->
  -			throw(rating_failed)
  +rate5(#subscriber{enabled = false, buckets = Buckets1} = Subscriber,
  +		#price{units = Units, size = UnitSize, amount = UnitPrice},
  +		_Validity, interim, DebitAmount, _ReserveAmount, SessionAttributes) ->
  +	SessionId = get_session_id(SessionAttributes),
  +	case update_session(Units, DebitAmount, 0, SessionId, Buckets1) of
  +		{DebitAmount, 0, Buckets2} ->
  +			rate6(Subscriber#subscriber{buckets = Buckets2}, interim,
  +					DebitAmount, DebitAmount, 0, 0, SessionAttributes);
  +		{UnitsCharged, 0, Buckets2} ->
  +			PriceChargeUnits = DebitAmount - UnitsCharged,
  +			{UnitCharge, PriceCharge} = price_units(PriceChargeUnits,
  +					UnitSize, UnitPrice),
  +			case update_session(cents, PriceCharge, 0, SessionId, Buckets2) of
  +				{PriceCharge, 0, Buckets3} ->
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, DebitAmount + UnitCharge,
  +							0, 0, SessionAttributes);
  +				{PriceCharged, 0, Buckets3} ->
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, UnitsCharged + (PriceCharged div UnitPrice),
  +							0, 0, SessionAttributes)
  +; Other -> erlang:display({?MODULE, ?LINE, Other})
  +			end
  +; Other -> erlang:display({?MODULE, ?LINE, Other})
  +	end;
  +rate5(#subscriber{buckets = Buckets1} = Subscriber,
  +		#price{units = Units, size = UnitSize, amount = UnitPrice},
  +		_Validity, interim, DebitAmount, ReserveAmount, SessionAttributes) ->
  +	SessionId = get_session_id(SessionAttributes),
  +erlang:display({?MODULE, ?LINE, DebitAmount, ReserveAmount, Units}),
  +	case update_session(Units, DebitAmount, ReserveAmount,
  +			SessionId, Buckets1) of
  +		{DebitAmount, ReserveAmount, Buckets2} ->
  +erlang:display({?MODULE, ?LINE, DebitAmount, ReserveAmount, Buckets2}),
  +			rate6(Subscriber#subscriber{buckets = Buckets2}, interim,
  +					DebitAmount, DebitAmount, ReserveAmount, ReserveAmount,
  +					SessionAttributes);
  +		{DebitAmount, UnitsReserved, Buckets2} ->
  +erlang:display({?MODULE, ?LINE, DebitAmount, UnitsReserved, Buckets2}),
  +			PriceReserveUnits = ReserveAmount - UnitsReserved,
  +			{UnitReserve, PriceReserve} = price_units(PriceReserveUnits,
  +					UnitSize, UnitPrice),
  +			case update_session(cents, 0, PriceReserve, SessionId, Buckets2) of
  +				{0, PriceReserve, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceReserve, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, DebitAmount, ReserveAmount,
  +							UnitReserve, SessionAttributes);
  +				{0, PriceReserved, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceReserve, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, DebitAmount, ReserveAmount,
  +							UnitsReserved + PriceReserved div UnitPrice,
  +							SessionAttributes)
  +			end;
  +		{UnitsCharged, 0, Buckets2} ->
  +erlang:display({?MODULE, ?LINE, UnitsCharged, Buckets2}),
  +			PriceChargeUnits = DebitAmount - UnitsCharged,
  +			{UnitCharge, PriceCharge} = price_units(PriceChargeUnits,
  +					UnitSize, UnitPrice),
  +			{UnitReserve, PriceReserve} = price_units(ReserveAmount,
  +					UnitSize, UnitPrice),
  +			case update_session(cents,
  +					PriceCharge, PriceReserve, SessionId, Buckets2) of
  +				{PriceCharge, PriceReserve, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceCharge, PriceReserve, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, UnitsCharged + UnitCharge, ReserveAmount,
  +							UnitReserve, SessionAttributes);
  +				{PriceCharge, PriceReserved, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceCharge, PriceReserved, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, UnitsCharged + UnitCharge, ReserveAmount,
  +							PriceReserved div UnitPrice, SessionAttributes);
  +				{PriceCharged, 0, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceCharged, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, interim,
  +							DebitAmount, UnitsCharged + (PriceCharged div UnitPrice),
  +							ReserveAmount, 0, SessionAttributes)
  +; Other -> erlang:display({?MODULE, ?LINE, Other})
  +			end
  +	end;
  +rate5(#subscriber{buckets = Buckets1} = Subscriber,
  +		#price{units = Units, size = UnitSize, amount = UnitPrice},
  +		_Validity, final, DebitAmount, 0, SessionAttributes) ->
  +	SessionId = get_session_id(SessionAttributes),
  +erlang:display({?MODULE, ?LINE, DebitAmount, Buckets1}),
  +	case charge_session(Units, DebitAmount, SessionId, Buckets1) of
  +		{DebitAmount, Buckets2} ->
  +erlang:display({?MODULE, ?LINE, DebitAmount, Buckets2}),
  +			rate6(Subscriber#subscriber{buckets = Buckets2}, final,
  +					DebitAmount, DebitAmount, 0, 0, SessionAttributes);
  +		{UnitsCharged, Buckets2} ->
  +erlang:display({?MODULE, ?LINE, UnitsCharged, Buckets2}),
  +			PriceChargeUnits = DebitAmount - UnitsCharged,
  +			{UnitCharge, PriceCharge} = price_units(PriceChargeUnits,
  +					UnitSize, UnitPrice),
  +			case charge_session(cents, PriceCharge, SessionId, Buckets2) of
  +				{PriceCharge, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceCharge, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, final,
  +							DebitAmount, UnitsCharged + UnitCharge,
  +							0, 0, SessionAttributes);
  +				{PriceCharged, Buckets3} ->
  +erlang:display({?MODULE, ?LINE, PriceCharged, Buckets3}),
  +					rate6(Subscriber#subscriber{buckets = Buckets3}, final,
  +					DebitAmount, UnitsCharged + (PriceCharged div UnitPrice),
  +					0, 0, SessionAttributes)
  +			end
   	end.
   %% @hidden
  -rate6(#subscriber{session_attributes = SessionList} = Subscriber,
  -		_Flag, RemainingCharge, _ReserveAmount, _SessionAttributes)
  -		when RemainingCharge > 0 ->
  -	Entry = Subscriber#subscriber{session_attributes = []},
  -	ok = mnesia:write(Entry),
  +rate6(#subscriber{session_attributes = SessionList} = Subscriber1,
  +		final, Charge, Charged, 0, 0, SessionAttributes)
  +		when Charged >= Charge ->
  +	NewSessionList = remove_session(SessionAttributes, SessionList),
  +	Subscriber2 = Subscriber1#subscriber{session_attributes = NewSessionList},
  +	ok = mnesia:write(Subscriber2),
  +erlang:display({?MODULE, ?LINE, grant, Subscriber2, Charged}),
  +	{grant, Subscriber2, Charged};
  +rate6(#subscriber{session_attributes = SessionList} = Subscriber1,
  +		final, _Charge, _Charged, 0, 0, _SessionAttributes) ->
  +	Subscriber2 = Subscriber1#subscriber{session_attributes = []},
  +	ok = mnesia:write(Subscriber2),
  +erlang:display({?MODULE, ?LINE, out_of_credit, Subscriber2, SessionList}),
   	{out_of_credit, SessionList};
   rate6(#subscriber{enabled = false,
  -		session_attributes = SessionList} = Subscriber,
  -		Flag_, _RemainingCharge, _ReserveAmount, _SessionAttributes) ->
  -	Entry = Subscriber#subscriber{session_attributes = []},
  -	ok = mnesia:write(Entry),
  +		session_attributes = SessionList} = Subscriber1, _Flag,
  +		_Charge, _Charged, _Reserve, _Reserved, _SessionAttributes) ->
  +	Subscriber2 = Subscriber1#subscriber{session_attributes = []},
  +	ok = mnesia:write(Subscriber2),
  +erlang:display({?MODULE, ?LINE, disabled, SessionList}),
   	{disabled, SessionList};
  -rate6(#subscriber{session_attributes = SessionList} = Subscriber,
  -		initial, _RemainingCharge, ReserveAmount, SessionAttributes) ->
  -	NewSessionList = update_session(SessionAttributes, SessionList),
  -	Entry = Subscriber#subscriber{session_attributes = NewSessionList},
  -	ok = mnesia:write(Entry),
  -	{grant, Entry, ReserveAmount};
  -rate6(#subscriber{session_attributes = SessionList} = Subscriber,
  -		final, _RemainingCharge, ReserveAmount, SessionAttributes) ->
  -	NewSessionList = remove_session(SessionList, SessionAttributes),
  -	Entry = Subscriber#subscriber{session_attributes = NewSessionList},
  -	ok = mnesia:write(Entry),
  -	{grant, Entry, ReserveAmount};
  -rate6(Subscriber, interim, _RemainingCharge, ReserveAmount, _SessionAttributes) ->
  +rate6(#subscriber{session_attributes = SessionList} = Subscriber1, _Flag,
  +		Charge, Charged, Reserve, Reserved, _SessionAttributes)
  +		when Charged < Charge; Reserved <  Reserve ->
  +	Subscriber2 = Subscriber1#subscriber{session_attributes = []},
  +	ok = mnesia:write(Subscriber2),
  +erlang:display({?MODULE, ?LINE, out_of_credit, Subscriber2, SessionList}),
  +	{out_of_credit, SessionList};
  +rate6(#subscriber{session_attributes = SessionList} = Subscriber1,
  +		initial, 0, 0, _Reserve, Reserved, SessionAttributes) ->
  +	NewSessionList = add_session(SessionAttributes, SessionList),
  +	Subscriber2 = Subscriber1#subscriber{session_attributes = NewSessionList},
  +	ok = mnesia:write(Subscriber2),
  +erlang:display({?MODULE, ?LINE, grant, Subscriber2, Reserved}),
  +	{grant, Subscriber2, Reserved};
  +rate6(Subscriber, interim, _Charge, _Charged, _Reserve, Reserved, _SessionAttributes) ->
   	ok = mnesia:write(Subscriber),
  -	{grant, Subscriber, ReserveAmount}.
  +erlang:display({?MODULE, ?LINE, grant, Subscriber, Reserved}),
  +	{grant, Subscriber, Reserved}.
   
   %%----------------------------------------------------------------------
   %%  internal functions
   %%----------------------------------------------------------------------
   
  --spec charge(Type, Charge, Final, Buckets) -> Result
  +-spec reserve_session(Type, Amount, SessionId, Buckets) -> Result
   	when
   		Type :: octets | seconds | cents,
  -		Charge :: integer(),
  -		Final :: boolean(),
  +		Amount :: non_neg_integer(),
  +		SessionId :: string() | binary(),
   		Buckets :: [#bucket{}],
  -		Result :: {RemainingCharge, Charged, NewBuckets},
  -		RemainingCharge :: integer(),
  -		Charged :: integer(),
  +		Result :: {Reserved, NewBuckets},
  +		Reserved :: non_neg_integer(),
   		NewBuckets :: [#bucket{}].
  -%% @doc Manage balance bucket reservations and debit amounts.
  -%%
  -%% 	Subscriber credit is kept in a `Buckets' list where
  -%% 	each `#bucket{}' has a `Type', an expiration time and
  -%% 	a remaining balance value. Charges may be made against
  -%% 	the `Buckets' list in any `Type'. The buckets are
  -%% 	processed starting with the oldest and expired buckets
  -%% 	are ignored and removed. Buckets matching `Type' are
  -%% 	are compared with `Charge'. If `Final' is `true' then
  -%% 	 `Charge' amount is debited from the buckets. Empty
  -%% 	buckets are removed.
  -%%
  -%% 	Returns `{RemainingCharge, Charged, NewBuckets}' where
  -%% 	`Charged' is the total amount debited from the buckets,
  -%% 	`RemainingCharge' is the left over amount not charged
  +%% @doc Perform reservation for a session.
  +%%
  +%% 	Creates a reservation within bucket(s) of `Type' and
  +%% 	decrements remaing balance by the same amount(s).
  +%%
  +%% 	Expired buckets are removed when no session
  +%% 	reservations remain.
  +%%
  +%% 	Returns `{Reserved, NewBuckets}' where
  +%% 	`Reserved' is the total amount of reservation(s) made
   %% 	and `NewBuckets' is the updated bucket list.
   %%
   %% @private
  -charge(Type, Charge, Final, Buckets) ->
  +reserve_session(Type, Amount, SessionId, Buckets) ->
   	Now = erlang:system_time(?MILLISECOND),
  -	F = fun(#bucket{termination_date = T1},
  -				#bucket{termination_date = T2}) when T1 =< T2 ->
  -			true;
  -		(_, _)->
  -			false
  -	end,
  -	SortedBuckets = lists:sort(F, Buckets),
  -	charge(Type, Charge, Now, Final, SortedBuckets, [], 0).
  -%% @hidden
  -charge(Type, Charge, Now, Final, [#bucket{units = Type,
  -		termination_date = T1} | T], Acc, Charged) when T1 =/= undefined, T1 =< Now->
  -	charge(Type, Charge, Now, Final, T, Acc, Charged);
  -charge(Type, Charge, _Now, true, [#bucket{units = Type,
  -		remain_amount = R} = B | T], Acc, Charged) when R > Charge ->
  +	reserve_session(Type, Amount, Now, SessionId, sort(Buckets), [], 0).
  +%% @hidden
  +reserve_session(Type, Amount, Now, SessionId,
  +		[#bucket{termination_date = Expires, reservations = []} | T],
  +		Acc, Reserved) when Expires /= undefined, Expires =< Now->
  +	reserve_session(Type, Amount, Now, SessionId, T, Acc, Reserved);
  +reserve_session(Type, Amount, Now, SessionId,
  +		[#bucket{units = Type, remain_amount = Remain,
  +		reservations = Reservations, termination_date = Expires} = B | T],
  +		Acc, Reserved) when Remain >= Amount,
  +		((Expires == undefined) or (Now < Expires)) ->
  +	NewReservation = {Now, Amount, SessionId},
  +	NewBuckets = lists:reverse(Acc)
  +			++ [B#bucket{remain_amount = Remain - Amount,
  +			reservations = [NewReservation | Reservations]} | T],
  +	{Reserved + Amount, NewBuckets};
  +reserve_session(Type, Amount, Now, SessionId,
  +		[#bucket{units = Type, remain_amount = Remain,
  +		reservations = Reservations, termination_date = Expires} = B | T],
  +		Acc, Reserved) when Remain < Amount,
  +		((Expires == undefined) or (Now < Expires)) ->
  +	NewReserve = Amount - Remain,
  +	NewReservation = {Now, NewReserve, SessionId},
  +	NewAcc = [B#bucket{remain_amount = 0,
  +			reservations = [NewReservation | Reservations]} | Acc],
  +	reserve_session(Type, Amount - NewReserve, Now,
  +			SessionId, T, NewAcc, Reserved + NewReserve);
  +reserve_session(Type, Amount, Now, SessionId, [H | T], Acc, Reserved) ->
  +	reserve_session(Type, Amount, Now, SessionId, T, [H | Acc], Reserved);
  +reserve_session(_, _, _, _, [], Acc, Reserved) ->
  +	{Reserved, lists:reverse(Acc)}.
  +
  +-spec update_session(Type, Charge, Reserve, SessionId, Buckets) -> Result
  +	when
  +		Type :: octets | seconds | cents,
  +		Charge :: non_neg_integer(),
  +		Reserve :: non_neg_integer(),
  +		SessionId :: string() | binary(),
  +		Buckets :: [#bucket{}],
  +		Result :: {Charged, Reserved, NewBuckets},
  +		Charged :: non_neg_integer(),
  +		Reserved :: non_neg_integer(),
  +		NewBuckets :: [#bucket{}].
  +%% @doc Perform debit and reservation for a session.
  +%%
  +%% 	Finds reservations matching `SessionId'.
  +%%
  +%% 	Empty or expired buckets are removed when no session
  +%% 	reservations remain.
  +%%
  +%% 	Returns `{Charged, Reserved, NewBuckets}' where
  +%% 	`Charged' is the total amount debited from bucket(s),
  +%% 	`Reserved' is the total amount of reservation(s) made,
  +%% 	and `NewBuckets' is the updated bucket list.
  +%%
  +%% @private
  +update_session(Type, Charge, Reserve, SessionId, Buckets) ->
  +	Now = erlang:system_time(?MILLISECOND),
  +	update_session(Type, Charge, Reserve, Now, SessionId,
  +			sort(Buckets), [], 0, 0).
  +%% @hidden
  +update_session(Type, Charge, Reserve, Now, SessionId,
  +		[#bucket{termination_date = Expires, reservations = []} | T],
  +		Acc, Charged, Reserved) when Expires /= undefined, Expires =< Now ->
  +	update_session(Type, Charge, Reserve,
  +			Now, SessionId, T, Acc, Charged, Reserved);
  +update_session(Type, Charge, Reserve, Now, SessionId,
  +		[#bucket{units = Type, remain_amount = Remain,
  +		termination_date = Expires, reservations = Reservations} = B | T],
  +		Acc, Charged, Reserved) ->
  +	case lists:keytake(SessionId, 3, Reservations) of
  +		{value, {_, Amount, _}, NewReservations}
  +				when Remain >= (Reserve - (Amount - Charge)),
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewReservation = {Now, Reserve, SessionId},
  +			NewBuckets = lists:reverse(Acc)
  +					++ [B#bucket{remain_amount = Remain
  +					- (Reserve - (Amount - Charge)),
  +					reservations = [NewReservation | NewReservations]} | T],
  +			{Charged + Charge, Reserved + Reserve, NewBuckets};
  +		{value, {_, Amount, _}, []}
  +				when (Remain + Amount) =< Charge,
  +				((Expires == undefined) or (Now < Expires)) ->
  +			update_session(Type, Charge - (Remain + Amount), Reserve,
  +					Now, SessionId, T, Acc, Charged + Remain + Amount, Reserved);
  +		{value, {_, Amount, _}, []}
  +				when Amount >= Charge, Expires /= undefined, Expires =< Now ->
  +			update_session(Type, 0, Reserve, Now,
  +					SessionId, T, Acc, Charge, Reserved);
  +		{value, {_, Amount, _}, NewReservations}
  +				when Amount >= Charge, Expires /= undefined, Expires =< Now ->
  +			NewAcc = [B#bucket{reservations = NewReservations} | Acc],
  +			update_session(Type, 0, Reserve, Now,
  +					SessionId, T, NewAcc, Charge, Reserved);
  +		{value, {_, Amount, _}, []}
  +				when Amount < Charge, Expires /= undefined, Expires =< Now ->
  +			update_session(Type, Charge - Amount, Reserve, Now,
  +					SessionId, T, Acc, Charge, Reserved);
  +		{value, {_, Amount, _}, NewReservations}
  +				when Amount < Charge, Expires /= undefined, Expires =< Now ->
  +			NewAcc = [B#bucket{reservations = NewReservations} | Acc],
  +			update_session(Type, Charge - Amount, Reserve, Now,
  +					SessionId, T, NewAcc, Charge, Reserved);
  +		{value, {_, Amount, _}, NewReservations}
  +				when (Remain + Amount) =< Charge,
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewAcc = [B#bucket{remain_amount = 0, reservations = NewReservations} | Acc],
  +			update_session(Type, Charge - (Remain + Amount), Reserve,
  +					Now, SessionId, T, NewAcc, Charged + Remain + Amount, Reserved);
  +		{value, {_, Amount, _}, NewReservations}
  +				when Remain >= (Charge - Amount),
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewReserve = Remain - (Charge - Amount),
  +			NewReservation = {Now, NewReserve, SessionId},
  +			NewAcc = [B#bucket{remain_amount = 0,
  +					reservations = [NewReservation | NewReservations]} | Acc],
  +			update_session(Type, 0, Reserve - NewReserve, Now, SessionId,
  +					T, NewAcc, Charged + Charge, Reserved + NewReserve);
  +		_ when Reservations == [], Expires /= undefined, Expires =< Now ->
  +			update_session(Type, Charge, Reserve, Now, SessionId,
  +					T, Acc, Charged, Reserved);
  +		false ->
  +			update_session(Type, Charge, Reserve, Now, SessionId,
  +					T, [B | Acc], Charged, Reserved)
  +	end;
  +update_session(_, _, _, _, _, [], Acc, Charged, Reserved) ->
  +	{Charged, Reserved, lists:reverse(Acc)}.
  +
  +-spec charge_session(Type, Charge, SessionId, Buckets) -> Result
  +	when
  +		Type :: octets | seconds | cents,
  +		Charge :: non_neg_integer(),
  +		SessionId :: string() | binary(),
  +		Buckets :: [#bucket{}],
  +		Result :: {Charged, NewBuckets},
  +		Charged :: non_neg_integer(),
  +		NewBuckets :: [#bucket{}].
  +%% @doc Peform final charging for a session.
  +%%
  +%% 	Finds and removes all reservations matching `SessionId'.
  +%% 	If the total reservation amounts are less than `Charge'
  +%% 	the deficit is debited. Any surplus is refunded within
  +%% 	the bucket containing the reservation.
  +%%
  +%% 	Empty buckets are removed. Expired buckets are removed
  +%% 	when no session reservations remain.
  +%%
  +%% 	Returns `{Charged, NewBuckets}' where
  +%% 	`Charged' is the total amount debited from the buckets
  +%% 	and `NewBuckets' is the updated bucket list.
  +%%
  +%% @private
  +charge_session(Type, Charge, SessionId, Buckets) ->
  +	Now = erlang:system_time(?MILLISECOND),
  +	charge_session(Type, Charge, Now, SessionId, sort(Buckets), 0, []).
  +%% @hidden
  +charge_session(Type, Charge, Now, SessionId,
  +		[#bucket{units = Type, termination_date = Expires,
  +		remain_amount = Remain, reservations = Reservations} = B | T],
  +		Charged, Acc) ->
  +erlang:display({?MODULE, ?LINE, Acc}),
  +	case lists:keytake(SessionId, 3, Reservations) of
  +		{value, {_, Amount, _}, NewReservations} when Amount >= Charge,
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewAcc = [B#bucket{remain_amount = Remain + (Amount - Charge),
  +					reservations = NewReservations} | Acc],
  +			charge_session(Type, 0, Now, SessionId, T, Charged + Charge, NewAcc);
  +		{value, {_, Amount, _}, []} when Amount >= Charge,
  +				Expires /= undefined, Expires =< Now ->
  +			charge_session(Type, 0, Now, SessionId, T, Charged + Charge, Acc);
  +		{value, {_, Amount, _}, NewReservations} when Amount >= Charge,
  +				Expires /= undefined, Expires =< Now ->
  +			NewAcc = [B#bucket{reservations = NewReservations} | Acc],
  +			charge_session(Type, 0, Now, SessionId, T, Charged + Charge, NewAcc);
  +		{value, {_, Amount, _}, NewReservations}
  +				when Amount < Charge, Remain > (Charge - Amount),
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewAcc = [B#bucket{remain_amount = Remain - (Charge - Amount),
  +					reservations = NewReservations} | Acc],
  +			charge_session(Type, 0, Now, SessionId, T, Charged + Charge, NewAcc);
  +		{value, {_, Amount, _}, []} when Amount < Charge,
  +				Expires /= undefined, Expires =< Now ->
  +			charge_session(Type, Charge - Amount, Now, SessionId, T, Charged + Charge, Acc);
  +		{value, {_, Amount, _}, NewReservations} when Amount < Charge,
  +				Expires /= undefined, Expires =< Now ->
  +			NewAcc = [B#bucket{reservations = NewReservations} | Acc],
  +			charge_session(Type, Charged + Charge, Now, SessionId, T, Charge - Amount, NewAcc);
  +		{value, {_, Amount, _}, []}
  +				when Amount < Charge, Remain =< (Charge - Amount),
  +				((Expires == undefined) or (Now < Expires)) ->
  +			charge_session(Type, Charge - Amount - Remain, Now, SessionId, T, Amount + Remain, Acc);
  +		{value, {_, Amount, _}, NewReservations}
  +				when Amount < Charge, Remain =< (Charge - Amount),
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewAcc = [B#bucket{reservations = NewReservations} | Acc],
  +			charge_session(Type, Charge - Amount - Remain, Now, SessionId, T, Amount + Remain, NewAcc);
  +		{value, {_, Amount, _}, NewReservations} when Charge =:= 0,
  +				((Expires == undefined) or (Now < Expires)) ->
  +			NewAcc = [B#bucket{remain_amount = Remain + Amount,
  +					reservations = NewReservations} | Acc],
  +			charge_session(Type, 0, Now, SessionId, T, Charged, NewAcc);
  +		_ when Reservations == [], Expires /= undefined, Expires =< Now ->
  +			charge_session(Type, Charge, Now, SessionId, T, Charged, Acc);
  +		false ->
  +			charge_session(Type, Charge, Now, SessionId, T, Charged, [B | Acc])
  +	end;
  +charge_session(Type, Charge, Now, SessionId, [H | T], Charged, Acc) ->
  +	charge_session(Type, Charge, Now, SessionId, T, Charged, [H | Acc]);
  +charge_session(_, Charge, _, _, [], Charge, Acc) ->
  +	{Charge, lists:reverse(Acc)};
  +charge_session(Type, Charge, Now, _, [], Charged, Acc) ->
  +	charge(Type, Charge, Now, lists:reverse(Acc), [], Charged).
  +
  +%% @hidden
  +charge(Type, Charge, Now,
  +		[#bucket{termination_date = Expires, reservations = []} | T],
  +		Acc, Charged) when Expires /= undefined, Expires =< Now ->
  +	charge(Type, Charge, Now, T, Acc, Charged);
  +charge(Type, Charge, Now, [#bucket{units = Type,
  +		remain_amount = R, termination_date = Expires} = B | T],
  +		Acc, Charged) when R > Charge,
  +		((Expires == undefined) or (Now < Expires)) ->
   	NewBuckets = [B#bucket{remain_amount = R - Charge} | T],
  -	{0, Charged + Charge, lists:reverse(Acc) ++ NewBuckets};
  -charge(Type, Charge, _Now, false, [#bucket{units = Type,
  -		remain_amount = R} | _] = L, Acc, Charged) when R > Charge ->
  -	{0, Charged + Charge, lists:reverse(Acc) ++ L};
  -charge(Type, Charge, Now, true, [#bucket{units = Type,
  -		remain_amount = R} | T], Acc, Charged) when R =< Charge ->
  -	charge(Type, Charge - R, Now, true, T, Acc, Charged + R);
  -charge(Type, Charge, Now, false, [#bucket{units = Type,
  -		remain_amount = R} = B | T], Acc, Charged) when R =< Charge ->
  -	charge(Type, Charge - R, Now, false, T, [B | Acc], Charged);
  -charge(_Type, 0, _Now, _Final, Buckets, Acc, Charged) ->
  -	{0, Charged, lists:reverse(Acc) ++ Buckets};
  -charge(Type, Charge, Now, Final, [H | T], Acc, Charged) ->
  -	charge(Type, Charge, Now, Final, T, [H | Acc], Charged);
  -charge(_Type, Charge, _Now, _Final, [], Acc, Charged) ->
  -	{Charge, Charged, lists:reverse(Acc)}.
  -
  --spec purchase(Type, Price, Size, Used, Validity, Final, Buckets) -> Result
  -	when
  -		Type :: octets | seconds,
  -		Price :: integer(),
  -		Size :: integer(),
  -		Used :: integer(),
  -		Validity :: integer(),
  -		Final :: boolean(),
  -		Buckets :: [#bucket{}],
  -		Result :: {RemainingUnits, UnitsCharged, NewBuckets},
  -		RemainingUnits :: integer(),
  -		UnitsCharged :: integer(),
  -		NewBuckets :: [#bucket{}].
  -%% @doc Manage usage pricing and debit monetary amount buckets.
  -%%
  -%% 	Subscribers are charged at a monetary rate of `Price' cents
  -%% 	per `Unit' of `Used' service.  The total number of units
  -%% 	required and total monetary amount is calculated and 
  -%% 	debited from available cents buckets as in {@link charge/4}.
  -%%
  -%% 	If `Final' is `false' a new `Type' bucket with the total
  -%% 	number of units required and expiration of `Validity' is
  -%% 	added to `Buckets'.
  -%%
  -%% 	Returns `{RemainingUnits, UnitsCharged, NewBuckets}' where
  -%% 	`UnitsCharged' is the total amount of units in the newly
  -%%		created usage bucket, `RemainingUnits' is the left over
  -%%		amount not charged and `NewBuckets' is the updated bucket list.
  -%%
  -%% @private
  -purchase(Type, Price, Size, Used, Validity, Final, Buckets) ->
  -	UnitsNeeded = case (Used rem Size) of
  -		0 ->
  -			Used div Size;
  -		_ ->
  -			(Used div Size) + 1
  -	end,
  -	Charge = UnitsNeeded * Price,
  -	case charge(cents, Charge, true, Buckets) of
  -		{0, Charge, NewBuckets} when Final == true,
  -				(UnitsNeeded * Size - Used) == 0 ->
  -			{0, UnitsNeeded * Size, NewBuckets};
  -		{0, Charge, NewBuckets} when Final == false ->
  -			Bucket = #bucket{units = Type,
  -				remain_amount = UnitsNeeded * Size,
  -				termination_date = Validity,
  -				start_date = erlang:system_time(?MILLISECOND)},
  -			{0, UnitsNeeded * Size, [Bucket | NewBuckets]};
  -		{0, Charge, NewBuckets} when Final == true ->
  -			Bucket = #bucket{units = Type,
  -				remain_amount = UnitsNeeded * Size - Used,
  -				termination_date = Validity,
  -				start_date = erlang:system_time(?MILLISECOND)},
  -			{0, UnitsNeeded * Size, [Bucket | NewBuckets]};
  -		{_RemainingCharge, Charged, NewBuckets} ->
  -			UnitsCharged = Charged div Price,
  -			{UnitsNeeded - UnitsCharged, UnitsCharged, NewBuckets}
  -	end.
  +	{Charged + Charge, lists:reverse(Acc) ++ NewBuckets};
  +charge(Type, Charge, Now, [#bucket{units = Type,
  +		remain_amount = R, reservations = [],
  +		termination_date = Expires} | T], Acc, Charged)
  +		when R =< Charge, ((Expires == undefined) or (Now < Expires)) ->
  +	charge(Type, Charge - R, Now, T, Acc, Charged + R);
  +charge(Type, Charge, Now, [#bucket{units = Type,
  +		remain_amount = R, termination_date = Expires} = B | T], Acc, Charged)
  +		when R =< Charge, ((Expires == undefined) or (Now < Expires)) ->
  +	NewAcc = [B#bucket{remain_amount = 0} | Acc],
  +	charge(Type, Charge - R, Now, T, NewAcc, Charged + R);
  +charge(_Type, 0, _Now, Buckets, Acc, Charged) ->
  +	{Charged, lists:reverse(Acc) ++ Buckets};
  +charge(Type, Charge, Now, [H | T], Acc, Charged) ->
  +	charge(Type, Charge, Now, T, [H | Acc], Charged);
  +charge(_, _, _, [], Acc, Charged) ->
  +	{Charged, lists:reverse(Acc)}.
   
   -spec remove_session(SessionAttributes, SessionList) -> NewSessionList
   	when
   		SessionAttributes :: [tuple()],
  -		SessionList :: [tuple()],
  -		NewSessionList :: [tuple()].
  +		SessionList :: [{pos_integer(), [tuple()]}],
  +		NewSessionList :: [{pos_integer(), [tuple()]}].
   %% @doc Remove session identification attributes set from active sessions list.
   %% @private
   remove_session(SessionAttributes, SessionList) ->
  
positive.code: -export([rate/6, rate/7]).
  
  -include("ocs.hrl").
  
  %% support deprecated_time_unit()
  -define(MILLISECOND, milli_seconds).
  %-define(MILLISECOND, millisecond).
  
  -spec rate(Protocol, SubscriberID, Destination, Flag, DebitAmount, ReserveAmount) -> Result
  	when
  		Protocol :: radius | diameter,
  		SubscriberID :: string() | binary(),
  		Destination :: string(),
  		Flag :: initial | interim | final,
  		DebitAmount :: [{Type, Amount}],
  		ReserveAmount :: [{Type, Amount}],
  		Type :: octets | seconds,
  		Amount :: integer(),
  		Result :: {ok, Subscriber, GrantedAmount} | {out_of_credit, SessionList} | {error, Reason},
  		Subscriber :: #subscriber{},
  		GrantedAmount :: integer(),
  		SessionList :: [tuple()],
  		Reason :: term().
  %% @equiv rate(Protocol, SubscriberID, Destination, Flag, DebitAmount, ReserveAmount, [])
  rate(Protocol, SubscriberID, Destination, Flag, DebitAmount, ReserveAmount) ->
  	rate(Protocol, SubscriberID, Destination, Flag, DebitAmount, ReserveAmount, []).
  
  -spec rate(Protocol, SubscriberID, Destination,
  		Flag, DebitAmount, ReserveAmount, SessionAttributes) -> Result
  	when
  		Protocol :: radius | diameter,
  		SubscriberID :: string() | binary(),
  		Destination :: string(),
  		Flag :: initial | interim | final,
  		DebitAmount :: [{Type, Amount}],
  		ReserveAmount :: [{Type, Amount}],
  		SessionAttributes :: [tuple()],
  		Type :: octets | seconds,
  		Amount :: integer(),
  
negative.code: 						[#product{} = Product] ->
  							Validity = proplists:get_value(validity, Chars),
  							rate1(Protocol, Subscriber, Destination, Product, Validity, Flag,
  									DebitAmounts, ReserveAmounts, SessionAttributes);
  						[] ->
  							throw(product_not_found)
  					end;
  