EatDrink.ash: Optimize your daily diet (and see how your old diet stacks up).

Theraze

Active member
I can make the stash function as an option, just like the closet or storage... but it would just be considered in the same way that the other 'have' locations are. Is this a can of worms to open that will involve in people getting booted from clans, or should we leave the impetus on the user to not screw themselves over by using the rare "do not use" items automatically?

Edit: Two more questions (besides the "will giving people easy fast-automatic-consume stash access destroy priceless items" one with the obvious answer):
1) Should storage use default to false? It's currently on, but if you've put it into storage, the reason presumably would be that you don't want it used...
2) Should ConsumeLast stop trying if you run out of adventures crafting food? I'm tempted to make it craft until it runs out, then consume. It would potentially involve multiple runnings of EatDrink, but provide for a more efficient crafting/consumption for the boxen-poor. The alternative is to just craft/consume the non-fancy stuffs. Alternatively, there could be another preference set for ContinueCrafting or something similar, which defaults to true. This would allow for people to consume the garbage, or run ED multiple times, but makes it their choice...
 
Last edited:

Theraze

Active member
Yeah... in my personal copy, I've temporarily implemented a stash option, but I'm waiting to see if people as a whole think it's a good or bad idea before uploading. If you wanted to consider the stash as 'free', you'd set the stash option, set the inventory is free option, and run the script... it'd use both your personal inventory and the stash and burn through both with wild abandon, ignoring the fact that you could have sold that for 9 million instead of eating it for 15 adventures.
 

th3y

Member
No consumables are effectively 0 cost. You could still pull items from your clan stash, mall them, and buy food that is more cost-efficient.

Yeah, I thought of that somewhat later and agree in theory. On the other hand, right now in practice I never take the effort to pull anything from clan stash. So if a script ended up helping me pull useful things due to ease of automation, I'd be coming out ahead.

[Evil digression - it would be interesting to have a script that identified the optimally-valuable set of pulls from clan stash, given daily karma limits.]

If you wanted to consider the stash as 'free', you'd set the stash option, set the inventory is free option, and run the script... it'd use both your personal inventory and the stash and burn through both with wild abandon, ignoring the fact that you could have sold that for 9 million instead of eating it for 15 adventures.

Just my individual use-case reaction: stash would not be that useful to me if it were treated the same as inventory. I understand in theory that stash sort of functions as an extension of your inventory (subject to daily karma limits). But you only experience value from the stash when you actually pull something out of it.

Anyhow, this was more "food for thought" than an important feature request. Thanks for some interesting points.
 

Theraze

Active member
Oh, I have no objection to enabling using the stash as an extension of your inventory... I just heavily suggest you don't also set that inventory is free.

The way that storage and closet work currently, it adds to your 'have' grouping... your inventory says you have 30 of these total, and you do... 5 in inventory, 20 in storage, and 5 in your closet. It knows that since the storage has limited pulls in Ronin, increase the cost of anything there by (default) 3000, so it doesn't waste your daily pulls on tiny foods. If inventory value is set to 0, then 10 of those objects have a value of 0 and the other 20 have a value of 3000 (due to the pull cost). It doesn't matter if they're spectral pickles and it's been 2 years since they've been available... if they're the best object in your inventory for food, they're going away.

On my local version of EatDrink, I can also set it to add the clan stash to my 'have' grouping. If there's 20 in the clan stash, and I'm out of HC, EatDrink would say I have 50 total... It would (with the way the groupings are currently done) consume my inventory, then closet, then stash (I should probably put that at the end), then pull items from storage. I think I'll put stash at the end, because that's the only non-personal one... but regardless... should it be possible?

Do I upload this patch, or is it something where we expect to see people railing angrily against us for having people who don't think things through destroying priceless history?
 
Last edited:

fronobulax

Developer
Staff member
To veer slightly, my personal preference would be that EatDrink always used the acquire command to obtain something since it will observe the stash, mall and creation preferences that are already in place and used elsewhere. So I don't want an EatDrink that has special handling for the stash. I would want one that uses or ignores the stash as allowed by my other preferences. I would want something that was robust in the presence of clan hopping, and in the presence of clan policies and karma balances that prevented something from being pulled.

To get that we need mafia support for clan hopping that is robust and until we do, I'd be quite happy to ignore the stash as a source for EatDrink. In the current state of things I think separate script that managed stash pulls might be more fruitful.

