https://wiki.secondlife.com/w/api.php?action=feedcontributions&user=LepreKhaun+Resident&feedformat=atom
Second Life Wiki - User contributions [en]
2024-03-28T11:54:13Z
User contributions
MediaWiki 1.36.1
https://wiki.secondlife.com/w/index.php?title=LlSetTextureAnim&diff=1188058
LlSetTextureAnim
2014-03-05T01:20:38Z
<p>LepreKhaun Resident: Only across a row is scrolling "smooth".</p>
<hr />
<div>{{LSL_Function<br />
|inject-2={{Issues/SVC-4897}}{{Issues/SVC-3925}}{{Issues/SVC-1242}}{{Issues/VWR-4018}}<br />
|inject-3=<br />
{{LSL_Function/face|face}}<br />
{{LSL_Function/negative index|true|start}}<br />
|func_id=211<br />
|func_sleep=0.0<br />
|func_energy=10.0<br />
|sort=SetTextureAnim<br />
|func=llSetTextureAnim<br />
|p1_type=integer|p1_subtype=bit_field|p1_name=mode|p1_desc=mask of Mode flags<br />
|p2_type=integer|p2_name=face<br />
|p3_type=integer|p3_name=sizex|p3_desc=horizontal frames (ignored for [[ROTATE]] and [[SCALE]])<br />
|p4_type=integer|p4_name=sizey|p4_desc=vertical frames (ignored for [[ROTATE]] and [[SCALE]])<br />
|p5_type=float|p5_name=start|p5_desc=Start position/frame number (or radians for [[ROTATE]])<br />
|p6_type=float|p6_name=length|p6_desc=number of frames to display (or radians for [[ROTATE]])<br />
|p7_type=float|p7_name=rate|p7_desc=frames per second (must not be zero)<br />
|func_footnote=Frames are numbered from left to right, top to bottom, starting at 0.<br/>If {{LSLP|rate}} is negative, it has the same effect as using the [[REVERSE]] flag.{{Footnote|Though if {{LSLP|rate}} is negative and the [[REVERSE]] flag is used, they cancel each other out.|Though if 'rate' is negative and the [[REVERSE]] flag is used, they cancel each other out.}}<br />
|func_desc=Animate the texture on the specified face/faces by setting the texture scale and offset.<br />
|return_text<br />
|spec=<br />
===Frames===<br />
Frames are sub-rectangles within the texture. A set of frames with 2 horizontal ({{LSLP|sizex}}) and 3 vertical ({{LSLP|sizey}}) means the overall texture is divided into 3 rows of 2 columns of images, each of which is a frame. llSetTextureAnim will animate across these 6 starting with the top left image and going across and down, optionally repeating. If [[SMOOTH]] is set, the frames slide smoothly from one to the next across each row but will "jump" from one row to the next, if off, each frame is displayed in turn centered on the face.<br />
|caveats=*You can only have one texture animation on a prim<br />
**Calling llSetTextureAnim more than once on a prim will reset the existing animation.<br />
**Calling llSetTextureAnim again with exact same values will not reset animation (a small difference in rate will suffice).<br />
*You cannot combine [[ROTATE]] and [[SCALE]] flags.<br />
*{{LSLP|sizex}} & {{LSLP|sizey}} are both limited to a range of 0 to 255<br />
*llSetTextureAnim, when on, shows the texture with 1 repeat in X and Y and 0 rotation and offset.<br />
*Selecting and un-selecting a prim with animation will reset animation from beginning.<br />
|constants={{{!}} class="sortable collapsible" {{Prettytable|style=margin-top:0;}}<br />
{{!}}-{{Hl2}}<br />
! Modes<br />
! title="Value" {{!}}<br />
! class="unsortable" {{!}} Description<br />
{{!}}-<br />
{{!}}[[ANIM_ON]]<br />
{{!}}{{LSL Hex||1|chars=2}}<br />
{{!}}Texture animation is on. This must be set to start the animation, cleared to stop it.<br />
{{!}}-<br />
{{!}}[[LOOP]]<br />
{{!}}{{LSL Hex||2|chars=2}}<br />
{{!}}Loop the texture animation.<br />
{{!}}-<br />
{{!}}[[REVERSE]]<br />
{{!}}{{LSL Hex||4|chars=2}}<br />
{{!}}Play animation in reverse direction.<br />
{{!}}-<br />
{{!}}[[PING_PONG]]<br />
{{!}}{{LSL Hex||8|chars=2}}<br />
{{!}}Play animation going forwards, then backwards.<br />
{{!}}-<br />
{{!}}[[SMOOTH]]<br />
{{!}}{{LSL Hex||16|chars=2}}<br />
{{!}}Slide in the X direction, instead of playing separate frames.<br/>In both [[SCALE]] and [[ROTATE]] modes, causes smooth transitions.<br />
{{!}}-<br />
{{!}}[[ROTATE]]<br />
{{!}}{{LSL Hex||32|chars=2}}<br />
{{!}}Animate texture rotation.<br>Does not work with [[SCALE]]<br />
{{!}}-<br />
{{!}}[[SCALE]]<br />
{{!}}{{LSL Hex||64|chars=2}}<br />
{{!}}Animate the texture scale.<br>Does not work with [[ROTATE]]<br />
{{!}}}<br />
|examples=<br />
This slides a texture smoothly, along the horizontal U-axis, and loops it when it gets to the end. Note - the texture's rotation for each side affects the apparent motion. So if the texture is rotated 90 degrees by use of the edit box, the texture may not flow in the direction expected.<br />
<lsl>llSetTextureAnim(ANIM_ON | SMOOTH | LOOP , ALL_SIDES, 1, 1, 1.0, 1.0, 1.0);</lsl><br />
<br />
This slides a texture smoothly, along the horizontal U-axis, in the opposite direction<br />
<lsl>llSetTextureAnim(ANIM_ON | SMOOTH | LOOP , ALL_SIDES, 1, 1, 1.0, 1.0, -1.0);</lsl><br />
<br />
This divides a texture into 64 "cells", 8 across, and 8 down, and flips through them, left to right, top to bottom. This is useful for cell animation.<br />
<lsl>llSetTextureAnim( ANIM_ON | LOOP, ALL_SIDES, 8, 8, 0.0, 64.0, 6.4 );</lsl><br />
<br />
This rotates a texture counter-clockwise at 2 revolutions per second. Change the last value to -2*TWO_PI to rotate clockwise.<br />
<lsl>llSetTextureAnim(ANIM_ON | SMOOTH | ROTATE | LOOP, ALL_SIDES,1,1,0, TWO_PI, 2*TWO_PI);</lsl><br />
<br />
This scales a texture larger and smaller.<br />
<lsl>llSetTextureAnim(ANIM_ON | SMOOTH | SCALE | PING_PONG | LOOP, ALL_SIDES, 1, 1, 1.0, 3.0, 2.0);</lsl><br />
<br />
This turns off all texture animations<br />
<lsl>llSetTextureAnim(FALSE, ALL_SIDES, 0, 0, 0.0, 0.0, 1.0);</lsl><br />
<br />
This toggles a looping animation to make it stop at a specific frame.<br />
<lsl><br />
integer textureIsBeingAnimated;<br />
<br />
default<br />
{<br />
touch_start(integer num_detected)<br />
{<br />
if (textureIsBeingAnimated)<br />
llSetTextureAnim(ANIM_ON | LOOP, ALL_SIDES, 1, 5, 0.0, 0.0, 1.0);<br />
else<br />
llSetTextureAnim(ANIM_ON | SMOOTH, ALL_SIDES, 1, 5, 5.0, 1.0, 1.0);<br />
<br />
// toggle back and forth between TRUE (1) and FALSE (0)<br />
textureIsBeingAnimated = !textureIsBeingAnimated;<br />
}<br />
}<br />
</lsl><br />
<br />
|helpers<br />
|also_functions={{LSL DefineRow||[[llSetLinkTextureAnim]]}}<br />
|also_events<br />
|also_articles<br />
|notes=<br />
Texture animation is a property of the prim (i.e., you can remove the script that started the animation, and the prim will remember the settings anyway.) Note, though, that as of Jan 2009, texture animation is still one of the prim properties that is lost when using the rezzed in world copy method of shift-drag. Originally brought up in {{Jira|VWR-640}}, it got its own issue in [[#SVC-3925|SVC-3925]]<br />
<br />
An online-tool for rough and ready conversion of moving gifs to animated textures is here: http://www.peregrinesalon.com/anim/ (link valid as of August 27, 2010.)<br />
|cat1=Media<br />
|cat2=Effects<br />
|cat3=Texture<br />
|cat4=Video<br />
|cat5<br />
|cat6<br />
|history={{LSL Added|0.4.0|remote=http://secondlife.wikia.com/wiki/Version_0.4.0#Scripting}} <br />
}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:Json_usage_in_LSL&diff=1187229
Talk:Json usage in LSL
2014-01-24T22:29:02Z
<p>LepreKhaun Resident: /* Inconsistent behavior on types */</p>
<hr />
<div>I am concerned because the JSON format specifies at json.org that you can use escape codes like \u0000 to represent Unicode byte values in strings. But LSL has the ugly habit of censoring and altering strings so that a character with byte value of 0x0000 is removed from the string, and some functions like llSHA1String are essentially broken since they also convert UTF-16 integers between \u0128–\u0255 into UTF-8 byte values starting with %c2 (which therefore have a different integer value due to the addition of the extraneous byte). Is LSL also going to mangle JSON strings' byte values when it renders them into LSL strings? Won't this corrupt attempts at efficiently verifying the signatures of any incoming messages, and thwart attempts to generate proper signatures for some outgoing JSON-formatted requests? Or do the Lindens have plans to finally give us a proper suite of escape codes in LSL (or some other solution)?<br />
--[[User:Gistya Eusebio|Gistya Eusebio]] 09:41, 30 May 2013 (PDT)<br />
<br />
Add to that the complete crash-and-burn if your string starts with a quote, generating invalid JSON. I really don't get why LL finds it advantageous to include magic switches which forces everybody to do workaround for normal use, and ensures that all future JSON implementations in SL must be hand-coded to keep backwards compatibility with the spec breaks currently implemented.<br />
[[User:Tali Rosca|Tali Rosca]] 15:50, 19 June 2013 (PDT)<br />
<br />
:This sounds like a bug, you should report it. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:49, 20 June 2013 (PDT)<br />
<br />
::nm I see that you did. {{jira|BUG-2594}} -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:50, 20 June 2013 (PDT)<br />
<br />
:::I've been kicking and screaming about getting a robust JSON handling :-) 2594 got us some way, but we still have {{jira|BUG-2736}}, which I consider so exceedingly ill-advised as to be a bug, despite the insistence that it's a really awesome feature. [[User:Tali Rosca|Tali Rosca]] 16:39, 21 June 2013 (PDT)<br />
<br />
::::&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The trailing quotation mark is the real nasty problem, not the leading one :D But yeah.. if they do add the capability to handle enquoted* text, how would that break anyone's scripts? Is anyone really relying on enquotation to invalidate their JSON strings on purpose? Besides when has breaking people's scripts stopped them from doing anything? I have tens of thousands of L$ worth of vehicles that are now worthless due to the Havok 4 update, but hey, life goes on. My copy of Microsoft Word 1.0 for Mac won't run on Mountain Lion either. I like backwards compatibility but we developers would be out of a job if software never had to be rewritten to work with the ever-evolving platforms that are out there :D <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--[[User:Gistya Eusebio|Gistya Eusebio]] 07:58, 23 June 2013 (PDT) <br>* I know "enquoted" is not in the dictionary. However it is in the lexicon. :D<br />
:::::A (somewhat kludgy) workaround for the mishandling of escaped characters can now be found [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|here]]. Hope someone finds this useful.[[User:LepreKhaun Resident|LepreKhaun Resident]] 23:41, 29 August 2013 (PDT)<br />
<br />
----<br />
<br />
I feel the paragraph within "Specifying Json Elements" that begins with "When JSON is presented in human-readable form,..." should be rewritten to show that the JSON string in its entirety is actually the root node of the structure, signified by an empty list used as "specifiers". [[User:LepreKhaun Resident|LepreKhaun Resident]] 15:23, 6 July 2013 (PDT)<br />
<br />
== Unsure of major edit ==<br />
<br />
After making the edit on 16:04, 15 August 2013 to correct code examples that wouldn't compile, I've come to realize that the given examples, as well as the surrounding text, is in error since json disallows empty values, as one might find in a "sparse" array.<br />
<br />
The author is pointing out "a rare exception" but then uses "{\"parent\":,}" and "{\"parent\":[ , , , , ]}" to illustrate. Neither of those can be arrived at with llList2Json(), since LSL doesn't allow empty list elements, but can only be obtained by hand coding to arrive at the non-compliant json strings.<br />
<br />
I feel that whole section should be rewritten to simply point out to the reader that they are advised to use llList2Json() in the formation of json strings and avoid hand coding, which may well result in mal-formed constructions that could lead to confusing results in later operations. <br />
<br />
However, doing so would excise a number of paragraphs and I'm unsure how that would set with the original author and others. Guidance on this would be appreciated. [[User:LepreKhaun Resident|LepreKhaun Resident]] 05:25, 18 August 2013 (PDT)<br />
<br />
== JSON example ==<br />
<br />
I want to submit a simple, working example on LSL JSON, but I don't know the right place for it<br />
:I hope Strife will and can place it, here it is:<br />
<lsl><br />
// JSON array forum example by Dora Gustafson, Studio Dora 2013<br />
// Building an 3 by 5 array in a JSON Object<br />
// Rows are indexed by name and columns are indexed by number = 0,1,2,3,4<br />
<br />
string JSONVotes;<br />
<br />
tellVotes( string voter)<br />
{<br />
string Js = llJsonGetValue( JSONVotes, [voter]);<br />
list Jl = llParseString2List( Js,[",","[","]","\""],[]);<br />
string output = llDumpList2String( Jl, ", ");<br />
llOwnerSay( "Votes from "+voter+" are: "+output);<br />
}<br />
<br />
default<br />
{<br />
state_entry()<br />
{ // Building the JSON object<br />
string votes = llList2Json( JSON_ARRAY, [0, 0, 0, 0, 0]); // one row<br />
JSONVotes = llList2Json( JSON_OBJECT, [ "Betty", votes, "Jerry", votes, "Pierre", votes]); // complete object<br />
}<br />
touch_end( integer num)<br />
{ // Testing the JSON object<br />
tellVotes( "Betty");<br />
tellVotes( "Jerry");<br />
tellVotes( "Pierre");<br />
// saving some random votes<br />
JSONVotes = llJsonSetValue( JSONVotes, ["Betty", 1], (string)llFrand( 100.0));<br />
JSONVotes = llJsonSetValue( JSONVotes, ["Jerry", 4], (string)llFrand( 100.0));<br />
// testing<br />
tellVotes( "Betty");<br />
tellVotes( "Jerry");<br />
tellVotes( "Pierre");<br />
// getting one vote, example<br />
string s = llJsonGetValue( JSONVotes, ["Betty",1]);<br />
llOwnerSay( "Betty votes "+s+" in second column");<br />
}<br />
}</lsl>[[User:Dora Gustafson|Dora Gustafson]] 06:23, 25 August 2013 (PDT)<br />
<br />
== Inconsistent behavior on types ==<br />
<br />
The documentation says: if the specifier list element is an integer, then the corresponding element in the json value must be an array and the list element is used as a zero-based index into the Json array.<br />
<br />
However, placing integers in a specifier used with a JSON_OBJECT and llJsonGetValue, they are automatically converted to strings. llList2Json and llJsonSetValue do not automatically convert integers to strings. Both will result in a JSON_INVALID if you try to put integers on the key side of a JSON_OBJECT.<br />
<br />
This example code, according to the documentation shouldn't even work (I'd presume it's supposed to return a JSON_INVALID):<br />
<br />
<lsl>string test = llList2Json(JSON_OBJECT, ["1", "one", "2", "two", "3", "three"]);<br />
llOwnerSay(llJsonGetValue(test, [3]));</lsl><br />
<br />
This little sniplet produces "three". Additionally, using llJsonValueType in place of llJsonGetValue in the above example will result in JSON_STRING. Attempting something like 'llJsonSetValue(test, [3], "three");' results in JSON_INVALID.<br><br><br />
[[USER:Chetar Ruby|Chetar Ruby]] 09:15, 14 October 2013 (PDT)<br />
<br />
: Yes, that's because what you meant to say was <code>llJsonSetValue(test, ["3"], "three")</code>– objects in LSL JSON land are always keyed on STRINGS– you can't pass numbers even when the string looks like a number. -- [[User:Winter Seale|Winter Seale]] 12:35, 23 January 2014 (PST)<br />
::Right, but you're overlooking what was being pointed out, a string isn't being required using llJsonGetValue() on a JSON object. It's an anomaly, though I can't see how this might adversely affect anything. [[User:LepreKhaun Resident|LepreKhaun Resident]] 14:29, 24 January 2014 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LlRound&diff=1187133
Talk:LlRound
2014-01-21T04:47:42Z
<p>LepreKhaun Resident: Just asking...</p>
<hr />
<div>In all seriousness, how does a "pretty table", which doubled the page width,<br />
https://wiki.secondlife.com/w/index.php?title=LlRound&diff=next&oldid=1187121<br />
fit in with the edit of https://wiki.secondlife.com/w/index.php?title=LlJsonSetValue&diff=prev&oldid=1181771 made for "...better readability on mobile screens..."??? [[User:LepreKhaun Resident|LepreKhaun Resident]] 20:47, 20 January 2014 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LlSleep&diff=1186908
Talk:LlSleep
2014-01-14T15:26:45Z
<p>LepreKhaun Resident: </p>
<hr />
<div>== Use of small values with llSleep() ==<br />
I believe these 2 script shows that a small value (as in less than 0.0222... (1/45)) sent to llSleep() causes the script to sleep out the rest of the server frame it's then active within, always causing a minimal delay of approximately 0.022s. They also show that llSleep(0.0); is a NOP.<br />
<br />
To show this, I'm using a technique to see what gets en-queued during the detach event. Both scripts announce when their attach event handler is triggered. The "Sub" script, when it detects a detach event message, also sends a link message to "Main" which then announces when it's been received.<br />
With either no llSleep() or with llSleep(0.0) in the indicated spot within "Sub", nothing is queued through the detachment. However, use of a small value will cause the response of the link message to delay until it's reattached again.<br />
<br />
To use, place both scripts within one prim, attach and detach enough times to note the chat messages and when they occur. Uncomment either of the llSleep() statements in "Sub" to observe the differences.<br />
<lsl>// Main<br />
default{<br />
link_message(integer sender_num, integer num, string msg, key id){<br />
llOwnerSay(msg);<br />
}<br />
<br />
attach(key id){<br />
if (id == NULL_KEY)<br />
llOwnerSay("Main detached.");<br />
else <br />
llOwnerSay("Main attached.");<br />
}<br />
}</lsl><br />
<br />
<lsl>// Sub<br />
default{<br />
attach(key id){<br />
<br />
<br />
if (id == NULL_KEY){<br />
llOwnerSay("Sub detached.");<br />
<br />
// Uncommenting next line will not change the observed behavior<br />
// llSleep(0.0);<br />
<br />
// Uncommenting next line will cause this script to sleep until the end of the server frame<br />
// llSleep(0.0001);<br />
<br />
llMessageLinked(0, 0, "DETACHED", NULL_KEY);<br />
} else<br />
llOwnerSay("Sub attached.");<br />
}<br />
}</lsl> [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:23, 13 January 2014 (PST)<br />
<br />
<br />
Try this:-<br />
<br />
<lsl><br />
default<br />
{<br />
touch_start(integer total_number)<br />
{<br />
llResetTime();<br />
llSleep(0.0001); // Try also with 0.0<br />
llSay(0, (string) llGetTime() );<br />
}<br />
}<br />
</lsl><br />
<br />
I got values as low as 0.01825, mostly around 0.021, and once 0.044 (2 frames) from a sleep of 0.0001<br />
<br />
but consistently 0.00000 from a sleep of 0.0<br />
<br />
[[User:Omei Qunhua|Omei Qunhua]] 03:28, 14 January 2014 (PST)<br />
:Mo' bettah, fo' sure. LOL I'd made the observation while tinkering with synchronicity in multiple scripts and never thought to simplify. I guess the question would be does it warrant mention on the front page and, if so, would it fall under Caveats?<br />
: [[User:LepreKhaun Resident|LepreKhaun Resident]] 07:26, 14 January 2014 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LlSleep&diff=1186902
Talk:LlSleep
2014-01-14T03:23:42Z
<p>LepreKhaun Resident: Use of small values with llSleep()</p>
<hr />
<div>== Use of small values with llSleep() ==<br />
I believe these 2 script shows that a small value (as in less than 0.0222... (1/45)) sent to llSleep() causes the script to sleep out the rest of the server frame it's then active within, always causing a minimal delay of approximately 0.022s. They also show that llSleep(0.0); is a NOP.<br />
<br />
To show this, I'm using a technique to see what gets en-queued during the detach event. Both scripts announce when their attach event handler is triggered. The "Sub" script, when it detects a detach event message, also sends a link message to "Main" which then announces when it's been received.<br />
With either no llSleep() or with llSleep(0.0) in the indicated spot within "Sub", nothing is queued through the detachment. However, use of a small value will cause the response of the link message to delay until it's reattached again.<br />
<br />
To use, place both scripts within one prim, attach and detach enough times to note the chat messages and when they occur. Uncomment either of the llSleep() statements in "Sub" to observe the differences.<br />
<lsl>// Main<br />
default{<br />
link_message(integer sender_num, integer num, string msg, key id){<br />
llOwnerSay(msg);<br />
}<br />
<br />
attach(key id){<br />
if (id == NULL_KEY)<br />
llOwnerSay("Main detached.");<br />
else <br />
llOwnerSay("Main attached.");<br />
}<br />
}</lsl><br />
<br />
<lsl>// Sub<br />
default{<br />
attach(key id){<br />
<br />
<br />
if (id == NULL_KEY){<br />
llOwnerSay("Sub detached.");<br />
<br />
// Uncommenting next line will not change the observed behavior<br />
// llSleep(0.0);<br />
<br />
// Uncommenting next line will cause this script to sleep until the end of the server frame<br />
// llSleep(0.0001);<br />
<br />
llMessageLinked(0, 0, "DETACHED", NULL_KEY);<br />
} else<br />
llOwnerSay("Sub attached.");<br />
}<br />
}</lsl> [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:23, 13 January 2014 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185834
Talk:LSL Script Memory
2013-12-28T10:26:48Z
<p>LepreKhaun Resident: </p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).] [[User:LepreKhaun Resident|LepreKhaun Resident]] 18:17, 19 December 2013 (PST)<br />
<br />
::If you look at my own page, [[https://wiki.secondlife.com/wiki/User:Omei_Qunhua]], and one by Pedro Oval, [[http://wiki.secondlife.com/wiki/User:Pedro_Oval/Mono_code_memory_usage]] , you will see our findings for Mono usage for a large number of code snippets. These were obtained generally by replicating the snippet 512 times, which obviates the effect of Mono's 512-byte memory grabbing forays. I balked at trying to do the same for strings, as I have a feeling the strings would need to have different contents each time. But another technique I have used, is to add a series of minimum-space padding code snippets, until I observe the memory usage jumping to the next 512 multiple, doing this both with and without my target bit of code to be measured, and hence one can compute the space used by the target code. These padding code fragments were first measured via the 512-times approach. e.g. You could use a series of x; (at 2 bytes each) or x++; (at 8 bytes each) etc. But the occasional interference by garbage collection at run time, still makes the exercise a bit fraught at times. Hope this helps [[User:Omei Qunhua|Omei Qunhua]] 19:04, 19 December 2013 (PST)<br />
:::Thank you, I've read those pages. Back to my original question, am I looking at a 48 byte base for local strings or not? And if not, where is the error in my approach?[[User:LepreKhaun Resident|LepreKhaun Resident]] 21:43, 19 December 2013 (PST)<br />
<br />
::::I did some tests today based on your code, but using llGetUsedMemory(). Results were not consistent. Strings assigned to named variables within an event gave an overhead of from 40 to 50 bytes per string (plus the 2 bytes per character). Defining global strings suggested a larger overhead around 60 bytes per string. Strings coded within an event but not assigned to named variables, gave 12 bytes overhead per string. Rather depressing reading :) [[User:Omei Qunhua|Omei Qunhua]] 08:49, 20 December 2013 (PST)<br />
<br />
::::Pedro Oval also saw non-consistent results from strings etc. [[https://wiki.secondlife.com/w/index.php?title=User_talk:Omei_Qunhua&oldid=1175754]] [[User:Omei Qunhua|Omei Qunhua]] 15:57, 20 December 2013 (PST)<br />
<br />
:::::Well strings are always funny critters and SLMono is provably non-deterministic at times. One thing I see lacking on the fronting page is the fact that the SLMono implementation has a base cost of 3364 bytes per program. That is to say, the minimal default state with one event is taking that amount off the top from the gitgo. I believe under LS0 it was 220-230 bytes???[[User:LepreKhaun Resident|LepreKhaun Resident]] 08:39, 21 December 2013 (PST)<br />
:::::And, of course, when one reads this: http://marc.info/?l=mono-devel-list&m=113761555126537&w=2 you have to wonder how accurate any measurement could ever be with the tools we have within LSL.[[User:LepreKhaun Resident|LepreKhaun Resident]] 02:26, 28 December 2013 (PST)<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:Premium_Continents&diff=1185411
Talk:Premium Continents
2013-12-21T19:27:47Z
<p>LepreKhaun Resident: Created page with "== A bit if trivia on Linden Home Sims == Go to any Linden Home Neighborhood on the Premium Continents, fly to 1000m and visit the (1, 1, 1000) corner of the Sim and you'll find …"</p>
<hr />
<div>== A bit if trivia on Linden Home Sims ==<br />
Go to any Linden Home Neighborhood on the Premium Continents, fly to 1000m and visit the (1, 1, 1000) corner of the Sim and you'll find a reddish box named "House Updater-0.13". A green cylinder "Border Relay-0.08", also by Stoic Mole, is set at the midpoint (128) of each side 2 meters from another of the same in the adjacent Sim (if there is one). These are apparently used by LL to update these areas.[[User:LepreKhaun Resident|LepreKhaun Resident]] 11:27, 21 December 2013 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185406
Talk:LSL Script Memory
2013-12-21T16:45:47Z
<p>LepreKhaun Resident: /* Size of Strings under Question */</p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).] [[User:LepreKhaun Resident|LepreKhaun Resident]] 18:17, 19 December 2013 (PST)<br />
<br />
::If you look at my own page, [[https://wiki.secondlife.com/wiki/User:Omei_Qunhua]], and one by Pedro Oval, [[http://wiki.secondlife.com/wiki/User:Pedro_Oval/Mono_code_memory_usage]] , you will see our findings for Mono usage for a large number of code snippets. These were obtained generally by replicating the snippet 512 times, which obviates the effect of Mono's 512-byte memory grabbing forays. I balked at trying to do the same for strings, as I have a feeling the strings would need to have different contents each time. But another technique I have used, is to add a series of minimum-space padding code snippets, until I observe the memory usage jumping to the next 512 multiple, doing this both with and without my target bit of code to be measured, and hence one can compute the space used by the target code. These padding code fragments were first measured via the 512-times approach. e.g. You could use a series of x; (at 2 bytes each) or x++; (at 8 bytes each) etc. But the occasional interference by garbage collection at run time, still makes the exercise a bit fraught at times. Hope this helps [[User:Omei Qunhua|Omei Qunhua]] 19:04, 19 December 2013 (PST)<br />
:::Thank you, I've read those pages. Back to my original question, am I looking at a 48 byte base for local strings or not? And if not, where is the error in my approach?[[User:LepreKhaun Resident|LepreKhaun Resident]] 21:43, 19 December 2013 (PST)<br />
<br />
::::I did some tests today based on your code, but using llGetUsedMemory(). Results were not consistent. Strings assigned to named variables within an event gave an overhead of from 40 to 50 bytes per string (plus the 2 bytes per character). Defining global strings suggested a larger overhead around 60 bytes per string. Strings coded within an event but not assigned to named variables, gave 12 bytes overhead per string. Rather depressing reading :) [[User:Omei Qunhua|Omei Qunhua]] 08:49, 20 December 2013 (PST)<br />
<br />
::::Pedro Oval also saw non-consistent results from strings etc. [[https://wiki.secondlife.com/w/index.php?title=User_talk:Omei_Qunhua&oldid=1175754]] [[User:Omei Qunhua|Omei Qunhua]] 15:57, 20 December 2013 (PST)<br />
<br />
:::::Well strings are always funny critters and SLMono is provably non-deterministic at times. One thing I see lacking on the fronting page is the fact that the SLMono implementation has a base cost of 3364 bytes per program. That is to say, the minimal default state with one event is taking that amount off the top from the gitgo. I believe under LS0 it was 220-230 bytes???[[User:LepreKhaun Resident|LepreKhaun Resident]] 08:39, 21 December 2013 (PST)<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185405
Talk:LSL Script Memory
2013-12-21T16:39:47Z
<p>LepreKhaun Resident: /* Size of Strings under Question */</p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).] [[User:LepreKhaun Resident|LepreKhaun Resident]] 18:17, 19 December 2013 (PST)<br />
<br />
::If you look at my own page, [[https://wiki.secondlife.com/wiki/User:Omei_Qunhua]], and one by Pedro Oval, [[http://wiki.secondlife.com/wiki/User:Pedro_Oval/Mono_code_memory_usage]] , you will see our findings for Mono usage for a large number of code snippets. These were obtained generally by replicating the snippet 512 times, which obviates the effect of Mono's 512-byte memory grabbing forays. I balked at trying to do the same for strings, as I have a feeling the strings would need to have different contents each time. But another technique I have used, is to add a series of minimum-space padding code snippets, until I observe the memory usage jumping to the next 512 multiple, doing this both with and without my target bit of code to be measured, and hence one can compute the space used by the target code. These padding code fragments were first measured via the 512-times approach. e.g. You could use a series of x; (at 2 bytes each) or x++; (at 8 bytes each) etc. But the occasional interference by garbage collection at run time, still makes the exercise a bit fraught at times. Hope this helps [[User:Omei Qunhua|Omei Qunhua]] 19:04, 19 December 2013 (PST)<br />
:::Thank you, I've read those pages. Back to my original question, am I looking at a 48 byte base for local strings or not? And if not, where is the error in my approach?[[User:LepreKhaun Resident|LepreKhaun Resident]] 21:43, 19 December 2013 (PST)<br />
<br />
::::I did some tests today based on your code, but using llGetUsedMemory(). Results were not consistent. Strings assigned to named variables within an event gave an overhead of from 40 to 50 bytes per string (plus the 2 bytes per character). Defining global strings suggested a larger overhead around 60 bytes per string. Strings coded within an event but not assigned to named variables, gave 12 bytes overhead per string. Rather depressing reading :) [[User:Omei Qunhua|Omei Qunhua]] 08:49, 20 December 2013 (PST)<br />
<br />
::::Pedro Oval also saw non-consistent results from strings etc. [[https://wiki.secondlife.com/w/index.php?title=User_talk:Omei_Qunhua&oldid=1175754]] [[User:Omei Qunhua|Omei Qunhua]] 15:57, 20 December 2013 (PST)<br />
<br />
:::::Well strings are always funny critters and SLMono is provably non-deterministic at times. One thing I see lacking on the fronting page is the fact that the SLMono implementation has a base cost of 3364 bytes per program. That is to say, the minimal default state with one event is taking that amount off the top from the gitgo.[[User:LepreKhaun Resident|LepreKhaun Resident]] 08:39, 21 December 2013 (PST)<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185346
Talk:LSL Script Memory
2013-12-20T05:43:06Z
<p>LepreKhaun Resident: </p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).] [[User:LepreKhaun Resident|LepreKhaun Resident]] 18:17, 19 December 2013 (PST)<br />
<br />
::If you look at my own page, [[https://wiki.secondlife.com/wiki/User:Omei_Qunhua]], and one by Pedro Oval, [[http://wiki.secondlife.com/wiki/User:Pedro_Oval/Mono_code_memory_usage]] , you will see our findings for Mono usage for a large number of code snippets. These were obtained generally by replicating the snippet 512 times, which obviates the effect of Mono's 512-byte memory grabbing forays. I balked at trying to do the same for strings, as I have a feeling the strings would need to have different contents each time. But another technique I have used, is to add a series of minimum-space padding code snippets, until I observe the memory usage jumping to the next 512 multiple, doing this both with and without my target bit of code to be measured, and hence one can compute the space used by the target code. These padding code fragments were first measured via the 512-times approach. e.g. You could use a series of x; (at 2 bytes each) or x++; (at 8 bytes each) etc. But the occasional interference by garbage collection at run time, still makes the exercise a bit fraught at times. Hope this helps [[User:Omei Qunhua|Omei Qunhua]] 19:04, 19 December 2013 (PST)<br />
:::Thank you, I've read those pages. Back to my original question, am I looking at a 48 byte base for local strings or not? And if not, where is the error in my approach?[[User:LepreKhaun Resident|LepreKhaun Resident]] 21:43, 19 December 2013 (PST)<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185338
Talk:LSL Script Memory
2013-12-20T02:17:42Z
<p>LepreKhaun Resident: Sig got lost...</p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).] [[User:LepreKhaun Resident|LepreKhaun Resident]] 18:17, 19 December 2013 (PST)<br />
<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185337
Talk:LSL Script Memory
2013-12-20T01:34:56Z
<p>LepreKhaun Resident: A bit of clarification on where I'm coming from.</p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br> [ETA This may really require a disambiguation page, LSO and SL's implementation of Mono are wickedly different. I'd suggest rolling back this to strictly LSO (which, in my limited experimentation, holds still) and having a link to the SL Mono implementation memory allocation. This would end the ambiguity of what applies when as well as separating what is known fact (LSO) from what might be supposed from working with the black box that is the SL Mono implementation (which does NOT conform with strict Mono btw).]<br />
<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185336
Talk:LSL Script Memory
2013-12-20T01:08:15Z
<p>LepreKhaun Resident: </p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
<br />
::::Um ... I think the attached page needs some serious editing as a lot of those figures relate to "Pre Mono" or LSO. Strife suggested a rewrite in December 2012. No one has done it yet. :( [[User:Omei Qunhua|Omei Qunhua]] 16:27, 19 December 2013 (PST)<br />
:::::I am in so much agreement, what with other discrepancies being found by my testing methods (which may or may not be correct, the algorithms are still being refined).<br>The problem (as I see it) is that anyone can post a table of figures- a string/float/vector/operator is "that many bytes" of your program. But no one is showing the underlying algorithm (verification coding in LSL) they use to obtain those "facts". Lacking peer review of derivative algorithms, it really is impossible to determine how the SL implementation of Mono is deriving our program size at any given point.<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185326
Talk:LSL Script Memory
2013-12-19T23:56:34Z
<p>LepreKhaun Resident: </p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
::Hello LepreKhaun. This page [[https://wiki.secondlife.com/wiki/String]] states that strings in Mono are encoded in UTF-16 and require 2 bytes per character. [[User:Omei Qunhua|Omei Qunhua]] 14:55, 19 December 2013 (PST)<br />
:::Yes, you're right, though the page fronting this states (within a local scope) it is only 1 byte per char. But then that makes my observation even more so- apparently the base cost of each string is '''twice''' what I was looking at, app '''48 bytes''' (which is '''4 times''' that of what is shown on the page fronting this). Yes?<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Script_Memory&diff=1185277
Talk:LSL Script Memory
2013-12-19T21:06:17Z
<p>LepreKhaun Resident: </p>
<hr />
<div>Has anyone tested the new MONO environment for memory usage? It seems its very different from the previous LSO numbers... I think a new section for MONO is needed.--[[User:Darwin Recreant|Darwin Recreant]] 21:21, 4 December 2008 (UTC)<br />
== Size of Strings under Question ==<br />
Unsure of code used by others to determine the size of a local string under Mono but my testing seems to show that a string is approximately 24 bytes + 1 per char. This is the code I'm using with the length of variable "i" such that the addition of one more character causes another page being allocated for memory used. Uncommenting each Test in turn and rerunning it with one additional character in any of the string variables (to show that you are actually at the edge of a page) should show you what I'm finding. Perhaps I'm misinterpreting the results???<br />
<LSL>default<br />
{<br />
state_entry()<br />
{<br />
// Test 1, add one char to string for memory jump of a page<br />
string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn";<br />
<br />
// Test 2 - difference of 32 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi";<br />
// string j = "a";<br />
<br />
// Test 3 - difference of 27 bytes in variable "i"<br />
// string i = "abcdefghijklmnopqrstuvwxyzabcdefgh";<br />
// string j = "a"; <br />
// string k = "b";<br />
<br />
// Test 4 - difference of 26 bytes in variable "i"<br />
// string i = "abcdefgh";<br />
// string j = "a";<br />
// string k = "b";<br />
// string l = "c";<br />
<br />
<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
}</LSL> [[User:LepreKhaun Resident|LepreKhaun Resident]] 13:06, 19 December 2013 (PST)<br />
<br />
=== Needed Updates ===<br />
Using the script below I found a few unusual things happening. One of them seems to be a change in free script memory at the time of compilation. This script provided the data listed below it.<lsl>integer count;<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
llSetTimerEvent(1.0);<br />
}<br />
timer()<br />
{<br />
llOwnerSay((string)llGetFreeMemory() + " , " + (string)(++count));<br />
list l = ["", "", "", ""];<br />
llOwnerSay((string)llGetFreeMemory());<br />
}<br />
touch_start(integer detected)<br />
{<br />
llResetScript();<br />
}<br />
}</lsl><lsl>[22:44] EddyFragment Robonaught: Test Begins<br />
[22:44] Object: 60664 , 1//Only just recompiled for touch reset.<br />
[22:44] Object: 60664<br />
[22:44] Object: 60664 , 2<br />
[22:44] Object: 60628 //Then evens out<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 5<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 6<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 7<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 8<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 9<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 10<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1//After a touch reset<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 3<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 4<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:44] Object: 60628 , 2<br />
[22:44] Object: 60628<br />
[22:44] Object: 60664 , 1<br />
[22:44] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//But this would happen (it seemed to me) after letting the script run a little more before the reset<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 3<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 4<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 7<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 8<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 9<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 10<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 11<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 12<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 2<br />
[22:45] Object: 60628<br />
[22:45] Object: 60664 , 1//And here again<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 2<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 3<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 4<br />
[22:45] Object: 60664<br />
[22:45] Object: 60664 , 5<br />
[22:45] Object: 60628<br />
[22:45] Object: 60628 , 6<br />
[22:45] Object: 60628</lsl> -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:01, 2 July 2009 (UTC)<br />
<br />
:This is interesting. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:36, 2 July 2009 (UTC)<br />
<br />
Thanks for the confidence boost and I thought so too. If getting inworld is still a problem for you tell me what to run and I'll happily do it for you. Otherwise ''my'' tests might be a bit less than useful. Those repeated 60664's are weird though. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 23:53, 2 July 2009 (UTC)<br />
<br />
It seems llGetFreeMemory() does not show true value and is dependent on sim performance (random like) on getting updated. I guess the only way to know true impact of operations and variables can only be tested after many subsequent tries similar to Eddy's method. --[[User:Darwin Recreant|Darwin Recreant]] 08:51, 10 December 2009 (UTC)<br />
<br />
I'd say the above observations were due the the random involvement of garbage collection. If you do an llSleep(2.0) or so before accessing llGetFreeMemory() you'll give garbage collection a good chance to get in, and results will be more consistent. But running this code in December 2012 did not show variation for me. So I'd guess this is an obsolete observation and this page can be revised down in size? [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
'''List Storage Requirements (Mono) need updating'''<br />
<br />
It appears that the storage requirements for lists in Mono have changed since this page was written. I plan to change the figures to those experienced in December 2012 as shown on my user page, unless anyone disagrees. [[User:Omei Qunhua|Omei Qunhua]] 17:27, 28 December 2012 (PST)<br />
<br />
:I would almost be inclined to suggest rewriting the article from scratch. It's an old article which had Mono info bolted one after the fact. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 21:13, 28 December 2012 (PST)<br />
<br />
<br />
The article talks about datas collected by llGetFreemomry and not llGetUsedMemory . Are the samples collected recently using always this old function ? <br />
Shouldn t have we some datas collected by llGetUsedMemory ? -- [[User:Miranda Umino|Miranda Umino]] 14:21, 16 February 2013 (PST)<br />
<br />
=Update pending=<br />
<lsl><br />
////////////////////////////////////////////////////////////////////////////////<br />
// <br />
// Script memory - work in progress<br />
// <br />
// (c) 1012<br />
// llDeleteSubString( "yepey Resident", llSubstringIndex( "yepey Resident", " " ), -1 );<br />
// <br />
// The script won't compile due to previously decalerd variables.<br />
// This script will, when finished, replace all of the above.<br />
// <br />
// Regards,<br />
// yepey<br />
// <br />
// <br />
// GLOBAL VARIABLES<br />
// --------------------------------------------------------------------<br />
integer int = 0; // 8<br />
float fl = 0.0; // 8<br />
string str = ""; // 22<br />
string str = "a"; // 22 + 2<br />
string str = "\n"; // 22 + 2<br />
key id = ""; // 8<br />
key id = NULL_KEY; // 8<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 8<br />
vector v = ZERO_VECTOR; // 16<br />
vector v = < 0, 0, 0 >; // 16<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 44<br />
list l = [ // 44 + o.O<br />
0, // 28<br />
1.0, // 28<br />
"", // 30<br />
"a", // 32<br />
"\n", // 32<br />
NULL_KEY, // 102<br />
ZERO_VECTOR, // 36<br />
ZERO_ROTATION // 40<br />
];<br />
<br />
default<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
// LOCAL VARIABLES<br />
// ------------------------------------------------------------------------<br />
integer int = 0; // 4<br />
float fl = 0.0; // 4<br />
string str = ""; // 18 +<br />
string str = "a"; // 2<br />
string str = "\n"; // 2<br />
key id = ""; // 4<br />
key id = NULL_KEY; // 4<br />
key id = "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"; // 4<br />
vector v = ZERO_VECTOR; // 12<br />
vector v = < 0, 0, 0 >; // 12<br />
rotation r = ZERO_ROTATION; // 16<br />
rotation r = < 0, 0, 0, 1 >; // 16<br />
list l = []; // 40<br />
list l = [ // 40 + o.O<br />
0, // 16<br />
1.0, // 16<br />
"", // 18 +<br />
"a", // 2<br />
"\n", // 2<br />
NULL_KEY, // 90<br />
ZERO_VECTOR, // 24<br />
ZERO_ROTATION // 28<br />
];<br />
<br />
}<br />
<br />
}<br />
<br />
state examples<br />
{<br />
<br />
state_entry()<br />
{<br />
<br />
/* IMPLEMENTATION NEEDED */<br />
<br />
}<br />
<br />
}<br />
</lsl><br />
[[User:Joanne Furlough|Joanne Furlough]] 20:07, 5 May 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=LlGetTextureRot&diff=1185079
LlGetTextureRot
2013-12-14T18:37:17Z
<p>LepreKhaun Resident: Return value clarified to match llRotateTexture.</p>
<hr />
<div>{{LSL_Function<br />
|inject-2={{LSL_Function/face|face|return=0.0}}<br />
{{LSL_Function/angle|angle}}<br />
|func_id=180|func_sleep=0.0|func_energy=10.0<br />
|func=llGetTextureRot<br />
|return_type=float|p1_type=integer|p1_name=face<br />
|func_footnote<br />
|func_desc<br />
|return_text=that is the texture rotation, expressed as an {{LSLP|angle}}, on {{LSLP|face}}<br />
|spec<br />
|caveats<br />
|constants<br />
|examples=<lsl>//Tells the owner the texture rotation on all sides<br />
default<br />
{<br />
state_entry()<br />
{<br />
integer i = 0;<br />
integer max = llGetNumberOfSides();<br />
while(i < max)<br />
{<br />
llSay(0,"Face "+(string)i+" texture rotation is " + (string)llGetTextureRot(i));<br />
++i;<br />
}<br />
}<br />
}</lsl><br />
|helpers<br />
|also_functions={{LSL DefineRow||[[llRotateTexture]]|}}<br />
{{LSL DefineRow||[[llGetNumberOfSides]]|}}<br />
|also_tests<br />
|also_events<br />
|also_articles<br />
|notes<br />
|cat1=Texture<br />
|cat2=Face<br />
|cat3<br />
|cat4<br />
}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=LlDialog&diff=1183560
LlDialog
2013-11-13T19:18:01Z
<p>LepreKhaun Resident: Added necessary clarification to Caveats.</p>
<hr />
<div>{{LSL_Function<br />
|func=llDialog<br />
|sort=Dialog<br />
|func_id=247|func_sleep=1.0|func_energy=10.0<br />
|inject-2=<br />
{{Issues/VWR-17064}}<br />
{{Issues/VWR-14537}}<br />
{{Issues/SVC-1815}}<br />
{{Issues/SCR-43}}<br />
{{LSL_Function/avatar|avatar|sim=*}}<br />
{{LSL_Function/chat|channel|message|dialog=dialog box}}<br />
|p1_type=key|p1_name=avatar|p1_desc<br />
|p2_type=string|p2_name=message|p2_desc<br />
|p3_type=list|p3_name=buttons|p3_desc=button labels<br />
|p4_type=integer|p4_name=channel|p4_desc<br />
|func_desc=Shows a dialog box in the lower right corner of the {{LSLP|avatar}}'s screen (upper right in Viewer 1.x) with a {{LSLP|message}} and choice {{LSLP|buttons}}, as well as an ignore button. This has many uses ranging from simple message delivery to complex menu systems.<br />
|func_footnote=When a button is pressed, the {{LSLP|avatar}} says the text of the button label on {{LSLP|channel}}.<br/>The position where the chat is generated is where the root prim of the dialog generating object was when the dialog button was pressed.<br />
|spec<br />
|caveats=<br />
*This function '''only''' opens a dialog box. The script must then also register a listener on the same ''channel'' using [[llListen]] and have a [[listen]] event handler to receive the response.<br />
*There is no way by script to kill a dialog box.<br />
*There is no way for the script to detect if the user clicked the small "Ignore" button (no chat is generated as a result of pressing this button).<br />
*There is no way to distinguish the input from a dialog box and regular chat made by the same user.<br />
**It is important to expect that the response may not be one of the buttons.<br />
*In 99.9% of cases, the listener will be in the same script as the llDialog, however in the vary rare case, if the distance between the root prim of the [[listen]]ing object and the dialog generating prim is greater than 20 meters when a button is pressed, the response will not be heard. See [[#Limits]].<br />
**This limitation affects attachments too if the wearer moves more than 20 meters from where the listener is located. See [[#Limits]].<br />
**If the [[listen]]er resides in the same script that created the dialog, then the dialog button is heard sim-wide.<br />
----<br />
*The '''dialog response''' (the generated chat) has its in world location at the '''root prim's global position'''.<br />
: It can generate a listen event within 20 meters from that position.<br />
*The listening location for a child prim in the object is either at the child prim's location or at the root prim's location<br />
: see bugtrace JIRA [https://jira.secondlife.com/browse/SCR-43 SCR-43]<br />
<br />
===<tt>message</tt> limits===<br />
*{{LSLP|message}} must be fewer than 512 bytes in length and be not empty. If it is empty, llDialog will shout "llDialog: must supply a message" on the [[DEBUG_CHANNEL]]. If you want to create an empty message, however, you can do it legally by using a line feed as your message, as in <lsl>llDialog(avatar_key," \n",button_list,dialog_channel);</lsl> If the message length is greater than or equal to 512 bytes, it shouts (again on the [[DEBUG_CHANNEL|debug channel]]): "llDialog: message too long, must be less than 512 characters"; in both instances, the dialog box will not be created for {{LSLP|avatar}}.<br />
*The client only displays 8 lines of {{LSLP|message}}. If it is longer, the dialog has a scroll bar. See [[#Appearance]].<br />
Note: this should be 7 lines in message; one of the 8 lines is the owner and name of the object.<br />
<br />
===<tt>buttons</tt> limits===<br />
*If {{LSLP|buttons}} is an empty list, it will default to as if it were <code>["OK"]</code><br />
*If a button is named "Ignore", it will behave like the small "Ignore" button of the menu (i.e. pressing it will *not* get "Ignore" sent to the menu channel). If you need an "Ignore" button in your menu and wish to have its name sent back to the script when you press it, then use spaces in the button name (e.g. " Ignore ").<br />
*An error will be shouted on [[DEBUG_CHANNEL]], if...<br />
**there are more than 12 buttons.<br />
**any list item is not a string.<br />
**any list item string length (measured in bytes, using UTF-8 encoding) is zero or greater than 24.<br />
***In other words, a button's text when encoded as UTF-8 cannot be longer than 24 bytes or a empty string.<br />
***This snippet can be used to truncate the string without giving an error: <code>llBase64ToString(llGetSubString(llStringToBase64(theString), 0, 31))</code><br />
*The client will not display all the characters of a button if the text is wider than the text space of the button. See [[#Appearance]].<br />
*If the script generates button labels from outside sources like inventory or object names, take care to avoid the special string "!!llTextBox!!". This text, in button 0, will cause llDialog to behave as [[llTextBox]] instead.<br />
|examples=<br />
<lsl><br />
// When the prim is touched, give the toucher the option of killing the prim.<br />
<br />
integer gListener; // Identity of the listener associated with the dialog, so we can clean up when not needed<br />
<br />
default<br />
{<br />
touch_start(integer total_number)<br />
{<br />
// Kill off any outstanding listener, to avoid any chance of multiple listeners being active<br />
llListenRemove(gListener);<br />
// get the UUID of the person touching this prim<br />
key user = llDetectedKey(0);<br />
// Listen to any reply from that user only, and only on the same channel to be used by llDialog<br />
// It's best to set up the listener before issuing the dialog<br />
gListener = llListen(-99, "", user, "");<br />
// Send a dialog to that person. We'll use a fixed negative channel number for simplicity<br />
llDialog(user, "\nDo you wish this prim to die?", ["Yes", "No" ] , -99);<br />
// Start a one-minute timer, after which we will stop listening for responses<br />
llSetTimerEvent(60.0);<br />
}<br />
listen(integer chan, string name, key id, string msg)<br />
{<br />
// If the user clicked the "Yes" button, kill this prim.<br />
if (msg == "Yes")<br />
llDie();<br />
// The user did not click "Yes" ...<br />
// Make the timer fire immediately, to do clean-up actions<br />
llSetTimerEvent(0.1); <br />
}<br />
timer()<br />
{<br />
// Stop listening. It's wise to do this to reduce lag<br />
llListenRemove(gListener);<br />
// Stop the timer now that its job is done<br />
llSetTimerEvent(0.0);<br />
}<br />
}<br />
</lsl><br />
{{LSL Tip|Please make sure that you close open listeners where possible. You'll make the Second Life experience so much better when paying attention to details here.}}<br />
{{LSL Tip|There are no built-in submenus nor pagination (like in a list with "previous" and "next") when using [[llDialog]]. You simply get one page with a max of 12 buttons, that's it. If you want a different dialog menu layout (other info and/or other buttons), you'll have to build that functionality into your script as the example below demonstrates. }}<br />
<lsl><br />
string mainMenuDialog = "\nWhich settings would you like to access?\nClick \"Close\" to close the menu.\n\nYou are here:\nMainmenu";<br />
list mainMenuButtons = ["sub 01", "sub 02", "Close"];<br />
<br />
string subMenu_01_Dialog = "\nClick \"Close\" to close the menu.\nClick \"-Main-\" to return to the main menu.\n\nYou are here:\nMainmenu > sub 01";<br />
list subMenu_01_Buttons = ["action 01a", "action 01b", "Close", "-Main-"];<br />
<br />
string subMenu_02_Dialog = "\nClick \"Close\" to close the menu.\nClick \"-Main-\" to return to the main menu.\n\nYou are here:\nMainmenu > sub 02";<br />
<br />
list subMenu_02_Buttons = ["action 02a", "action 02b", "Close", "-Main-"];<br />
<br />
integer dialogChannel;<br />
integer dialogHandle;<br />
<br />
open_menu(key inputKey, string inputString, list inputList)<br />
{<br />
dialogChannel = (integer)llFrand(DEBUG_CHANNEL)*-1;<br />
dialogHandle = llListen(dialogChannel, "", inputKey, "");<br />
llDialog(inputKey, inputString, inputList, dialogChannel);<br />
llSetTimerEvent(30.0);<br />
}<br />
<br />
close_menu()<br />
{<br />
llSetTimerEvent(0);<br />
llListenRemove(dialogHandle);<br />
}<br />
<br />
default<br />
{<br />
on_rez(integer start_param)<br />
{<br />
llResetScript();<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
key id = llDetectedKey(0);<br />
// Ensure any outstanding listener is removed before creating a new one<br />
close_menu();<br />
open_menu(id, mainMenuDialog, mainMenuButtons);<br />
}<br />
<br />
listen(integer channel, string name, key id, string message)<br />
{<br />
if(channel != dialogChannel)<br />
return;<br />
<br />
close_menu();<br />
<br />
if(message == "-Main-")<br />
open_menu(id, mainMenuDialog, mainMenuButtons);<br />
<br />
else if(message == "sub 01")<br />
open_menu(id, subMenu_01_Dialog, subMenu_01_Buttons);<br />
<br />
else if(message == "sub 02")<br />
open_menu(id, subMenu_02_Dialog, subMenu_02_Buttons);<br />
<br />
else if (message == "action 01a")<br />
{<br />
//do something<br />
open_menu(id, subMenu_01_Dialog, subMenu_01_Buttons);<br />
}<br />
else if (message == "action 01b")<br />
{<br />
//do something else<br />
<br />
//maybe not re-open the menu for this option?<br />
//open_menu(id, subMenu_01_Dialog, subMenu_01_Buttons);<br />
}<br />
else if (message == "action 02a")<br />
{<br />
//do something<br />
open_menu(id, subMenu_02_Dialog, subMenu_02_Buttons);<br />
}<br />
else if (message == "action 02b")<br />
{<br />
//do something else<br />
open_menu(id, subMenu_02_Dialog, subMenu_02_Buttons);<br />
}<br />
}<br />
<br />
timer()<br />
{<br />
close_menu();<br />
}<br />
}<br />
</lsl><br />
|helpers=<lsl>//Compact function to put buttons in "correct" human-readable order<br />
integer channel;<br />
<br />
list order_buttons(list buttons)<br />
{<br />
return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4)<br />
+ llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);<br />
}<br />
<br />
default<br />
{<br />
state_entry()<br />
{ // Create random channel within range [-1000000000,-2000000000]<br />
channel = (integer)(llFrand(-1000000000.0) - 1000000000.0);<br />
<br />
llListen(channel,"", "","");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
llDialog(llDetectedKey(0),"\nPlease choose an option:\n",<br />
order_buttons(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]),channel);<br />
}<br />
<br />
listen(integer _chan, string _name, key _id, string _option)<br />
{<br />
llSay(0, _name + " selected option " + _option);<br />
}<br />
}</lsl><br />
=== Helper Functions ===<br />
{{{!}}<br />
{{LSL DefineRow||[[User:Void_Singer/Functions#uDlgBtnPagList|uDlgBtnPagList]]|Compact Pagination for [[llDialog]] lists, remenu, and multi-user support}}<br />
{{!}}}<br />
|constants={{#vardefine:constants_nb}}<br />
{{{!}}<br />
{{!}}- valign="top"<br />
{{!}}<br />
{{{!}}{{Prettytable|style=margin-top:0;}}<br />
{{!}}-{{Hl2}}<br />
! colspan="4" {{!}} Button Order<br />
{{!}}-<br />
{{!}}9&nbsp;&nbsp;<br />
{{!}}10<br />
{{!}}11<br />
{{!}}-<br />
{{!}}6<br />
{{!}}7<br />
{{!}}8&nbsp;&nbsp;<br />
{{!}}-<br />
{{!}}3<br />
{{!}}4<br />
{{!}}5<br />
{{!}}-<br />
{{!}}0<br />
{{!}}1<br />
{{!}}2<br />
{{!}}}<br />
{{!}}<br />
{{!}}}<br />
|related<br />
|notes=<br />
To use dialog boxes to make menu systems, see [[Dialog Menus|Dialog Menus: A step by step guide]] (aimed at learners).<br />
<br />
===Tips===<br />
It is a good idea to use a very negative channel (if never more negative than the most negative 32-bit integer that is -2,147,483,648), ''e.g.'',<br />
<lsl>// Create random channel within range [-1000000000,-2000000000]<br />
integer channel = (integer)(llFrand(-1000000000.0) - 1000000000.0);<br />
<br />
llDialog(llDetectedKey(0), "Please choose one of the below options:",<br />
["Yes", "No", "0", "1"], channel);</lsl><br />
Negative channels are popular for script communications because the standard SL client is unable to chat directly on those channels. The only way to do so prior to [[llTextBox]] was to use [[llDialog]] which was limited to 24 bytes. (Several third party viewers can access them from the chat bar.)<br />
<br />
You can be reasonably confident that all of your scripted objects have a unique chat channel with this small function:<br />
<br />
<lsl>integer dialog_channel; // top of script in variables<br />
<br />
integer channel() { // top of script in functions<br />
return (integer)("0x"+llGetSubString((string)llGetKey(),-8,-1));<br />
}<br />
<br />
dialog_channel = channel(); // somewhere in actual script execution, such as state_entry()</lsl><br />
<br />
'''Note:''' Since this function uses public information to generate the channel number it should by no means considered secret.<br />
<br />
The preceding code can produce both positive and negative channels, depending on the 8th to last character of the key.<br />
The following examples will always produce negative channels:-<br />
<lsl><br />
gChannel = 0x80000000 | (integer)("0x"+(string)llGetKey());<br />
gChannel = 0x80000000 | (integer)("0x"+(string)llGetOwner());<br />
</lsl> <br />
<br />
This next version returns a channel number between -1073741823 (0xBFFFFFFF) and -2147483648 (0x80000000). It is also only one line of code.<br />
<lsl>privchan = ((integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;</lsl><br />
<br />
===Appearance===<br />
<br />
If {{LSLP|message}} requires more than 8 lines, a vertical scroll bar will appear in the dialog.<br />
: In viewer 3 there is no scroll bar, only the 512 chars message limit is effective, so you may show more than 40 short lines in the message<br />
: Too many lines will hide some of the buttons or all of them outside the window though<br />
<br />
The message text can be formatted somewhat using "\n" (for newline) and "\t" (for tab). If URLs are in the text, they will appear as clickable links, and some [[Viewer URI Name Space|viewer application URLs]] will receive special formatting. (Clickable links were not available before Viewer 2.) You can do nothing though to influence the font face, size or weight.<br />
<br />
There is no way to change the actual size of the dialog, nor change its color.<br />
<br />
The average number of characters that can be displayed on a dialog line is about 35 characters per line in ASCII7 characters. It depends upon the width of the characters, the viewer version, and font settings.<br />
<br />
The number of characters that can be displayed in a button depends upon the width of the characters. You should expect around 10 chars, give or take, not the full 24 in the button definition. The full button definition IS said, up to 24 chars, into the chat channel even though fewer characters may be displayed in the button itself.<br />
<br />
<br />
===Limits===<br />
<br />
My testing shows the a Dialog box now works anywhere in the same Region as the object OR any region it hands you off to (e.g. the region you teleport to). It will not work for any subsequent hand offs. I have tested this with teleport only, I haven't tested it walking between regions. <br />
<br />
I've tested from the next SIM with an Alt, and from 2 SIMs away myself. Both worked without restriction apart from some lag on the messages. (OQ).<br />
<br />
|also_events=<br />
{{LSL DefineRow||[[listen]]|}}<br />
|also_functions=<br />
{{LSL DefineRow||[[llListen]]|}}<br />
{{LSL DefineRow||[[llTextBox]]|}}<br />
{{LSL DefineRow||[[llRegionSay]]|}}<br />
{{LSL DefineRow||[[llWhisper]]|Sends chat limited to 10 meters}}<br />
{{LSL DefineRow||[[llSay]]|Sends chat limited to 20 meters}}<br />
{{LSL DefineRow||[[llShout]]|Sends chat limited to 100 meters}}<br />
{{LSL DefineRow||[[llInstantMessage]]|Sends chat to the specified user}}<br />
{{LSL DefineRow||[[llOwnerSay]]|Sends chat to the owner only}}<br />
|also_tests<br />
|also_articles=<br />
{{LSL DefineRow||[[Dialog Menus|Dialog Menus: A step by step guide]]|A walk through of the entire dialog menu process (aimed at learners).}}<br />
|cat1=Chat<br />
|cat2=Communications<br />
|cat3=Dialog<br />
|cat4}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LlDialog&diff=1183559
Talk:LlDialog
2013-11-13T18:38:56Z
<p>LepreKhaun Resident: Added possible insight to why the confusion may have arisen.</p>
<hr />
<div>Telling an end user that the max length of a button label is 24 bytes ... well, not overly helpful. But there is the problem of what what characters translate to how many bytes. Still, is there any way we can give examples of characters?<br />
<br />
[[User:Chaz Longstaff|Chaz Longstaff]] 05:18, 27 November 2009 (UTC)<br />
<br />
: Can you use a function like this to find long strings? Then the user will not have to guess what button is bad Somebody check my work please, I am sleepy as always.<br />
<lsl>integer GetStringBytes(string s) {<br />
list chopped = llParseString2List(llEscapeURL("*" + s), ["%"], []);<br />
return llStringLength((string)chopped) - llGetListLength(chopped) - 1;<br />
}</lsl><br />
:--[[User:Cerise Sorbet|Cerise Sorbet]] 10:03, 27 November 2009 (UTC)<br />
:: I was too sleepy. Maybe this time. --[[User:Cerise Sorbet|Cerise Sorbet]] 11:06, 27 November 2009 (UTC)<br />
:: Maybe this one will be more nice to memory? --[[User:Cerise Sorbet|Cerise Sorbet]] 13:03, 27 November 2009 (UTC)<br />
<lsl>integer GetStringBytes2(string s) {<br />
s = llEscapeURL(s);<br />
integer i = 0;<br />
integer j;<br />
for (j = llStringLength(s); j > -1; j--)<br />
i += (llGetSubString(s, j, j) == "%");<br />
return llStringLength(s) - i - i;<br />
}</lsl><br />
----<br />
Strife, Chaz here. Most ordinary users in SL, and most user documentation in SL, refer to dialog boxes in SL as menus. While that may be as technically inaccurate as referring to a tomato as a vegetable, people don't look for tomatoes in between the apples and bananas at their green grocer (grin), and they are going to come here looking for info on menus, not dialogue boxes. I think we need to at least acknowledge the word menu, even if we do correct them about its usage right away. (I also dislike how people use the word less when they should be using fewer, but that is also just the way it is, sadly :} )[[User:Chaz Longstaff|Chaz Longstaff]] 18:17, 15 July 2008 (PDT)<br />
<br />
:Very good point. I'll also keep a lookout for improper uses of "less". -- [[User:Strife Onizuka|Strife Onizuka]] 18:32, 15 July 2008 (PDT)<br />
<br />
The Wiki mentions that clicking on a button causes the value to be chatted on the specified channel, but doesn't clarify whether it's simply said(llSay) or shouted(llShout). It does mention that errors will be shouted on the Debug Channel, but I think it's important to clarify this within the Wiki.<br />
--{{User|Deimos Damone}}<br />
<br />
:I have reworded the applicable caveat to clarify the functionality. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 11:49, 15 October 2008 (PDT)<br />
<br />
It may be worth including some explicit explanation of the difference between bytes and unicode characters, especially since the inworld error messages somewhat ambiguously talk about characters, when in fact referring to bytes. -- [[User:Tali Rosca|Tali Rosca]] 10:45, 15 October 2008 (PDT)<br />
<br />
:Many functions use byte limits and not character limits. I think it would be better to make the word "byte" a link to a (new?) subsection of the [[string]] article where that can be better addressed. It would be inappropriate to duplicate this information on multiple articles, it would end up clogging the articles. That said, I'll try to find the best method for presenting this information; as you point out the current caveat is inadequate and more information is needed. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 11:49, 15 October 2008 (PDT)<br />
<br />
::I agree that the actual explanation shouldn't be here, but a link should be fairly prominent, since this is the most likely place people will run into the difference. [[User:Tali Rosca|Tali Rosca]] 12:03, 15 October 2008 (PDT)<br />
<br />
== Multiple dialogs tips ==<br />
<br />
It may worth mention in tips.<br />
<br />
Sending multiple dialogs in a row to one avatar may be inappropriate. In old viewer it creates stack of messages in notification area, which complicates reading other things. In viewer version 2 (as of 16/Sep/2010) newer dialogs replace unanswered dialogs from the same object, so any information and chance to react is lost.<br />
<br />
If you need to present more than 12 options, add buttons for browsing option pages (see [[SimpleDialogMenuSystem]]).<br />
<br />
If dialogs are not requested by user, but rather are triggered by some events, you may want to either queue further events or discard them until the first dialog will be answered, or at least throttle them. In any case, if you are sending many dialogs, there should be an option to stop them. (Making user mute your object is bad because he may then forget to unmute it when he will want to interact with the object again).<br />
<br />
If you just need to report something that does not require an answer, consider using other means of communication. Though, you may still want to send one dialog to draw user's attention.<br />
<br />
[[User:Wicked Winslet|Wicked Winslet]] 12:25, 16 September 2010 (UTC)<br />
<br />
== Example ==<br />
<br />
the first example is very likely to stop working over time with a "too many listens" error in a multi-user environment. Cause: any user that clicks on the object will generate a new listen handle, but only the last one is saved, so only the last one is closed. any user (including the current) that touches the prim before the current user has clicked on a dialog response (or within 60seconds if they do not, or click cancel on the dialog) will cause the current open listen handle to advance, and the previous one will never be closed.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 12:03, 13 January 2013 (PST)<br />
:: I suspect the prim will have died long before that LOL. But you have a point [[User:Omei Qunhua|Omei Qunhua]] 13:47, 13 January 2013 (PST)<br />
<br />
:: In fact it would have to be clicked by 65 different users all choosing to ignore the dialog. A subsequent listen using the same filters as a previous is assigned to the same handle. (Thanks Pedro and Innula) [[User:Omei Qunhua|Omei Qunhua]] 10:30, 14 January 2013 (PST)<br />
<br />
Also in the first example, the call to llDialog() happens before the listen is created. In my experience it's possible for this to result in a situation where the dialog is shown to the user and, if they click fast enough, the reply is lost. Might it be a good idea to do it the other way round? [[User:Antony Fairport|Antony Fairport]] 05:29, 16 January 2013 (PST)<br />
<br />
:: Wow, you type fast! I couldn't even move my mouse onto the dialog window that fast. Anyway I changed it. Example #2 had the same remote possibility of accumulating active listeners, I believe. [[User:Omei Qunhua|Omei Qunhua]] 08:10, 16 January 2013 (PST)<br />
<br />
::: Admittedly it's unlikely to be an issue with that actual example but it's possible that a dialog that spawns a dialog that spawns a dialog... (etc) will have someone camping on a button and a reply can get missed. So I was just thinking it might be an idea to encourage starting the listen fist. [[User:Antony Fairport|Antony Fairport]] 08:25, 16 January 2013 (PST)<br />
<br />
== Where's order_buttons? ==<br />
Didn't there used to be an example of that very useful helper function, order_buttons(), on this page? Unless there was a particular reason for removing it, I think it would be good to have it back. [[User:Innula Zenovka|Innula Zenovka]] 11:27, 18 February 2013 (PST)<br />
: It's back, a name collision hid it. --[[User:ObviousAltIsObvious Resident|ObviousAltIsObvious Resident]] 12:11, 18 February 2013 (PST)<br />
<br />
== Fundamental flaw in first code sample (fails to remove multiple listeners) ==<br />
<br />
The first code sample has the following fundamental problem (as can be easily demonstrated): at any point in time there can be '''multiple''' listeners attached because any number of users can click on the prim. But the script sample has only '''one''' global variable to keep track of it. Result: The last user to click on the prim "wins" in the sense that whoever closes the dialog first will remove his listener. All other listeners will remain active.<br />
<br />
The obvious mediation is <br />
# either to introduce a more sophisticated listener tracking (and most likely some form of polling in a regular timer event) <br />
# or to keep it simple and introduce a single static listener, omitting the need for a timer event altogether.<br />
<br />
I personally opt for the latter. If there are no objections I can make those changes. Proposal:<br />
<br />
<lsl><br />
// When the prim is touched, give the toucher the option of killing the prim.<br />
<br />
integer gListener; // Identity of the listener associated with the dialog, so we can clean up when not needed<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
// Set up a listener for potential llDialog() calls<br />
// it might seem like a waste at this stage, but overall it is way more efficient<br />
// than trying to track listeners on a per-user basis<br />
gListener = llListen(-99, "", NULL_KEY, "");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// get the UUID of the person touching this prim<br />
key user = llDetectedKey(0);<br />
// Send a dialog to that person. We'll use a fixed negative channel number for simplicity<br />
llDialog(user, "\nDo you wish this prim to die?", ["Yes", "No" ] , -99);<br />
}<br />
listen(integer chan, string name, key id, string msg)<br />
{<br />
// If the user clicked the "Yes" button, kill this prim.<br />
if (msg == "Yes")<br />
llDie();<br />
}<br />
}<br />
</lsl><br />
<br />
Btw, the same fundamental flaw is present in the tutorial https://wiki.secondlife.com/wiki/Dialog_Menus .<br />
<br />
Edit: the second code sample contains the flaw, too<br />
<br />
--[[User:LovingAndRejected Resident|LovingAndRejected Resident]] 05:37, 13 November 2013 (PST)<br />
<br />
: I'm not seeing where the multiple listens will come from given that the touch event (in the first sample on this page) removes any previous listen. [[User:Antony Fairport|Antony Fairport]] 08:42, 13 November 2013 (PST)<br />
: Agreed. llListenRemove(gListener) will close any pre-existing instance of gListener. Because a dialog box will never self-cancel and we have no way to detect whether a user has clicked "Ignore", it is necessary to include a timer that will remove the listen handle as well.[[User:Rolig Loon|Rolig Loon]] 09:06 13 November 2013 (PST)<br />
: Your understanding of the examples is incomplete. As written, they do close any possible open listeners before registering another. Note the first line within the touch_start() event handler of the first example, which is commented to that effect, and the call to close_menu() in the second.<br />
: Your proposed change goes against the preferred practice of only opening a listener when required and then closing it immediately afterwards. The (still present under Mono) overhead involved with each and every open listener on a sim should be considered by the scripter. [[User:LepreKhaun Resident|LepreKhaun Resident]] 09:24, 13 November 2013 (PST)<br />
:Ahhh, I now see that there '''is''' a problem with the page though! It does imply that listeners are being registered by the '''llDialog();''' call by not explicitly stating that the function merely opens a dialog menu and it is '''llListen();''' which opens the listener. That is confusing and should be corrected imo. [[User:LepreKhaun Resident|LepreKhaun Resident]] 10:38, 13 November 2013 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Talk:LlDialog&diff=1183558
Talk:LlDialog
2013-11-13T17:24:19Z
<p>LepreKhaun Resident: Comment added to proposed change in examples.</p>
<hr />
<div>Telling an end user that the max length of a button label is 24 bytes ... well, not overly helpful. But there is the problem of what what characters translate to how many bytes. Still, is there any way we can give examples of characters?<br />
<br />
[[User:Chaz Longstaff|Chaz Longstaff]] 05:18, 27 November 2009 (UTC)<br />
<br />
: Can you use a function like this to find long strings? Then the user will not have to guess what button is bad Somebody check my work please, I am sleepy as always.<br />
<lsl>integer GetStringBytes(string s) {<br />
list chopped = llParseString2List(llEscapeURL("*" + s), ["%"], []);<br />
return llStringLength((string)chopped) - llGetListLength(chopped) - 1;<br />
}</lsl><br />
:--[[User:Cerise Sorbet|Cerise Sorbet]] 10:03, 27 November 2009 (UTC)<br />
:: I was too sleepy. Maybe this time. --[[User:Cerise Sorbet|Cerise Sorbet]] 11:06, 27 November 2009 (UTC)<br />
:: Maybe this one will be more nice to memory? --[[User:Cerise Sorbet|Cerise Sorbet]] 13:03, 27 November 2009 (UTC)<br />
<lsl>integer GetStringBytes2(string s) {<br />
s = llEscapeURL(s);<br />
integer i = 0;<br />
integer j;<br />
for (j = llStringLength(s); j > -1; j--)<br />
i += (llGetSubString(s, j, j) == "%");<br />
return llStringLength(s) - i - i;<br />
}</lsl><br />
----<br />
Strife, Chaz here. Most ordinary users in SL, and most user documentation in SL, refer to dialog boxes in SL as menus. While that may be as technically inaccurate as referring to a tomato as a vegetable, people don't look for tomatoes in between the apples and bananas at their green grocer (grin), and they are going to come here looking for info on menus, not dialogue boxes. I think we need to at least acknowledge the word menu, even if we do correct them about its usage right away. (I also dislike how people use the word less when they should be using fewer, but that is also just the way it is, sadly :} )[[User:Chaz Longstaff|Chaz Longstaff]] 18:17, 15 July 2008 (PDT)<br />
<br />
:Very good point. I'll also keep a lookout for improper uses of "less". -- [[User:Strife Onizuka|Strife Onizuka]] 18:32, 15 July 2008 (PDT)<br />
<br />
The Wiki mentions that clicking on a button causes the value to be chatted on the specified channel, but doesn't clarify whether it's simply said(llSay) or shouted(llShout). It does mention that errors will be shouted on the Debug Channel, but I think it's important to clarify this within the Wiki.<br />
--{{User|Deimos Damone}}<br />
<br />
:I have reworded the applicable caveat to clarify the functionality. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 11:49, 15 October 2008 (PDT)<br />
<br />
It may be worth including some explicit explanation of the difference between bytes and unicode characters, especially since the inworld error messages somewhat ambiguously talk about characters, when in fact referring to bytes. -- [[User:Tali Rosca|Tali Rosca]] 10:45, 15 October 2008 (PDT)<br />
<br />
:Many functions use byte limits and not character limits. I think it would be better to make the word "byte" a link to a (new?) subsection of the [[string]] article where that can be better addressed. It would be inappropriate to duplicate this information on multiple articles, it would end up clogging the articles. That said, I'll try to find the best method for presenting this information; as you point out the current caveat is inadequate and more information is needed. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 11:49, 15 October 2008 (PDT)<br />
<br />
::I agree that the actual explanation shouldn't be here, but a link should be fairly prominent, since this is the most likely place people will run into the difference. [[User:Tali Rosca|Tali Rosca]] 12:03, 15 October 2008 (PDT)<br />
<br />
== Multiple dialogs tips ==<br />
<br />
It may worth mention in tips.<br />
<br />
Sending multiple dialogs in a row to one avatar may be inappropriate. In old viewer it creates stack of messages in notification area, which complicates reading other things. In viewer version 2 (as of 16/Sep/2010) newer dialogs replace unanswered dialogs from the same object, so any information and chance to react is lost.<br />
<br />
If you need to present more than 12 options, add buttons for browsing option pages (see [[SimpleDialogMenuSystem]]).<br />
<br />
If dialogs are not requested by user, but rather are triggered by some events, you may want to either queue further events or discard them until the first dialog will be answered, or at least throttle them. In any case, if you are sending many dialogs, there should be an option to stop them. (Making user mute your object is bad because he may then forget to unmute it when he will want to interact with the object again).<br />
<br />
If you just need to report something that does not require an answer, consider using other means of communication. Though, you may still want to send one dialog to draw user's attention.<br />
<br />
[[User:Wicked Winslet|Wicked Winslet]] 12:25, 16 September 2010 (UTC)<br />
<br />
== Example ==<br />
<br />
the first example is very likely to stop working over time with a "too many listens" error in a multi-user environment. Cause: any user that clicks on the object will generate a new listen handle, but only the last one is saved, so only the last one is closed. any user (including the current) that touches the prim before the current user has clicked on a dialog response (or within 60seconds if they do not, or click cancel on the dialog) will cause the current open listen handle to advance, and the previous one will never be closed.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 12:03, 13 January 2013 (PST)<br />
:: I suspect the prim will have died long before that LOL. But you have a point [[User:Omei Qunhua|Omei Qunhua]] 13:47, 13 January 2013 (PST)<br />
<br />
:: In fact it would have to be clicked by 65 different users all choosing to ignore the dialog. A subsequent listen using the same filters as a previous is assigned to the same handle. (Thanks Pedro and Innula) [[User:Omei Qunhua|Omei Qunhua]] 10:30, 14 January 2013 (PST)<br />
<br />
Also in the first example, the call to llDialog() happens before the listen is created. In my experience it's possible for this to result in a situation where the dialog is shown to the user and, if they click fast enough, the reply is lost. Might it be a good idea to do it the other way round? [[User:Antony Fairport|Antony Fairport]] 05:29, 16 January 2013 (PST)<br />
<br />
:: Wow, you type fast! I couldn't even move my mouse onto the dialog window that fast. Anyway I changed it. Example #2 had the same remote possibility of accumulating active listeners, I believe. [[User:Omei Qunhua|Omei Qunhua]] 08:10, 16 January 2013 (PST)<br />
<br />
::: Admittedly it's unlikely to be an issue with that actual example but it's possible that a dialog that spawns a dialog that spawns a dialog... (etc) will have someone camping on a button and a reply can get missed. So I was just thinking it might be an idea to encourage starting the listen fist. [[User:Antony Fairport|Antony Fairport]] 08:25, 16 January 2013 (PST)<br />
<br />
== Where's order_buttons? ==<br />
Didn't there used to be an example of that very useful helper function, order_buttons(), on this page? Unless there was a particular reason for removing it, I think it would be good to have it back. [[User:Innula Zenovka|Innula Zenovka]] 11:27, 18 February 2013 (PST)<br />
: It's back, a name collision hid it. --[[User:ObviousAltIsObvious Resident|ObviousAltIsObvious Resident]] 12:11, 18 February 2013 (PST)<br />
<br />
== Fundamental flaw in first code sample (fails to remove multiple listeners) ==<br />
<br />
The first code sample has the following fundamental problem (as can be easily demonstrated): at any point in time there can be '''multiple''' listeners attached because any number of users can click on the prim. But the script sample has only '''one''' global variable to keep track of it. Result: The last user to click on the prim "wins" in the sense that whoever closes the dialog first will remove his listener. All other listeners will remain active.<br />
<br />
The obvious mediation is <br />
# either to introduce a more sophisticated listener tracking (and most likely some form of polling in a regular timer event) <br />
# or to keep it simple and introduce a single static listener, omitting the need for a timer event altogether.<br />
<br />
I personally opt for the latter. If there are no objections I can make those changes. Proposal:<br />
<br />
<lsl><br />
// When the prim is touched, give the toucher the option of killing the prim.<br />
<br />
integer gListener; // Identity of the listener associated with the dialog, so we can clean up when not needed<br />
<br />
default<br />
{<br />
state_entry()<br />
{<br />
// Set up a listener for potential llDialog() calls<br />
// it might seem like a waste at this stage, but overall it is way more efficient<br />
// than trying to track listeners on a per-user basis<br />
gListener = llListen(-99, "", NULL_KEY, "");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// get the UUID of the person touching this prim<br />
key user = llDetectedKey(0);<br />
// Send a dialog to that person. We'll use a fixed negative channel number for simplicity<br />
llDialog(user, "\nDo you wish this prim to die?", ["Yes", "No" ] , -99);<br />
}<br />
listen(integer chan, string name, key id, string msg)<br />
{<br />
// If the user clicked the "Yes" button, kill this prim.<br />
if (msg == "Yes")<br />
llDie();<br />
}<br />
}<br />
</lsl><br />
<br />
Btw, the same fundamental flaw is present in the tutorial https://wiki.secondlife.com/wiki/Dialog_Menus .<br />
<br />
Edit: the second code sample contains the flaw, too<br />
<br />
--[[User:LovingAndRejected Resident|LovingAndRejected Resident]] 05:37, 13 November 2013 (PST)<br />
<br />
: I'm not seeing where the multiple listens will come from given that the touch event (in the first sample on this page) removes any previous listen. [[User:Antony Fairport|Antony Fairport]] 08:42, 13 November 2013 (PST)<br />
: Agreed. llListenRemove(gListener) will close any pre-existing instance of gListener. Because a dialog box will never self-cancel and we have no way to detect whether a user has clicked "Ignore", it is necessary to include a timer that will remove the listen handle as well.[[User:Rolig Loon|Rolig Loon]] 09:06 13 November 2013 (PST)<br />
: Your understanding of the examples is incomplete. As written, they do close any possible open listeners before registering another. Note the first line within the touch_start() event handler of the first example, which is commented to that effect, and the call to close_menu() in the second.<br />
: Your proposed change goes against the preferred practice of only opening a listener when required and then closing it immediately afterwards. The (still present under Mono) overhead involved with each and every open listener on a sim should be considered by the scripter. [[User:LepreKhaun Resident|LepreKhaun Resident]] 09:24, 13 November 2013 (PST)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText&diff=1182654
User talk:LepreKhaun Resident/Workaround4Escaped Chars within JsonText
2013-10-16T02:51:46Z
<p>LepreKhaun Resident: </p>
<hr />
<div>== Loop ==<br />
<br />
That is a little ugly.<br />
<lsl>while ((iter = ++iter + (type == JSON_OBJECT)) < listLength)</lsl><br />
For readability and speed I would recommend this:<br />
<lsl>integer step = 1 + (type == JSON_OBJECT);<br />
while ((iter += step) < listLength)</lsl><br />
-- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 10:15, 14 October 2013 (PDT)<br />
<br />
:If you are ok with negative indexing you can simplify it more... <br />
<lsl>integer iter = ~llGetListLength(values);<br />
// Step through list, hitting every other item if JSON_OBJECT<br />
integer step = 1 + (type == JSON_OBJECT);<br />
while ((iter += step) < 0)</lsl><br />
:-- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 10:28, 14 October 2013 (PDT)<br />
:Both excellent suggestions, ty! Have gone with the first one, feeling it is the more readable of the 2.<br />
:Will look over the coding a bit more for this as well as the (4K in size) workaround for uJsonGetValue. Had hoped there wouldn't be a need for any of this but LL remains determined not to fix our implementation. meh -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:51, 15 October 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText&diff=1182653
User:LepreKhaun Resident/Workaround4Escaped Chars within JsonText
2013-10-16T02:44:11Z
<p>LepreKhaun Resident: (Made while condition more readable)</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
=== uList2Json() and uJsonSetValue()===<br />
<br />
As many of you may be aware, LSL has the habit of "enhancing" Strings. This is regarded as a "feature" of the language and usually works out for the best, giving one the option of formatting chatted text by using "\t" and "\n". Unfortunately, one didn't have a way to opt out of this behavior. Put in computereze, LSL simply lacked "raw strings".<br />
<br />
This has bedeviled those working with Json text, either for web communications or developing other uses for it, because some strings just wouldn't encode properly. That is to say, these are all perfectly valid Json strings that simply couldn't be directly formed with llList2Json() and llJsonSetValue():<br />
*"\"Go!\" he yelled.\n"<br />
*"She replied \"No!\""<br />
*"Copyright symbol is \u00A9"<br />
*"oops]"<br />
*"Control characters are \t\n\r\f\b"<br />
<br />
I've spent a few weeks studying the problem, [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText_0ld|most of it going about it the wrong way]], but had an epiphany. A one line addition Maestro Linden added to [[Json_usage_in_LSL|Json Usage in LSL]] on the 10th ("LSL strings which both begin and end with "\"" are interpreted literally as JSON strings, while those without are parsed when converted into JSON.") confirmed what I had begun to surmise- a Json String (being a LSL String that is further enclosed within double quotes) is a "raw string"! Once I had that in hand, the following two functions practically wrote themselves.<br />
<br />
<br />
<div><lsl>//////////////////////////////<br />
// function string uList2Json (string type, list values)<br />
// This function takes the exact same parameters as<br />
// llList2Json() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uList2Json (string type, list values)<br />
{<br />
<br />
integer iter = -1;<br />
integer listLength = llGetListLength(values);<br />
<br />
// Step through list, hitting every other item if JSON_OBJECT<br />
integer step = 1 + (type == JSON_OBJECT);<br />
while ((iter += step) < listLength)<br />
// necessary so we don't choke on next if test<br />
if (llGetListEntryType(values, iter) == TYPE_STRING)<br />
// make sure it is not a JSON_* Value or a Number<br />
if (llJsonValueType(llList2String(values, iter), []) == JSON_INVALID)<br />
values = llListReplaceList(values, ["\"" + llList2String(values, iter) + "\""], iter, iter);<br />
<br />
return llList2Json(type, values);<br />
} <br />
<br />
//////////////////////////////<br />
// function string uJsonSetValue ( string json, list specifiers, string value )<br />
// This function takes the exact same parameters as<br />
// llJsonSetValue() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// NOTE: To encode a Float or Integer as a String<br />
// within the Json text, enclose it with escaped quotes<br />
// (ie '"3"' => '3' BUT '"\"3\""' => '"3"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uJsonSetValue(string json, list specifiers, string value)<br />
{<br />
// We don't want to change the string representation of <br />
// an integer, a float or any Json Value Type<br />
if (llJsonValueType(value, []) == JSON_INVALID)<br />
value = "\"" + value + "\"";<br />
return llJsonSetValue(json, specifiers, value);<br />
}<br />
<br />
<br />
///////////<br />
// Examples showing usage<br />
///////////<br />
<br />
default<br />
{<br />
touch_end(integer i)<br />
{<br />
string temp;<br />
string jsonText;<br />
<br />
// To encode '{"A":"\"Go!\" he yelled.\nShe replied \"No!\"","Z":"\\escaped \\ slosh\\"}'<br />
jsonText = uList2Json (JSON_OBJECT, [<br />
"A", "\\\"Go!\\\" he yelled.\\nShe replied \\\"No!\\\"", <br />
"Z", "\\\\escaped \\\\ slosh\\\\" //"//wiki syntax highlighter kludge<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '{"Control Chars":"\b\r\f\n\t and Windows uses \r\n for EOL","©":"\u00A9"}'<br />
jsonText = uList2Json(JSON_OBJECT, [<br />
"Control Chars", "\\b\\r\\f\\n\\t and Windows uses \\r\\n for EOL", <br />
"©", "\\u00A9"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '["WebSite","http:\/\/my.com\/ask.php?what%20is%20it","\t"]'<br />
jsonText = uList2Json(JSON_ARRAY, [<br />
"WebSite",<br />
"http:\\/\\/my.com\\/ask.php?what%20is%20it",<br />
"\\t"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// Make a Json object...<br />
temp = uList2Json(JSON_OBJECT, [<br />
"A", 99,<br />
"Z", "88]",<br />
"C", JSON_TRUE<br />
]);<br />
// ... add it to end of the array ...<br />
jsonText = uJsonSetValue(jsonText, [JSON_APPEND], temp);<br />
// ... change our web address ...<br />
jsonText = uJsonSetValue(jsonText, [1], "http:\\/\\/www.google.com");<br />
// ... change that TAB in the third spot to PI<br />
jsonText = uJsonSetValue(jsonText, [2], (string)PI);<br />
// ... and add a new "Key":Value pair to our object<br />
jsonText = uJsonSetValue(jsonText, [3, "New"], ((string)PI + "\\n"));<br />
<br />
// ["WebSite","http:\/\/www.google.com",3.141593,{"A":99,"C":true,"New":"3.141593\n","Z":"88]"}]<br />
llOwnerSay(jsonText);<br />
<br />
}<br />
}</lsl></div><br />
<br />
Now, if I can just get the retrieval worked out as simply... ;=)<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:LepreKhaun_Resident&diff=1181923
User talk:LepreKhaun Resident
2013-09-27T05:00:08Z
<p>LepreKhaun Resident: /* Template:Issues/BUG-3692 */</p>
<hr />
<div>== LSL indent style: ==<br />
Hi, I edited a few of your example scripts. I'd appreciate you using method two (BSD style) as described on the [[LSL_Style_Guide]] page. It's easier to read for beginners. It might be easier for the Javascript people to follow their [http://en.wikipedia.org/wiki/Indent_style indent style] (that would be K&R), but if you're starting from zero without any knowledge of any programming language BSD really is easier to read even though you have extra lines.-- [[User:Kireji Haiku|Kireji Haiku]] 11:37, 23 September 2013 (PDT)<br />
: Edit all you want, but outside of my Name Space please. Lynne Truss said it best using an [http://www.goodreads.com/quotes/487553-there-is-an-old-german-fable-about-porcupines-who-need old German fable]. OK?<br />
<br />
: Oh, and personal style opinions are merely that. After 3 decades in the industry (some of it actually teaching beginners), I pretty much have my own worked out to my satisfaction. -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 17:01, 23 September 2013 (PDT)<br />
<br />
== [[Template:Issues/BUG-3692]] ==<br />
<br />
I like what you did there, I'm going to bake something like that into the template (may take me a month to get around to it). -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:31, 25 September 2013 (PDT)<br />
: Good, I was hoping I'd gotten that right. Now, if I could just figure out where the <nowiki><lsl>LSL Language</lsl></nowiki> tags are stored, I'd update them with the new functions... -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:18, 25 September 2013 (PDT)<br />
<br />
:: It's not how the template was designed to be used. It will take some thought on how to redesign it. The current design isn't very user friendly, and irritates me. This presents an opportunity to redesign the templates.<br />
:: You and everyone else. It's a config file we don't have access to. Unless you visit LL in meat space, or you know a Linden who can get it done, good luck getting it updated. It hasn't been updated in years (and it's not because no one has tried). -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 20:28, 25 September 2013 (PDT)<br />
::: Ohoh, apparently no one has warned you about the thing with me and quests. :=) --[[User:LepreKhaun Resident|LepreKhaun Resident]] 22:00, 26 September 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:LepreKhaun_Resident&diff=1181854
User talk:LepreKhaun Resident
2013-09-26T02:20:39Z
<p>LepreKhaun Resident: </p>
<hr />
<div>== LSL indent style: ==<br />
Hi, I edited a few of your example scripts. I'd appreciate you using method two (BSD style) as described on the [[LSL_Style_Guide]] page. It's easier to read for beginners. It might be easier for the Javascript people to follow their [http://en.wikipedia.org/wiki/Indent_style indent style] (that would be K&R), but if you're starting from zero without any knowledge of any programming language BSD really is easier to read even though you have extra lines.-- [[User:Kireji Haiku|Kireji Haiku]] 11:37, 23 September 2013 (PDT)<br />
: Edit all you want, but outside of my Name Space please. Lynne Truss said it best using an [http://www.goodreads.com/quotes/487553-there-is-an-old-german-fable-about-porcupines-who-need old German fable]. OK?<br />
<br />
: Oh, and personal style opinions are merely that. After 3 decades in the industry (some of it actually teaching beginners), I pretty much have my own worked out to my satisfaction. -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 17:01, 23 September 2013 (PDT)<br />
<br />
== [[Template:Issues/BUG-3692]] ==<br />
<br />
I like what you did there, I'm going to bake something like that into the template (may take me a month to get around to it). -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:31, 25 September 2013 (PDT)<br />
: Good, I was hoping I'd gotten that right. Now, if I could just figure out where the <lsl>LSL Language</lsl> tags are stored, I'd update them with the new functions... -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:18, 25 September 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:LepreKhaun_Resident&diff=1181853
User talk:LepreKhaun Resident
2013-09-26T02:18:43Z
<p>LepreKhaun Resident: </p>
<hr />
<div>== LSL indent style: ==<br />
Hi, I edited a few of your example scripts. I'd appreciate you using method two (BSD style) as described on the [[LSL_Style_Guide]] page. It's easier to read for beginners. It might be easier for the Javascript people to follow their [http://en.wikipedia.org/wiki/Indent_style indent style] (that would be K&R), but if you're starting from zero without any knowledge of any programming language BSD really is easier to read even though you have extra lines.-- [[User:Kireji Haiku|Kireji Haiku]] 11:37, 23 September 2013 (PDT)<br />
: Edit all you want, but outside of my Name Space please. Lynne Truss said it best using an [http://www.goodreads.com/quotes/487553-there-is-an-old-german-fable-about-porcupines-who-need old German fable]. OK?<br />
<br />
: Oh, and personal style opinions are merely that. After 3 decades in the industry (some of it actually teaching beginners), I pretty much have my own worked out to my satisfaction. -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 17:01, 23 September 2013 (PDT)<br />
<br />
== [[Template:Issues/BUG-3692]] ==<br />
<br />
I like what you did there, I'm going to bake something like that into the template (may take me a month to get around to it). -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:31, 25 September 2013 (PDT)<br />
: Good, I was hoping I'd gotten that right. Now, if I could just figure out where the <lsl></lsl> tags are stored, I'd update them with the new functions... -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 19:18, 25 September 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText_0ld&diff=1181831
User:LepreKhaun Resident/Workaround4Escaped Chars within JsonText 0ld
2013-09-25T03:35:40Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
=== Workaround for Escaped Characters within Json Text ***Old*** ===<br />
<br />
'''NOTE: This is an archived page showing earlier thoughts to this problem and is kept only for reference to show how one can initially choose the wrong approach to a problem and worry it to death before the light bulb goes off. Please refer to [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|this page]] for the final, much more elegant workaround.'''<br />
<br />
[ETA: The reasoning here was correct, it was just the approach that was faulty, kept thinking it had to be kludged. :=)]<br />
----<br />
<br />
Because of the way LSL handles strings (we have no "raw strings", which are taken as written and not messed with), escape sequences such as "\t" are interpreted as 4 spaces for us as soon as they are encountered. Trying to encode "\t" by escaping the escape character (using "\\t") results in (incorrectly) placing '\\t' within your Json text. Same for newlines, "\n".<br />
<br />
And it's worse when you try to encode something like "\"Stop!\" he shouted." or "She said \"No\"". And UTF encoding such as "\u7650" is perfectly valid within a Json text but is elusive to obtain using LSL strings.<br />
<br />
Here's the only work around I've been able to work out. A kludge, granted, but at least it allows one to encode something like this:<br />
<br />
<pre>{<br />
"A": "\b\f\t\r \n aba \u0000",<br />
"B": "\"he\"", <br />
"C": "\t"<br />
}<br />
<br />
string jText;<br />
string i = llEscapeURL("\\b\\f\\t\\r \\n aba \\u0000");<br />
string j = llEscapeURL("\\\"he\\\"");<br />
<br />
jText = llList2Json(JSON_OBJECT, ["A", i, "B", j]);<br />
jText = llJsonSetValue(jText, ["C"], llEscapeURL("\\t"));<br />
jText = llUnescapeURL(jText);</pre><br />
<br />
'''jText == {"A":"\b\f\t\r \n aba \u0000","B":"\"he\"","C":"\t"}'''<br />
<br />
----<br />
[ETA: 9/13/2013]<br />
<br />
So, I was working the LSL string mis-handling of the escape character ("\") and, looking deeper into have not only found another workaround but made an exciting discovery- LSL does have "raw strings" of a sort, and they are the JSON_STRING! First the alternate workaround:<br />
<br />
<lsl><br />
// NOTE: Deprecated 9/19/2013 and replaced by<br />
// uList2Json() and uJsonSetValue()<br />
<br />
// Global constants<br />
integer QUOTE = 0; // '\"' (Double Quote)<br />
integer SLOSH = 1; // '\\' (Reverse Solidus)<br />
integer SLASH = 2; // '\/' (Solidus)<br />
integer BP = 3; // '\b' (Break Point)<br />
integer FF = 4; // '\f' (Form Feed)<br />
integer NL = 5; // '\n' (New Line)<br />
integer CR = 6; // '\r' (Carriage Return)<br />
integer TAB = 7; // '\t' (Tab)<br />
integer U_ = 8; /* '\u' (Unicode Prefix- MUST immediately precede <br />
a string of 4 Hex digits, 0-G, sans '0x') */<br />
// Optional, included for completeness only<br />
integer CRLF = 9; // '\r\n' (Windows end-of-line)<br />
<br />
//////////////////////////////<br />
// function string uList2JsonStringSafe (list jasonStringParts)<br />
// This function takes a list, jasonStringParts,<br />
// of the parts of the Json string one wishes and<br />
// returns a LSL string within double quotes ("")<br />
// with embedded escape characters within it that<br />
// correctly encodes as a Json string using either<br />
// llList2Json() or llJsonSetValue().<br />
//<br />
// NOTE: Deprecated 9/19/2013 and replaced by<br />
// uList2Json() and uJsonSetValue()<br />
// Version 1.0 by LepreKhaun 9/9/2013 <br />
// May be freely used, modified and distributed with this header intact.<br />
// Compiled Size = 2,088 bytes<br />
///////////////////////////////<br />
string uList2JsonStringSafe (list jasonStringParts)<br />
{<br />
list escapeCodes = ["%5C%22", "%5C%5C", "%5C/", "%5Cb", "%5Cf", "%5Cn", "%5Cr", "%5Ct", "%5Cu", "%5Cr%5Cn"];<br />
<br />
integer iter = llGetListLength(jasonStringParts);<br />
<br />
// rString must be enclosed with escaped double quotes<br />
// to keep the LSL String "enhanced features" out of play<br />
string rString = "\"";<br />
<br />
// build return string 'backwards'<br />
while (~--iter) <br />
{<br />
if(llGetListEntryType(jasonStringParts, iter) == TYPE_INTEGER)<br />
{<br />
// substitute encoding for integer constants<br />
rString = llList2String(escapeCodes, llList2Integer(jasonStringParts, iter)) + rString;<br />
}<br />
else<br />
{<br />
// escape String chunks to preserve them properly<br />
rString = llEscapeURL(llList2String(jasonStringParts, iter)) + rString;<br />
}<br />
}<br />
return llUnescapeURL("\"" + rString);<br />
}<br />
<br />
///////////<br />
// Example encodings showing usage<br />
///////////<br />
<br />
default<br />
{<br />
touch_end(integer i)<br />
{<br />
string jsonString;<br />
string jsonText;<br />
<br />
// To encode '{"A":"\"Go!\" he yelled.\nShe replied \"No!\"","Z":"\\escaped \\ slosh\\"}'<br />
jsonString = uList2JsonStringSafe([QUOTE, "Go!", QUOTE, " he yelled.", NL, "She replied ", QUOTE, "No!", QUOTE]);<br />
jsonText = llList2Json(JSON_OBJECT, ["A", jsonString]);<br />
jsonString = uList2JsonStringSafe([SLOSH, "escaped ", SLOSH, " slosh", SLOSH]);<br />
jsonText = llJsonSetValue(jsonText, ["Z"], jsonString);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '{"Control Chars":"\b\r\f\n\t and Windows uses \r\n for EOL","©":"\u00A9"}'<br />
jsonString = uList2JsonStringSafe([BP, CR, FF, NL, TAB, " and Windows uses ", CRLF, " for EOL"]);<br />
jsonText = llList2Json(JSON_OBJECT, ["Control Chars", jsonString]);<br />
jsonString = uList2JsonStringSafe([U_, "00A9"]);<br />
jsonText = llJsonSetValue(jsonText, ["©"], jsonString);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '["WebSite","http:\/\/my.com\/ask.php?what%20is%20it","\t"]'<br />
jsonString = uList2JsonStringSafe(["http:", SLASH, SLASH, "my.com", SLASH, "ask.php?what%20is%20it"]);<br />
jsonText = llList2Json(JSON_ARRAY, ["WebSite", jsonString]);<br />
jsonText = llJsonSetValue(jsonText, [JSON_APPEND], uList2JsonStringSafe([TAB]));<br />
llOwnerSay(jsonText);<br />
}<br />
}</lsl><br />
<br />
The how and why this approach works is based on an earlier observation I had made that Json text (LSL strings that were enclosed within '{}' or '[]') were being handled differently than other LSL strings in that their enclosed escape codes (such as '\t') were not being translated (to '%09" or '%20%20%20%20'), a "feature" LSL strings have.<br />
<br />
I then noticed a difference in definitions between [http://tools.ietf.org/html/rfc4627 RFC 4627] and [http://www.json.org/ JSON.org]. The RFC defines a Json text to be either an array or an object but at json.org it's defined as any Json Value, including the JSON_STRING. And a JSON_STRING is defined, of course, as being enclosed within double quotes (""). So I began experimenting with that type of LSL string and found the same exception to "enhanced features" was afforded!<br />
<br />
But then another problem surfaced: The LSL functions llJsonGetValue() llJson2List() extracts a JSON_STRING as a regular LSL String, resulting in these escaped character sequences being "enhanced" by translation (in other words '\t' becomes '%09', which is further "enhanced" to '%20%20%20%20' when chatted and '\u23B5' becomes 'u23B5'. Grrrrr.... This wasn't good for further processing, we needed a String to preserve these after the extraction.<br />
<br />
And that lead to the development of [[LepreKhaun_Resident/Json_Get_Value_Safe|uJsonGetValueSafe()]], which returns the requested Value explicitly enclosed within double quotes {""}, just as it appears within the Json text...<br />
<br />
And, of course, this was complicated by the RFC stating:<br />
<pre> Insignificant whitespace is allowed before or after any of the six<br />
structural characters.<br />
<br />
ws = *(<br />
%x20 / ; Space<br />
%x09 / ; Horizontal tab<br />
%x0A / ; Line feed or New line<br />
%x0D ; Carriage return<br />
</pre> )<br />
Hooboy!<br />
<br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Get_Value_Safe&diff=1181830
User:LepreKhaun Resident/Json Get Value Safe
2013-09-25T03:34:42Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
<lsl>//////////////////////////////<br />
// function string uJsonGetValueSafe (string jsonText, list specifiers)<br />
// Same specification as llJsonGetValue() except returns all Strings<br />
// enclosed within double quotes and exactly as they appear within jsonText<br />
//<br />
// Version 1.0 by LepreKhaun 9/9/20<br />
// May be freely used, modified and distributed with this header intact.<br />
// Compiled Size = 4,608 bytes<br />
///////////////////////////////<br />
<br />
string uJsonGetValueSafe (string jsonText, list specifiers)<br />
{<br />
string rString = "";<br />
<br />
// no need for further processing if not String<br />
if (llJsonValueType(jsonText, specifiers) != JSON_STRING) <br />
{<br />
rString = llJsonGetValue(jsonText, specifiers);<br />
<br />
// specifiers may be an empty list and we're dealing with simply a JSON_STRING<br />
}<br />
else if (llGetListLength(specifiers) == 0) <br />
{<br />
rString = jsonText;<br />
<br />
}<br />
else<br />
{<br />
// used for assembling the return string<br />
string char = "";<br />
string prevChar = "";<br />
<br />
// boolean flag<br />
integer inQuote = FALSE;<br />
<br />
// used to step through Array/Object Values<br />
// NOTE: Takes valid, compliant Json text for granted<br />
integer inArrayObject = 0;<br />
<br />
integer iter = 0;<br />
<br />
// we need to extract the parent of the String Value<br />
list valueSpecifier = llList2List(specifiers, -1, -1);<br />
<br />
// shorten specifiers to point to parent of the Value<br />
specifiers = llDeleteSubList(specifiers, -1, -1);<br />
<br />
// extract the parent<br />
jsonText = llJsonGetValue(jsonText, specifiers);<br />
<br />
if (llGetListEntryType(valueSpecifier, 0) == TYPE_INTEGER)<br />
{<br />
// we're dealing with an array<br />
integer sPos = llList2Integer(valueSpecifier, 0);<br />
<br />
// used to step through array Values<br />
integer count = 0;<br />
<br />
// find start of our String Value within array<br />
while (count < sPos)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = !inQuote;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
else if (char == "," && !inQuote && !inArrayObject)<br />
{<br />
++count;<br />
}<br />
prevChar = char;<br />
}<br />
// eat possible white space<br />
while ((rString = llGetSubString(jsonText, ++iter, iter)) != "\""){};<br />
// Now assemble return string<br />
inQuote = TRUE;<br />
prevChar = "";<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
}<br />
else<br />
{<br />
// otherwise, we must be dealing with an object<br />
<br />
// make the key for comparison<br />
string sKey = llList2String(valueSpecifier, 0);<br />
<br />
// and encode it as a JSON_STRING if it's not<br />
if (llGetSubString(sKey, 0, 0) != "\"")<br />
{<br />
sKey = "\"" + sKey + "\"";<br />
}<br />
<br />
// used for a possible "Key" used in comparison<br />
string pKey;<br />
<br />
integer jtLength = llStringLength(jsonText) - 1;<br />
<br />
while (iter < jtLength)<br />
{<br />
// go to start of a possible "Key"<br />
while (llGetSubString(jsonText, ++iter, iter) != "\"")<br />
{<br />
};<br />
<br />
// form pKey<br />
pKey = "\"";<br />
inQuote = TRUE;<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
pKey = pKey + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to start of Value, eating possible white space<br />
while (llGetSubString(jsonText, ++iter, iter) != ":")<br />
{<br />
};<br />
<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
<br />
while (char == "%20" || char == "%09" || char == "%0a" || char == "%0d")<br />
{<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
}<br />
<br />
char = llUnescapeURL(char);<br />
<br />
// check "Key" for match with sKey AND start of a String Value<br />
if (pKey == sKey && char == "\"")<br />
{<br />
// assemble Value<br />
prevChar = "";<br />
inQuote = TRUE;<br />
rString = "\"";<br />
<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to ',' or '}' (next "Key"Value pair or end of object)<br />
while(!(llGetSubString(jsonText, ++iter, iter) == "," || llGetSubString(jsonText, iter, iter) == "}")){};<br />
}<br />
else<br />
{<br />
// eat Value to next Key or end of object<br />
integer inValue = TRUE;<br />
prevChar = "";<br />
inArrayObject = 0;<br />
inQuote = FALSE;<br />
<br />
while (inValue)<br />
{<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = !inQuote; <br />
}<br />
else if ((char == "," || char == "}") && !inQuote && !inArrayObject)<br />
{<br />
inValue = FALSE;<br />
--iter;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
prevChar = char;<br />
}<br />
}<br />
}<br />
}<br />
}<br />
return rString;<br />
}<br />
<br />
// example usage and comparison<br />
default {<br />
touch_end (integer i){<br />
string jText = "{\"B\":\"Z\",\"C\":[1,\"a\\r\\t\\f\",3],\"A\":\"H\\n\\u23AF\"}";<br />
llOwnerSay(jText); // => '{"B":"Z","C":[1,"a\r\t\f",3],"A":"H\n\u23AF"}'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["A"])); // => 'H' then Unicode character for New Line then 'u23AF'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["A"])); // => "H\n\u23AF"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["B"])); // => 'Z'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["B"])); // => "Z"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 0])); // => '1'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 0])); // => '1'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 1])); // => 'a' then Unicode characters for the escaped sequences<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 1])); // => "a\r\t\f"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 2])); // => '3'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 2])); // => '3'<br />
}<br />
}</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Stack_Implementations_using_Json_Arrays&diff=1181829
User:LepreKhaun Resident/Stack Implementations using Json Arrays
2013-09-25T03:33:51Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== Three Stack Implementations using Json Arrays ==<br />
<br />
<br />
The [http://en.wikipedia.org/wiki/Stack_(abstract_data_type) Stack] is a much used abstract data type with properties that make it invalualabe for recursive operations. It is known as a LIFO, Last-In-First-Out, data type with some elementary operations; PUSH (which adds a Value to the Stack), POP (which retrieves the last Value added to it) and PEEK (which "looks" at the last Value added to the top of the stack without removing it). Additionally, a SIZE_OF method is handy to see how many Values are currently held within the Stack; one doesn't want to POP a Value when there are no Values there to be POPPED, which would result in a condition known as "underflow".<br />
<br />
It might be noted here that a Value need not be really "removed" from the Stack when it is POPPED, but the size of the Stack is simply decreased. This is because the size of the Stack is used as a pointer to the top of the Stack and the Value can be safely ignored from then on since it's no longer "within" the Stack and it'll be overwritten by a new Value whenever the length gets back up to that point again.<br />
<br />
Here are three Stack implementations of increasing complexity. The first is simply one global Stack which may be accessed anywhere within the script.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR ONE GLOBAL STACK<br />
////////////////<br />
<br />
// Global stack declaration and initialization<br />
string ourStack = "[]";<br />
// SIZE_OF the stack may be had by simply checking this<br />
integer stackSize = 0;<br />
<br />
<br />
// Takes a (string)item and appends it to stack<br />
PUSH (string ITEM) {<br />
ourStack = llJsonSetValue(ourStack, [stackSize++], ITEM);<br />
}<br />
<br />
// "Removes" and returns the top of the stack<br />
string POP () {<br />
if (stackSize) return llJsonGetValue(ourStack, [--stackSize]);<br />
else return "";<br />
}<br />
<br />
// Just "looks" at the top of the stack<br />
// and returns item<br />
string PEEK () {<br />
if (stackSize) return llJsonGetValue(ourStack, [(stackSize-1)]);<br />
else return "";<br />
}<br />
<br />
/////////////////<br />
// end STACK METHODS FOR GLOBAL STACK<br />
////////////////</lsl><br />
<br />
The second implementation forms a Stack as needed, which is then held and sent to its [http://en.wikipedia.org/wiki/Method_(computer_programming) methods] (geek term for a function that is object specific) in it's entirity. This may be preferred over the third implementation in that there is no global(s) used, however the passing by reference of an entire stack for each operation may outweigh that and the third implementation may prove better in some cases.<br />
<br />
In this and the next implementation, the size of the Stack is the first element within the array, making the indexing for its Values one-based instead of zero-based. In other words, the last element (top of the Stack) will now be found with length_of_array instead of length_of_array-1 with length_of_array always to be found at index 0.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR MULTIPLE STACKS<br />
////////////////<br />
<br />
// returns a JSON_ARRAY as a Stack Object<br />
string stINIT () {<br />
return "[0]";<br />
}<br />
<br />
// returns the number of items in stack<br />
integer stSIZE_OF (string jsonST) {<br />
return (integer)llJsonGetValue(jsonST, [0]);<br />
}<br />
<br />
// Takes [stack, item] and appends item to stack<br />
// (Could be written using two parameters instead of a list)<br />
string stPUSH (list jsonST_ITEM) {<br />
string jsonST = llList2String(jsonST_ITEM, 0);<br />
string item = llList2String(jsonST_ITEM, 1);<br />
integer size = stSIZE_OF(jsonST);<br />
<br />
jsonST = llJsonSetValue(jsonST, [0], (string)++size));<br />
return llJsonSetValue(jsonST, [size], item);<br />
}<br />
<br />
// "Removes" the top of the stack<br />
// and returns a list of [stack, item]<br />
list stPOP (string jsonST) {<br />
integer size = stSIZE_OF(jsonST);<br />
// Check for "underflow" condition...<br />
if (size) {<br />
string item = llJsonGetValue(jsonST, [size]);<br />
// set stack pointer to one less<br />
return [llJsonSetValue(jsonST, [0], --size), item];<br />
} else {<br />
return [jsonST, ""];<br />
}<br />
}<br />
<br />
// Just "looks" at the top of the stack<br />
// and returns item<br />
string stPEEK (string jsonST) {<br />
integer size = stSIZE_OF(jsonST);<br />
if (size) {<br />
return llJsonGetValue(jsonST, [size]);<br />
} else {<br />
return "";<br />
}<br />
}<br />
/////////////////<br />
// end -- STACK METHODS FOR MULTIPLE STACKS<br />
////////////////</lsl><br />
<br />
In this final implementation, we'll use integers as (primitive) "pointers", holding and passing them instead of entire stacks. This [http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming) encapsulates] the concept of Stack and almost completely [http://en.dahnielson.com/2012/01/decoupling/ decouples] them from the rest of the code, a good thing. In other words, if we decided at some point that a Stack could be better represented as a Json object, we'd only need to change these methods as given here, anything else calling them would not need to be touched.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR MULTIPLE STACKS USING "POINTERS" WITHIN A GLOBAL STACK "OBJECT"<br />
////////////////<br />
<br />
// Global declaration and initialization of ourStacks as a Stacks object<br />
// Index 0 is used to determine next available stack "pointer"<br />
ourStacks = "[0]";<br />
<br />
// initialation of a new Stack<br />
// returns a "pointer" to a new stack<br />
integer getNewStackPtr() {<br />
integer numberOfStacks = llJsonGetValue(ourStacks, [0]);<br />
ourStacks = llJsonSetValue (ourStacks, [JSON_APPEND], "[0]");<br />
ourStacks = llJsonSetValue (ourStacks, [0]), ++numberOfStacks);<br />
return numberOfStacks;<br />
}<br />
<br />
// returns the number of items in a stack<br />
integer stPtrSIZE_OF (integer stPtr) {<br />
return (integer)llJsonGetValue(ourStacks, [stPtr, 0]);<br />
}<br />
<br />
// Takes [stackPointer, item] and appends item to stack<br />
stPtrPUSH (list stPtr_ITEM) {<br />
integer stPtr = llList2Integer(stPtr_ITEM, 0);<br />
string item = llList2String(stPtr_ITEM, 1);<br />
integer size = stPtrSIZE_OF(stPtr);<br />
<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, 0], (string)++size));<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, size], item);<br />
}<br />
<br />
// "Removes" the top of the stack<br />
// and returns [stackPointer, item]<br />
string stPtrPOP (integer stPtr) {<br />
integer size = stPtrSIZE_OF(stPtr);<br />
// Avoid "underflow" condition.<br />
if (size) {<br />
string item = llJsonGetValue(ourStacks, [stPtr, size]);<br />
// set stack pointer to one less<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, 0], --size);<br />
return item;<br />
} else {<br />
return "";<br />
}<br />
}<br />
<br />
// Just "looks" at the top of a stack<br />
// and returns item<br />
string stPtrPEEK (integer stPtr) {<br />
if (stPtrSIZE_OF(stPtr)) {<br />
return llJsonGetValue(ourStacks, [stPtr, stPtrSIZE_OF(stPtr)]);<br />
} else {<br />
return "";<br />
}<br />
}<br />
/////////////////<br />
// end STACK METHODS FOR MULTIPLE STACKS USING "POINTERS" WITHIN A GLOBAL STACK "OBJECT"<br />
////////////////</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText&diff=1181828
User:LepreKhaun Resident/Workaround4Escaped Chars within JsonText
2013-09-25T03:33:11Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
=== uList2Json() and uJsonSetValue()===<br />
<br />
As many of you may be aware, LSL has the habit of "enhancing" Strings. This is regarded as a "feature" of the language and usually works out for the best, giving one the option of formatting chatted text by using "\t" and "\n". Unfortunately, one didn't have a way to opt out of this behavior. Put in computereze, LSL simply lacked "raw strings".<br />
<br />
This has bedeviled those working with Json text, either for web communications or developing other uses for it, because some strings just wouldn't encode properly. That is to say, these are all perfectly valid Json strings that simply couldn't be directly formed with llList2Json() and llJsonSetValue():<br />
*"\"Go!\" he yelled.\n"<br />
*"She replied \"No!\""<br />
*"Copyright symbol is \u00A9"<br />
*"oops]"<br />
*"Control characters are \t\n\r\f\b"<br />
<br />
I've spent a few weeks studying the problem, [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText_0ld|most of it going about it the wrong way]], but had an epiphany. A one line addition Maestro Linden added to [[Json_usage_in_LSL|Json Usage in LSL]] on the 10th ("LSL strings which both begin and end with "\"" are interpreted literally as JSON strings, while those without are parsed when converted into JSON.") confirmed what I had begun to surmise- a Json String (being a LSL String that is further enclosed within double quotes) is a "raw string"! Once I had that in hand, the following two functions practically wrote themselves.<br />
<br />
<br />
<div><lsl>//////////////////////////////<br />
// function string uList2Json (string type, list values)<br />
// This function takes the exact same parameters as<br />
// llList2Json() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uList2Json (string type, list values)<br />
{<br />
<br />
integer iter = -1;<br />
integer listLength = llGetListLength(values);<br />
<br />
// Step through list, hitting every other item if JSON_OBJECT<br />
while ((iter = ++iter + (type == JSON_OBJECT)) < listLength)<br />
// necessary so we don't choke on next if test<br />
if (llGetListEntryType(values, iter) == TYPE_STRING)<br />
// make sure it is not a JSON_* Value or a Number<br />
if (llJsonValueType(llList2String(values, iter), []) == JSON_INVALID)<br />
values = llListReplaceList(values, ["\"" + llList2String(values, iter) + "\""], iter, iter);<br />
<br />
return llList2Json(type, values);<br />
} <br />
<br />
//////////////////////////////<br />
// function string uJsonSetValue ( string json, list specifiers, string value )<br />
// This function takes the exact same parameters as<br />
// llJsonSetValue() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// NOTE: To encode a Float or Integer as a String<br />
// within the Json text, enclose it with escaped quotes<br />
// (ie '"3"' => '3' BUT '"\"3\""' => '"3"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uJsonSetValue(string json, list specifiers, string value)<br />
{<br />
// We don't want to change the string representation of <br />
// an integer, a float or any Json Value Type<br />
if (llJsonValueType(value, []) == JSON_INVALID)<br />
value = "\"" + value + "\"";<br />
return llJsonSetValue(json, specifiers, value);<br />
}<br />
<br />
<br />
///////////<br />
// Examples showing usage<br />
///////////<br />
<br />
default<br />
{<br />
touch_end(integer i)<br />
{<br />
string temp;<br />
string jsonText;<br />
<br />
// To encode '{"A":"\"Go!\" he yelled.\nShe replied \"No!\"","Z":"\\escaped \\ slosh\\"}'<br />
jsonText = uList2Json (JSON_OBJECT, [<br />
"A", "\\\"Go!\\\" he yelled.\\nShe replied \\\"No!\\\"", <br />
"Z", "\\\\escaped \\\\ slosh\\\\" //"//wiki syntax highlighter kludge<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '{"Control Chars":"\b\r\f\n\t and Windows uses \r\n for EOL","©":"\u00A9"}'<br />
jsonText = uList2Json(JSON_OBJECT, [<br />
"Control Chars", "\\b\\r\\f\\n\\t and Windows uses \\r\\n for EOL", <br />
"©", "\\u00A9"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '["WebSite","http:\/\/my.com\/ask.php?what%20is%20it","\t"]'<br />
jsonText = uList2Json(JSON_ARRAY, [<br />
"WebSite",<br />
"http:\\/\\/my.com\\/ask.php?what%20is%20it",<br />
"\\t"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// Make a Json object...<br />
temp = uList2Json(JSON_OBJECT, [<br />
"A", 99,<br />
"Z", "88]",<br />
"C", JSON_TRUE<br />
]);<br />
// ... add it to end of the array ...<br />
jsonText = uJsonSetValue(jsonText, [JSON_APPEND], temp);<br />
// ... change our web address ...<br />
jsonText = uJsonSetValue(jsonText, [1], "http:\\/\\/www.google.com");<br />
// ... change that TAB in the third spot to PI<br />
jsonText = uJsonSetValue(jsonText, [2], (string)PI);<br />
// ... and add a new "Key":Value pair to our object<br />
jsonText = uJsonSetValue(jsonText, [3, "New"], ((string)PI + "\\n"));<br />
<br />
// ["WebSite","http:\/\/www.google.com",3.141593,{"A":99,"C":true,"New":"3.141593\n","Z":"88]"}]<br />
llOwnerSay(jsonText);<br />
<br />
}<br />
}</lsl></div><br />
<br />
Now, if I can just get the retrieval worked out as simply... ;=)<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Database_2_Chat&diff=1181827
User:LepreKhaun Resident/Json Database 2 Chat
2013-09-25T03:32:09Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
You may find at some point that you've written an application with a Json text database within it that is 10k or so in size and now you need to update the code, perhaps to add some new record fields you realize you require. Ohoh!<br />
<br />
Let's hope you have the following code in place to retrieve the database, so you can update and debug your code and then reset everything properly. Otherwise, you'll have lost your entire database. Ouch!<br />
<br />
Can also ('''now!''' lol) be used just to obtain a back up of your database at times.<br />
<br />
<pre>// Where myDataBase is a global Json text string<br />
// function jsonDb2Chat ();<br />
// Version 1.5 (8/29/2013 - added a necessary conversion of DB back to original!)<br />
// Version 1.0<br />
// By LepreKhaun 8/28/2013<br />
<br />
jsonDb2Chat () {<br />
integer count = 0;<br />
<br />
// Needed to keep internal quotes and escape characters intact<br />
// Be *certain* you have the available memory needed for this inflation!<br />
myDataBase = llEscapeURL(myDataBase);<br />
<br />
// Keeping in mind chat can only output 1024 single-byte characters at a time:<br />
integer totalChunks = (integer)(llStringLength (myDataBase)/1022);<br />
llOwnerSay ("Chatting your database.\n\n");<br />
while (count < totalChunks) {<br />
llOwnerSay ("\n" + llGetSubString (myDataBase, count*1022, ((++count)*1022)-1));<br />
}<br />
llOwnerSay ("\n" + llGetSubString(myDataBase, count*1022, -1));<br />
// convert DB back so this can be used to simply retrieve a back up at times<br />
myDataBase = llUnescapeURL(myDataBase); <br />
<br />
}</pre><br />
<br />
After calling this function (possibly as a response to a button within your admin menu- "ChatDB", or a chatted command that's listened for on some obscure channel that is masked for the owner's key), the object will chat out the database for you.<br />
<br />
All that remains now is to copy&paste this output to a text document, remove the inserted new lines and '[time stamp] Object:' bits, and then put double quotes around it all. Finally, have the following initialization line in your rewritten code's default state_entry() event for your global 'string myDataBase;':<br />
<pre>myDataBase = llUnescapeURL('your cleaned and double quote enclosed chat output');</pre><br />
<br />
'''NOTE:''' When using Json text for a database, you should check free memory after each insertion of new data into it. Only by doing so will you be able to realize that things may be getting a wee bit too tight for comfort within your program.<br />
<br />
At that point, you need to consider a way to either shorten the length of your database, possible by going with (shudder) one character "Key"s (making a note in comments of what Key "Z" stands for) deleting older or no longer necessary records and/or transferring the entire database into a stand alone script with minimal functionality and having a link message protocol worked out for retrieval, insertion, deletion and updating the records.<br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Delete_Json_Element&diff=1181826
User:LepreKhaun Resident/Delete Json Element
2013-09-25T03:31:24Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
<lsl><br />
// Function: string deleteJsonElement( string jsonSource, list pathtoElement );<br />
// Version 1.5 9/7/2013 Fixed case for a single item pathtoElement<br />
// Version 1.0 by LepreKhaun, 6/21/2013. Free to copy, modify and use as one wishes with this comment included.<br />
// This function takes a JSON text string and returns a copy of it with a specified element removed from it.<br />
// jsonSource is the JSON text to remove an element from.<br />
// pathToElement is a List containing the transversal path to the element<br />
// (as defined as "specifiers" in http://wiki.secondlife.com/wiki/Json_usage_in_LSL )<br />
// AND ending with the element to remove.<br />
// The element may be an array Value or the "Key" within an object<br />
// If the parent of the element is a JSON_ARRAY, the element to be removed must be an integer INDEX <br />
// If the parent of the element is a JSON_OBJECT, the element to be removed must be a string "KEY"<br />
//<br />
// NOTE: This code is not optimized nor does it contain any error checking!!! <br />
// Add whatever you feel is needed to ensure correct operation of your script.<br />
<br />
string deleteJsonElement( string jsonSource, list pathtoElement ) <br />
{<br />
<br />
integer placeinlist;<br />
<br />
// Obtain the JSON object of the parent of the element<br />
string jsonParent = llJsonGetValue( jsonSource, llDeleteSubList( pathtoElement, -1, -1 ) );<br />
<br />
// Convert it to a list<br />
list listParent = llJson2List( jsonParent );<br />
<br />
// Do test<br />
if (llJsonValueType( jsonParent, [] ) == JSON_ARRAY)<br />
{<br />
placeinlist = llList2Integer( pathtoElement, -1 );<br />
listParent = llDeleteSubList( listParent, placeinlist, placeinlist );<br />
<br />
// convert to a JSON object<br />
jsonParent = llList2Json( JSON_ARRAY, listParent );<br />
<br />
} <br />
else // We are dealing with a JSON_OBJECT<br />
{<br />
placeinlist = llListFindList( listParent, llList2List( pathtoElement, -1, -1 ) );<br />
listParent = llDeleteSubList( listParent, placeinlist, placeinlist + 1 );<br />
<br />
// convert to a JSON object<br />
jsonParent = llList2Json( JSON_OBJECT, listParent );<br />
}<br />
<br />
<br />
// Insert our results and return<br />
return llJsonSetValue( jsonSource, llList2List( pathtoElement, 0, -2 ), jsonParent ); <br />
}<br />
</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181825
User:LepreKhaun Resident/Json Pretty Printer
2013-09-25T03:30:16Z
<p>LepreKhaun Resident: Nicety rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
<strike>It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.</strike> (No longer true with V2.0!)<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<div><lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 2.0 by LepreKhaun -- 2013-09-24<br />
// Complete rewrite w/o recursion and now handles<br />
// escape codes within JSON text correctly<br />
// Version 1.2 -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// helper function<br />
chatThis (string output, integer lvl) {<br />
while (lvl--) output = "\t" + output;<br />
llOwnerSay (output);<br />
}<br />
<br />
prettyPrint( string jsonText ) {<br />
integer jLength = llStringLength( jsonText );<br />
string result = "";<br />
integer level = 0;<br />
integer iter = 0;<br />
string char;<br />
string prevChar;<br />
integer inQuote = FALSE;<br />
<br />
while (iter < jLength) {<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") { //"//<br />
inQuote = !inQuote;<br />
result += char;<br />
} else if (!inQuote) {<br />
if (char == "[" || char == "{" || char == ",") {<br />
chatThis(result + char, level);<br />
result = "";<br />
if (char != ",") ++level;<br />
} else if (char == "]" || char == "}") {<br />
if (result != "") chatThis(result, level);<br />
--level;<br />
result = char;<br />
} else if (char == ":") {<br />
result += ": ";<br />
} else {<br />
result += char;<br />
}<br />
} else {<br />
result += char;<br />
}<br />
prevChar = char;<br />
}<br />
chatThis(result, level);<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
prettyPrint(message);<br />
}<br />
}<br />
}<br />
</lsl></div><br />
<br />
Harness program, showing usage:<br />
<br />
<div><lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co<br />
// From Heading: "Pretty Print" Code in JavaScript<br />
string source = <br />
"{\"apiVersion\":\"2.0\",\"data\":{\"updated\":\"2010-01-07T19:58:42.949Z\",\"totalItems\":800," + <br />
"\"startIndex\":1,\"itemsPerPage\":1,\"items\":[{\"id\":\"hYB0mn5zh2c\",\"uploaded\":" + <br />
"\"2007-06-05T22:07:03.000Z\",\"updated\":\"2010-01-07T13:26:50.000Z\"," + <br />
"\"uploader\":\"GoogleDeveloperDay\",\"category\":\"News\",\"title\":\"Google Developers Day US" + <br />
" - Maps API Introduction\",\"description\":\"Google Maps API Introduction...\",\"tags\":" + <br />
"[\"GDD07\",\"GDD07US\",\"Maps\"],\"thumbnail\":{\"default\":\"http://i.ytimg.com/vi/" + <br />
"hYB0mn5zh2c/default.jpg\",\"hqDefault\":\"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg\"}," + <br />
"\"player\":{\"default\":\"https://www.youtube.com/watch?v=hYB0mn5zh2c\",\"mobile\":" + <br />
"\"https://m.youtube.com/details?v=hYB0mn5zh2c\"},\"content\":{\"1\":\"rtsp://v5.cache3.c." + <br />
"youtube.com/CiILENy.../0/0/0/video.3gp\",\"5\":\"http://www.youtube.com/v/hYB0mn5zh2c?" + <br />
"f...\",\"6\":\"rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp\"},\"duration\":2840," + <br />
"\"aspectRatio\":\"widescreen\",\"likeCount\":171,\"rating\":4.63,\"ratingCount\":68,\"viewCount" + <br />
"\":220101,\"favoriteCount\":201,\"commentCount\":22,\"status\":{\"value\":\"restricted\"," + <br />
"\"reason\":\"limitedSyndication\"},\"accessControl\":{\"syndicate\":\"allowed\"," + <br />
"\"commentVote\":\"allowed\",\"rate\":\"allowed\",\"list\":\"allowed\",\"comment\":\"allowed\"," + <br />
"\"embed\":\"allowed\",\"videoRespond\":\"moderated\"}}]}}";<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl></div><br />
<br />
Outputs:<br />
<br />
<div><pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat V2.0 is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: {<br />
Object: "apiVersion": "2.0",<br />
Object: "data": {<br />
Object: "updated": "2010-01-07T19:58:42.949Z",<br />
Object: "totalItems": 800,<br />
Object: "startIndex": 1,<br />
Object: "itemsPerPage": 1,<br />
Object: "items": [<br />
Object: {<br />
Object: "id": "hYB0mn5zh2c",<br />
Object: "uploaded": "2007-06-05T22:07:03.000Z",<br />
Object: "updated": "2010-01-07T13:26:50.000Z",<br />
Object: "uploader": "GoogleDeveloperDay",<br />
Object: "category": "News",<br />
Object: "title": "Google Developers Day US - Maps API Introduction",<br />
Object: "description": "Google Maps API Introduction...",<br />
Object: "tags": [<br />
Object: "GDD07",<br />
Object: "GDD07US",<br />
Object: "Maps"<br />
Object: ],<br />
Object: "thumbnail": {<br />
Object: "default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",<br />
Object: "hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"<br />
Object: },<br />
Object: "player": {<br />
Object: "default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",<br />
Object: "mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"<br />
Object: },<br />
Object: "content": {<br />
Object: "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp",<br />
Object: "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",<br />
Object: "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp"<br />
Object: },<br />
Object: "duration": 2840,<br />
Object: "aspectRatio": "widescreen",<br />
Object: "likeCount": 171,<br />
Object: "rating": 4.63,<br />
Object: "ratingCount": 68,<br />
Object: "viewCount": 220101,<br />
Object: "favoriteCount": 201,<br />
Object: "commentCount": 22,<br />
Object: "status": {<br />
Object: "value": "restricted",<br />
Object: "reason": "limitedSyndication"<br />
Object: },<br />
Object: "accessControl": {<br />
Object: "syndicate": "allowed",<br />
Object: "commentVote": "allowed",<br />
Object: "rate": "allowed",<br />
Object: "list": "allowed",<br />
Object: "comment": "allowed",<br />
Object: "embed": "allowed",<br />
Object: "videoRespond": "moderated"<br />
Object: }<br />
Object: }<br />
Object: ]<br />
Object: }<br />
Object: }<br />
</pre></div><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident&diff=1181824
User:LepreKhaun Resident
2013-09-25T03:28:40Z
<p>LepreKhaun Resident: Nicety Rewording.</p>
<hr />
<div>['''NOTE:''' Pages within my Name Space are a WIP and constantly changing. As my understanding of the problems I attempt to address and the grasp of the subject matter itself deepens, I regularly review what I have written and update the content as better algorithms occur to me.<br />
<br />
However, for this process of refinement, improvement and tweaking to result in something that might (hopefully!) benefit the community at large, I ask that comments, suggested improvements, corrections of fact or your own personal style preferences be made ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== A bit about me (well, maybe a byte or so) ==<br />
I'm a semi-retired, long-time resident of New Orleans, LA, though I traveled extensively in my youth. I got my first computer in 1984, a [http://en.wikipedia.org/wiki/Commodore_64 Commodore 64] and self taught myself both Basic and assembly language on it. From that point on, I've always had a computer, sometimes several at a time, and my interest in this fascinating tool/toy has grown.<br />
<br />
Along the way I decided to get some formal education so I got my GED in 1992, and enrolled in [http://www.uno.edu/ UNO] as a Computer Science major. During my 4 year enrollment there, I worked for two professors as a teachers aide, both teaching course material as well as grading programming efforts of other students. At the end, I ended up with a GPA of 3.45, two letters of recommendation and fell 15 hours short of getting my Bachelors Degree (which I plan to rectify next year).<br />
<br />
After college, during which I had discovered this thing called the [http://en.wikipedia.org/wiki/World_Wide_Web Internet], I began free-lancing as a [http://www.perl.org/ Perl] [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI] programmer, designing and implementing both user interfaces as well as complete back end solutions.<br />
<br />
That business venture lasted until Y2K or so, when [https://en.wikipedia.org/wiki/PHP PHP] functionality and [https://en.wikipedia.org/wiki/Active_Server_Pages ASP] began to supplant the need for such but my interest didn't wane. I've since taught myself [https://en.wikipedia.org/wiki/Object-oriented_programming OOP] as well as a number of scripting languages such as [https://en.wikipedia.org/wiki/ActionScript ActionScript] and, most recently, [http://en.wikipedia.org/wiki/Linden_Scripting_Language LSL].<br />
<br />
I'm also a practising zen buddhist, semi-professional performer, skilled carpenter & renovator, amateur sculptor, avid reader and an active volunteer in a number of causes I believe in.<br />
<br />
I'm in Second Life to learn, create and share, the same as my RL.<br />
<br />
<br />
== Code bits that one might find useful ==<br />
<br />
===Json Related===<br />
#[[User:LepreKhaun_Resident/Json_Pretty_Printer|'''JSON Pretty Printer''']] A Json debugging tool that "pretty prints" a Json text to chat. Version 2.0 released.<br />
#[[User:LepreKhaun_Resident/Delete_Json_Element|'''Delete Json Element''']] A function that removes an element (either a Value from an array or a "Key":Value pair from an object) from the supplied Json text.<br />
#[[User:LepreKhaun_Resident/Json_Database_2_Chat|'''Json Database 2 Chat''']] A function to retrieve a Json text from within a script, to be reused later in its original form.<br />
#[[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|'''Workaround for Escaped Characters within Json Text''']] A way to encode '\t', '\n' and such as well as `"\"he said\""' within Json text. ['''ETA 9/13/2013: added User Function for same!''']<br />
#[[User:LepreKhaun_Resident/Stack_Implementations_using_Json_Arrays|'''Stack Implementations using Json Arrays''']] Showing 3 ways to implement a Stack in LSL using Json Text.<br />
#[[User:LepreKhaun_Resident/Json_Get_Value_Safe|'''Json Get Value Safe (user function)''']] A way to retrieve JSON_STRING without having it "enhanced" by LSL String handling.<br />
<br />
----<br />
{{Jira Reporter}}<br />
{{ISO 639-3/cat-speaking|eng}}<br />
{{skills <br />
|Builder=*<br />
|Scripter=* <br />
|}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=LlJsonSetValue&diff=1181823
LlJsonSetValue
2013-09-25T02:35:57Z
<p>LepreKhaun Resident: Updated example to reflect recent bug fix.</p>
<hr />
<div>{{LSL Function<br />
|inject-2={{Issues/BUG-3692}}<br />
|func_id=|func_sleep=0.0|func_energy=10.0<br />
|func=llJsonSetValue|return_type=string|p1_type=string|p1_name=json|p2_type=list|p2_name=specifiers|p3_type=string|p3_name=value<br />
|func_footnote<br />
|func_desc=Returns, if successful, a new [http://json.org JSON] text ''string'' which is ''json'' with the value indicated by the ''specifiers'' list set to ''value''.<br />
<br />
If unsuccessful (usually because of specifying an out of range array index) it should, and usually will, return [[JSON_INVALID]]. However this is currently, 8/20/2013, broken at depths lower than the topmost level, where it will silently invalidate the return ''string'', so '''be careful'''! The return ''string'' should always be checked for [[JSON_INVALID]] before overwriting the original Json text.<br />
<br />
An "out of range array index" is defined to be any Integer ''specifier'' greater than the length of an existing array at that level within the Json text or greater than 0 (zero) at a level an array doesn't exist.<br />
<br />
A special ''specifier'', [[JSON_APPEND]], is accepted which appends the ''value'' to the end of the array at the ''specified'' level. Care should be taken- if that level is not an array, the existing Value there will be overwritten and replaced with an array containing ''value'' at it's first (0) index.<br />
<br />
Contrary to [[LSL_List]], negative indexing of Json arrays is '''not''' supported.<br />
<br />
If an existing "Key" is ''specified'' at that level, its Value will be overwritten by ''value'', otherwise a new "Key":Value pair will be formed within the Json object.<br />
<br />
If ''value'' is [[JSON_TRUE]], [[JSON_FALSE]] or [[JSON_NULL]], the Value set will be the bare words 'true', 'false' or 'null', respectively, at the ''specified'' location within ''json''.<br />
<br />
|return_text=<br />
|spec=See [[Json_usage_in_LSL]]<br />
|constants<br />
|examples=<br />
<lsl><br />
string TEST_STRING_JSON;<br />
<br />
init()<br />
{<br />
TEST_STRING_JSON = "[9,\"<1,1,1>\",false,{\"A\":8,\"Z\":9}]";<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"Z":9}]<br />
say("Original TEST_STRING_JSON: " + TEST_STRING_JSON);<br />
}<br />
<br />
run_json_test(string input)<br />
{<br />
string output;<br />
<br />
// changing values within the json string<br />
<br />
// change the first value in the array to 10<br />
output = llJsonSetValue(input, [0], "10");<br />
<br />
// [10,"<1,1,1>",false,{"A":8,"Z":9}]<br />
say("( 1): " + output);<br />
<br />
// change the third value in the array to 'true'<br />
output = llJsonSetValue(input, [2], JSON_TRUE);<br />
<br />
// [9,"<1,1,1>",true,{"A":8,"Z":9}]<br />
say("( 2): " + output);<br />
<br />
// change the value of "A" within the Json object to 3<br />
output = llJsonSetValue(input, [3, "A"], "3");<br />
<br />
// [9,"<1,1,1>",false,{"A":3,"Z":9}]<br />
say("( 3): " + output);<br />
<br />
// adding a value or new key-value-pair within the input<br />
<br />
// add the value "Hello" to the end of the array<br />
// NOTE: One cannot insert, only add to the end<br />
output = llJsonSetValue(input, [JSON_APPEND], "Hello");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"Z":9},"Hello"]<br />
say("( 4): " + output);<br />
<br />
// add the key-value-pair "B":10 to the object<br />
output = llJsonSetValue(input, [3, "B"], "10");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"B":10,"Z":9}]<br />
say("( 5): " + output);<br />
<br />
<br />
// Things to look out for when modifying Json text<br />
// ~!~ Be careful when using this function ~!~<br />
<br />
// out of bounds array assignment:<br />
// defined as attempting to add a value to a position ...<br />
// ...greater than the length of the array (which may be 0)<br />
// JSON_APPEND is ALWAYS the preferred way to add to an array<br />
output = llJsonSetValue(input, [5], "10");<br />
<br />
// %EF%B7%90 (URL escaped JSON_INVALID)<br />
say("( 6): " + llEscapeURL(output));<br />
<br />
// BUT, this works, since it is in bounds<br />
// (eqivalent to JSON_APPEND in this case)<br />
output = llJsonSetValue(input, [4], "10");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"Z":9},10]<br />
say("( 7): " + output);<br />
<br />
// careless formation of new arrays<br />
// ( the 4 and all subsequent 0's are all in bounds.)<br />
output = llJsonSetValue(input, [4, 0, 0, 0], "10");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"Z":9},[[[10]]]]<br />
say("( 8): " + output);<br />
<br />
// overwriting an object with an array:<br />
// ~!~ mistaken use of JSON_APPEND on an object ~!~<br />
output = llJsonSetValue(input, [3, JSON_APPEND], "10");<br />
<br />
// [9,"<1,1,1>",false,[10]]<br />
say("( 9): " + output);<br />
<br />
// careless formation of new objects<br />
// NOTE: "Key" assignemts will NEVER result in a return of JSON_INVALID!<br />
output = llJsonSetValue(input, [3, "W", "X"], "10");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"W":{"X":10},"Z":9}]<br />
say("(10): " + output);<br />
<br />
output = llJsonSetValue(input, [3, "W", "X", "Y"], "10");<br />
<br />
// [9,"<1,1,1>",false,{"A":8,"W":{"X":{"Y":10}},"Z":9}]<br />
say("(11): " + output);<br />
<br />
// overwriting an array with an object<br />
output = llJsonSetValue(input, ["X"], "10");<br />
<br />
// {"X":10}<br />
say("(12): " + output);<br />
<br />
// special case considerations:<br />
<br />
<br />
// BUG-3692: (NOTE: Corrected in release 13.09.21.281328!)<br />
// a bug where, instead of JSON_INVALID being returned, if the out of<br />
// bounds index is at a lower level than the topmost (root) level, a<br />
// non-compliant JSON text would be formed<br />
output = llJsonSetValue(input, [1, 7], "Disappearing Text");<br />
<br />
// Note the "empty" second position that resulted in the returned array<br />
// [9,,false,{"A":8,"Z":9}]<br />
// (But now correctly shows JSON_INVALID)<br />
say("(13): " + output);<br />
<br />
// though there is no way to directly delete a key-value-pair <br />
// nor remove a value from an array,<br />
// the use of JSON_NULL may prove adequate<br />
output = llJsonSetValue(input, [3, "A"], JSON_NULL);<br />
<br />
// [9,"<1,1,1>",false,{"A":null,"Z":9}]<br />
say("(14): " + output);<br />
<br />
// if a JSON text object has been formed with llList2Json()<br />
// that contains one or more duplicated "Keys", (allowable<br />
// but NOT recommended!) ANY change<br />
// made to that object will correct the condition,<br />
// with all but the last such "Key" being removed<br />
output = llList2Json(JSON_OBJECT, ["A", 1, "A", 2, "A", 3, "B", 4, "B", 4]);<br />
<br />
// both Keys "A" and "B" are duplicated<br />
// {"A":1,"A":2,"A":3,"B":4,"B":4}<br />
say("(15): " + output);<br />
<br />
// only the last value of the duplications is accessable though<br />
<br />
// 3<br />
say("(16): " + llJsonGetValue(output, ["A"]));<br />
<br />
// condition corrected by adding a key-value-pair...<br />
<br />
// {"A":3,"B":4,"Z":5}<br />
say("(17): " + llJsonSetValue(output, ["Z"], "5"));<br />
<br />
// ... or by changing a value<br />
<br />
// {"A":5,"B":4}<br />
say("(18): " + llJsonSetValue(output, ["A"], "5"));<br />
}<br />
<br />
say(string message)<br />
{<br />
llOwnerSay(message);<br />
// llRegionSayTo(llGetOwner(), PUBLIC_CHANNEL, message);<br />
// llWhisper(PUBLIC_CHANNEL, message);<br />
}<br />
<br />
default<br />
{<br />
on_rez(integer start_param)<br />
{<br />
llResetScript();<br />
}<br />
<br />
state_entry()<br />
{<br />
init();<br />
}<br />
<br />
touch_end(integer num_detected)<br />
{<br />
// copy 'TEST_STRING_JSON' from the following function call<br />
// to the string 'input' in the function declaration<br />
// and run a test on 'input' to not (!) modify 'TEST_STRING_JSON'<br />
// but its copy instead<br />
run_json_test(TEST_STRING_JSON);<br />
}<br />
}<br />
</lsl><br />
|caveats=<br />
|helpers<br />
|also_functions={{LSL DefineRow||[[llList2Json]]|}}<br />
{{LSL DefineRow||[[llJson2List]]|}}<br />
{{LSL DefineRow||[[llJsonGetValue]]|}}<br />
{{LSL DefineRow||[[llJsonValueType]]|}}<br />
|also_events<br />
|also_tests<br />
|also_articles={{LSL DefineRow||[[Typecast]]|}}<br />
|notes=<br />
|permission<br />
|negative_index<br />
|sort=JsonSetValue<br />
|cat1=List<br />
|cat2=String<br />
|cat3=Data Conversion<br />
|cat4=JSON<br />
|history = Date of Release [[ Release_Notes/Second_Life_Server/13#13.05.20.276191 | 20/05/2013 ]]<br />
}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=Template:Issues/BUG-3692&diff=1181822
Template:Issues/BUG-3692
2013-09-25T01:56:54Z
<p>LepreKhaun Resident: Fixed with release 13.09.21.281328</p>
<hr />
<div>{{Issues|BUG-3692|type=bug|<s>[[JSON_NULL]] may be deceptively returned instead of [[JSON_INVALID]] when [http://tools.ietf.org/html/rfc4627 noncompliant Json text] is encountered by either [[llJsonValueType]] or [[llJsonGetValue]].</s> Fixed with release 13.09.21.281328.}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181821
User:LepreKhaun Resident/Json Pretty Printer
2013-09-24T23:52:46Z
<p>LepreKhaun Resident: Formatting fix.</p>
<hr />
<div>== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
<strike>It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.</strike> (No longer true with V2.0!)<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<div><lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 2.0 by LepreKhaun -- 2013-09-24<br />
// Complete rewrite w/o recursion and now handles<br />
// escape codes within JSON text correctly<br />
// Version 1.2 -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// helper function<br />
chatThis (string output, integer lvl) {<br />
while (lvl--) output = "\t" + output;<br />
llOwnerSay (output);<br />
}<br />
<br />
prettyPrint( string jsonText ) {<br />
integer jLength = llStringLength( jsonText );<br />
string result = "";<br />
integer level = 0;<br />
integer iter = 0;<br />
string char;<br />
string prevChar;<br />
integer inQuote = FALSE;<br />
<br />
while (iter < jLength) {<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") { //"//<br />
inQuote = !inQuote;<br />
result += char;<br />
} else if (!inQuote) {<br />
if (char == "[" || char == "{" || char == ",") {<br />
chatThis(result + char, level);<br />
result = "";<br />
if (char != ",") ++level;<br />
} else if (char == "]" || char == "}") {<br />
if (result != "") chatThis(result, level);<br />
--level;<br />
result = char;<br />
} else if (char == ":") {<br />
result += ": ";<br />
} else {<br />
result += char;<br />
}<br />
} else {<br />
result += char;<br />
}<br />
prevChar = char;<br />
}<br />
chatThis(result, level);<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
prettyPrint(message);<br />
}<br />
}<br />
}<br />
</lsl></div><br />
<br />
Harness program, showing usage:<br />
<br />
<div><lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co<br />
// From Heading: "Pretty Print" Code in JavaScript<br />
string source = <br />
"{\"apiVersion\":\"2.0\",\"data\":{\"updated\":\"2010-01-07T19:58:42.949Z\",\"totalItems\":800," + <br />
"\"startIndex\":1,\"itemsPerPage\":1,\"items\":[{\"id\":\"hYB0mn5zh2c\",\"uploaded\":" + <br />
"\"2007-06-05T22:07:03.000Z\",\"updated\":\"2010-01-07T13:26:50.000Z\"," + <br />
"\"uploader\":\"GoogleDeveloperDay\",\"category\":\"News\",\"title\":\"Google Developers Day US" + <br />
" - Maps API Introduction\",\"description\":\"Google Maps API Introduction...\",\"tags\":" + <br />
"[\"GDD07\",\"GDD07US\",\"Maps\"],\"thumbnail\":{\"default\":\"http://i.ytimg.com/vi/" + <br />
"hYB0mn5zh2c/default.jpg\",\"hqDefault\":\"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg\"}," + <br />
"\"player\":{\"default\":\"https://www.youtube.com/watch?v=hYB0mn5zh2c\",\"mobile\":" + <br />
"\"https://m.youtube.com/details?v=hYB0mn5zh2c\"},\"content\":{\"1\":\"rtsp://v5.cache3.c." + <br />
"youtube.com/CiILENy.../0/0/0/video.3gp\",\"5\":\"http://www.youtube.com/v/hYB0mn5zh2c?" + <br />
"f...\",\"6\":\"rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp\"},\"duration\":2840," + <br />
"\"aspectRatio\":\"widescreen\",\"likeCount\":171,\"rating\":4.63,\"ratingCount\":68,\"viewCount" + <br />
"\":220101,\"favoriteCount\":201,\"commentCount\":22,\"status\":{\"value\":\"restricted\"," + <br />
"\"reason\":\"limitedSyndication\"},\"accessControl\":{\"syndicate\":\"allowed\"," + <br />
"\"commentVote\":\"allowed\",\"rate\":\"allowed\",\"list\":\"allowed\",\"comment\":\"allowed\"," + <br />
"\"embed\":\"allowed\",\"videoRespond\":\"moderated\"}}]}}";<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl></div><br />
<br />
Outputs:<br />
<br />
<div><pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat V2.0 is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: {<br />
Object: "apiVersion": "2.0",<br />
Object: "data": {<br />
Object: "updated": "2010-01-07T19:58:42.949Z",<br />
Object: "totalItems": 800,<br />
Object: "startIndex": 1,<br />
Object: "itemsPerPage": 1,<br />
Object: "items": [<br />
Object: {<br />
Object: "id": "hYB0mn5zh2c",<br />
Object: "uploaded": "2007-06-05T22:07:03.000Z",<br />
Object: "updated": "2010-01-07T13:26:50.000Z",<br />
Object: "uploader": "GoogleDeveloperDay",<br />
Object: "category": "News",<br />
Object: "title": "Google Developers Day US - Maps API Introduction",<br />
Object: "description": "Google Maps API Introduction...",<br />
Object: "tags": [<br />
Object: "GDD07",<br />
Object: "GDD07US",<br />
Object: "Maps"<br />
Object: ],<br />
Object: "thumbnail": {<br />
Object: "default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",<br />
Object: "hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"<br />
Object: },<br />
Object: "player": {<br />
Object: "default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",<br />
Object: "mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"<br />
Object: },<br />
Object: "content": {<br />
Object: "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp",<br />
Object: "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",<br />
Object: "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp"<br />
Object: },<br />
Object: "duration": 2840,<br />
Object: "aspectRatio": "widescreen",<br />
Object: "likeCount": 171,<br />
Object: "rating": 4.63,<br />
Object: "ratingCount": 68,<br />
Object: "viewCount": 220101,<br />
Object: "favoriteCount": 201,<br />
Object: "commentCount": 22,<br />
Object: "status": {<br />
Object: "value": "restricted",<br />
Object: "reason": "limitedSyndication"<br />
Object: },<br />
Object: "accessControl": {<br />
Object: "syndicate": "allowed",<br />
Object: "commentVote": "allowed",<br />
Object: "rate": "allowed",<br />
Object: "list": "allowed",<br />
Object: "comment": "allowed",<br />
Object: "embed": "allowed",<br />
Object: "videoRespond": "moderated"<br />
Object: }<br />
Object: }<br />
Object: ]<br />
Object: }<br />
Object: }<br />
</pre></div><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Get_Value_Safe&diff=1181820
User:LepreKhaun Resident/Json Get Value Safe
2013-09-24T23:48:31Z
<p>LepreKhaun Resident: Formatting fix.</p>
<hr />
<div><lsl>//////////////////////////////<br />
// function string uJsonGetValueSafe (string jsonText, list specifiers)<br />
// Same specification as llJsonGetValue() except returns all Strings<br />
// enclosed within double quotes and exactly as they appear within jsonText<br />
//<br />
// Version 1.0 by LepreKhaun 9/9/20<br />
// May be freely used, modified and distributed with this header intact.<br />
// Compiled Size = 4,608 bytes<br />
///////////////////////////////<br />
<br />
string uJsonGetValueSafe (string jsonText, list specifiers)<br />
{<br />
string rString = "";<br />
<br />
// no need for further processing if not String<br />
if (llJsonValueType(jsonText, specifiers) != JSON_STRING) <br />
{<br />
rString = llJsonGetValue(jsonText, specifiers);<br />
<br />
// specifiers may be an empty list and we're dealing with simply a JSON_STRING<br />
}<br />
else if (llGetListLength(specifiers) == 0) <br />
{<br />
rString = jsonText;<br />
<br />
}<br />
else<br />
{<br />
// used for assembling the return string<br />
string char = "";<br />
string prevChar = "";<br />
<br />
// boolean flag<br />
integer inQuote = FALSE;<br />
<br />
// used to step through Array/Object Values<br />
// NOTE: Takes valid, compliant Json text for granted<br />
integer inArrayObject = 0;<br />
<br />
integer iter = 0;<br />
<br />
// we need to extract the parent of the String Value<br />
list valueSpecifier = llList2List(specifiers, -1, -1);<br />
<br />
// shorten specifiers to point to parent of the Value<br />
specifiers = llDeleteSubList(specifiers, -1, -1);<br />
<br />
// extract the parent<br />
jsonText = llJsonGetValue(jsonText, specifiers);<br />
<br />
if (llGetListEntryType(valueSpecifier, 0) == TYPE_INTEGER)<br />
{<br />
// we're dealing with an array<br />
integer sPos = llList2Integer(valueSpecifier, 0);<br />
<br />
// used to step through array Values<br />
integer count = 0;<br />
<br />
// find start of our String Value within array<br />
while (count < sPos)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = !inQuote;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
else if (char == "," && !inQuote && !inArrayObject)<br />
{<br />
++count;<br />
}<br />
prevChar = char;<br />
}<br />
// eat possible white space<br />
while ((rString = llGetSubString(jsonText, ++iter, iter)) != "\""){};<br />
// Now assemble return string<br />
inQuote = TRUE;<br />
prevChar = "";<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
}<br />
else<br />
{<br />
// otherwise, we must be dealing with an object<br />
<br />
// make the key for comparison<br />
string sKey = llList2String(valueSpecifier, 0);<br />
<br />
// and encode it as a JSON_STRING if it's not<br />
if (llGetSubString(sKey, 0, 0) != "\"")<br />
{<br />
sKey = "\"" + sKey + "\"";<br />
}<br />
<br />
// used for a possible "Key" used in comparison<br />
string pKey;<br />
<br />
integer jtLength = llStringLength(jsonText) - 1;<br />
<br />
while (iter < jtLength)<br />
{<br />
// go to start of a possible "Key"<br />
while (llGetSubString(jsonText, ++iter, iter) != "\"")<br />
{<br />
};<br />
<br />
// form pKey<br />
pKey = "\"";<br />
inQuote = TRUE;<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
pKey = pKey + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to start of Value, eating possible white space<br />
while (llGetSubString(jsonText, ++iter, iter) != ":")<br />
{<br />
};<br />
<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
<br />
while (char == "%20" || char == "%09" || char == "%0a" || char == "%0d")<br />
{<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
}<br />
<br />
char = llUnescapeURL(char);<br />
<br />
// check "Key" for match with sKey AND start of a String Value<br />
if (pKey == sKey && char == "\"")<br />
{<br />
// assemble Value<br />
prevChar = "";<br />
inQuote = TRUE;<br />
rString = "\"";<br />
<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to ',' or '}' (next "Key"Value pair or end of object)<br />
while(!(llGetSubString(jsonText, ++iter, iter) == "," || llGetSubString(jsonText, iter, iter) == "}")){};<br />
}<br />
else<br />
{<br />
// eat Value to next Key or end of object<br />
integer inValue = TRUE;<br />
prevChar = "";<br />
inArrayObject = 0;<br />
inQuote = FALSE;<br />
<br />
while (inValue)<br />
{<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") //"//<br />
{<br />
inQuote = !inQuote; <br />
}<br />
else if ((char == "," || char == "}") && !inQuote && !inArrayObject)<br />
{<br />
inValue = FALSE;<br />
--iter;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
prevChar = char;<br />
}<br />
}<br />
}<br />
}<br />
}<br />
return rString;<br />
}<br />
<br />
// example usage and comparison<br />
default {<br />
touch_end (integer i){<br />
string jText = "{\"B\":\"Z\",\"C\":[1,\"a\\r\\t\\f\",3],\"A\":\"H\\n\\u23AF\"}";<br />
llOwnerSay(jText); // => '{"B":"Z","C":[1,"a\r\t\f",3],"A":"H\n\u23AF"}'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["A"])); // => 'H' then Unicode character for New Line then 'u23AF'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["A"])); // => "H\n\u23AF"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["B"])); // => 'Z'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["B"])); // => "Z"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 0])); // => '1'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 0])); // => '1'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 1])); // => 'a' then Unicode characters for the escaped sequences<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 1])); // => "a\r\t\f"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 2])); // => '3'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 2])); // => '3'<br />
}<br />
}</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181809
User:LepreKhaun Resident/Json Pretty Printer
2013-09-24T14:19:08Z
<p>LepreKhaun Resident: Minor format correction.</p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
<strike>It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.</strike> (No longer true with V2.0!)<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<div><lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 2.0 by LepreKhaun -- 2013-09-24<br />
// Complete rewrite w/o recursion and now handles<br />
// escape codes within JSON text correctly<br />
// Version 1.2 -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// helper function<br />
chatThis (string output, integer lvl) {<br />
while (lvl--) output = "\t" + output;<br />
llOwnerSay (output);<br />
}<br />
<br />
prettyPrint( string jsonText ) {<br />
integer jLength = llStringLength( jsonText );<br />
string result = "";<br />
integer level = 0;<br />
integer iter = 0;<br />
string char;<br />
string prevChar;<br />
integer inQuote = FALSE;<br />
<br />
while (iter < jLength) {<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") {<br />
inQuote = !inQuote;<br />
result += char;<br />
} else if (!inQuote) {<br />
if (char == "[" || char == "{" || char == ",") {<br />
chatThis(result + char, level);<br />
result = "";<br />
if (char != ",") ++level;<br />
} else if (char == "]" || char == "}") {<br />
if (result != "") chatThis(result, level);<br />
--level;<br />
result = char;<br />
} else if (char == ":") {<br />
result += ": ";<br />
} else {<br />
result += char;<br />
}<br />
} else {<br />
result += char;<br />
}<br />
prevChar = char;<br />
}<br />
chatThis(result, level);<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
prettyPrint(message);<br />
}<br />
}<br />
}<br />
</lsl></div><br />
<br />
Harness program, showing usage:<br />
<br />
<div><lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co<br />
// From Heading: "Pretty Print" Code in JavaScript<br />
string source = <br />
"{\"apiVersion\":\"2.0\",\"data\":{\"updated\":\"2010-01-07T19:58:42.949Z\",\"totalItems\":800," + <br />
"\"startIndex\":1,\"itemsPerPage\":1,\"items\":[{\"id\":\"hYB0mn5zh2c\",\"uploaded\":" + <br />
"\"2007-06-05T22:07:03.000Z\",\"updated\":\"2010-01-07T13:26:50.000Z\"," + <br />
"\"uploader\":\"GoogleDeveloperDay\",\"category\":\"News\",\"title\":\"Google Developers Day US" + <br />
" - Maps API Introduction\",\"description\":\"Google Maps API Introduction...\",\"tags\":" + <br />
"[\"GDD07\",\"GDD07US\",\"Maps\"],\"thumbnail\":{\"default\":\"http://i.ytimg.com/vi/" + <br />
"hYB0mn5zh2c/default.jpg\",\"hqDefault\":\"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg\"}," + <br />
"\"player\":{\"default\":\"https://www.youtube.com/watch?v=hYB0mn5zh2c\",\"mobile\":" + <br />
"\"https://m.youtube.com/details?v=hYB0mn5zh2c\"},\"content\":{\"1\":\"rtsp://v5.cache3.c." + <br />
"youtube.com/CiILENy.../0/0/0/video.3gp\",\"5\":\"http://www.youtube.com/v/hYB0mn5zh2c?" + <br />
"f...\",\"6\":\"rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp\"},\"duration\":2840," + <br />
"\"aspectRatio\":\"widescreen\",\"likeCount\":171,\"rating\":4.63,\"ratingCount\":68,\"viewCount" + <br />
"\":220101,\"favoriteCount\":201,\"commentCount\":22,\"status\":{\"value\":\"restricted\"," + <br />
"\"reason\":\"limitedSyndication\"},\"accessControl\":{\"syndicate\":\"allowed\"," + <br />
"\"commentVote\":\"allowed\",\"rate\":\"allowed\",\"list\":\"allowed\",\"comment\":\"allowed\"," + <br />
"\"embed\":\"allowed\",\"videoRespond\":\"moderated\"}}]}}";<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl></div><br />
<br />
Outputs:<br />
<br />
<div><pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat V2.0 is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: {<br />
Object: "apiVersion": "2.0",<br />
Object: "data": {<br />
Object: "updated": "2010-01-07T19:58:42.949Z",<br />
Object: "totalItems": 800,<br />
Object: "startIndex": 1,<br />
Object: "itemsPerPage": 1,<br />
Object: "items": [<br />
Object: {<br />
Object: "id": "hYB0mn5zh2c",<br />
Object: "uploaded": "2007-06-05T22:07:03.000Z",<br />
Object: "updated": "2010-01-07T13:26:50.000Z",<br />
Object: "uploader": "GoogleDeveloperDay",<br />
Object: "category": "News",<br />
Object: "title": "Google Developers Day US - Maps API Introduction",<br />
Object: "description": "Google Maps API Introduction...",<br />
Object: "tags": [<br />
Object: "GDD07",<br />
Object: "GDD07US",<br />
Object: "Maps"<br />
Object: ],<br />
Object: "thumbnail": {<br />
Object: "default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",<br />
Object: "hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"<br />
Object: },<br />
Object: "player": {<br />
Object: "default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",<br />
Object: "mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"<br />
Object: },<br />
Object: "content": {<br />
Object: "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp",<br />
Object: "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",<br />
Object: "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp"<br />
Object: },<br />
Object: "duration": 2840,<br />
Object: "aspectRatio": "widescreen",<br />
Object: "likeCount": 171,<br />
Object: "rating": 4.63,<br />
Object: "ratingCount": 68,<br />
Object: "viewCount": 220101,<br />
Object: "favoriteCount": 201,<br />
Object: "commentCount": 22,<br />
Object: "status": {<br />
Object: "value": "restricted",<br />
Object: "reason": "limitedSyndication"<br />
Object: },<br />
Object: "accessControl": {<br />
Object: "syndicate": "allowed",<br />
Object: "commentVote": "allowed",<br />
Object: "rate": "allowed",<br />
Object: "list": "allowed",<br />
Object: "comment": "allowed",<br />
Object: "embed": "allowed",<br />
Object: "videoRespond": "moderated"<br />
Object: }<br />
Object: }<br />
Object: ]<br />
Object: }<br />
Object: }<br />
</pre></div><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181808
User:LepreKhaun Resident/Json Pretty Printer
2013-09-24T14:14:38Z
<p>LepreKhaun Resident: Needed to strike through a paragraph...</p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
<strike>It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.</strike> (No longer true with V2.0!)<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 2.0 by LepreKhaun -- 2013-09-24<br />
// Complete rewrite w/o recursion and now handles<br />
// escape codes within JSON text correctly<br />
// Version 1.2 -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// helper function<br />
chatThis (string output, integer lvl) {<br />
while (lvl--) output = "\t" + output;<br />
llOwnerSay (output);<br />
}<br />
<br />
prettyPrint( string jsonText ) {<br />
integer jLength = llStringLength( jsonText );<br />
string result = "";<br />
integer level = 0;<br />
integer iter = 0;<br />
string char;<br />
string prevChar;<br />
integer inQuote = FALSE;<br />
<br />
while (iter < jLength) {<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") {<br />
inQuote = !inQuote;<br />
result += char;<br />
} else if (!inQuote) {<br />
if (char == "[" || char == "{" || char == ",") {<br />
chatThis(result + char, level);<br />
result = "";<br />
if (char != ",") ++level;<br />
} else if (char == "]" || char == "}") {<br />
if (result != "") chatThis(result, level);<br />
--level;<br />
result = char;<br />
} else if (char == ":") {<br />
result += ": ";<br />
} else {<br />
result += char;<br />
}<br />
} else {<br />
result += char;<br />
}<br />
prevChar = char;<br />
}<br />
chatThis(result, level);<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
prettyPrint(message);<br />
}<br />
}<br />
}<br />
</lsl><br />
<br />
Harness program, showing usage:<br />
<br />
<lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co<br />
// From Heading: "Pretty Print" Code in JavaScript<br />
string source = <br />
"{\"apiVersion\":\"2.0\",\"data\":{\"updated\":\"2010-01-07T19:58:42.949Z\",\"totalItems\":800," + <br />
"\"startIndex\":1,\"itemsPerPage\":1,\"items\":[{\"id\":\"hYB0mn5zh2c\",\"uploaded\":" + <br />
"\"2007-06-05T22:07:03.000Z\",\"updated\":\"2010-01-07T13:26:50.000Z\"," + <br />
"\"uploader\":\"GoogleDeveloperDay\",\"category\":\"News\",\"title\":\"Google Developers Day US" + <br />
" - Maps API Introduction\",\"description\":\"Google Maps API Introduction...\",\"tags\":" + <br />
"[\"GDD07\",\"GDD07US\",\"Maps\"],\"thumbnail\":{\"default\":\"http://i.ytimg.com/vi/" + <br />
"hYB0mn5zh2c/default.jpg\",\"hqDefault\":\"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg\"}," + <br />
"\"player\":{\"default\":\"https://www.youtube.com/watch?v=hYB0mn5zh2c\",\"mobile\":" + <br />
"\"https://m.youtube.com/details?v=hYB0mn5zh2c\"},\"content\":{\"1\":\"rtsp://v5.cache3.c." + <br />
"youtube.com/CiILENy.../0/0/0/video.3gp\",\"5\":\"http://www.youtube.com/v/hYB0mn5zh2c?" + <br />
"f...\",\"6\":\"rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp\"},\"duration\":2840," + <br />
"\"aspectRatio\":\"widescreen\",\"likeCount\":171,\"rating\":4.63,\"ratingCount\":68,\"viewCount" + <br />
"\":220101,\"favoriteCount\":201,\"commentCount\":22,\"status\":{\"value\":\"restricted\"," + <br />
"\"reason\":\"limitedSyndication\"},\"accessControl\":{\"syndicate\":\"allowed\"," + <br />
"\"commentVote\":\"allowed\",\"rate\":\"allowed\",\"list\":\"allowed\",\"comment\":\"allowed\"," + <br />
"\"embed\":\"allowed\",\"videoRespond\":\"moderated\"}}]}}";<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl><br />
<br />
Outputs:<br />
<pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat V2.0 is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: {<br />
Object: "apiVersion": "2.0",<br />
Object: "data": {<br />
Object: "updated": "2010-01-07T19:58:42.949Z",<br />
Object: "totalItems": 800,<br />
Object: "startIndex": 1,<br />
Object: "itemsPerPage": 1,<br />
Object: "items": [<br />
Object: {<br />
Object: "id": "hYB0mn5zh2c",<br />
Object: "uploaded": "2007-06-05T22:07:03.000Z",<br />
Object: "updated": "2010-01-07T13:26:50.000Z",<br />
Object: "uploader": "GoogleDeveloperDay",<br />
Object: "category": "News",<br />
Object: "title": "Google Developers Day US - Maps API Introduction",<br />
Object: "description": "Google Maps API Introduction...",<br />
Object: "tags": [<br />
Object: "GDD07",<br />
Object: "GDD07US",<br />
Object: "Maps"<br />
Object: ],<br />
Object: "thumbnail": {<br />
Object: "default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",<br />
Object: "hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"<br />
Object: },<br />
Object: "player": {<br />
Object: "default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",<br />
Object: "mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"<br />
Object: },<br />
Object: "content": {<br />
Object: "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp",<br />
Object: "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",<br />
Object: "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp"<br />
Object: },<br />
Object: "duration": 2840,<br />
Object: "aspectRatio": "widescreen",<br />
Object: "likeCount": 171,<br />
Object: "rating": 4.63,<br />
Object: "ratingCount": 68,<br />
Object: "viewCount": 220101,<br />
Object: "favoriteCount": 201,<br />
Object: "commentCount": 22,<br />
Object: "status": {<br />
Object: "value": "restricted",<br />
Object: "reason": "limitedSyndication"<br />
Object: },<br />
Object: "accessControl": {<br />
Object: "syndicate": "allowed",<br />
Object: "commentVote": "allowed",<br />
Object: "rate": "allowed",<br />
Object: "list": "allowed",<br />
Object: "comment": "allowed",<br />
Object: "embed": "allowed",<br />
Object: "videoRespond": "moderated"<br />
Object: }<br />
Object: }<br />
Object: ]<br />
Object: }<br />
Object: }<br />
</pre><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident&diff=1181807
User:LepreKhaun Resident
2013-09-24T14:08:45Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== A bit about me (well, maybe a byte or so) ==<br />
I'm a semi-retired, long-time resident of New Orleans, LA, though I traveled extensively in my youth. I got my first computer in 1984, a [http://en.wikipedia.org/wiki/Commodore_64 Commodore 64] and self taught myself both Basic and assembly language on it. From that point on, I've always had a computer, sometimes several at a time, and my interest in this fascinating tool/toy has grown.<br />
<br />
Along the way I decided to get some formal education so I got my GED in 1992, and enrolled in [http://www.uno.edu/ UNO] as a Computer Science major. During my 4 year enrollment there, I worked for two professors as a teachers aide, both teaching course material as well as grading programming efforts of other students. At the end, I ended up with a GPA of 3.45, two letters of recommendation and fell 15 hours short of getting my Bachelors Degree (which I plan to rectify next year).<br />
<br />
After college, during which I had discovered this thing called the [http://en.wikipedia.org/wiki/World_Wide_Web Internet], I began free-lancing as a [http://www.perl.org/ Perl] [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI] programmer, designing and implementing both user interfaces as well as complete back end solutions.<br />
<br />
That business venture lasted until Y2K or so, when [https://en.wikipedia.org/wiki/PHP PHP] functionality and [https://en.wikipedia.org/wiki/Active_Server_Pages ASP] began to supplant the need for such but my interest didn't wane. I've since taught myself [https://en.wikipedia.org/wiki/Object-oriented_programming OOP] as well as a number of scripting languages such as [https://en.wikipedia.org/wiki/ActionScript ActionScript] and, most recently, [http://en.wikipedia.org/wiki/Linden_Scripting_Language LSL].<br />
<br />
I'm also a practising zen buddhist, semi-professional performer, skilled carpenter & renovator, amateur sculptor, avid reader and an active volunteer in a number of causes I believe in.<br />
<br />
I'm in Second Life to learn, create and share, the same as my RL.<br />
<br />
<br />
== Code bits that one might find useful ==<br />
<br />
===Json Related===<br />
#[[User:LepreKhaun_Resident/Json_Pretty_Printer|'''JSON Pretty Printer''']] A Json debugging tool that "pretty prints" a Json text to chat. Version 2.0 released.<br />
#[[User:LepreKhaun_Resident/Delete_Json_Element|'''Delete Json Element''']] A function that removes an element (either a Value from an array or a "Key":Value pair from an object) from the supplied Json text.<br />
#[[User:LepreKhaun_Resident/Json_Database_2_Chat|'''Json Database 2 Chat''']] A function to retrieve a Json text from within a script, to be reused later in its original form.<br />
#[[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|'''Workaround for Escaped Characters within Json Text''']] A way to encode '\t', '\n' and such as well as `"\"he said\""' within Json text. ['''ETA 9/13/2013: added User Function for same!''']<br />
#[[User:LepreKhaun_Resident/Stack_Implementations_using_Json_Arrays|'''Stack Implementations using Json Arrays''']] Showing 3 ways to implement a Stack in LSL using Json Text.<br />
#[[User:LepreKhaun_Resident/Json_Get_Value_Safe|'''Json Get Value Safe (user function)''']] A way to retrieve JSON_STRING without having it "enhanced" by LSL String handling.<br />
<br />
----<br />
{{Jira Reporter}}<br />
{{ISO 639-3/cat-speaking|eng}}<br />
{{skills <br />
|Builder=*<br />
|Scripter=* <br />
|}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181806
User:LepreKhaun Resident/Json Pretty Printer
2013-09-24T14:07:27Z
<p>LepreKhaun Resident: Version 2.0, major rewrite and way mo' bettah. :)</p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 2.0 by LepreKhaun -- 2013-09-24<br />
// Complete rewrite w/o recursion and now handles<br />
// escape codes within JSON text correctly<br />
// Version 1.2 -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// helper function<br />
chatThis (string output, integer lvl) {<br />
while (lvl--) output = "\t" + output;<br />
llOwnerSay (output);<br />
}<br />
<br />
prettyPrint( string jsonText ) {<br />
integer jLength = llStringLength( jsonText );<br />
string result = "";<br />
integer level = 0;<br />
integer iter = 0;<br />
string char;<br />
string prevChar;<br />
integer inQuote = FALSE;<br />
<br />
while (iter < jLength) {<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\") {<br />
inQuote = !inQuote;<br />
result += char;<br />
} else if (!inQuote) {<br />
if (char == "[" || char == "{" || char == ",") {<br />
chatThis(result + char, level);<br />
result = "";<br />
if (char != ",") ++level;<br />
} else if (char == "]" || char == "}") {<br />
if (result != "") chatThis(result, level);<br />
--level;<br />
result = char;<br />
} else if (char == ":") {<br />
result += ": ";<br />
} else {<br />
result += char;<br />
}<br />
} else {<br />
result += char;<br />
}<br />
prevChar = char;<br />
}<br />
chatThis(result, level);<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat V2.0 awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
prettyPrint(message);<br />
}<br />
}<br />
}<br />
</lsl><br />
<br />
Harness program, showing usage:<br />
<br />
<lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// http://www.codeproject.com/Articles/426142/JSON-Pretty-Print-and-JSON-Multi-level-Collapse-Co<br />
// From Heading: "Pretty Print" Code in JavaScript<br />
string source = <br />
"{\"apiVersion\":\"2.0\",\"data\":{\"updated\":\"2010-01-07T19:58:42.949Z\",\"totalItems\":800," + <br />
"\"startIndex\":1,\"itemsPerPage\":1,\"items\":[{\"id\":\"hYB0mn5zh2c\",\"uploaded\":" + <br />
"\"2007-06-05T22:07:03.000Z\",\"updated\":\"2010-01-07T13:26:50.000Z\"," + <br />
"\"uploader\":\"GoogleDeveloperDay\",\"category\":\"News\",\"title\":\"Google Developers Day US" + <br />
" - Maps API Introduction\",\"description\":\"Google Maps API Introduction...\",\"tags\":" + <br />
"[\"GDD07\",\"GDD07US\",\"Maps\"],\"thumbnail\":{\"default\":\"http://i.ytimg.com/vi/" + <br />
"hYB0mn5zh2c/default.jpg\",\"hqDefault\":\"http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg\"}," + <br />
"\"player\":{\"default\":\"https://www.youtube.com/watch?v=hYB0mn5zh2c\",\"mobile\":" + <br />
"\"https://m.youtube.com/details?v=hYB0mn5zh2c\"},\"content\":{\"1\":\"rtsp://v5.cache3.c." + <br />
"youtube.com/CiILENy.../0/0/0/video.3gp\",\"5\":\"http://www.youtube.com/v/hYB0mn5zh2c?" + <br />
"f...\",\"6\":\"rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp\"},\"duration\":2840," + <br />
"\"aspectRatio\":\"widescreen\",\"likeCount\":171,\"rating\":4.63,\"ratingCount\":68,\"viewCount" + <br />
"\":220101,\"favoriteCount\":201,\"commentCount\":22,\"status\":{\"value\":\"restricted\"," + <br />
"\"reason\":\"limitedSyndication\"},\"accessControl\":{\"syndicate\":\"allowed\"," + <br />
"\"commentVote\":\"allowed\",\"rate\":\"allowed\",\"list\":\"allowed\",\"comment\":\"allowed\"," + <br />
"\"embed\":\"allowed\",\"videoRespond\":\"moderated\"}}]}}";<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl><br />
<br />
Outputs:<br />
<pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat V2.0 is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: {<br />
Object: "apiVersion": "2.0",<br />
Object: "data": {<br />
Object: "updated": "2010-01-07T19:58:42.949Z",<br />
Object: "totalItems": 800,<br />
Object: "startIndex": 1,<br />
Object: "itemsPerPage": 1,<br />
Object: "items": [<br />
Object: {<br />
Object: "id": "hYB0mn5zh2c",<br />
Object: "uploaded": "2007-06-05T22:07:03.000Z",<br />
Object: "updated": "2010-01-07T13:26:50.000Z",<br />
Object: "uploader": "GoogleDeveloperDay",<br />
Object: "category": "News",<br />
Object: "title": "Google Developers Day US - Maps API Introduction",<br />
Object: "description": "Google Maps API Introduction...",<br />
Object: "tags": [<br />
Object: "GDD07",<br />
Object: "GDD07US",<br />
Object: "Maps"<br />
Object: ],<br />
Object: "thumbnail": {<br />
Object: "default": "http://i.ytimg.com/vi/hYB0mn5zh2c/default.jpg",<br />
Object: "hqDefault": "http://i.ytimg.com/vi/hYB0mn5zh2c/hqdefault.jpg"<br />
Object: },<br />
Object: "player": {<br />
Object: "default": "https://www.youtube.com/watch?v=hYB0mn5zh2c",<br />
Object: "mobile": "https://m.youtube.com/details?v=hYB0mn5zh2c"<br />
Object: },<br />
Object: "content": {<br />
Object: "1": "rtsp://v5.cache3.c.youtube.com/CiILENy.../0/0/0/video.3gp",<br />
Object: "5": "http://www.youtube.com/v/hYB0mn5zh2c?f...",<br />
Object: "6": "rtsp://v1.cache1.c.youtube.com/CiILENy.../0/0/0/video.3gp"<br />
Object: },<br />
Object: "duration": 2840,<br />
Object: "aspectRatio": "widescreen",<br />
Object: "likeCount": 171,<br />
Object: "rating": 4.63,<br />
Object: "ratingCount": 68,<br />
Object: "viewCount": 220101,<br />
Object: "favoriteCount": 201,<br />
Object: "commentCount": 22,<br />
Object: "status": {<br />
Object: "value": "restricted",<br />
Object: "reason": "limitedSyndication"<br />
Object: },<br />
Object: "accessControl": {<br />
Object: "syndicate": "allowed",<br />
Object: "commentVote": "allowed",<br />
Object: "rate": "allowed",<br />
Object: "list": "allowed",<br />
Object: "comment": "allowed",<br />
Object: "embed": "allowed",<br />
Object: "videoRespond": "moderated"<br />
Object: }<br />
Object: }<br />
Object: ]<br />
Object: }<br />
Object: }<br />
</pre><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Get_Value_Safe&diff=1181804
User:LepreKhaun Resident/Json Get Value Safe
2013-09-24T00:41:48Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
<lsl>//////////////////////////////<br />
// function string uJsonGetValueSafe (string jsonText, list specifiers)<br />
// Same specification as llJsonGetValue() except returns all Strings<br />
// enclosed within double quotes and exactly as they appear within jsonText<br />
//<br />
// Version 1.0 by LepreKhaun 9/9/20<br />
// May be freely used, modified and distributed with this header intact.<br />
// Compiled Size = 4,608 bytes<br />
///////////////////////////////<br />
<br />
string uJsonGetValueSafe (string jsonText, list specifiers)<br />
{<br />
string rString = "";<br />
<br />
// no need for further processing if not String<br />
if (llJsonValueType(jsonText, specifiers) != JSON_STRING) <br />
{<br />
rString = llJsonGetValue(jsonText, specifiers);<br />
<br />
// specifiers may be an empty list and we're dealing with simply a JSON_STRING<br />
}<br />
else if (llGetListLength(specifiers) == 0) <br />
{<br />
rString = jsonText;<br />
<br />
}<br />
else<br />
{<br />
// used for assembling the return string<br />
string char = "";<br />
string prevChar = "";<br />
<br />
// boolean flag<br />
integer inQuote = FALSE;<br />
<br />
// used to step through Array/Object Values<br />
// NOTE: Takes valid, compliant Json text for granted<br />
integer inArrayObject = 0;<br />
<br />
integer iter = 0;<br />
<br />
// we need to extract the parent of the String Value<br />
list valueSpecifier = llList2List(specifiers, -1, -1);<br />
<br />
// shorten specifiers to point to parent of the Value<br />
specifiers = llDeleteSubList(specifiers, -1, -1);<br />
<br />
// extract the parent<br />
jsonText = llJsonGetValue(jsonText, specifiers);<br />
<br />
if (llGetListEntryType(valueSpecifier, 0) == TYPE_INTEGER)<br />
{<br />
// we're dealing with an array<br />
integer sPos = llList2Integer(valueSpecifier, 0);<br />
<br />
// used to step through array Values<br />
integer count = 0;<br />
<br />
// find start of our String Value within array<br />
while (count < sPos)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
if (char == "\"" && prevChar != "\\")<br />
{<br />
inQuote = !inQuote;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
else if (char == "," && !inQuote && !inArrayObject)<br />
{<br />
++count;<br />
}<br />
prevChar = char;<br />
}<br />
// eat possible white space<br />
while ((rString = llGetSubString(jsonText, ++iter, iter)) != "\""){};<br />
// Now assemble return string<br />
inQuote = TRUE;<br />
prevChar = "";<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\")<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
}<br />
else<br />
{<br />
// otherwise, we must be dealing with an object<br />
<br />
// make the key for comparison<br />
string sKey = llList2String(valueSpecifier, 0);<br />
<br />
// and encode it as a JSON_STRING if it's not<br />
if (llGetSubString(sKey, 0, 0) != "\"")<br />
{<br />
sKey = "\"" + sKey + "\"";<br />
}<br />
<br />
// used for a possible "Key" used in comparison<br />
string pKey;<br />
<br />
integer jtLength = llStringLength(jsonText) - 1;<br />
<br />
while (iter < jtLength)<br />
{<br />
// go to start of a possible "Key"<br />
while (llGetSubString(jsonText, ++iter, iter) != "\"")<br />
{<br />
};<br />
<br />
// form pKey<br />
pKey = "\"";<br />
inQuote = TRUE;<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
pKey = pKey + char;<br />
if (char == "\"" && prevChar != "\\")<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to start of Value, eating possible white space<br />
while (llGetSubString(jsonText, ++iter, iter) != ":")<br />
{<br />
};<br />
<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
<br />
while (char == "%20" || char == "%09" || char == "%0a" || char == "%0d")<br />
{<br />
char = llEscapeURL(llGetSubString(jsonText, ++iter, iter));<br />
}<br />
<br />
char = llUnescapeURL(char);<br />
<br />
// check "Key" for match with sKey AND start of a String Value<br />
if (pKey == sKey && char == "\"")<br />
{<br />
// assemble Value<br />
prevChar = "";<br />
inQuote = TRUE;<br />
rString = "\"";<br />
<br />
while (inQuote)<br />
{<br />
char = llGetSubString(jsonText, ++iter, iter);<br />
rString = rString + char;<br />
if (char == "\"" && prevChar != "\\")<br />
{<br />
inQuote = FALSE;<br />
}<br />
prevChar = char;<br />
}<br />
<br />
// move to ',' or '}' (next "Key"Value pair or end of object)<br />
while(!(llGetSubString(jsonText, ++iter, iter) == "," || llGetSubString(jsonText, iter, iter) == "}")){};<br />
}<br />
else<br />
{<br />
// eat Value to next Key or end of object<br />
integer inValue = TRUE;<br />
prevChar = "";<br />
inArrayObject = 0;<br />
inQuote = FALSE;<br />
<br />
while (inValue)<br />
{<br />
char = llGetSubString(jsonText, iter, iter++);<br />
if (char == "\"" && prevChar != "\\")<br />
{<br />
inQuote = !inQuote; <br />
}<br />
else if ((char == "," || char == "}") && !inQuote && !inArrayObject)<br />
{<br />
inValue = FALSE;<br />
--iter;<br />
}<br />
else if ((char == "[" || char == "{") && !inQuote)<br />
{<br />
++inArrayObject;<br />
}<br />
else if ((char == "]" || char == "}") && !inQuote)<br />
{<br />
--inArrayObject;<br />
}<br />
prevChar = char;<br />
}<br />
}<br />
}<br />
}<br />
}<br />
return rString;<br />
}<br />
<br />
// example usage and comparison<br />
default {<br />
touch_end (integer i){<br />
string jText = "{\"B\":\"Z\",\"C\":[1,\"a\\r\\t\\f\",3],\"A\":\"H\\n\\u23AF\"}";<br />
llOwnerSay(jText); // => '{"B":"Z","C":[1,"a\r\t\f",3],"A":"H\n\u23AF"}'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["A"])); // => 'H' then Unicode character for New Line then 'u23AF'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["A"])); // => "H\n\u23AF"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["B"])); // => 'Z'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["B"])); // => "Z"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C"])); // => '[1,"a\r\t\f",3]'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 0])); // => '1'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 0])); // => '1'<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 1])); // => 'a' then Unicode characters for the escaped sequences<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 1])); // => "a\r\t\f"<br />
<br />
llOwnerSay(llJsonGetValue(jText, ["C", 2])); // => '3'<br />
llOwnerSay(uJsonGetValueSafe(jText, ["C", 2])); // => '3'<br />
}<br />
}</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Stack_Implementations_using_Json_Arrays&diff=1181803
User:LepreKhaun Resident/Stack Implementations using Json Arrays
2013-09-24T00:40:43Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== Three Stack Implementations using Json Arrays ==<br />
<br />
<br />
The [http://en.wikipedia.org/wiki/Stack_(abstract_data_type) Stack] is a much used abstract data type with properties that make it invalualabe for recursive operations. It is known as a LIFO, Last-In-First-Out, data type with some elementary operations; PUSH (which adds a Value to the Stack), POP (which retrieves the last Value added to it) and PEEK (which "looks" at the last Value added to the top of the stack without removing it). Additionally, a SIZE_OF method is handy to see how many Values are currently held within the Stack; one doesn't want to POP a Value when there are no Values there to be POPPED, which would result in a condition known as "underflow".<br />
<br />
It might be noted here that a Value need not be really "removed" from the Stack when it is POPPED, but the size of the Stack is simply decreased. This is because the size of the Stack is used as a pointer to the top of the Stack and the Value can be safely ignored from then on since it's no longer "within" the Stack and it'll be overwritten by a new Value whenever the length gets back up to that point again.<br />
<br />
Here are three Stack implementations of increasing complexity. The first is simply one global Stack which may be accessed anywhere within the script.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR ONE GLOBAL STACK<br />
////////////////<br />
<br />
// Global stack declaration and initialization<br />
string ourStack = "[]";<br />
// SIZE_OF the stack may be had by simply checking this<br />
integer stackSize = 0;<br />
<br />
<br />
// Takes a (string)item and appends it to stack<br />
PUSH (string ITEM) {<br />
ourStack = llJsonSetValue(ourStack, [stackSize++], ITEM);<br />
}<br />
<br />
// "Removes" and returns the top of the stack<br />
string POP () {<br />
if (stackSize) return llJsonGetValue(ourStack, [--stackSize]);<br />
else return "";<br />
}<br />
<br />
// Just "looks" at the top of the stack<br />
// and returns item<br />
string PEEK () {<br />
if (stackSize) return llJsonGetValue(ourStack, [(stackSize-1)]);<br />
else return "";<br />
}<br />
<br />
/////////////////<br />
// end STACK METHODS FOR GLOBAL STACK<br />
////////////////</lsl><br />
<br />
The second implementation forms a Stack as needed, which is then held and sent to its [http://en.wikipedia.org/wiki/Method_(computer_programming) methods] (geek term for a function that is object specific) in it's entirity. This may be preferred over the third implementation in that there is no global(s) used, however the passing by reference of an entire stack for each operation may outweigh that and the third implementation may prove better in some cases.<br />
<br />
In this and the next implementation, the size of the Stack is the first element within the array, making the indexing for its Values one-based instead of zero-based. In other words, the last element (top of the Stack) will now be found with length_of_array instead of length_of_array-1 with length_of_array always to be found at index 0.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR MULTIPLE STACKS<br />
////////////////<br />
<br />
// returns a JSON_ARRAY as a Stack Object<br />
string stINIT () {<br />
return "[0]";<br />
}<br />
<br />
// returns the number of items in stack<br />
integer stSIZE_OF (string jsonST) {<br />
return (integer)llJsonGetValue(jsonST, [0]);<br />
}<br />
<br />
// Takes [stack, item] and appends item to stack<br />
// (Could be written using two parameters instead of a list)<br />
string stPUSH (list jsonST_ITEM) {<br />
string jsonST = llList2String(jsonST_ITEM, 0);<br />
string item = llList2String(jsonST_ITEM, 1);<br />
integer size = stSIZE_OF(jsonST);<br />
<br />
jsonST = llJsonSetValue(jsonST, [0], (string)++size));<br />
return llJsonSetValue(jsonST, [size], item);<br />
}<br />
<br />
// "Removes" the top of the stack<br />
// and returns a list of [stack, item]<br />
list stPOP (string jsonST) {<br />
integer size = stSIZE_OF(jsonST);<br />
// Check for "underflow" condition...<br />
if (size) {<br />
string item = llJsonGetValue(jsonST, [size]);<br />
// set stack pointer to one less<br />
return [llJsonSetValue(jsonST, [0], --size), item];<br />
} else {<br />
return [jsonST, ""];<br />
}<br />
}<br />
<br />
// Just "looks" at the top of the stack<br />
// and returns item<br />
string stPEEK (string jsonST) {<br />
integer size = stSIZE_OF(jsonST);<br />
if (size) {<br />
return llJsonGetValue(jsonST, [size]);<br />
} else {<br />
return "";<br />
}<br />
}<br />
/////////////////<br />
// end -- STACK METHODS FOR MULTIPLE STACKS<br />
////////////////</lsl><br />
<br />
In this final implementation, we'll use integers as (primitive) "pointers", holding and passing them instead of entire stacks. This [http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming) encapsulates] the concept of Stack and almost completely [http://en.dahnielson.com/2012/01/decoupling/ decouples] them from the rest of the code, a good thing. In other words, if we decided at some point that a Stack could be better represented as a Json object, we'd only need to change these methods as given here, anything else calling them would not need to be touched.<br />
<br />
<lsl>/////////////////<br />
// STACK METHODS FOR MULTIPLE STACKS USING "POINTERS" WITHIN A GLOBAL STACK "OBJECT"<br />
////////////////<br />
<br />
// Global declaration and initialization of ourStacks as a Stacks object<br />
// Index 0 is used to determine next available stack "pointer"<br />
ourStacks = "[0]";<br />
<br />
// initialation of a new Stack<br />
// returns a "pointer" to a new stack<br />
integer getNewStackPtr() {<br />
integer numberOfStacks = llJsonGetValue(ourStacks, [0]);<br />
ourStacks = llJsonSetValue (ourStacks, [JSON_APPEND], "[0]");<br />
ourStacks = llJsonSetValue (ourStacks, [0]), ++numberOfStacks);<br />
return numberOfStacks;<br />
}<br />
<br />
// returns the number of items in a stack<br />
integer stPtrSIZE_OF (integer stPtr) {<br />
return (integer)llJsonGetValue(ourStacks, [stPtr, 0]);<br />
}<br />
<br />
// Takes [stackPointer, item] and appends item to stack<br />
stPtrPUSH (list stPtr_ITEM) {<br />
integer stPtr = llList2Integer(stPtr_ITEM, 0);<br />
string item = llList2String(stPtr_ITEM, 1);<br />
integer size = stPtrSIZE_OF(stPtr);<br />
<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, 0], (string)++size));<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, size], item);<br />
}<br />
<br />
// "Removes" the top of the stack<br />
// and returns [stackPointer, item]<br />
string stPtrPOP (integer stPtr) {<br />
integer size = stPtrSIZE_OF(stPtr);<br />
// Avoid "underflow" condition.<br />
if (size) {<br />
string item = llJsonGetValue(ourStacks, [stPtr, size]);<br />
// set stack pointer to one less<br />
ourStacks = llJsonSetValue(ourStacks, [stPtr, 0], --size);<br />
return item;<br />
} else {<br />
return "";<br />
}<br />
}<br />
<br />
// Just "looks" at the top of a stack<br />
// and returns item<br />
string stPtrPEEK (integer stPtr) {<br />
if (stPtrSIZE_OF(stPtr)) {<br />
return llJsonGetValue(ourStacks, [stPtr, stPtrSIZE_OF(stPtr)]);<br />
} else {<br />
return "";<br />
}<br />
}<br />
/////////////////<br />
// end STACK METHODS FOR MULTIPLE STACKS USING "POINTERS" WITHIN A GLOBAL STACK "OBJECT"<br />
////////////////</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText_0ld&diff=1181802
User:LepreKhaun Resident/Workaround4Escaped Chars within JsonText 0ld
2013-09-24T00:39:49Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
=== Workaround for Escaped Characters within Json Text ***Old*** ===<br />
<br />
'''NOTE: This is an archived page showing earlier thoughts to this problem and is kept only for reference to show how one can initially choose the wrong approach to a problem and worry it to death before the light bulb goes off. Please refer to [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|this page]] for the final, much more elegant workaround.'''<br />
<br />
[ETA: The reasoning here was correct, it was just the approach that was faulty, kept thinking it had to be kludged. :=)]<br />
----<br />
<br />
Because of the way LSL handles strings (we have no "raw strings", which are taken as written and not messed with), escape sequences such as "\t" are interpreted as 4 spaces for us as soon as they are encountered. Trying to encode "\t" by escaping the escape character (using "\\t") results in (incorrectly) placing '\\t' within your Json text. Same for newlines, "\n".<br />
<br />
And it's worse when you try to encode something like "\"Stop!\" he shouted." or "She said \"No\"". And UTF encoding such as "\u7650" is perfectly valid within a Json text but is elusive to obtain using LSL strings.<br />
<br />
Here's the only work around I've been able to work out. A kludge, granted, but at least it allows one to encode something like this:<br />
<br />
<pre>{<br />
"A": "\b\f\t\r \n aba \u0000",<br />
"B": "\"he\"", <br />
"C": "\t"<br />
}<br />
<br />
string jText;<br />
string i = llEscapeURL("\\b\\f\\t\\r \\n aba \\u0000");<br />
string j = llEscapeURL("\\\"he\\\"");<br />
<br />
jText = llList2Json(JSON_OBJECT, ["A", i, "B", j]);<br />
jText = llJsonSetValue(jText, ["C"], llEscapeURL("\\t"));<br />
jText = llUnescapeURL(jText);</pre><br />
<br />
'''jText == {"A":"\b\f\t\r \n aba \u0000","B":"\"he\"","C":"\t"}'''<br />
<br />
----<br />
[ETA: 9/13/2013]<br />
<br />
So, I was working the LSL string mis-handling of the escape character ("\") and, looking deeper into have not only found another workaround but made an exciting discovery- LSL does have "raw strings" of a sort, and they are the JSON_STRING! First the alternate workaround:<br />
<br />
<lsl><br />
// NOTE: Deprecated 9/19/2013 and replaced by<br />
// uList2Json() and uJsonSetValue()<br />
<br />
// Global constants<br />
integer QUOTE = 0; // '\"' (Double Quote)<br />
integer SLOSH = 1; // '\\' (Reverse Solidus)<br />
integer SLASH = 2; // '\/' (Solidus)<br />
integer BP = 3; // '\b' (Break Point)<br />
integer FF = 4; // '\f' (Form Feed)<br />
integer NL = 5; // '\n' (New Line)<br />
integer CR = 6; // '\r' (Carriage Return)<br />
integer TAB = 7; // '\t' (Tab)<br />
integer U_ = 8; /* '\u' (Unicode Prefix- MUST immediately precede <br />
a string of 4 Hex digits, 0-G, sans '0x') */<br />
// Optional, included for completeness only<br />
integer CRLF = 9; // '\r\n' (Windows end-of-line)<br />
<br />
//////////////////////////////<br />
// function string uList2JsonStringSafe (list jasonStringParts)<br />
// This function takes a list, jasonStringParts,<br />
// of the parts of the Json string one wishes and<br />
// returns a LSL string within double quotes ("")<br />
// with embedded escape characters within it that<br />
// correctly encodes as a Json string using either<br />
// llList2Json() or llJsonSetValue().<br />
//<br />
// NOTE: Deprecated 9/19/2013 and replaced by<br />
// uList2Json() and uJsonSetValue()<br />
// Version 1.0 by LepreKhaun 9/9/2013 <br />
// May be freely used, modified and distributed with this header intact.<br />
// Compiled Size = 2,088 bytes<br />
///////////////////////////////<br />
string uList2JsonStringSafe (list jasonStringParts)<br />
{<br />
list escapeCodes = ["%5C%22", "%5C%5C", "%5C/", "%5Cb", "%5Cf", "%5Cn", "%5Cr", "%5Ct", "%5Cu", "%5Cr%5Cn"];<br />
<br />
integer iter = llGetListLength(jasonStringParts);<br />
<br />
// rString must be enclosed with escaped double quotes<br />
// to keep the LSL String "enhanced features" out of play<br />
string rString = "\"";<br />
<br />
// build return string 'backwards'<br />
while (~--iter) <br />
{<br />
if(llGetListEntryType(jasonStringParts, iter) == TYPE_INTEGER)<br />
{<br />
// substitute encoding for integer constants<br />
rString = llList2String(escapeCodes, llList2Integer(jasonStringParts, iter)) + rString;<br />
}<br />
else<br />
{<br />
// escape String chunks to preserve them properly<br />
rString = llEscapeURL(llList2String(jasonStringParts, iter)) + rString;<br />
}<br />
}<br />
return llUnescapeURL("\"" + rString);<br />
}<br />
<br />
///////////<br />
// Example encodings showing usage<br />
///////////<br />
<br />
default<br />
{<br />
touch_end(integer i)<br />
{<br />
string jsonString;<br />
string jsonText;<br />
<br />
// To encode '{"A":"\"Go!\" he yelled.\nShe replied \"No!\"","Z":"\\escaped \\ slosh\\"}'<br />
jsonString = uList2JsonStringSafe([QUOTE, "Go!", QUOTE, " he yelled.", NL, "She replied ", QUOTE, "No!", QUOTE]);<br />
jsonText = llList2Json(JSON_OBJECT, ["A", jsonString]);<br />
jsonString = uList2JsonStringSafe([SLOSH, "escaped ", SLOSH, " slosh", SLOSH]);<br />
jsonText = llJsonSetValue(jsonText, ["Z"], jsonString);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '{"Control Chars":"\b\r\f\n\t and Windows uses \r\n for EOL","©":"\u00A9"}'<br />
jsonString = uList2JsonStringSafe([BP, CR, FF, NL, TAB, " and Windows uses ", CRLF, " for EOL"]);<br />
jsonText = llList2Json(JSON_OBJECT, ["Control Chars", jsonString]);<br />
jsonString = uList2JsonStringSafe([U_, "00A9"]);<br />
jsonText = llJsonSetValue(jsonText, ["©"], jsonString);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '["WebSite","http:\/\/my.com\/ask.php?what%20is%20it","\t"]'<br />
jsonString = uList2JsonStringSafe(["http:", SLASH, SLASH, "my.com", SLASH, "ask.php?what%20is%20it"]);<br />
jsonText = llList2Json(JSON_ARRAY, ["WebSite", jsonString]);<br />
jsonText = llJsonSetValue(jsonText, [JSON_APPEND], uList2JsonStringSafe([TAB]));<br />
llOwnerSay(jsonText);<br />
}<br />
}</lsl><br />
<br />
The how and why this approach works is based on an earlier observation I had made that Json text (LSL strings that were enclosed within '{}' or '[]') were being handled differently than other LSL strings in that their enclosed escape codes (such as '\t') were not being translated (to '%09" or '%20%20%20%20'), a "feature" LSL strings have.<br />
<br />
I then noticed a difference in definitions between [http://tools.ietf.org/html/rfc4627 RFC 4627] and [http://www.json.org/ JSON.org]. The RFC defines a Json text to be either an array or an object but at json.org it's defined as any Json Value, including the JSON_STRING. And a JSON_STRING is defined, of course, as being enclosed within double quotes (""). So I began experimenting with that type of LSL string and found the same exception to "enhanced features" was afforded!<br />
<br />
But then another problem surfaced: The LSL functions llJsonGetValue() llJson2List() extracts a JSON_STRING as a regular LSL String, resulting in these escaped character sequences being "enhanced" by translation (in other words '\t' becomes '%09', which is further "enhanced" to '%20%20%20%20' when chatted and '\u23B5' becomes 'u23B5'. Grrrrr.... This wasn't good for further processing, we needed a String to preserve these after the extraction.<br />
<br />
And that lead to the development of [[LepreKhaun_Resident/Json_Get_Value_Safe|uJsonGetValueSafe()]], which returns the requested Value explicitly enclosed within double quotes {""}, just as it appears within the Json text...<br />
<br />
And, of course, this was complicated by the RFC stating:<br />
<pre> Insignificant whitespace is allowed before or after any of the six<br />
structural characters.<br />
<br />
ws = *(<br />
%x20 / ; Space<br />
%x09 / ; Horizontal tab<br />
%x0A / ; Line feed or New line<br />
%x0D ; Carriage return<br />
</pre> )<br />
Hooboy!<br />
<br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText&diff=1181801
User:LepreKhaun Resident/Workaround4Escaped Chars within JsonText
2013-09-24T00:38:56Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
=== uList2Json() and uJsonSetValue()===<br />
<br />
As many of you may be aware, LSL has the habit of "enhancing" Strings. This is regarded as a "feature" of the language and usually works out for the best, giving one the option of formatting chatted text by using "\t" and "\n". Unfortunately, one didn't have a way to opt out of this behavior. Put in computereze, LSL simply lacked "raw strings".<br />
<br />
This has bedeviled those working with Json text, either for web communications or developing other uses for it, because some strings just wouldn't encode properly. That is to say, these are all perfectly valid Json strings that simply couldn't be directly formed with llList2Json() and llJsonSetValue():<br />
*"\"Go!\" he yelled.\n"<br />
*"She replied \"No!\""<br />
*"Copyright symbol is \u00A9"<br />
*"oops]"<br />
*"Control characters are \t\n\r\f\b"<br />
<br />
I've spent a few weeks studying the problem, [[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText_0ld|most of it going about it the wrong way]], but had an epiphany. A one line addition Maestro Linden added to [[Json_usage_in_LSL|Json Usage in LSL]] on the 10th ("LSL strings which both begin and end with "\"" are interpreted literally as JSON strings, while those without are parsed when converted into JSON.") confirmed what I had begun to surmise- a Json String (being a LSL String that is further enclosed within double quotes) is a "raw string"! Once I had that in hand, the following two functions practically wrote themselves.<br />
<br />
<br />
<div><lsl>//////////////////////////////<br />
// function string uList2Json (string type, list values)<br />
// This function takes the exact same parameters as<br />
// llList2Json() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uList2Json (string type, list values)<br />
{<br />
<br />
integer iter = -1;<br />
integer listLength = llGetListLength(values);<br />
<br />
// Step through list, hitting every other item if JSON_OBJECT<br />
while ((iter = ++iter + (type == JSON_OBJECT)) < listLength)<br />
// necessary so we don't choke on next if test<br />
if (llGetListEntryType(values, iter) == TYPE_STRING)<br />
// make sure it is not a JSON_* Value or a Number<br />
if (llJsonValueType(llList2String(values, iter), []) == JSON_INVALID)<br />
values = llListReplaceList(values, ["\"" + llList2String(values, iter) + "\""], iter, iter);<br />
<br />
return llList2Json(type, values);<br />
} <br />
<br />
//////////////////////////////<br />
// function string uJsonSetValue ( string json, list specifiers, string value )<br />
// This function takes the exact same parameters as<br />
// llJsonSetValue() but correctly encodes all possible strings<br />
// including those with escape characters within them.<br />
//<br />
// Initial strings must escape all instances of the<br />
// desired escape character itself <br />
// (ie "\\t" => '\t', "\\\\" => '\\', "\\/" => '\/')<br />
// as well as any double quotes ("\\\"" => '\"')<br />
//<br />
// NOTE: To encode a Float or Integer as a String<br />
// within the Json text, enclose it with escaped quotes<br />
// (ie '"3"' => '3' BUT '"\"3\""' => '"3"')<br />
//<br />
// Version 1.0 by LepreKhaun 9/19/2013<br />
// May be freely used, modified and distributed with this header intact.<br />
///////////////////////////////<br />
string uJsonSetValue(string json, list specifiers, string value)<br />
{<br />
// We don't want to change the string representation of <br />
// an integer, a float or any Json Value Type<br />
if (llJsonValueType(value, []) == JSON_INVALID)<br />
value = "\"" + value + "\"";<br />
return llJsonSetValue(json, specifiers, value);<br />
}<br />
<br />
<br />
///////////<br />
// Examples showing usage<br />
///////////<br />
<br />
default<br />
{<br />
touch_end(integer i)<br />
{<br />
string temp;<br />
string jsonText;<br />
<br />
// To encode '{"A":"\"Go!\" he yelled.\nShe replied \"No!\"","Z":"\\escaped \\ slosh\\"}'<br />
jsonText = uList2Json (JSON_OBJECT, [<br />
"A", "\\\"Go!\\\" he yelled.\\nShe replied \\\"No!\\\"", <br />
"Z", "\\\\escaped \\\\ slosh\\\\"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '{"Control Chars":"\b\r\f\n\t and Windows uses \r\n for EOL","©":"\u00A9"}'<br />
jsonText = uList2Json(JSON_OBJECT, [<br />
"Control Chars", "\\b\\r\\f\\n\\t and Windows uses \\r\\n for EOL", <br />
"©", "\\u00A9"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// To encode '["WebSite","http:\/\/my.com\/ask.php?what%20is%20it","\t"]'<br />
jsonText = uList2Json(JSON_ARRAY, [<br />
"WebSite",<br />
"http:\\/\\/my.com\\/ask.php?what%20is%20it",<br />
"\\t"<br />
]);<br />
llOwnerSay(jsonText);<br />
<br />
// Make a Json object...<br />
temp = uList2Json(JSON_OBJECT, [<br />
"A", 99,<br />
"Z", "88]",<br />
"C", JSON_TRUE<br />
]);<br />
// ... add it to end of the array ...<br />
jsonText = uJsonSetValue(jsonText, [JSON_APPEND], temp);<br />
// ... change our web address ...<br />
jsonText = uJsonSetValue(jsonText, [1], "http:\\/\\/www.google.com");<br />
// ... change that TAB in the third spot to PI<br />
jsonText = uJsonSetValue(jsonText, [2], (string)PI);<br />
// ... and add a new "Key":Value pair to our object<br />
jsonText = uJsonSetValue(jsonText, [3, "New"], ((string)PI + "\\n"));<br />
<br />
// ["WebSite","http:\/\/www.google.com",3.141593,{"A":99,"C":true,"New":"3.141593\n","Z":"88]"}]<br />
llOwnerSay(jsonText);<br />
<br />
}<br />
}</lsl></div><br />
<br />
Now, if I can just get the retrieval worked out as simply... ;=)<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Database_2_Chat&diff=1181800
User:LepreKhaun Resident/Json Database 2 Chat
2013-09-24T00:38:14Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
You may find at some point that you've written an application with a Json text database within it that is 10k or so in size and now you need to update the code, perhaps to add some new record fields you realize you require. Ohoh!<br />
<br />
Let's hope you have the following code in place to retrieve the database, so you can update and debug your code and then reset everything properly. Otherwise, you'll have lost your entire database. Ouch!<br />
<br />
Can also ('''now!''' lol) be used just to obtain a back up of your database at times.<br />
<br />
<pre>// Where myDataBase is a global Json text string<br />
// function jsonDb2Chat ();<br />
// Version 1.5 (8/29/2013 - added a necessary conversion of DB back to original!)<br />
// Version 1.0<br />
// By LepreKhaun 8/28/2013<br />
<br />
jsonDb2Chat () {<br />
integer count = 0;<br />
<br />
// Needed to keep internal quotes and escape characters intact<br />
// Be *certain* you have the available memory needed for this inflation!<br />
myDataBase = llEscapeURL(myDataBase);<br />
<br />
// Keeping in mind chat can only output 1024 single-byte characters at a time:<br />
integer totalChunks = (integer)(llStringLength (myDataBase)/1022);<br />
llOwnerSay ("Chatting your database.\n\n");<br />
while (count < totalChunks) {<br />
llOwnerSay ("\n" + llGetSubString (myDataBase, count*1022, ((++count)*1022)-1));<br />
}<br />
llOwnerSay ("\n" + llGetSubString(myDataBase, count*1022, -1));<br />
// convert DB back so this can be used to simply retrieve a back up at times<br />
myDataBase = llUnescapeURL(myDataBase); <br />
<br />
}</pre><br />
<br />
After calling this function (possibly as a response to a button within your admin menu- "ChatDB", or a chatted command that's listened for on some obscure channel that is masked for the owner's key), the object will chat out the database for you.<br />
<br />
All that remains now is to copy&paste this output to a text document, remove the inserted new lines and '[time stamp] Object:' bits, and then put double quotes around it all. Finally, have the following initialization line in your rewritten code's default state_entry() event for your global 'string myDataBase;':<br />
<pre>myDataBase = llUnescapeURL('your cleaned and double quote enclosed chat output');</pre><br />
<br />
'''NOTE:''' When using Json text for a database, you should check free memory after each insertion of new data into it. Only by doing so will you be able to realize that things may be getting a wee bit too tight for comfort within your program.<br />
<br />
At that point, you need to consider a way to either shorten the length of your database, possible by going with (shudder) one character "Key"s (making a note in comments of what Key "Z" stands for) deleting older or no longer necessary records and/or transferring the entire database into a stand alone script with minimal functionality and having a link message protocol worked out for retrieval, insertion, deletion and updating the records.<br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Delete_Json_Element&diff=1181799
User:LepreKhaun Resident/Delete Json Element
2013-09-24T00:37:39Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
<lsl><br />
// Function: string deleteJsonElement( string jsonSource, list pathtoElement );<br />
// Version 1.5 9/7/2013 Fixed case for a single item pathtoElement<br />
// Version 1.0 by LepreKhaun, 6/21/2013. Free to copy, modify and use as one wishes with this comment included.<br />
// This function takes a JSON text string and returns a copy of it with a specified element removed from it.<br />
// jsonSource is the JSON text to remove an element from.<br />
// pathToElement is a List containing the transversal path to the element<br />
// (as defined as "specifiers" in http://wiki.secondlife.com/wiki/Json_usage_in_LSL )<br />
// AND ending with the element to remove.<br />
// The element may be an array Value or the "Key" within an object<br />
// If the parent of the element is a JSON_ARRAY, the element to be removed must be an integer INDEX <br />
// If the parent of the element is a JSON_OBJECT, the element to be removed must be a string "KEY"<br />
//<br />
// NOTE: This code is not optimized nor does it contain any error checking!!! <br />
// Add whatever you feel is needed to ensure correct operation of your script.<br />
<br />
string deleteJsonElement( string jsonSource, list pathtoElement ) <br />
{<br />
<br />
integer placeinlist;<br />
<br />
// Obtain the JSON object of the parent of the element<br />
string jsonParent = llJsonGetValue( jsonSource, llDeleteSubList( pathtoElement, -1, -1 ) );<br />
<br />
// Convert it to a list<br />
list listParent = llJson2List( jsonParent );<br />
<br />
// Do test<br />
if (llJsonValueType( jsonParent, [] ) == JSON_ARRAY)<br />
{<br />
placeinlist = llList2Integer( pathtoElement, -1 );<br />
listParent = llDeleteSubList( listParent, placeinlist, placeinlist );<br />
<br />
// convert to a JSON object<br />
jsonParent = llList2Json( JSON_ARRAY, listParent );<br />
<br />
} <br />
else // We are dealing with a JSON_OBJECT<br />
{<br />
placeinlist = llListFindList( listParent, llList2List( pathtoElement, -1, -1 ) );<br />
listParent = llDeleteSubList( listParent, placeinlist, placeinlist + 1 );<br />
<br />
// convert to a JSON object<br />
jsonParent = llList2Json( JSON_OBJECT, listParent );<br />
}<br />
<br />
<br />
// Insert our results and return<br />
return llJsonSetValue( jsonSource, llList2List( pathtoElement, 0, -2 ), jsonParent ); <br />
}<br />
</lsl><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident/Json_Pretty_Printer&diff=1181798
User:LepreKhaun Resident/Json Pretty Printer
2013-09-24T00:37:01Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== JsonPrettyChat.lsl - a JSON Pretty Printer ==<br />
<br />
This is a stand alone debugging tool for working with JSON text. It acts like all JSON pretty printers and outputs to llOwnerSay(). This is NOT a JSON validator, meaning it may well "pretty print" your string even if your strings within it are mal-formed json constructions (such as having "\s" within it or empty values such as "[,,,]", which breaks strict JSON compliance). But, it will separate your strings out for visual inspection.<br />
<br />
It uses recursion A LOT so will likely crash if you have a very large JSON structure. However, it'll have worked it up to a point where you can determine where it hit the stack heap collision, and you simply need to break parts of the JSON string out to continue deeper into it.<br />
<br />
It expects a link message with the JSON string as the third parameter. The second parameter is used as a "channel ID" (defaults to 75 as written). If this conflicts with your existing link messaging system, I'd expect you should see how to modify the code to suit yourself.<br />
<br />
<lsl><br />
////////////////////////////////////////////////////<br />
// JsonPrettyChat.lsl<br />
//<br />
// A debugging tool for Json construction<br />
// Version 1.2 by LepreKhaun -- 2013-07-10<br />
// Corrected mishandling of quoted numbers.<br />
// Corrected formatting of Key values in json objects.<br />
// Version 1.0 Released -- 2013-07-09<br />
//<br />
// Usage: Place this stand-alone script within object containing program<br />
// you wish to debug and address it with<br />
// llMessageLinked ( integer LINK_SET, integer MESSAGE_CHANNEL, string json, key NULL_KEY );<br />
// at the point(s) you wish to review the JSON string.<br />
////////////////////////////////////////////////////<br />
<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
// How deep we are in the json structure<br />
integer LEVEL = 0;<br />
<br />
// User functions<br />
chatThis (string message) {<br />
string indent = "";<br />
integer iter = LEVEL;<br />
<br />
while (iter--){<br />
indent += "\t";<br />
}<br />
llOwnerSay (indent + message);<br />
}<br />
<br />
handleValue (string prePend, string value, string apPend) {<br />
// JSON Value Type<br />
string valueType = llJsonValueType(value, []);<br />
<br />
if (valueType == JSON_FALSE) {<br />
chatThis (prePend + "false" + apPend);<br />
} else if (valueType == JSON_TRUE) {<br />
chatThis (prePend + "true" + apPend);<br />
} else if (valueType == JSON_NULL) {<br />
chatThis (prePend + "null" + apPend);<br />
} else if (valueType == JSON_NUMBER) {<br />
chatThis (prePend + value + apPend);<br />
} else if (valueType == JSON_ARRAY) {<br />
chatThis (prePend + "[");<br />
++LEVEL;<br />
handleJsonArray (value);<br />
--LEVEL;<br />
chatThis ("]" + apPend);<br />
} else if (valueType == JSON_OBJECT) {<br />
chatThis (prePend + "{");<br />
++LEVEL;<br />
handleJsonObject (value);<br />
--LEVEL;<br />
chatThis ("}" + apPend);<br />
// NOTE: Once back in list form, all strings evaluate to JSON_INVALID<br />
// because of having their enclosing double quotes (") stripped, So...<br />
} else {<br />
// We'll treat it as a String<br />
chatThis (prePend + value + apPend);<br />
}<br />
}<br />
<br />
handleJsonArray (string jsonArray) {<br />
list valueList = llJson2List(jsonArray);<br />
integer iter = 0;<br />
integer listLength = llGetListLength(valueList);<br />
<br />
while (iter<listLength) {<br />
string value = llList2String(valueList, iter);<br />
if (llJsonValueType(jsonArray,[iter])== JSON_STRING) value = "\"" + value + "\"";<br />
if (++iter == listLength) handleValue ("", value, "");<br />
else handleValue ("", value, ",");<br />
}<br />
}<br />
<br />
handleJsonObject (string jsonObject) {<br />
list valueList = llJson2List(jsonObject);<br />
integer iter = 0;<br />
integer listLength = llGetListLength(valueList);<br />
while (iter<listLength) {<br />
string myKey = llList2String(valueList, iter);<br />
string value = llList2String(valueList, ++iter);<br />
if (llJsonValueType(jsonObject,[myKey])== JSON_STRING) value = "\"" + value + "\"";<br />
myKey = "\"" + myKey + "\": ";<br />
<br />
if (++iter == listLength) handleValue (myKey, value, "");<br />
else handleValue (myKey, value, ",");<br />
}<br />
}<br />
<br />
// Main Program<br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay ("Hello, " + llKey2Name(llGetOwner()));<br />
llOwnerSay ("Json Pretty Chat awaits your JSON string");<br />
llOwnerSay ("Use " + (string)MESSAGE_CHANNEL + " for the second paramater of");<br />
llOwnerSay ("llMessageLinked\(\) and supply your JSON string in the third.");<br />
}<br />
<br />
link_message(integer sender_number, integer number, string message, key id)<br />
{<br />
if (number == MESSAGE_CHANNEL) {<br />
llOwnerSay("Pretty Chat of: " + message);<br />
handleValue("", message, "");<br />
}<br />
}<br />
}<br />
</lsl><br />
<br />
Harness program, showing usage:<br />
<lsl><br />
default<br />
{<br />
state_entry()<br />
{<br />
llOwnerSay("Hello, Avatar!");<br />
}<br />
<br />
touch_start(integer total_number)<br />
{<br />
// Used as a "channel ID' for link messages<br />
integer MESSAGE_CHANNEL = 75;<br />
<br />
string source = llList2Json(JSON_OBJECT, ["x",llList2Json(JSON_ARRAY, ["x", 1, JSON_TRUE]),"Y",JSON_FALSE]);<br />
<br />
llMessageLinked (LINK_THIS, MESSAGE_CHANNEL, source, NULL_KEY);<br />
}<br />
}<br />
</lsl><br />
<br />
Outputs:<br />
<pre><br />
Object: Hello, LepreKhaun Resident<br />
Object: Json Pretty Chat is waiting for your JSON string<br />
Object: Use 75 for the second paramater of<br />
Object: llMessageLinked() and supply your JSON string in the third.<br />
<br />
// Harness program checking in.<br />
Object: Hello, Avatar!<br />
<br />
// Result of touch_start()<br />
Object: Pretty Chat of: {"x":["x",1,true],"Y":false}<br />
Object: {<br />
Object: "x": [<br />
Object: "x",<br />
Object: 1,<br />
Object: true<br />
Object: ],<br />
Object: "Y": false<br />
Object: }<br />
</pre><br />
<br />
----<br />
<br />
<center>== [[User:LepreKhaun_Resident|'''More Json Tips, Tricks and Coding Examples''']] ==</center></div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User:LepreKhaun_Resident&diff=1181797
User:LepreKhaun Resident
2013-09-24T00:35:04Z
<p>LepreKhaun Resident: </p>
<hr />
<div>['''NOTE:''' Since I refrain from rearranging the flamingos in front of your trailer home, you are expected to extend the courtesy and leave comments, suggested improvements, corrections of fact or your own personal preferences ONLY on the Discussion Pages within my Name Space. Thank you!]<br />
<br />
== A bit about me (well, maybe a byte or so) ==<br />
I'm a semi-retired, long-time resident of New Orleans, LA, though I traveled extensively in my youth. I got my first computer in 1984, a [http://en.wikipedia.org/wiki/Commodore_64 Commodore 64] and self taught myself both Basic and assembly language on it. From that point on, I've always had a computer, sometimes several at a time, and my interest in this fascinating tool/toy has grown.<br />
<br />
Along the way I decided to get some formal education so I got my GED in 1992, and enrolled in [http://www.uno.edu/ UNO] as a Computer Science major. During my 4 year enrollment there, I worked for two professors as a teachers aide, both teaching course material as well as grading programming efforts of other students. At the end, I ended up with a GPA of 3.45, two letters of recommendation and fell 15 hours short of getting my Bachelors Degree (which I plan to rectify next year).<br />
<br />
After college, during which I had discovered this thing called the [http://en.wikipedia.org/wiki/World_Wide_Web Internet], I began free-lancing as a [http://www.perl.org/ Perl] [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI] programmer, designing and implementing both user interfaces as well as complete back end solutions.<br />
<br />
That business venture lasted until Y2K or so, when [https://en.wikipedia.org/wiki/PHP PHP] functionality and [https://en.wikipedia.org/wiki/Active_Server_Pages ASP] began to supplant the need for such but my interest didn't wane. I've since taught myself [https://en.wikipedia.org/wiki/Object-oriented_programming OOP] as well as a number of scripting languages such as [https://en.wikipedia.org/wiki/ActionScript ActionScript] and, most recently, [http://en.wikipedia.org/wiki/Linden_Scripting_Language LSL].<br />
<br />
I'm also a practising zen buddhist, semi-professional performer, skilled carpenter & renovator, amateur sculptor, avid reader and an active volunteer in a number of causes I believe in.<br />
<br />
I'm in Second Life to learn, create and share, the same as my RL.<br />
<br />
<br />
== Code bits that one might find useful ==<br />
<br />
===Json Related===<br />
#[[User:LepreKhaun_Resident/Json_Pretty_Printer|'''JSON Pretty Printer''']] A Json debugging tool that "pretty prints" a Json text to chat.<br />
#[[User:LepreKhaun_Resident/Delete_Json_Element|'''Delete Json Element''']] A function that removes an element (either a Value from an array or a "Key":Value pair from an object) from the supplied Json text.<br />
#[[User:LepreKhaun_Resident/Json_Database_2_Chat|'''Json Database 2 Chat''']] A function to retrieve a Json text from within a script, to be reused later in its original form.<br />
#[[User:LepreKhaun_Resident/Workaround4Escaped_Chars_within_JsonText|'''Workaround for Escaped Characters within Json Text''']] A way to encode '\t', '\n' and such as well as `"\"he said\""' within Json text. ['''ETA 9/13/2013: added User Function for same!''']<br />
#[[User:LepreKhaun_Resident/Stack_Implementations_using_Json_Arrays|'''Stack Implementations using Json Arrays''']] Showing 3 ways to implement a Stack in LSL using Json Text.<br />
#[[User:LepreKhaun_Resident/Json_Get_Value_Safe|'''Json Get Value Safe (user function)''']] A way to retrieve JSON_STRING without having it "enhanced" by LSL String handling.<br />
<br />
----<br />
{{Jira Reporter}}<br />
{{ISO 639-3/cat-speaking|eng}}<br />
{{skills <br />
|Builder=*<br />
|Scripter=* <br />
|}}</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:LepreKhaun_Resident&diff=1181794
User talk:LepreKhaun Resident
2013-09-24T00:01:30Z
<p>LepreKhaun Resident: </p>
<hr />
<div>== LSL indent style: ==<br />
Hi, I edited a few of your example scripts. I'd appreciate you using method two (BSD style) as described on the [[LSL_Style_Guide]] page. It's easier to read for beginners. It might be easier for the Javascript people to follow their [http://en.wikipedia.org/wiki/Indent_style indent style] (that would be K&R), but if you're starting from zero without any knowledge of any programming language BSD really is easier to read even though you have extra lines.-- [[User:Kireji Haiku|Kireji Haiku]] 11:37, 23 September 2013 (PDT)<br />
: Edit all you want, but outside of my Name Space please. Lynne Truss said it best using an [http://www.goodreads.com/quotes/487553-there-is-an-old-german-fable-about-porcupines-who-need old German fable]. OK?<br />
<br />
: Oh, and personal style opinions are merely that. After 3 decades in the industry (some of it actually teaching beginners), I pretty much have my own worked out to my satisfaction. -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 17:01, 23 September 2013 (PDT)</div>
LepreKhaun Resident
https://wiki.secondlife.com/w/index.php?title=User_talk:Kireji_Haiku&diff=1181793
User talk:Kireji Haiku
2013-09-23T23:41:41Z
<p>LepreKhaun Resident: There's an old German fable about porcupines...</p>
<hr />
<div>== Thanks for the Diff ==<br />
<br />
It's terribly hard to keep up with every item, especially when the wiki isn't complete. Been trying to fill in some holes lately. some of the invalid stuff is Opensim Related. Not needed for SL true, but no harm being there either. :) [[User:Darien Caldwell|Darien Caldwell]] 18:14, 10 July 2013 (PDT)<br />
<br />
<br />
== Stay out of my User Space. Please ==<br />
You can add as many comments, criticisms and suggested changes to any talk page within my name space: [[User:LepreKhaun_Resident]] but, as a personal courtesy, please refrain from editing the pages themselves. Thank you. -- [[User:LepreKhaun Resident|LepreKhaun Resident]] 16:41, 23 September 2013 (PDT)</div>
LepreKhaun Resident