Jan 04 2010

Calculation Context Part I: Overview

Categories: Calculation Context,Report Techniques Dave Rathbun @ 6:28 pm

One of the hardest concepts to explain when introducing new folks to Business Objects is context.

I now imagine blog readers who have been working with the tools for a while have started nodding their heads in agreement, only to stop and say, “Hey, wait a second, is Dave talking about universe contexts or report calculation contexts?”

And the answer is, of course, yes. πŸ˜†

Both concepts can be quite complicated and take a while to fully understand. Since I have already written a number of blog posts about universe contexts I thought it was time to turn my attention to the report technique of calculation contexts. Note that this concept is used in Desktop Intelligence and Web Intelligence but not in Crystal. This post is intended to be an overview only. I have plans for a detailed post on each of the various context operators where I will go into much more depth. For this post my goal is to introduce the concept and provide some basic definitions.

Introducing Calculation Context

The default calculation context is defined by the dimensions that participate in a report block. It is this feature that makes the dynamic nature of measures possible. When dimensions are removed from or added to a block the context changes and the measure amounts also change. This is controlled by the projection function set on each measure by the universe designer.

However, a report writer sometimes wants a measure to be fixed at a particular value. Percentages are a really simple example. To calculate a contribution percentage I need to divide each individual value by the overall grand total. In order to do that, I need to know how to generate the grand total anywhere I want it. In order to do that, I need to understand how to use the various calculation context operators.

Context Operators

There is a simple (but powerful) set of context operators that I can choose from. I intend to briefly define each one in this blog post and then dive into more detail in future posts. As I mentioned when I started, the default context for a measure is based on the dimension values present in the block structure. I can alter which of those dimensions impact the calculation using one of the following three context operators.

  • In is used to specify exactly which dimensions to include in a context. Other dimensions in the block are ignored. Adding / removing elements from the block does not impact this calculation unless a removed dimension was specified in the context. In that case a #MULTIVALUE error is displayed.
  • ForEach is used to include a dimension in a context. The calculation context is still affected by other values in the block.
  • ForAll is used to exclude a dimension from a context. Other dimensions of the block will still be considered. Adding or removing values from a block might change the value, but it will always ignore the ForAll items.

The operators listed above all require one or more dimensions as part of their syntax. However, calculation context can be specified by more than a set of dimension values. There are a series of report structure keywords that can be used as well.

  • In Report sets the context at the report or “grand total” level. Any formula with these keywords for the context will return an overall total. Note that the total may still be affected by report filters.
  • In Block sets the context for each block section. For years I have been waiting for this setting to be renamed to reflect how it really works, but it hasn’t. I suppose it’s for backwards compatibility. If there is only one block on a report then “In Block” and “In Report” are going to be the same. But when a block is broken up into sections, then this context will generate a total for each section value. For that reason I submit that a better name might have been “In Section” instead, but as long as I know what it does the specific word does not really matter.
  • In Body is the standard default context for each row of data.

With Desktop Intelligence we have the option of In CurrentPage which can be quite useful and unfortunately not yet available in Web Intelligence. I probably don’t have to explain how the “CurrentPage” total is derived. πŸ™‚

Finally, these keywords can appear in several places in a formula. The most common are the “input” and “output” context settings, but certain functions (like RunningSum() for example) also have a “reset” context.

  • Input context is used to determine the input values for the formula.
  • Output context is used to determine the output scope of the formula.
  • Reset context is used to determine when a running function starts over at zero.

Dimensions referenced in the input context do not have to appear in the block. Output and reset dimensions must appear in the block in order to function correctly. For many calculations the default input context works just fine. I will show an example where it’s crucial to understand input context later on. For now I would like to move on to a simple example.

Simple Calculation Context Example

It’s hard to fully grasp some of the subtleties of calculation context without good examples. For this post I will provide one simple but common example that I mentioned earlier: contribution percent. I will start with a simple block with one dimension (resort), one measure (revenue), and a grand total as shown here.

simple report block

This block already has a total on it. If this were a typical spreadsheet I could reference the total value using a row/column address, but that doesn’t work in Web Intelligence. That means I have to use another technique to generate the grand total. I mentioned the solution earlier… all I have to do is create a simple formula that looks like this:

calculation context formula

Here’s the formula again:

=[Revenue] / [Revenue] In Report