Related, my vision would be easier to bring about if there were a speculative form of acquire that returned the "cost" of acquiring an item. This would be difficult because the cost would include meat, inventory (from bag, closet, Hagnk's or stash) items and possibly uses of a limited resource. ConsumeLast would have to track all of these things and recognize that a consumption plan was invalid because something was lacking.
 

Theraze

Active member
ConsumeLast would have to track all of these things and recognize that a consumption plan was invalid because something was lacking.
Not really... ConsumeLast just needs to take the current consumption stack and craft it all at once, then consume it all at once... that's ConsumeLast. Regarding overhauling the acquisition system... that's completely different.

So... current consensus is to skip the clan stash as an option, yes? Revert my copy to release, and move on to CL?

That leaves the other two questions I had... should storage use default to false or true? Currently it defaults to true. Should ConsumeLast stop trying to craft (and possibly consume the stack up to that point) once you run out of adventures, should it keep going knowing that your crafted food will almost certainly be suboptimal, or should it have a preference to allow the user to decide? If it's a preference, would probably have 3 options... continue (good for automation), repeat internally (use what's on the stack and rerun that stage of the consumption, like continue in automation, but might still cause suboptimal milk/ode usage), or abort (use what's on the stack and go on to the next step, will take running ED 2 times to actually get full consumption done).
 

fronobulax

Developer
Staff member
I'm not sure ConsumeLast is of any benefit to me unless it recognizes that a consumption stack is "invalid" and readjusts the stack until it can be executed. Any implementation of ConsumeLast that requires ED to be rerun will be looked at in an unfavorable light. I'm adopting the point of view that automation trumps efficiency which I believe is consistent with dj_d's vision for Ascend which is what drives me while I am a steward.

That said, perhaps a fairly detailed description of what you expect to implement as ConsumeLast might be in order?
 

Theraze

Active member
Okay, so that leaves two questions remaining.

1) Should storage default to use or not?
2) Should EatDrink create/consume substandard food if it runs out of adventures (but started with some), or should it consume that stack (once it runs out) and create a new stack that looks based on difference between current consumption levels and targetted goal? So if you create 2 pastas and have used up 8 appetite with a target of 15, should it just continue creating non-fancy food, or create a new stack after consuming that tries to find the best for 7 appetite, since you'll once again have adventures for crafting? I'm tending towards the second implementation, since you'll get better food out of it. The problem is that you're more likely to end up wasting turns of milk or ode, but it's still better than the current implementation where it wastes them as soon as the first bite happens.
 

th3y

Member
1) Should storage default to use or not?

Based on the last few posts, I think it's just as well to leave stash use out of EatDrink. However, if it's in, I'd agree with Fronobulax that EatDrink should mirror the user's mafia preferences regarding stash use (rather than having its own preferences).
 

fronobulax

Developer
Staff member
Storage, not stash. Hagnik's.

As noted, "storage" is overloaded and could mean bag, closet, stash, display case or Hagnks.

I think Hagnk's use by EatDrink should operate in one of three modes: In the first mode, Hagnk's is never considered. In the second mode, which is deliberately speculative, EatDrink would generate a list of items that it would like to pull but will not actually pull then. In the third mode it will pull what was needed up to a user specified number of pulls. It is quite possible to implement this so that the second and third modes are differentiated by the Simulate flag and not by a mode.

Thus
Hangk's Simulate Result
n T Generate list of up to n items to be pulled but don't pull any.
n F Pull up to n items as needed.
0 T Do not consider Hagnk's and simulate normally.
0 F Do not consider Hagnk's and consume normally.

However before we get this far in the weeds, what about non-consumable or non-ingredient pulls? For example, boxen, outfit parts that allow shopping, fancy range or cocktail kit, items that effect skill casting and so on?
 

fronobulax

Developer
Staff member
2) Should EatDrink create/consume substandard food if it runs out of adventures (but started with some), or should it consume that stack (once it runs out) and create a new stack that looks based on difference between current consumption levels and targetted goal? So if you create 2 pastas and have used up 8 appetite with a target of 15, should it just continue creating non-fancy food, or create a new stack after consuming that tries to find the best for 7 appetite, since you'll once again have adventures for crafting? I'm tending towards the second implementation, since you'll get better food out of it. The problem is that you're more likely to end up wasting turns of milk or ode, but it's still better than the current implementation where it wastes them as soon as the first bite happens.

