• GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.

Useful

A Useful Script - "Mass Distribution by List of Names in a Notecard"

I recently had cause to distribute a number of items to a large number of people, whose names I was in possession of a list of, but not, of course, their keys.

The appalling lack of a useful llName2Key function unfortunately makes it a little challenging to send things out, but this is a problem that I have encountered before, and the obvious course of action is to

  1. put all of the items to be sent out into a prim;
  2. add a notecard containing the list of names to which these items are to be sent;
  3. add a script which simply goes through these names, queries one of the several "name2key" databases in existence, and, should it find an appropriate key, sends the items out.

For general use I include such a script herein.

In this I included features which tell one how many lines of the names notecard remain, and an estimate of the how much time remains, as well, though this may or may not be terribly accurate.

I am aware that it could be made considerably faster by the use of subscripts to send the inventory items, but that would make for a rather poor example script; I would prefer to keep the whole affair as simple as possible, in other words, in one script that is put into one prim. The introduction of inventory-giving subscripts is left as an exercise for the keen student.

~*~

As a further note, a future script using this sort of system to be published here will be a vendor that optionally sends the item to another person - in other words, a gift-giver that allows people to purchase copy/no-trans goods for others, which will allow those who had been forced to rely upon Xstreet for this the opportunity to abandon the dratted site.

Mass distribution script

Code summary: 

Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't.

To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.)

Then, touch to start sending. There will be a display of names left to check and estimated time remaining.

There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies.

