Increase Script memory Limit
tracked
Christina Riederer
With the introduction of PBR and new features in SL the The 64k memory limit is becoming increasingly hard to work with and not suitable for modern designs. When designing more feature intensive HUDS its hard not to keep running out of memory, suggestion to double or increase the limit would be very much welcome for 2024.
Log In
Tapple Gao
(cross-posted to https://feedback.secondlife.com/scripting-features/p/add-llmessagelinkedscript-integer-link-string-script-name-integer-num-string-str)
I have a vehicle script I've been working on for 12 years. It started out as a single script, with control event setting vehicle parameters. I have expanded it a lot since then. It now includes AI (control keys simulateed by another script, 7 vehicle mode controlers (ground, swim, fly, each with a physical and nonphysical option, plus attached mode), security features for restricting it to moving within a user-defined area.
It ran beyond the capabilities of one script a long time ago. The most obvious way to split it was at the control boundary: put all the code that takes user control and modifies that into one script (pilot for manual, autopilot for not), and put the different vehicle modes (ground vs flying vs attached) into seperate scripts. However, after using that for a while and comparing that with the old script, I realized I'd lost something important:
input responsiveness.
Just having a link message on the critical path from control event to vehicle parameters made the vehicle harder to steer due to input responsiveness. And people use it for racing. So, I redesigned the scripts again, and went with a design I still dislike: I duplicated the pilot script (input handling) into all 3 motion scripts (ground, flying, attached). I got back input responsiveness, but, now with duplicated code (and now I get to deal with obscure bugs with multiple scripts having llTakeControls active at once)
The script was actually better when it was split: I could use dedicated timers in each script at optimal frequencies for each one, and they don't actually share a lot of state. However, link messages are NOT a great way to split scripts:
- They do cause delay, usually 1 sim frame between send and wakeup, which is bad for vehicles
- They broadcast to every script in the prim. This is ok for some uses, but it's not great when there are 20 or so scripts in the prim, and every link message causes 20 script wakeups
- They require serializing to string at the sender, and parsing from string at the sender, which adds unnecessary cpu usage
We really need a better way to send one message to one other script in the prim. It should ideally be:
- immediate. It is processed as soon as it is called, or, at latest, immediately when the current script ends its active event. No putting it in a queue until the next frame, unless the script would be pre-empted anyway
- synchronous. It would be best if the remote call was an rpc, and did not resume the calling script until the callee script finished. The callee script could possibly even return a value to the caller, making it a remote function and not a remote procedure. This would make it possible to share functions between scripts
- typed, so I can pass things other than strings. I'd like to pass a list and get back a list, without serializing/parsing in the middle, since that's the only typed variable type in LSL
something like:
// sender
list returnValue = llRPC(string scriptName, integer fn, list params);
// receiver
RPC(integer fn, list params) {
if (fn == ECHO) {
llRPCResponse(params);
}
}
Link messages can stay; they are good for shared state updates to all scripts in the prim. But, splitting scripts to deal with exhausted memory needs a finer grained control like a remote procedure call, that addresses the issues with link messages
Send Starlight
Thank you for suggesting this. To naysayers claiming that less memory makes us more efficient and therefore we shouldn't have access to more, you are all just creating multiple scripts to get around the issue when it suits you. I keep my code pretty tight, usually most of my devices only have 1 script. But, having to send messages back and forth between scripts when I have to work with something more complicated or having to develop a webserver app to compensate is a pain and a time waster. In one case, I made a Zelda-clone where I stored the entire collision matrix for the map as a stream of bits. In just 1 script I also implemented the entire card game of Arkanoid (all 31 levels + boss... it has 1k left of ram, any more features and it crashes.. i can't even add a h.s. board), Splendor, a Trivia game, etc. And in another, I developed a complete client-side 2D Nethack for SL that has magic scroll reading, going upstairs/downstairs, potion drinking, supports dozens of types of weapons and monsters, fighting, chest storage, walking inside houses, entering caves that are cellular generated, cutting down trees, mining for ore, picking up torches, dropping items, a full inventory system and it was multiplayer with up to eight people in about 2 scripts. But, it was so tedious acquiring more memory for it (it would have taken another rewrite) that I gave up adding features to it and it isn't really finished as a result. I have many more projects like that where the uphill battle is the lack of memory. My AI image generator for example is running really close to running out of script memory, preventing people from typing longer prompts. Yea, I can expand to more scripts but then it requires wasting time rewriting it all, it's exhausting and tedious. I'd rather focus on developing features and not spend time with frivolous rewrites. The key/value system they added recently has helped a bit if you use the protected mode and set an empty string for the passcode so that it doesn't waste the main script's memory by double fetching, but it is a far cry from what we really need. I have so many interesting things I could develop, if only more memory existed. It isn't 2003 anymore.
rhet0rica Resident
Mishelle Rayna
I'm the scripter Christina is talking about and I assure you that I know how to code efficiently. However, I do like to code things that can be more dynamically configured, adapt to changes, be used in more than one product, etc. The flexibility to read and adapt to the environment does take a little more code than something that has absolutely everything embedded into a script that has a single purpose and can't be easily leveraged for the next product.
What's more, I like to embed some textual help and descriptions into those things that have menus. Strings take a lot of space. If you read the documentation, SL says they use 8-bit Unicode. It doesn't look like that is the case in reality. Microsoft .Net, which is where Mono comes from is 16-bit Unicode. So even if LSL is 8, once it gets to mono, it is likely 16-bit. Also, code takes up a lot more memory than you'd think if you compare it to something from years ago that was compiled into bytes for use on an 8-bit microprocessor. I don't know why. Maybe once again, it's Mono.
If you'll recall, when they went to Mono script memory grew from 16k to 64k. They didn't do that because they were being nice. They did it because Mono is just bigger.
I also like to leave 4k to 8k free, because LSL doesn't run the same way twice. If you don't believe me look at it.
To compensate for a 1980s memory model, I end up splitting functions out, which means more scripts and more script memory. Things that region owners don't like. Splitting something apart that barely fits in 64k doesn't equal two new 32k scripts. You get overhead for whatever you have to include for communication and synchronization. You also get a cpu time hit for every extra script, even if it has nothing currently to do. And, SL counts every few scripts as one LI. I don't know the formula, but I know it happens.
This problem has existed for a long time. It became more pronounced because of the number of possible things you might have to store and swap for lighting changes to faces with PBR.
So, please. More memory so I can stop some of this foolishness.
Woolfyy Resident
+1 with Peter on the 64K script + 64K data so that we don't end up with lazy programmers making spaghetti programming. PS: Knowing that in the data space i would include constants in order to keep the full script space.
Zi Ree
Better fix the PBR scripting calls than increase memory to mask the real issue.
Mishelle Rayna
Zi Ree it's not so much the scripting calls, although they can be cumbersome because they are all llSetPrimitiveParam functions and you may want to change just one thing, but have to set 3 or 4 other things with that one thing. So, all of that has to be maintained in the script. Then since every side has it's own PBR options, you may have to do this for every visible side. Again, that's more memory to represent different effects that you may want to flip through on demand.
Anyway, it was just this discussion about PBR and builder desires of what they wanted to do with PBR that added to the memory issues. Memory for anything very complicated has been an issue for a long time.
Signal Linden
tracked
Peter Stindberg
I am scripting on and off for 16 years now. I harbored similar thoughts like you have many many times. And while I certainly would welcome 128 K or more of script memory, for the past 3-4 years I realized it is not a weakness or shortcoming of SL, but a strength!
The limited memory forces us to do proper, efficient coding. It forces us to get to learn the language properly. And it forces us to find elegant, original, smart concepts and ideas. Ultimately, it forces us to make damn good code.
Yes, it's painful. Yes, it is literally a learning curve. Yes, some give up on the way. But my, what an exciting journey that is.
Peter Stindberg
Having slept about it, what I WOULD welcome is: 64 K script memory and 64 K variable memory. That would still keep us disciplined, but also be flexible enough, especially with a strict separation of both.
I just dread a situation where a "Hello World" takes up 4 MBytes.
Bleuhazenfurfle Resident
Peter Stindberg: I think you might be unwell. You should see a specialist about that.
For most of my living, I've been in the micro-controller realm, where 64K was actually
huge
. The modern ųC's with a MB or two RAM are wonderful
, all that room
…! (Especially when you're doing HTTPS stuff.) I'm in no hurry to go back to the bad old days.But, we also had these things called "bytes" which only took up 8 bits, and "words" (16), and a 32-bit numbers, took up 32 bits (instead of 16 bytes — shocking, I know!), and this concept called an "unsigned" number (scandalous!). Oh, and optimisation! A mysterious process wherein a compiler makes your code smaller and faster for you!!!
On that basis, I figure an LSL script has about 8KB of "real" memory, which is two or four times more than many of the ųC I was working on (1990's tech, old, because it's cheaper). However, I had a proper language with actual constructs, allowing even that to be more efficiently used. On top of that, those were typically split (Harvard) architectures (with about 4x as much program memory as data); and considering script memory in LSL is apparently shared with other instances of the same script, that kinda feels like it maps across to LSL too, with the separate program and variable memory thing (it is also really annoying when you figure out how to squeeze your data into the space available… and then find out you need to add a feature).
So, lets say, a factor of 8; 4x for the expansion of a basic value (locals don't count), and another 2x accounting for LSL's limitations… 128K working ram sounds comparable to… the larger side of 2000's ųC's. Is prolly about time we caught up with the 2000s, at least. 😛
Christina Riederer
Peter Stindberg The coder I use for my store has over 40 years of experience scripting he's one of the best Ive ever met in world, unfortunately with the amount of features needed in some HUDs it gets very annoying having to constantly create another script when you run out memory for adding something as little as a few texture swaps :D
Peter Stindberg
Bleuhazenfurfle Resident:p
Woolfyy Resident
Sorry but what is the relation in between scripts memory for huds and PBR ?
Bleuhazenfurfle Resident
Woolfyy Resident:
shhhh
Let it be. We need this!Christina Riederer
Woolfyy Resident The amount of code you need to texture swap on PBR is alot higher than before, takes up alot more space
Woolfyy Resident
Christina Riederer my personal vision is that "scripters" could better script and they would have no memory problem ... knowing too that splitting scripts is much more efficient in performance than doing a spaghetti programming but it needs to think architecture and not just copy / paste.
At the end, the problem of real programming is that it needs real scripters ... not users that simply drop a script and change 2 lines saying that they are scripters because their avatar has been more than 10 years on SL ...
PS: In spite of simply doing a "swap" maybe time too to upgrade old scripts ? In the same style, when i see all the "scripters" still using "warp" it makes me smile ...
Christina Riederer
Woolfyy Resident We write
everything new from scratch. nothing is a copy/paste., My coder is a real coder as in his real job and isn't a spaghetti scripter, we're also trying to push away from the basics of every single HUD you see in SL, I don't really get the snobbery towards my request as if I don't understand anything.
Woolfyy Resident
Christina Riederer great so if he is a "real coder' he has no real problem with the 64K script limit :-) knowing anyway that it has already been said that things should be addressed when SL will move to a full 64-bit architecture.
Mishelle Rayna
Woolfyy Resident you can read above for some of what my "real problem" is.
Woolfyy Resident
Mishelle Rayna FYI some of my own scripts are structurally architectured to manage hundreds of thousands of items ... isn't that sufficient on your side ? Seriously .. .there are times when noobs should learn real scripting or get back to school to learn what programming architecture means in spite of cooking spaghettis.
Anwyay, as i mentionned, i guess that i am not the only one to have read that on the go 64-bit evolutions server side on SL would certainly make some memory evolutions adressed later on ...
Patience, patience ...
PS: Reading back the feed, FYI for fun and as it seems to have never been done on SL that way till now ... those times (when i can find enough free time) i am having fun making a contextual / multi language help system based on a controller managing a bunch of textual ressources with quite no limit, so that i can extract all the text from my core programming scripts. Ahah and even if Bleuhazenfurfle finds preprocessor stuff useless, in that case i use it too to make indexing parameters readable :-)
example :
llOwnerSay( msg(ENG,HELLO) );
And i get a hello message in English (ISO-3166-3 numerical coding of the country) at just the cost of a call and 2 integers ... knowing that i also manage a TOC, cascading messages, 2 short and extended message display, search, dictionary of parameters etc. and maybe i'll even add a "related" messages if i consider that when i give some textual help it needs to provide an extra hyperlink navigation.
Mishelle Rayna
Woolfyy ResidentI I really don't understand your need to be passively aggressive in a forum making suggestions for improvement. Nor do I understand why you seem to want to measure yourself against others.
Woolfyy Resident
Mishelle Rayna Frankly, as my friends know, i don't care at all, to "measure" as you say. llscript is much simpler than the crazy skills and patience debugging needed by those having hands into the viewer code for example.
I was just giving you a related example to show how text contraints can need much less memory simply relying on a correct programming architecture and "brain juice".
For the rest, i find pointless those spaghetti programmers who spend their time crying like babies in spite of improving their skills. But i suppose that such a behavior is based on years of Microsoft environments making programmers think that optimization no more matters as the machine will compensate and external libraries will do most of their work. As I'm used to say ... better not open the Pandora box ...
The real problem is that, at the end, badly optimized scripts or meshes etc. end up making all around lagging or needing over powered systems. BTW i'll be curious to see the result of extending texture resolution to 2048 on users that will think that using such a resolution everywhere is a must or a sales argument ... but I suppose (hope) that LL already thought about solutions to automatically downgrade it where such a resolution is not needed.
Mishelle Rayna
Woolfyy Resident you really should just stop making assumptions regarding my abilities. I'm not going to whip out my credentials to make a point. If you aren't having challenges with memory usage, good for you. Move along.
Woolfyy Resident
Mishelle Rayna as i m used to say ... there are always solutions. If 64K is a limit for you, for sure i don't even care about your credentials (anyway i never cared about any credentials).
But you can also ask Bleu for solutions as on his side he is a real programmer recognized as so, even if he is like me sometimes harsh :-) but as he joked on, he has an excuse as he is Australian (and i am French).
More seriously think architecture in spite of spaghetti cooking, otherwise you will always face a wall, whatever language you use.
PS: As i also mentioned, there are some SL servers changes on the go, so let them happen too. Patience ... and end of ping pong as my sim is restarted.
Mishelle Rayna
Woolfyy Resident once again, you go to the assumption that I am somehow doing something wrong or are incapable. You just need to stop. If you want to be argumentative, passive aggressive, and condescending, go post on Facebook.
Woolfyy Resident
Mishelle Rayna I gave you a reply with a solution to the problem that you had described just to show that it was a no problem ... re read what i wrote before going on with your lack of arguments or describe professionally a problem to hope having solutions provided by the community ... In the meantime relax and have a good day. Busy on my side.
PS: FYI in another feedback feed a user provided a smart solution and i deployed it in all my scripts. That is what is named a programmers community.
Mishelle Rayna
Woolfyy Resident I don't have spaghetti code as you call it. And, I do architect my projects. I just constantly find myself having to split out functions for things that really should b able to reside in one script.
I've asked you politely. Move along.
Soap Frenzy
Christina Riederer you can use a material uuid for texture swapping which takes up the memory of a single key and changes 4 textures. You can also just change base color, roughness, emissive, and normal independently and not touch any other textures which also would mean you only need to change one texture. But I do agree more script memory would be nice
Woolfyy Resident
Soap Frenzy To complement and close the subject as it seems that some have no real practice of real programming : let's look for example at the C++/C# way of programming = functions are split in a bunch of files. Moreover i guess many here don't have any idea of how a micro controller is done but maybe they should look at it to understand what is efficient programming.
Applied to SL when scripters are a minimum skilled ... architecture = do supervisor scripts. Then sky is the limit ! On my side i even did for fun some architectures able to manage over 350 000 contents just inside a build as well as in old times a database scripting transforming a region into a data storage area, just for fun and to demo to a friend that there was no need at all to rely on external web sites.
But as i said there are 2 problems :
1/ "programmers" have been living in luxury with the Microsoft wasteland empire and are totally lacking the historical knowledge of what is optimization. Moreover, keep in mind that the more you will let people the keys to develop fat and lazy programming the more SL will be slow as most "scripters" don't know scripting correctly.
2/ even RL "engineers" are basically more and more lacking the knowledge of what is architecture because studies are more and more based on quick pissing of lines of one-use derived code and thinking spaghetti cooking or simply injecting code that they even often not even created ... and i don't even talk about those doing it without even understanding how it works.
On my side, i do with what i have and i try to make it concise and quick to run, in spite of always running after what is not existing. That is also the fun part of scripting = being challenged with yourself.
Once said ... end of discussion on my side. I gave computing lessons long ago and i have no more patience for that.
UPDATE OK let's just add one thing : i am skilled in more that 10 languages from machine language to AI and one thing that i learnt with time is that programming correctly is also understanding / programming the way a language has been done, with its existing features and limits, in spite of trying to replicate "as is" what is done in another language. This also includes rethinking old source when new features happen in spite or recycling as is. Lazy work (making things easy) is rarely lazy programming (pissing mindless code) ...
Mishelle Rayna
Woolfyy Resident the subject isn't closed. You only know 10 languages? I can't even count the languages that I know, which include at least 3 different machine/Assembler languages. An uncountable number of scripting languages. I assure you, I know what I'm doing and your insistence that you know more than anyone else is beyond arrogance.
Woolfyy Resident
Mishelle Rayna Lunch time on my RL side, so let's end up with a joke as you seem to like bragging indefinitely like a frustrated kid iin spite of understanding what was written before :-) Yummy gran ma spaghetti bolognese on my RL side ! Bon appétit ...
BTW and for the kids having a short memory or needing glasses, i also wrote it in that feed : "Anwyay, as i mentionned, i guess that i am not the only one to have read that on the go 64-bit evolutions server side on SL would certainly make some memory evolutions adressed later on ..."
And to end up talking about "modern" languages, you will certainly also have noticed that they split code into modules in spite of making an endless block of spaghetti ... a point that is for sure lacking efficiency in llscript ... A smarter point to address would be : why scan scripts in an inventory in spite of addressing directly the one concerned by llMessageLinked() ?
Mishelle Rayna
Woolfyy Resident you are the one that endlessly brags. You have also turned around a little from saying you should be able to do everything in one script to saying just use multiple scripts. If you'll go back and read, you'll see that's exactly what I'm trying to get away from. Using too many scripts. Every time I move a function out to save memory, that means duplicating variables, creating the communications mechanism, and sometimes duplicating internal functions needed by both. All of which uses even more server memory and has impacts on region resources.
You also need to drop this "spaghetti code" phrase. That's just ridiculous. You know nothing of me or what I'm trying to accomplish, but endlessly accuse me of not knowing what I'm doing because LSL/Mono just inherently uses a lot of memory. Mono was not created to run on memory deficient hardware. Even though LSL is pretty simplistic, Mono is not.
Just go eat your spaghetti and leave those of us alone that are trying to actually create something.
Woolfyy Resident
Mishelle Rayna OK just to end up with the subject as in old time i also did an operating system, there are easy protocols that make it possible to avoid duplicating all ... but that means understanding what is architecture (and this also applies to LL compiling optimizations)
I guess that you should also look at the way modern languages work as most of them are done in a modular way though once again you are talking spaghetti programming.
Once said, due to the time you spend trolling that feed, i suppose that it would be better used getting back to your scripts.
On my side, diner time now, and definitely my latest post on this feed as i'm not here to manage a bragging trolling kid that should better focus on being better skilled; even if some of my friends (real skilled programmers) really laughed at your kiddy posts LOL
Good night ! I guess that i am also going to ask for a feature to silent stubborn trolling kids on Canny ... update: done LOL
Mishelle Rayna
Woolfyy Resident you are the one trolling. This was our request due to issues we face. Yet you come here endlessly telling us we don't need it because you think we have "spaghetti code". And, you make that determination with absolutely zero basis. What's more. LSL isn't exactly a "modern language".
So, just troll your way on to dinner and how about you just quit telling people they don't know what they are doing when you have no idea regarding what they are doing.
Woolfyy Resident
Mishelle Rayna As i already said .... good night .. and hurry up ... your spaghetti are already cold and your trolling discussion kiddy and technically totally uninteresting. But i guess that you also need to learn what the word "end of discussion means" ...
Mishelle Rayna
Woolfyy Resident I don't have any spaghetti code. That must be yours. We opened this issue. You stated your opinion. So, run along now. Your continued harassment violates Second Life Terms of Service.
Woolfyy Resident
Mishelle Rayna as i already said several times : end of discussion ... so YOU stop trolling me ! Said differently shut up in spite of trolling if you better understand it that way ... and this is my latest message as i'm frankly bored of your bistro stupid kiddy trolling ...
Mishelle Rayna
Woolfyy Resident as I said, this feature is our request and you've made your repeatedly unfounded determinations of why we don't need it. So, just move along.
Woolfyy Resident
Mishelle Rayna as just said one of my friends ... "stop talking to that stupid avatar and her kiddy spaghetti programming" ... so ... good night ! Have fun losing your time talking to a wall !
Mishelle Rayna
Woolfyy Resident you keep saying you are done, but yet you always come back. If anyone comments, you seem to feel you need to. This is our request. Not yours.
Woolfyy Resident
Mishelle Rayna When i say i'm done you each time go on ... so either my friend is right and you are definitely totally stupid either you need to understand what a technical feed means ... once again ... end of discussion and good night !
Mishelle Rayna
Woolfyy Resident I'm still waiting for you to actually leave the issue that we opened and go away.
Woolfyy Resident
Mishelle Rayna As said my friend you just proved that you were definitely stupid LOL good night !
Mishelle Rayna
Woolfyy Resident and you are still here. I'm here to manage our interests in our request. You seem to be here for the total purpose of trolling.
Woolfyy Resident
Mishelle Rayna ...
Mishelle Rayna
Woolfyy Resident and you are still here. I thought you were leaving.
Woolfyy Resident
Mishelle Rayna The "..." was a joke with my friend to see if he was right but definitely you digged it LOL good night .. and enjoy your spaghetti
Mishelle Rayna
Woolfyy Resident as I said, it's our request. Not yours. You said you were done long ago, yet you keep coming back to troll "our request".
Woolfyy Resident
Mishelle Rayna FYI i said more than 4 times "good night" / "end of discussion" and you go on replying ... even when you dig it as my friend said "showing that you are definitely stupid" going on and going on and going on ... for sure now i believe him and i guess that i am not the only one to think so LOL ... good night .. end of discussion ...
Mishelle Rayna
Soap Frenzy yeah we're taking the one key approach. The memory issue has been a long term issue once anything gets a little complicated. I complain to Christina constantly on projects because I'll end up getting near to the limit and then wasting time figuring out what I can push off to another script. The PBR thing just brought it out because of how one of our meshers wants to take advantage of PBR and the potential tracking of a large number of faces and PBR swaps. So, Christina just opened a feature request to try to get more attention on the issue. We know we aren't the only ones with this problem.
Mishelle Rayna
Woolfyy Resident you keep saying that and yet you keep coming back. Perhaps your English translator is messing up and you don't know what "end of discussion" means. Not that you've actually provided any real discussion. You just belittle everyone else's capabilities and desires. That's not a discussion. That's trolling.
Woolfyy Resident
Mishelle Rayna To sump up and close the technical discussion : I already replied to that point = 1/ a better programming architecture on the scripter's side already circumvents such a point even if PBR made optimizations much needed 2/ as many here have certainly read, memory will be a point certainly addressed when LL will have made upgrades servers side.
FYI on my side i also added a feedback request for a direct addressing of scripts inside linked prims in order to have an even better performance and much more modular approach rather than getting a longer code or tricking spreading scripts on several prims to speed up processes. PS: my personal fun is to constantly gain on performance whatever i do ...
Once said and as far as i understand, i'm sorry if you need to rethink your scripts in spite of just changing parameters but that's the daily life of scripters who make rolling releases, each time optimizing their code. LL will not go quicker than the time they need to update much more important points concerning their own architecture to be completed and (as i already mentioned) better rely on your own code than hypothetical new features whose timing is never known until released.
In the meantime and just for fun, if you need some tech support, send me your source and i will tell you how to optimize it (I did much more complex things than that) or there is certainly an old friend that will find it funny to optimize it.
Good night !
Mishelle Rayna
Woolfyy Resident based on your rambling, I'm pretty sure there is nothing you can fix for me. I'm quite capable of doing things myself. The issue is that we have a great deal of function in our products and have to spend too much time reorganizing and splitting code because of the ridiculously low memory available to us. The things we want to do with PBR just make it even worse.
So, do what you said you were going to do long ago and leave.
Woolfyy Resident
Mishelle Rayna So you know what you have to do in the meantime ... better optimize your scripts ! Good night ! FYI I did scripts with supervisors managing tens of thousands of lines never reaching limits, with an architecture approach that is like managing micro controllers in the hardware industry ... while you complain just for a 64K limit.
Mishelle Rayna
Woolfyy Resident they are very optimized. How many times are you going to "leave"?