I'm still not seeing how this is an improvement over the current implementation, especially since you postulate a failure mode that could waste turns of ode or milk which is the only motivation for the change that has made it through my dense skull.

I solve this kind of problem a lot and a "Plan than Execute" pattern seems to work pretty well. Right now consumption is a multi-step process and EatDrink Plans one step than Executes it. ConsumeLast should Plan all steps and then Execute them. Ideally a Plan would never fail. It would always Execute to completion. In the absence of that Ideal, Execution should always Abort if it is unable to complete the current Plan. Furthermore Execution should be ordered in such a way that if it aborts without completing a Plan, the completed steps are the most beneficial/least harmful. Thus, ConsumeLast probably tries to obtain all ingredients first and abort if it can't get something. This includes obtaining MP regen items if Ode is to be cast and milk. Next it probably creates every item and aborts if it can't create things. Finally it casts the desired amount of turns, aborting if that is not achieved and consumes. Phrased like this, a failure to ConsumeLast should return control to whatever called EatDrink because these failures usually indicate something that EatDrink Planned on is not feasible. In an environment where automation trumps all then either the calling entity needs to be aware that EatDrink might fail and handle that accordingly or EatDrink needs an alwaysContinue type of flag that would Plan and Execute as best it could until the original fullness goals had been met or shown to be unfeasible.
 

Theraze

Active member
I'm still not seeing how this is an improvement over the current implementation, especially since you postulate a failure mode that could waste turns of ode or milk which is the only motivation for the change that has made it through my dense skull.

I solve this kind of problem a lot and a "Plan than Execute" pattern seems to work pretty well. Right now consumption is a multi-step process and EatDrink Plans one step than Executes it. ConsumeLast should Plan all steps and then Execute them. Ideally a Plan would never fail. It would always Execute to completion. In the absence of that Ideal, Execution should always Abort if it is unable to complete the current Plan. Furthermore Execution should be ordered in such a way that if it aborts without completing a Plan, the completed steps are the most beneficial/least harmful. Thus, ConsumeLast probably tries to obtain all ingredients first and abort if it can't get something. This includes obtaining MP regen items if Ode is to be cast and milk. Next it probably creates every item and aborts if it can't create things. Finally it casts the desired amount of turns, aborting if that is not achieved and consumes. Phrased like this, a failure to ConsumeLast should return control to whatever called EatDrink because these failures usually indicate something that EatDrink Planned on is not feasible. In an environment where automation trumps all then either the calling entity needs to be aware that EatDrink might fail and handle that accordingly or EatDrink needs an alwaysContinue type of flag that would Plan and Execute as best it could until the original fullness goals had been met or shown to be unfeasible.

The current problem is that, if you have Value of Adventures set below the price of a single milk, or it costs more to restore mana to cast ode then you'd gain for that amount of booze, ED will skip it as a bad idea. We'll call this problem 1. As well, ED will, if you aren't using box servants, happily burn away your milk or ode crafting. This is problem 2.

Problem 1 can be solved in 4 basic ways, we'll call these a-d.
1a) Ignore it. People can deal with it, or raise their VoA.
1b) Ignore prices and always buy milk/cast ode, basically ignore VoA. [sarcasm]The admins would NEVER do something that made milk or a formerly cheap restorative go sky high in the mall. Ever.[/sarcasm]
1c) Moderately ignore VoA by assuming that people always have as much food as they want. [sarcasm]If someone, as a level 1 casual on their first additional ascension, currently possessing 2000 meat (their first ascension sort of sucked), wants to eat up to 15 appetite, of COURSE they'll be able to afford 15 decent foods after buying two 900 meat milks.[/sarcasm]
1d) Implement an intelligent crafting/consumption stack, that actually knows how much it can consume, crafts it all first, then uses its milk and ode to consume it. This would be aware of how much milk and ode is actually needed for the amount being consumed.

Regarding problem 2, we really only have 2 options, so we'll call those a and b.
2a) Ignore it. It's their fault for not knowing in advance what they wanted.
2b) Implement a crafting/consumption stack that crafts it all first, then uses its milk and ode to consume it. This would mean that milk and ode only get burned off by the food, not the crafting.