// Mass distribution script // Ordinal Malaprop 2010-01-15 11:29 //..................................................................... // Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't. // To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.) // Then, touch to start sending. There will be a display of names left to check and estimated time remaining. // There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies. // The original script can be found at http://ordinalmalaprop.com/engine/code/mass-distribution-script //--------------------------------------------------------------------- // LICENCE - Creative Commons "Attribution" 3.0 // http://creativecommons.org/licenses/by/3.0/ // Basically use it how you like, but if you do, please include a mention somewhere of me, and if possible a link to the original script. //--------------------------------------------------------------------- // Globals and constants // Configurable string NAME_NOTECARD = "Names"; // Change this if you want to call the notecard with your list of names on it something else. float TIMEOUT = 10.0; // There is no particular reason you would change this but you might wish to perhaps. integer TEST = FALSE; // change to TRUE to just run through the names in your notecard without sending anything // Not configurable - leave these alone key gQuery = NULL_KEY; string gAvName = ""; integer gLine = 0; integer gNumberOfLines = 0; list gItems = []; list gNotFound = []; integer gQuerySource = -1; //--------------------------------------------------------------------- // Functions // Looks for the next name on the list get_next_name() { llSetTimerEvent(TIMEOUT); if (gNumberOfLines == 0) { llSetText("Checking list size", <1.0, 1.0, 0.0>, 1.0); gQuery = llGetNumberOfNotecardLines(NAME_NOTECARD); } else { gQuery = llGetNotecardLine(NAME_NOTECARD, gLine++); update(); } } // Updates the prim display update() { integer line = gLine - 1; integer done = llRound(100 * line / gNumberOfLines); float x = (float)done / 100.0; llSetColor(, ALL_SIDES); llSetText((string)done + "% done (" + (string)line + "/" + (string)gNumberOfLines + ")\nRemaining time: " + time_left(line), <1.0, 1.0, 0.0>, 1.0); } string time_left(integer line) { if (gNumberOfLines == 0) return "unknown"; if (line == 0) { llResetTime(); return "unknown"; } float timePerLine = llGetTime() / line; return minutes_seconds(llRound(timePerLine * (float)(gNumberOfLines - line))); } string minutes_seconds(integer seconds) { if (seconds < 60) return (string)seconds + "s"; integer minutes = seconds / 60; seconds -= minutes * 60; string msg = (string)minutes + "m"; if (seconds > 0) msg += (string)seconds + "s"; return msg; } // This function sends queries to web databases to get keys from names. It moves through a series of different ones based on the current value of gQuerySource - if a query fails, it moves to the next one. I think that three different databases should eventually provide a reasonable result. Note that you can move the databases around according to your preference by cutting and pasting within the "if ... else" blocks. make_key_request(string name) { gAvName = name; llSetTimerEvent(TIMEOUT); gQuerySource++; string source = ""; if (gQuerySource == 0) { // modularsystems.sl name2key service source = "lawlinter.net"; gQuery = llHTTPRequest("http://lawlinter.net/secondlifeutility/name2key.php5?name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 1) { // visiontech - slow, but claims to be complete source = "VisionTech"; name = llDumpList2String(llParseString2List(name, [" "], []), "_"); gQuery = llHTTPRequest("http://vision-tech.org/name2key/search.php?name=" + name, [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 2) { // w-hat source = "w-hat"; gQuery = llHTTPRequest("http://w-hat.com/name2key?terse=1&name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } if (source == "") { // failed, try a new one llOwnerSay("All sources failed to find a key for '" + gAvName + "', moving on."); gQuerySource = -1; gNotFound = (gNotFound = []) + gNotFound + [gAvName]; get_next_name(); } else if (gQuerySource > 0) { llOwnerSay("Trying " + source + " database..."); } } // Gets all of the items to be sent, and sets text based on what they are list get_item_list() { integer f = llGetInventoryNumber(INVENTORY_ALL) - 1; list items = []; string thisScript = llGetScriptName(); while (f >= 0) { string name = llGetInventoryName(INVENTORY_ALL, f); if (name != "" && name != thisScript && name != NAME_NOTECARD) { items = (items = []) + items + [name]; } f--; } if (llGetListLength(items) > 0) { string msg = "Sending:\n" + llDumpList2String(items, "\n"); if (TEST) msg = "[TEST] Not " + (msg = "") + msg; llSetText(msg, <0.0, 1.0, 0.0>, 1.0); } else { llSetText("No items found to send", <1.0, 0.0, 0.0>, 1.0); } return items; } // Sends the actual items to a particular avatar send_items(key id) { integer f = llGetListLength(gItems) - 1; llOwnerSay("Giving items..."); while (f >= 0) { string name = llList2String(gItems, f); if (TEST) llSleep(2.0); else llGiveInventory(id, name); f--; } llOwnerSay("Done."); } //--------------------------------------------------------------------- // Main // The default state is "not sending anything right at this moment". default { state_entry() { llSetText("", <0.0, 0.0, 0.0>, 1.0); llSetColor(<1.0, 1.0, 1.0>, ALL_SIDES); gItems = get_item_list(); llOwnerSay(llGetScriptName() + " ready, touch to start sending inventory."); } on_rez(integer p) { llResetScript(); } touch_start(integer n) { if (llGetListLength(gItems) == 0) { llOwnerSay("Nothing suitable in this item's inventory to give!"); } else if (llGetInventoryType(NAME_NOTECARD) == INVENTORY_NONE) { llOwnerSay("You need a notecard called '" + NAME_NOTECARD + "' in this item for it to send its contents to people."); } else { state sending; } } changed(integer change) { if (change & CHANGED_INVENTORY) llResetScript(); } } // In "sending" state, we are actually reading names, finding keys and sending things out. state sending { state_entry() { gNumberOfLines = 0; gLine = 0; gNotFound = []; gQuerySource = -1; llOwnerSay("Beginning send - take into inventory to stop this."); get_next_name(); } on_rez(integer p) { llResetScript(); } dataserver(key query, string data) { if (query != gQuery) return; if (data == EOF) { llOwnerSay("All notecard lines scanned."); state default; } else if (gNumberOfLines == 0) { gNumberOfLines = (integer)data; get_next_name(); } else if (data != "") { make_key_request(data); } else get_next_name(); } http_response(key query, integer status, list metadata, string data) { if (query != gQuery) return; llSetTimerEvent(0.0); key avKey = (key)data; if (llStringLength(data) == 36 && avKey != NULL_KEY) { llOwnerSay("Found key for '" + gAvName + "' : " + (string)avKey); gQuerySource = -1; send_items(avKey); } else { llOwnerSay("ERROR: Could not find avatar name '" + gAvName + "' in database."); make_key_request(gAvName); } get_next_name(); } timer() { llOwnerSay("ERROR: timed out looking for avatar name '" + gAvName + "'."); make_key_request(gAvName); } state_exit() { llOwnerSay("Names not found: " + llList2CSV(gNotFound)); float time = llGetTime(); llOwnerSay("Total time: " + minutes_seconds((integer)time) + " seconds (" + (string)(time / gNumberOfLines) + " seconds per line)."); } }