Remember that the In Report context projects the measure up to the overall report total. By using that calculation context operator in the denominator of my division I ensure that I will always be dividing by the grand total in this formula. The results?

Finished report block

What’s Next?

This post barely scratched the surface of the calculation context question. It provided a few brief definitions and one simple example. I have several other posts planned that will dive into much greater detail about this often confusing subject. First I plan to talk more about In versus ForEach versus ForAll and how they are different. Next I plan to cover input versus output context and when each should be used. As I write this post neither of those two are much more than an outline for now, so I don’t have an estimated publish date.

But they’ll get published. Eventually. 😎

144 Responses to “Calculation Context Part I: Overview”

  1. Comment by av

    Hi dave,

    say if I have a measure object in my report and I create a variable out of it(with no context defined) Example categorizing the revenue measure(1-100 million,100-200 million) .

    what will be the default context on that measure? would it consider all the dimensions within the report while creating the variable?

    Thanks,
    AV

  2. Comment by Dave Rathbun

    The default context is based on the dimensions that are included in the block (or section) containing the new variable. For example, if the measure is in a stand-alone cell the output context would be “In Report.” If the measure is within a block, then the dimensions in the block determine the output context. If you include the specific context “In Report” within the formula, and place that measure inside of a block, then the specified context will override the dimension structure and you’ll get the overall report total instead.

  3. Comment by av

    Thanks, Dave, for the quick response. But the problem for me is, I have to create a section on the new variable.

    Just to let u know, when I used only rev in the formula ‘rev =1mill’ then ‘1-100mill’..same Id is appearing in different categories(investigating this i found that the id has two rows in the table(database) because of a column(which is not available in my report) which has different values).

    So for the formula I used something like this ‘rev in (id)=1mill’ then ‘1-100mill’…thus defining the context for the measure limiting it to only the id.

    I was able to set up the section on this variable but ran into issues when trying to create an input control on this variable.

    I understand this blog is not intended for personnel issues…please ignore this if am wasting your time.

    Really appreciate your contribution to Business Intelligence world..especially for starters like me.

    BIG FAN,
    AV

  4. Comment by Dave Rathbun

    You generally cannot use a measure (or a variable derived from a measure) as a section. The reason for that is the measure scope (or context) is defined by the section, not the other way around. When I have had to create a break down by range (10-19, 20-29, 30-39 and so on for ages, for example) then I have created that as a dimension object in my universe instead of trying to do it on the report.

  5. Comment by Tracy

    I am new to BOB webi reporting and have started at a new company where the universe is set up differently than I have worked with before, we are trying to create a simple TY vs. LY rolling 12 month report (month to date plus last 11 months compared with same time LY) I am able to get the rolling using (year*100)+ month Nbr for each block. (block1 has LY data and block2 has TY data) the issue I am having is creating a variable that can calculate data from each block. The report is displaying Month, week of month, Returns, Sales and RA% Sales for each 12 month block.

    Last Year (Block1) This Year (Block2)
    Month Week RRA LY Sales LY Month Week RRA TY Sales TY
    Aug 1 $50 $6,000 Aug 1 $20 $7,000

    What I am wanting to do is add a 3rd block or incorporate the totals into the 2nd block that calculates RRA TY – RRA LY (created variable RRA TY-LY Change) and another calculation that shows the % difference (=[RRA TY-LY Change]/[RRA LY])
    When I try and add these to the report I get a single value duplicated in each row or a multivalue error.
    Any suggestions?

  6. Comment by Marcus

    Hi Dave,

    Hope you can help a complete newbie. I’m working in Webi Intelligence (BOXI XI R2) with no access universe design.

    I have created a report measure variable in web intelligence which returns 1 if a record is current and 0 if not. I have a table on the report with a section break on case manager. If I do a sum on this measure in the table footer it returns the correct value for that section.

    However, I’ve been trying to do a summary table in a seperate block and when I try exactly the same formula in that, i get the #multivalue error. Any ideas?

  7. Comment by Dave Rathbun

    Marcus, the problem is probably related to the fact that your 0/1 indicator is only valid at the row level. Once you try to project it to a higher level you get a #MULTIVALUE error because there are multiple values (two different states, in this case) to pick from. What you might try instead is to use your current indicator as part of a “Where” clause on a sum, as the values used there do not have to appear in the block. Something like:

    sum([Measure]) where ([Current Flag] = 1)

  8. Comment by Dave Rathbun

    Do you have separate objects in the universe for this year (TY) and last year (LY) or are you breaking them apart on the report?

  9. Comment by Karthik

    Hi Dave,

    I have a problem in calculating the time taken for a particular status alone involved in a service request , #multivalue error.One service request will have multiple no of status such as ( pending, work in progress , closed etc).Now i want to calculate the time taken for the status ” pending” which should in the business days calculation.

    Request Status Start Time Stop Time Total Time Taken
    101 draft 1-Jul-13 5-Jul-13 4
    101 review 6-Jul-13 7-Jul-13 1
    101 WIP 7-Jul-13 8-Jul-13 1
    101 Pending 8-Jul-13 9-Jul-13 1
    101 Pending 10-Jul-13 11-Jul-13 1

    Expected output
    Request No Total Time Taken(Pending)
    101 2

  10. Comment by Riaz

    Hi,
    Can you provide me Calculation Context Part II

  11. Comment by Dawei

    Hi Dave thanks for the extrordinary articles always…. 4 years had past we are eagerly waiting for the later chapters!

  12. Comment by Dave Rathbun

    Me too! When am I going to get around to writing them, does anybody know? πŸ˜‰

    In all seriousness, I have dusted off my draft for part two of this article and hopefully will have it ready to post without too much delay.

  13. Comment by Tietje

    Hi Dave,

    I love your blogs and am so glad they come up frequently when I am searching for something. I’m a little stumped here… I have a situation where I am pulling in a couple of dimensions (customer and fiscal periods) and the sales $ associated. What I want to do is show the sales $ for each customer for ONLY the latest fiscal period.

    So for example I am showing:

    Cust 1 — 201401 — $1,000
    Cust 1 — 201402 — $2,000
    Cust 1 — 201403 — $1,500
    Cust 2 — 201401 — $1,700
    Cust 2 — 201402 — $2,000
    Cust 2 — 201403 — $2,500

    What I WANT to show is:

    Cust 1 — 201403 — $1,500
    Cust 2 — 201403 — $2,500

    I’ve gotten it pretty close, but I can’t seem to get it just right. Is there any way to get a measure for the max (dimension)? If there is, I can’t seem to find it anywhere or guess at what the syntax might be. So I created a variable to give me the max fiscal period and since they are chosen via prompt, the varialbe is =Max([Main Query].[Fiscal Period]) In Report. I called it MaxUserResponse.

    Then I came up with this formula: =([Sales $] ForEach ([MaxUserResponse]))

    The result I am getting is the total of Sales $ across the fiscal periods, which makes sense, since that is what ForEach does. But I tried =([Sales $] In([MaxUserResponse])) also. I got the total for all customers for all fiscal periods. when I tried =([Sales $] In([Customer];[MaxUserResponse])) I got the total across all fiscal periods per customer.

    What am I missing? I know I am close… Please help? Thank you!

  14. Comment by Tietje

    Hi Dave,

    I think I figured it out. I just added a where clause to my formula. So now it looks like:

    ([Sales $] In ([Main Query].[Customer Name])) Where ([Main Query].[Fiscal Period] = [MaxUserResponse])

    Thanks for reading…
    Tietje

  15. Comment by puneet

    Hey Dave,

    excellent post… Were you able to publish rest of the context operators as per suggested by you… I am sure reading your posts will surely help clarify lods of my doubts.. Moreover do you have a link or website where in i can access other posts of yours to get better insight of BO

  16. Comment by Poorni

    Hi, I need to implement a similar solution.I need to split the data into three category , based on the percent to total value, the top 70% into catagory 1 , next 20% to category 2, last 10% to category 3. Any idea how i can do that ?

    Thanks

  17. Comment by Baby

    Ver Useful Link, It saved my day.Thanks Dave.

  18. Comment by Srikar

    Hi Dave,

    I have a requirement to display an average number of beds in a hospital, but each hospital has a validity start and end date. I need to display the number of beds per hospital at a summary level, which is an average number for each hospital irrespective of how many entries there are for validity dates per hospital.

    Detail level data:

    Hospital- Validity start – Validity End – No of Beds
    ————————————————————————–
    ABC – 01/01/2000 – 31/01/2000 – 10
    ABC – 01/02/2000 – 28/02/2000 – 20
    DEF – 01/01/2000 – 31/01/2000 – 20
    GHI – 01/01/2000 – 31/01/2000 – 30
    GHI – 01/02/2000 – 28/02/2000 – 30

    I need the above data summarised as follows:

    Hospital – Avg. No of Beds per hospital
    —————————————————
    ABC – 15
    DEF – 20
    GHI – 30

    I have tried to average the measure ForAll “Validity Start”, in an effort to exclude the date dimension from the calculation. I have also tried to average the measure “In Hospital” in an effort to only include Hospital in the calculation context. In both cases, I get the following output, where it adds up the measure for every entry of date, per hospital:

    Hospital – Avg. No of Beds per hospital
    —————————————————
    ABC – 30
    DEF – 20
    GHI – 60

    Can you please help?

    Thanks

  19. Comment by Vineet

    Hi Dave,

    I have a weird situation. I have Account nos and balance coming from one query. The BO report seems to neglecting the negative balance. So when I sum up the balance only positive values are considered.
    That is to say Sum([Balance]) gives the same result as Sum([Balance]) Where ([Balance]>0) and Sum([Balance]) Where ([Balance]<0) returns null.
    But there is negative balance. If I pull account no and balance into a separate report and apply a report filter for [Balance]<0 then I can see the negative balances against the accounts. But if I remove the accounts then it displays blank cell for balance.
    Any idea what is going on???

  20. Comment by Brenda

    Hi Dave,

    I used the example from this link http://bi.srivatsakr.com/2011/08/converting-rows-into-single-cell-comma.html to get multiple text values corresponding to an id into one cell, but as I need to do this for two type of multiple values, and my main query has already too much information, I did everything exactly as in the example in my main query and worked beautifully, but for the second one I am attempting to create it in a second query (as if I include this one also in the main query it takes forever), I tested in a second report and it worked fine, but then I tried to include it in the main report and I get #multivalue, I merged the main ids, I made the variables as detail variables, I created an indicator variable (Boolean) for the comparison to the maximum value and it still doesn’t work.

    In the second query and report I have something like this

    ID – type of contact
    123 – regular mail
    123 – email
    123 – phone
    234 – email

    when I do the link example in a second report I’m able to get it to look like this:

    ID – Type of contact
    123 – mail, email, phone
    234 – email

    but when I try to move it to the main report it looks like this:

    ID – Type of contact
    123 – #multivalue
    234 – email

    my variables look like this:
    This one I also tried it as a Boolean and it still didn’t work.
    Max Type Contact=Max([Type of Contact]) In ([Query2].[ID])

    A detail variable link to the main id of Query1
    ID Type of Contact = =[Type of Contact]

    A detail variable link to the main id of Query1
    Concat Type Contact = If IsNull(Previous(Self;([ID])))Then [ID Type of Contact] Else ([ID Type of Contact]+”, “+Previous(Self;([ID])))

    A measure variable:
    All Type of Contact = = [Concat Type Contact] Where ([ID Type of Contact] = [Max Type Contact])

    What am I missing? how can I properly link it to the main report and get it to work?

    Thanks a lot in advance,

    Brenda

  21. Comment by Adhish

    Hi Dave,
    when are you going to write about context in much more details.
    awaiting your post.please make it fast.

  22. Comment by RoyG

    Was wondering if you could help me calculate the percentages (G) of inlist values (V/X)% and (Y/X)% within the same dimension(V,X,Y) on a crosstabs.

    V X Y G F
    A 6 100 25 % %
    B 12 200 50 % %
    B 18 300 75 % %
    C 24 400 100 % %
    D 30 500 125 % %
    E 36 600 150 % %

  23. Comment by Nanda Kishore

    Hi,

    I have a requirement in a Webi Report as below.I have everything except the YTD Planned cost.So now I need to calculate the YTD Planned cost based on the Planned cost,Portfolio,Project Name,Month and Frequency.
    Can some body help me how to achieve this in BO Webi or through SQL query is also fine.

    Portfolio Project Emp Name PlannedCost	Month	Frequency	YTD PlannedCost
    BO	  ABC1	  John	   10000	Aug-15	    Monthly	10000
    BO	  ABC1	  John	   8000	        Sep-15	    Monthly	18000
    BO	  ABC1	  John	   5000	        Oct-15	    Monthly	23000
  24. Comment by Arup Chakraborty

    Hi Dave,
    I became a big fan of you. But I am not able to find the next blogs on input and output contexts as promised by you in this blog.
    Is it that you have not published those yet or I am not finding the proper link?
    Eagerly waiting for your posts.
    Regards,
    Arup

  25. Comment by Store_query

    Hi Dave,

    I am having a lot of trouble getting a simple query to change to what i want it to – I believe i am inputting the formula correctly as i have not have problems before using something like this:.

    query 1 (Product / Store / Stock)
    Query 2 (Store) Distinct list of store’s set by myself in a different universe.

    Merge: query1.store = query2.store
    Source dimension: Query2.store

    Currently query 1 will give me a total stock figure by store / product level.
    I require the store’s from query 2 to be the one i sum up against so i’ve tried:

    =Sum([stock].[Total Branch Stock Unit] ForEach ([Query 2].[STORE]))

    This still gives me the stock figure from query 1 (it should be lower as i have tested this on another tab to see what the output is).

    I’ve tried many variations of the above formula but all seem to get me the sum of product from query 1 when infact i need it to sum against query 2 store.

    Please advise, help would be much appreciated.

    AR

  26. Comment by Helen

    Webi 4.1. I need to retrieve a measure in my Webi “dashboard” based on the max date for that measure. If the answer to this question has been posted elsewhere, please forgive me and point me in the right direction.

    Thank you in advance.

  27. Comment by Gbs

    Hi Dave , little bit different issue. I have a table displaying in report having column year/ accounts no / city .
    Data is like
    2003 /c01 /London
    2004 /c01 / NYcity
    I want to display another column which displays city value where year = max year for all rows
    For example:
    2003 /c01 /London / NYcity
    2004 /c01 / NYcity / NYcity
    Any clue how I can sort this.
    Regards
    Gbs

  28. Comment by Gibs

    Hi Dave
    I have created a cross tab report with 5 years data starting from 2001 to 2005
    There is a object year (type number) in universe.
    In report another variable created MAX_YEAR_NO , which is max(Year).

    In cross tab I have used this report variable in the formula
    =([Revnue] Where ([Year]=[ MAX_YEAR_NO]) ForAll([Year] )

    Formula is summing up Revenue for all 5 years, but in this cross tab I am expecting only data for max year, which is 2005.
    If I modify formula by adding constant value 2005 instead of variable ]=[ MAX_YEAR_NO] it works.
    But I want to use dynamic formula rather than constant hard coded value.

    Any clue ??? thanks in advance

  29. Comment by Chris

    Hi Dave,

    I’m trying to create a line graph that shows the most recent 12 months of Charges and Payments. That’s the simple part. I am also trying to add two “baseline” lines that show the average charges and payments for the initial 12 month window. For example, the average charges over the initial 12 months were $18000 per month. I want to graph the monthly charges on a line, then have another line that goes across current 12 month time period at $18000. Is there a way to do this dynamically instead of hard coding??

  30. Comment by Dave Rathbun

    Max(Year) if you include the Year is going to be the year itself. If you want the maximum year for the report, then your MAX_YEAR_NO should probably be something like Max([Year]) In Report.

  31. Comment by Prabhakar

    Hi Dave,

    Thanks for the blog. The information is very helpful for a young developer like me.

    Has the other parts of this series is being published? I have read all your blogs but i couldn’t find it. I have searched BOB forum as well but no luck.

    Regards,
    Prabhakar

  32. Comment by Dave Rathbun

    As mentioned, this is by far the most requested post that I have not yet written. I have actually started part of it since getting back to this site, but I don’t know if / when it will be completed. Thanks for your interest / comment!

  33. Comment by Prabhakar

    Thanks for the update Dave. Is there any other works done by you is available to read not limited to BO?

  34. Comment by Dave Rathbun

    I have been working more with Tableau recently, so my most recent post talks about similarities between Web Intelligence and Tableau as far as variables and formulas. If you’re looking for other things I write that are not even remotely BI related, well, let me know and I’ll post some links. πŸ™‚

  35. Comment by Robert

    Have long been a fan of your blog– helpful, clear, and well written. Always useful info when I’m Googling some issue or another.

    Recently, a question took me to your site, and another…
    Thought I’d make you aware of your content, used elsewhere (almost entirely word for word) without credit: http://bo-reports.blogspot.com/2016/06/introducing-calculation-context-default.html?_sm_au_=iVVvvvNRJt65HBV6

  36. Comment by Dave Rathbun

    Hi, thanks for the find. I have added that domain to my hotlink script.

  37. Comment by JJ

    Hi Dave,

    Thank you for creating this blog, really useful what you are sharing with us. I have an issue where can’t seem to find the solution/have the wrong approach.

    I need to calculate the revenue contribution of each employee with the following formula: (hours/total hours)*revenue

    This works fine when i have the Customer dimension in the table, i do a break on the Employee and hide the table lines with the customer. I need to replicate the same in a chart and can’t seem to do the same trick by hiding the lines and show only the subtotal on the employee break.

    Column1 Column2 Column3
    Employee Customer Formula —— hide this line
    Employee Total Sum(Formula)

    Formula= ([Hours]/([Hours] ForAll ([Employee])))*[Revenue]

    I would need to replicate the above but without the Customer dimension i.e.

    Column 1 Column 2
    Employee Formula

    I tried with:

    Sum([Hours] ForEach ([Customer])) / Sum([Hours] ForAll ([Employee]) In ([Customer]) * Sum([Revenue] ForEach ([Customer]))

    but won’t take into consideration the customer dimension.

    Any idea how i can get this work?

    Many thanks
    JJ

  38. Comment by Prabhakar

    I have been working more with Tableau recently, so my most recent post talks about similarities between Web Intelligence and Tableau as far as variables and formulas. If you’re looking for other things I write that are not even remotely BI related, well, let me know and I’ll post some links. πŸ™‚ – Yes i am very much interested.

  39. Comment by LivingLarge

    Best explanation of calculation contexts I’ve found online. Many thanks for this

  40. Comment by Darsh

    Hi Dave I am currently trying to Break column based on Manager Name and I want to sum Revenue, for each manager name at the end of break. The problem I am facing is that I am getting total sum of the column at breaks, instead of sum for each manager. I performed similar function on GP column and it worked fine. I am facing problem only on Revenue column.

    Do you know where I am going wrong?

  41. Comment by Dave Rathbun

    I would need to see the structure of your report. Can you provide a few more details?

    If you need quicker response you might try posting on BOB if you have not already. There are lots of formula experts out there. πŸ™‚

  42. Comment by Shams

    Hi Dave,
    In one of my reports I am creating a bucket variable that is based on two more variables and If I bring the bucket variable to the report it is giving a multivalue error. I know multivalue errors are created when there are two or more values returned for that variable. But this is an unmerged dimension. I cannot figure out webi is behaving this way. I have created bucket variables as dimensions in other reports and they worked fine.

    Here is the bucket variable

    var bucket
    = If([var DaysLetterVerified]<6 ) Then "0-5"
    ElseIf( ([var DaysLetterVerified]<11 ) )Then "6-10"
    ElseIf( ([var DaysLetterVerified]<16) ) Then "11-15"
    ElseIf( ([var DaysLetterVerified]<21) ) Then "16-20"
    ElseIf( ([var DaysLetterVerified]<26) ) Then "21-25"
    ElseIf( ([var DaysLetterVerified]<30) ) Then "26-30"
    ElseIf( ([var DaysLetterVerified]35) ) Then “36+”

    [var DaysLetterVerified]
    =DaysBetween([var MinLetterDt];[Verified Dt])

    [var MinLetterDt]
    =Min([Verification Letter Sent Dt]) ForEach ([Verification Bar Code ID])

    If u can sense something very obvious please let me know. ( I am a beginner)

  43. Comment by Dave

    Hi Dave,

    I’m trying to evaluate the result of a measure EXCLUDING itself. Ex. If I have 10 rows in a table. I’d like to create a measure which would calculate the result of a formula considering the other 9 rows (excluding current row), for each of the 10 rows. Is there something like “no in body” context I could use for that?

    Thanks.

  44. Comment by Dave Rathbun

    Not directly, that I am aware of, but this (or something like this) would work:
    sum(x) In Report - sum(x) In Body
    You said if you had 10 lines you wanted to sum nine of them and leave out the current line. That’s what that formula would do.