Options 1a and 2a all have the advantages of us not doing anything.
Option 1b has the advantage of being easy. Instead of actually checking VoA and the consumption stack, we just toss a "can they?" check into the milk/ode validator, and move on.
Option 1c has the advantage of ease as well. We just use the requested amount by the player and expect success at all times. No complicated futzing with the details.
Options 1d and 2b are what I'm proposing to do with ConsumeLast. Make ED actually aware of what it's doing, save adventures, and respect the player's desires.

So, you've changed desires from your post in 788?
I'm not sure ConsumeLast is of any benefit to me unless it recognizes that a consumption stack is "invalid" and readjusts the stack until it can be executed. Any implementation of ConsumeLast that requires ED to be rerun will be looked at in an unfavorable light. I'm adopting the point of view that automation trumps efficiency which I believe is consistent with dj_d's vision for Ascend which is what drives me while I am a steward.
to this:
Ideally a Plan would never fail. It would always Execute to completion. In the absence of that Ideal, Execution should always Abort if it is unable to complete the current Plan.

You gave that initial 'nay' to this question:
Should ConsumeLast stop trying to craft (and possibly consume the stack up to that point) once you run out of adventures, should it keep going knowing that your crafted food will almost certainly be suboptimal, or should it have a preference to allow the user to decide? If it's a preference, would probably have 3 options... continue (good for automation), repeat internally (use what's on the stack and rerun that stage of the consumption, like continue in automation, but might still cause suboptimal milk/ode usage), or abort (use what's on the stack and go on to the next step, will take running ED 2 times to actually get full consumption done).

It appears that you've changed your mind, and want it to have a preference as I proposed, yes? Though the specifics may be slightly varied... we'd probably just have a preference for abort if stack-failure. If you run out of adventures while running ED and started with adventures, it should consume the stack up to that point. If the abort-preference is set, it could either move on to the next consumption type (alcohol or spleen) or completely abort the script. If it's set to continue, it should then rerun its 'best' check, and find out what fancy items it next wants to craft. The consumption of the first few might have made a different item more appealing, and the initial filtering was based on how many adventures you had at the time... because of that, your "initial plan" was based on running out of adventures and crafting suboptimal food.

We can continue to run your initial plan if you prefer, but that's not the best plan, and it won't give you food results as good as the current EatDrink does. Because the current EatDrink will consume the best item until it can't anymore, then it will find the best item based on your current state... it won't give up on fancy crafting because you started crafting with 1 adventure left.
 

fronobulax

Developer
Staff member
On my soapbox, for a moment. The entire premise of EatDrink, that everything can be converted to meat and thus apples and oranges can be compared, is suspect. It does not solve a real problem, but solves a problem that is a close enough approximation to a real problem to be useful. What EatDrink actually should be doing is computing a consumption plan that produces the maximum number of adventures subject to constraints on fullness and resources available. What is does is make a list of items and tries to relate the "cost" of the item, the benefit of the item and how the net cost compares to the value of adventure. As I climb down off the soapbox I can imagine a time when EatDrink's lack of transparency as well as mathematically sub-optimal consumption plans drives me to write an alternative. But that day is not now.

I am quite content to solve problem 1 by letting people tweak their VoA which is 1a. 1b will never solve the problem for a character in Ronin or Hardcore unless the player has made some kind of strategic decision (pull milk, perm ode, etc.) to have the option available. 1c is an argument in favor of some kind of change to EatDrink but the problem here is that the current implementation is is just not smart enough to know that if it spends meat on extenders then the meat is not available for consumables. ConsumeLast is a partial solution to this. In my opinion 1c and 1d are practically the same because the problem is not the VoA setting but the fact that the plan is not feasible because it requires resources that are not available simultaneously. Thus ConsumeLast has some benefit here as well.

I agree that 2 can be a problem for some people and that 2b is a better solution.

Bottom line, you have reminded me why ConsumeLast does have benefit.

I have had my greatest successes at leading programming teams by having pointed discussions before any code actually gets written. This usually results in a product that is comparatively bug free and meets the requirements that were understood at the time of the discussion. During such discussions I often seem to change my position which is either the result of hearing something that changes my mind or deliberately adopting a different tack in order to flesh out the design/requirements/solution. I think we are in the midst of such a discussion :)