An Illustration of the Cosmology of the Grid

I have noticed that there does still seem to be some Confusion amongst Residents as to precisely the relationships between Linden Laboratorye, the Grid itself, other Parts and also the Broader Aethernet, which does seem to be causing Misapprehensions as to the origins and behaviour of certain Aspects and Components.

I am always of a bent to properly Explain the Technical Nature of how these things operate, and for that purpose I have prepared a small diagram of the Cosmology of the Grid and Second Life, which I hope will prove useful. No doubt other Grid-Cosmological Types will have disagreements with the Details, but I believe that the basic structure is sound. Please excuse the poor handwriting.

Justified Meat-Potting

It was suggested today (in an entirely friendly and complimentary way, I might add) that I had ceased journalling altogether, and I was forced to admit that it might indeed appear so - simply, I had found little to actually write about recently, or rather had not had sufficient rigour and drive to go out and actively locate things regarding which to write.

A new Forum; an old Complaint

stippled_script2.jpgWhilst somewhat re-enabled in Aethernet terms, I am still unable to enter the Grid itself, and have been attempting to ameliorate the symptoms of my withdrawal with such things as the Scripting Section of the Official Forums.

To tell the truth I have been there infrequently of late. Previously I would spend many hours bickering over semicolons, but I have found it drawing me less and less in recent months until I barely ever participate unless at an extremely loose end. I am not entirely sure what caused this change; perhaps it was the closure of many parts of it and the enforcement of apparently somewhat arbitary conditions, making the place far less welcoming as a whole, or perhaps there was some Social Shift, with either the tenor of new participants changing or the departure of those I previously enjoyed engaging with. Or, perhaps, it is entirely down to a change in my own character.

“Frustration” by Sally Dunham
“Frustration” by Sally Dunham

One thing that most definitely has put me off ever returning, or at least offering actual Script-Code Solutions, is the current impossibility of posting up any sort of Code in any sort of Legible Form. I fear that I became infuriated by this and vowed never to return, or at least never to attempt to put up examples again. This is yet another manifestation of the dread [#WEB-156] BBCode not working on official SL Forums, one the annoyance of which I had not fully appreciated (and believe me, I have been incredibly annoyed by it already). This one thing now makes the huge Scripting Library unreadable and greatly discourages any further contributions, as well as vastly increasing the effort required to actually help anyone with their own problems or post solutions. Short queries and functions and theoretical discussions are bearable, but the prospect of struggling through some poor novice's hundred lines of unformatted code in order to chase down curly brackets is enough to make one simply not bother.

{}?

It all infuriates me even more as there are dozens of people eager to help with this, perhaps the most opaque skill within Second Life for a beginner or Non-Technical Sort to deal with, yet they face obstacles which even have the effect of making previous stored advice less valuable. A grid full of professional Old Resident engineers, lonely newer auto-didacts and terrible ancient scripts handed down from generation to generation due to the lack of anything more recent and efficient is not the sort of vision I have ever had, and discussion and mutual education at least goes some way to preventing this dystopia and helping the broadest group and greatest number of people. Even if one has no intention of dirtying one's hands with any sort of Coding, one may still benefit from proper samples to be cut and pasted directly into an In-World Device.

As a small sticking-plaster I have now set up my own Scripting Colloquium, where one might post Code in a manner which can actually be Read (as well as Images and Links and Things In Italics and So On). These things rarely survive for more than a few weeks, and it may die an undignified death, but I would encourage anyone with scripts and questions about scripts who is put off discussion within the Official Forums by this or other matters to visit and participate. At the least it may build up some useable examples.

A new Product of Limited Cleverness

I feel obliged to mention the existence of a new version of one of the Free Devices that I provide which has proven to be of Enormous Popularity. Really, it is not a complex thing, but may be of use to some.

A new Giver of Free Things

Upon the suggestion of Ms Ariel Miranda, I added the ability for the "Freebie Giver" to display an Illustration of the particular "Freebie" that is being dispensed.

Syndicate content