At the moment, ConsumeLast is looking like a good idea.

I don't think we have completely considered the effect of ConsumeLast on unattended automation. My thoughts have evolved to support something along what Bale did with UR. Most people are not going to care about automation and will want to be presented with a problem that EatDrink cannot deal with. Those who do care about automation can make the decision about what to do external to EatDrink.

One option in that regard would be a neverAbort preference that if set would force EatDrink to make whatever decisions it needed to in order to eat, drink and spleen to the desired fullness even if that turns out to be 15 toasts with no milk. #788 was my thinking before I realized I would accept a preference. I would now call it a suggestion for the way EatDrink acts if the neverAbort preference is set.

So I think we are in closer agreement than we were before.

Because the current EatDrink will consume the best item until it can't anymore, then it will find the best item based on your current state

Consider the following:

15 fullness to be consumed. Mall access allowed. No milk. 4700 meat available. 15 toast in inventory.


Best first consumption gives you 24.5 adventures from a bat wing chow mein @4.7K plus 10 from 10 toast for a total of 34.5 adventures.

Compare to 5 pear tarts @ 600 each with 11 adventures each for a total 55 adventures.

In the example, which is not as contrived as might be imagined, Best First sacrificed 11 adventures and cost 1,700 more.
 

Theraze

Active member
ConsumeLast would remain a preference as it is now, disabled by default, unless we wanted to push it on new users. As such, 'normal' consumption would still follow the current consume rules. I'm just trying to create an option where we can meet the needs of the meat/adventure-poor gamer. :)

One thing I'm pondering about the eventual neverAbort is whether (and this goes for all ED runs) it would be better if we check adventure count. If the player has 0 adventures, consume one item (if on a real execution, as long as they have a fancy stove/kit) and then check craftables again... This would mean that even if you run ED with 0 adventures, you'll get a better result and won't need to cancel it after the first item gets eaten/drunk, but it will figure that out for you...

By best first consumption, I don't mean the single best item... I think? When we have a proper consumption stack for CL, we'll be able to decide how many adventures it will get... What we may need to do is if my_meat() < VoA*ConsumptionLimit, run a speculative VoA against my_meat()/ConsumptionLimit for VoA. If the speculative works better for total adventures, run that level of VoA instead of your saved VoA. This would only lower VoA, not raise it. Does that sound reasonable? It does triple the length of ED executions if it needs to speculate, since you're running a speculate based on given VoA, speculate based on calculated VoA, and an actual execution... I'd suggest that one as a preference as well, named something like speculateValue or speculateAdventures or something similar. Note that for eating, that would only run if the character had less than 7500 meat (given default VoA of 500), which generally doesn't happen for me unless something very depressing has happened and I didn't notice and follow it up with a trip to the treasury for a day.
 

tgetgel

Member
The speculateValue seems like a VoA calculation. Has there been a discussion regarding a dynamic VoA based on level and progress of the character? Granted that a VoA of 500 is the default, what are the guidelines/rules/calculations for changing that as you advance in levels?

Frankly, does that matter? Isn't the VoA an average of how much you are willing to spend to gain a given amount of adventures? If that is the case, then minimizing the budget and maximizing the returns are what is needed. But that needs to be balanced by the available resources. By fronobulax's example, 5 pear tarts (VoA of 272 [3000 cost/ 55 adv gained]) are better than the bat wing chow mein and toast (VoA of ~136 [4700/34.5]). By evaluating the plans, the calculated/expected VoA can be compared to the player specified VoA; if it is lower, great! When you add in the effects of milk and ode, you can then decide which menu items to select for your meal for the day.

To limit the use of expensive/rare items, you use the budget allowance variable, MAXMEAT or eatdrink_budget. If you have an item that costs 25,000 but gives 50 adventures, the calculated Voa is 500.

If you start with 0 adventures, the meal plan should start with finding out what is the best meal plan, then what will yield the maximum number of adventures (with the minimum need for crafting the first item for consumption) at the lowest VoA. Once that is chosen, the meal plan can be reevaluated/revamped haven taken the starter into consideration.
 
Last edited:

Theraze

Active member
If we actually get an official VoA calculation anywhere, great... but until then, it's up to the player to set their own. The question is, do we want to sometimes calculate out a speculative VoA and compare that to their chosen results? The problem is, as I said, that it's going to take 3* as long to run, and people already complain about ED taking too long... If so, it should definitely be something that people can disable...
 

Winterbay

Active member
Feature request: When the script, due to heavy lagging issues such as the ones I've been experiencing today, manages to hit the inebriety limit before it thinks it is done could it just continue instead of picking the next booze in the list and then failing again and so on and so on?

Code:
Creating a a little sump'm sump'm in 3 seconds
Countdown: 3 seconds...
Countdown: 2 seconds...
Countdown: 1 second...
Waiting completed.
Verifying ingredients for a little sump'm sump'm (1)...
Creating a little sump'm sump'm (1)...
You acquire an item: a little sump'm sump'm
Successfully created a little sump'm sump'm (1)
Since you are not in a Moxie sign, you may not visit the brewery.
Drinking 1 a little sump'm sump'm...
Inebriety limit reached.
a little sump'm sump'm price updated from 1000 to 1000.
FAIL: a little sump'm sump'm lev:4 gain:4.0 adv:12.0 musc:0.0 myst:26.0 mox:9.0 meat:1000 own:2 value:9690
a little sump'm sump'm cannot currently be consumed. Skipping.
Choosing drink to consume.
Waiting to consume...
horizontal tango lev:4 gain:4.0 adv:12.0 musc:0.0 myst:35.0 mox:0.0 meat:945 own:0 value:9673
Countdown: 3 seconds...
Countdown: 2 seconds...
Countdown: 1 second...
Waiting completed.
Shopping for a horizontal tango in 3 seconds
Countdown: 3 seconds...
Countdown: 2 seconds...
Countdown: 1 second...
Waiting completed.
budgeting 1181 for 1 additional horizontal tango. You have 172413 meat. You have 0 in inventory already.
Looks like you have enough meat to buy it
You have 0 right now
Searching for "horizontal tango"...
Search complete.
Purchasing horizontal tango (1 @ 945)...
You acquire an item: horizontal tango
Purchases complete.
You now have a total of 1
Purchased 1 horizontal tango for 945 meat.
Since you are not in a Moxie sign, you may not visit the brewery.
Drinking 1 horizontal tango...
Inebriety limit reached.
horizontal tango price updated from 945 to 945.
FAIL: horizontal tango lev:4 gain:4.0 adv:12.0 musc:0.0 myst:35.0 mox:0.0 meat:945 own:0 value:9673
horizontal tango cannot currently be consumed. Skipping.
Choosing drink to consume.
Waiting to consume...
blended frozen swill lev:4 gain:4.0 adv:12.0 musc:2.5 myst:2.5 mox:28.0 meat:1200 own:0 value:9638
Countdown: 3 seconds...
Countdown: 2 seconds...
Countdown: 1 second...
Waiting completed.
Shopping for a blended frozen swill in 3 seconds
Countdown: 3 seconds...
Countdown: 2 seconds...
Countdown: 1 second...
Waiting completed.
budgeting 1500 for 1 additional blended frozen swill. You have 171468 meat. You have 0 in inventory already.
Looks like you have enough meat to buy it
You have 0 right now
Searching for "blended frozen swill"...
Search complete.
Purchasing blended frozen swill (1 @ 1,300)...
You acquire an item: blended frozen swill
Purchases complete.
You now have a total of 1
Purchased 1 blended frozen swill for 1300 meat.
Since you are not in a Moxie sign, you may not visit the brewery.
Drinking 1 blended frozen swill...
Inebriety limit reached.
blended frozen swill price updated from 1200 to 1300.
FAIL: blended frozen swill lev:4 gain:4.0 adv:12.0 musc:2.5 myst:2.5 mox:28.0 meat:1200 own:0 value:9638
Choosing drink to consume.

And so on and so on...
 

Theraze

Active member
You see a failure, I see an infinite loop aversion success. :) The message:
a little sump'm sump'm cannot currently be consumed. Skipping.
is the one I added for when the price is updated from itself to itself. With ED 3.1.2, it would have keep trying to drink the same drink forever, instead of skipping the failed one and cycling through the list.

I'm not sure if there IS a good way to avoid that. If lag manages to eat up the consumption of an item and decide that it didn't happen at all, while mafia can fix itself, I believe that any script that runs will continue to do so based on the information that mafia originally gave it...
 
Top