Jump to content

May Suki

  • Posts

  • Joined

  • Last visited

Everything posted by May Suki

  1. I should have mentioned this up front - but this Key will be available to all for free. I have the scripts in a couple Key objects (which I did not make) but only some of the Keys I have a transferable. The scripts are available to all, and should work in any Key object - or at least, they are designed to! I also have Updaters that you can use to update the Key when it is worn. If someone wants to go down the rabbit hole with me, let me know! I'll send you a copy of a Key object with current Development code or an Updater or both.
  2. Good idea. I would, however, note that there is already such a script. While a lot of the items passing back and forth may be marked elsewhere, the UpdaterClient script - normally quiescent and waiting for an Update - on the Development Key it is watching every link message going back and forth, and reporting on them: [00:02:34] Dolly Mei's Key: DEBUG-CHAT(5):1000: Got a chat channel message: Lady Mei メイ Mэй Suki/c5e11d0a-694f-46cc-864b-e42340890934/ms inject 305#teleport|Home [00:02:34] Dolly Mei's Key: DEBUG-CHAT(5):1022: Got a chat message: inject [00:02:34] Dolly Mei's Key: Injected link message code 305 with data ChatHandler|teleport|Home and key [00:02:34] Dolly Mei's Key: DEBUG-LINKMONITOR(8):199: Link message #INTERNAL_CMD cmd: teleport [ChatHandler] = Home [00:02:36] Dolly Mei's Key: DEBUG-LANDMARK(6):83: queryLandmarkData set to 9a410471-58bc-9d54-cc86-456e8a9a7e20 [00:02:36] Dolly Mei's Key: DEBUG-LANDMARK(6):84: Teleporting dolly to inventory tpLandmark "Home". [00:02:36] Dolly Mei's Key: DEBUG-LANDMARK(6):186: queryLandmarkData now equals 9a410471-58bc-9d54-cc86-456e8a9a7e20 The notes about "chat message" and "chat channel" and "Injected" refer to the chat control message I recently mentioned. The script monitoring the link messages marks itself with the "DEBUG-LINKMONITOR" tag you see there. "DEBUG-LANDMARK" messages are specifically related to the TP/Landmark processing. After these messages, the timer fires off after 20 seconds and gives an error message: no teleport occurred. Normal quiet processing looks like this: [00:03:54] Dolly Mei's Key: DEBUG-TRANSFORM(5):375: Transform Timer fired, interval 30.00s. [00:03:55] Dolly Mei's Key: DEBUG-MAIN(5):448: Main Timer fired, interval 29.98s. [00:03:55] Dolly Mei's Key: DEBUG-LINKMONITOR(8):199: Link message #SEND_CONFIG cmd: timeLeftOnKey [Main] = 1515 [00:04:24] Dolly Mei's Key: DEBUG-TRANSFORM(5):375: Transform Timer fired, interval 30.00s. [00:04:25] Dolly Mei's Key: DEBUG-MAIN(5):448: Main Timer fired, interval 30.05s. [00:04:25] Dolly Mei's Key: DEBUG-LINKMONITOR(8):199: Link message #SEND_CONFIG cmd: timeLeftOnKey [Main] = 1485 [00:04:54] Dolly Mei's Key: DEBUG-TRANSFORM(5):375: Transform Timer fired, interval 30.00s. [00:04:55] Dolly Mei's Key: DEBUG-MAIN(5):448: Main Timer fired, interval 29.96s. [00:04:55] Dolly Mei's Key: DEBUG-LINKMONITOR(8):199: Link message #SEND_CONFIG cmd: timeLeftOnKey [Main] = 1456 The timers don't actually result in any link messages, nor in any listen messages going back and forth: only the variable "timeLeftOnKey" (in seconds) is sent around (by the Main timer processing I believe). When the variable "timeLeftOnKey" reaches zero Dolly goes *splat!*
  3. In my current working git repo, I don't have EMERGENCY_TP: I think I pulled all of that when I tried to get Teleport working again. Now the equivalent would be TP_HOME. Since I'm using Ubuntu Linux 20.04 for development: $ pwd /home/emd/LSL/work/cdkey/src $ grep EMERGENCY_TP *lsl */* $ grep TP_HOME *lsl */* Aux.lsl:#ifdef TP_HOME Aux.lsl:#ifdef TP_HOME MenuHandler.lsl:#ifdef TP_HOME StatusRLV.lsl:#ifdef TP_HOME StatusRLV.lsl:#ifdef TP_HOME StatusRLV.lsl:#ifdef TP_HOME include/config.h:// #define TP_HOME 1 include/config.h:#ifdef TP_HOME The idea is that all Teleport functions can be activated by setting TP_HOME to 1, and all can be removed by not setting TP_HOME at all.Idea with EMERGENCY_TP was the same, as it is with the other settings in include/config.h. (Side note, HOMING_BEACON is related to TP_HOME, and only works if TP_HOME is set.) TP_HOME is a manually activated Teleport to the "Home" landmark; HOMING_BEACON activates an automatic activation of the same Teleport. Also, Firestorm optimizes and removes all unused variables and functions - so the post-processed code is probably considerably simpler. The full Development key should, when the teleport functions are enabled, react to a chat command on channel 75 (by default) like this: /75 <prefix> inject 305#teleport|Home Where prefix is your initials - for me, it's ms now (May Suki) whereas it used to be mr (Maystone Resident before user name change). During normal Development Key (quiet resting) operation, the only things that should be seen is the activation of the two main timers, and a link message counting down the number of seconds remaining on Dolly's timer. (I'm rather proud of the total reduction of link messages - I worked hard on that!) In terms of TP_HOME, enabling it will only require a recompile of Aux.lsl, MenuHandler.lsl, and StatusRLV.lsl with the code as I have it in git.
  4. Now the new alternate key is showing the same symptoms as before. I moved the relevant code back into the script I want it in for the released product, and while llRequestInventoryData() works, no dataserver event fires. It worked when it was an isolated item in the Key. I don't know if this is a Firestorm thing, or an object thing, or if its something else. I hate to give up without resolving what is going on, but this feature is a "nice to have"... but still.
  5. The testing I did had no link messages: it was done with a version of the script that is self-contained, uses no macros outside of those actually in the script, and performs a teleport to the Landmark "Home" on script startup.
  6. I took off that Key, and used a different model of Key - every Dolly needs at least a dozen This secondary Key I've been using for testing the scripts when they are installed into a fresh key - the scripts are designed to be able to work in any physical Key object. This secondary Key I stripped everything out of, then added the LM and the script. It worked. The Key I've been working with has many prims (12?) and this key I think has 3. This key might also be mesh, I don't know. Since this secondary Key is also one I've been using on a regular basis, I may switch to this for now (for daily use and development) and come back to the other for more testing. (I'm not giving up!) Could the problems be something in the build of the more complicated (primwise) Key? I'm pretty sure the scripts are all in the Root Prim.
  7. I did more testing... the "testObject" (sphere) is cleared: that was an error on my part, as the script stops itself after running. The bare-bones key still does not work. This is completely bizarre - but it's freeing in another way. Means no matter how much I change the script, that won't fix it.
  8. I turned off RLV just in case... and strangely, the results were the same: The key failed. The older test object failed. The brand new cube succeeded. This is determined by code in the dataserver event that directly uses llOwnerSay() to make message to the user, as well as to use RLV to perform the teleport: [09:01:52] Object: Dolly is now teleporting. [09:01:52] Object: @unsit=y,tploc=y,tpto:269931/357972/21=force (It also generates an error as it tries to stop the script, and it is called "New Script" not "Teleport" as it expects.) Just to be doubly sure I renamed it, and it still works. Note I have my Open Collar on, as well as all three objects... So interaction doesn't seem to be part of the problem. No wonder this problem was so infuriating: it appears to depend on the object itself, and perhaps its age.
  9. Thank you all so much! So far, with the testing, it doesn't seem to be anything actually connected with the code. Given my test, and Wulfie's test, the script doesn't seem to be the problem. I did something interesting... I wondered if it was going to come to this. In the past, I tested scripts in an unscripted key that came as part of the original set of Key stuff. (I didn't make the object the scripts are in.) That worked. This time, I copied the Key I have been working with - my every day fully scripted Development key - and stripped out everything but the standalone Teleport script and the Home landmark. This did not work. I don't know how, but it appears to be embedded into the object itself. To be sure, I tested it with my "testObject" (a sphere I had created earlier to test this script). The sphere only contains the script and landmark. Surprisingly, it failed here. I created a new (cube) object and put the landmark and script into that. That worked. It seems to be something to do with the object itself. This doesn't surprise me that much - a while ago I had a Key object that would not turn, no matter what I did - stymied me such that I quit developing the Key for 6 years. When I came back to it, I "gave up" trying to make the working Key object turn and just used an old copy of that same Key that did spin - and all the scripts worked perfectly, including when the Key spin was stopped and started programmatically.
  10. //======================================== // Teleport.lsl //======================================== // This script now exists solely to give llRequestInventoryData() a place to run. // It only works for "Home" and not for arbitrary landmarks. #define RUNNING TRUE #define NOT_RUNNING FALSE #define cdRunScript(a) llSetScriptState(a, RUNNING) #define cdStopScript(a) llSetScriptState(a, NOT_RUNNING) string tpLandmark = "Home"; key tpLandmarkQueryID; //======================================== // STATES //======================================== default { //---------------------------------------- // STATE ENTRY //---------------------------------------- state_entry() { tpLandmarkQueryID = llRequestInventoryData(tpLandmark); } //---------------------------------------- // TIMER //---------------------------------------- // Timer is used solely to follow the carrier timer() { if (tpLandmarkQueryID) { llSay(DEBUG_CHANNEL,"TP failed to occur; notify developer."); llSetTimerEvent(0.0); llSetScriptState("Teleport", NOT_RUNNING); } } //---------------------------------------- // DATASERVER //---------------------------------------- dataserver(key queryID, string queryData) { #define getRegionLocation(d) (llGetRegionCorner() + ((vector)d)) #define locationToString(d) ((string)((integer)d.x) + "/" + (string)((integer)d.y) + "/" + (string)((integer)d.z)) if (queryID == tpLandmarkQueryID) { string locationData = queryData; vector globalLocation = getRegionLocation(locationData); string globalPosition = locationToString(globalLocation); llOwnerSay("Dolly is now teleporting."); // Perform TP llOwnerSay("@unsit=y,tploc=y,tpto:" + globalPosition + "=force"); llSetTimerEvent(0.0); tpLandmarkQueryID = NULL_KEY; llSetScriptState("Teleport", NOT_RUNNING); } } } //========== TELEPORT ========== I tried a last ditch effort - created a script that was completely and hermetically sealed from the other scripts, and who would activate a fixed teleport on startup. This script works fine alone in a test object, and fine in an unscripted Doll Key of the sort I'm using. It fails with all of the other scripts present and active... Just outrageous. It has no dependencies on hidden macros, nor any inputs from the other keys, nor does it perform anything else other than the teleport on startup - then it stops running itself. I'm going to sleep on this.
  11. I converted the code to respond to the link_message event by sending a listener message with the name of the Landmark on it. This changed nothing. The function appears to work, and then fails quietly as it times out. This is so frustrating! This should be simple - even when I strip it down to near nothing, it fails. I'm at full-on desperation here. This should not be this hard! Sigh. Maybe I should just give up and throw the entire lot of this code out the window. What a waste of time.
  12. Everything I'm seeing strongly suggests that using llRequestInventoryData() within a link_message event fails. At this point, I've stripped everything in the link_message all the way down to just running the doTeleport function and waiting for a dataserver response - which never comes. Seems I'll have to shift to a listener or something.
  13. The if/jump blocks are the LSL implementation of the Firestorm switch/case statements. The if statements were all just: if (condition) jump (location); The location being each case, then the case (normally) ends with a jump to the end of the switch statement. Your testing shows what I've been suspicious of, too - that something in the link message processing is killing the teleport.
  14. I actually took the Firestorm post-processed (LSL-only) code, cleaned it up, and tried that. It too failed - but at least now the code is LSL-only and self-contained - *and* isolated. Here it is (hope this posting isn't too much): //======================================== // Teleport.lsl (#2) //======================================== // // vim:sw=4 et nowrap: //======================================== // VARIABLES //======================================== key keyID = NULL_KEY; list split = []; string dollName; string script; string myName; integer code; integer optHeader; integer remoteSeq; integer rlvOk = -1; integer debugLevel = 8; integer mySeqNum; key queryLandmarkData = NULL_KEY; key tpLandmarkQueryID = NULL_KEY; string tpLandmark; //======================================== // FUNCTIONS //======================================== rlvTeleport(string locationData) { vector globalLocation = (llGetRegionCorner() + ((vector)locationData)); string globalPosition = ((string)((integer)globalLocation.x) + "/" + (string)((integer)globalLocation.y) + "/" + (string)((integer)globalLocation.z)); if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)71)+": "+("Dolly should be teleporting now...")); if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)72)+": "+("Position = " + globalPosition)); llOwnerSay("Dolly is now teleporting."); llOwnerSay("@unsit=y,tploc=y,tpto:" + globalPosition + "=force"); } memReport(string script, float delay) { if (delay != 0.0) llSleep(delay); integer usedMemory = llGetUsedMemory(); integer memoryLimit = llGetMemoryLimit(); integer freeMemory = memoryLimit - usedMemory; integer availMemory = freeMemory + (65536 - memoryLimit); llMessageLinked((LINK_THIS), (((++mySeqNum) << 16) | (0 << 10) | 136), myName + "|" + (string)usedMemory + "|" + (string)memoryLimit + "|" + (string)freeMemory + "|" + (string)availMemory, llGetKey()); } key doTeleport(string tpLandmark) { if (!(llGetInventoryType(tpLandmark) == INVENTORY_LANDMARK)) { if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)90)+": "+("No landmark by the name of \"" + tpLandmark + "\" is present in inventory.")); return NULL_KEY; } tpLandmarkQueryID = llRequestInventoryData(tpLandmark); if (tpLandmarkQueryID == NULL_KEY) { llSay(0x7FFFFFFF,"Landmark data request failed."); return NULL_KEY; } if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)103)+": "+("queryLandmarkData set to " + (string)tpLandmarkQueryID)); if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)104)+": "+("Teleporting dolly " + dollName + " to inventory tpLandmark \"" + tpLandmark + "\".")); return tpLandmarkQueryID; } //======================================== // STATES //======================================== default { //======================================== // STATE_ENTRY //======================================== state_entry() { rlvOk = 1; myName = llGetScriptName(); keyID = llGetKey(); mySeqNum = llRound(llFrand(1<<15)); } //======================================== // ON_REZ //======================================== on_rez(integer start) { mySeqNum = llRound(llFrand(1<<15)); } //======================================== // LINK MESSAGE //======================================== link_message(integer lmSource, integer lmInteger, string lmData, key lmID) { split = llParseStringKeepNulls((lmData), [ "|" ], []); script = llList2String(split,0); remoteSeq = (lmInteger & 0xFFFF0000) >> 16; optHeader = (lmInteger & 0x00000C00) >> 10; code = lmInteger & 0x000003FF; split = llDeleteSubList(split, 0, 0 + optHeader); if (code == 300) { string name = llList2String(split,0); string value = llList2String(split,1); integer integerValue = (integer)value; {if((name) == ("debugLevel"))jump cFq00I; if((name) == ("rlvOk"))jump cxHZCC; jump cTgu2x; @cxHZCC; { rlvOk = integerValue; jump cTgu2x; } @cFq00I; { debugLevel = integerValue; jump cTgu2x; } @cTgu2x; } return; } else if (code == 305) { string cmd = llList2String(split,0); {if((cmd) == ("instantMessage"))jump csmNBm; if((cmd) == ("teleport"))jump ct5mYL; jump cpzYqz; @csmNBm; { llInstantMessage(lmID,llList2String(split,0)); jump cpzYqz; } @ct5mYL; { tpLandmark = llList2String(split,1); queryLandmarkData = doTeleport(tpLandmark); if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)181)+": "+("queryLandmarkData now equals " + (string)queryLandmarkData)); llSetTimerEvent(20.0); jump cpzYqz; } @cpzYqz; } } else if (code == 350) { rlvOk = llList2Integer(split,0); } else if (code < 200) { if (code == 142) { llOwnerSay("Teleport" + ": Compiled by " + "May Suki" + " on " + "Jun 28 2021" + " at " + "12:08:59" + " Options: " + llList2CSV((["Adult"] + ["Mode=Developer"] + ["RollOver"] + [] + [] + ["PreserveDirectory"] + ["DefaultWind=" + (string)llFloor(1800.0 / 60.0)] ))); } else if (code == 135) { float delay = llList2Float(split,0); memReport(myName,delay); } } } //======================================== // TIMER //======================================== timer() { if (queryLandmarkData) { llSay(0x7FFFFFFF,"TP failed to occur; notify developer."); llSetTimerEvent(0.0); } } //======================================== // DATASERVER //======================================== dataserver(key queryID, string queryData) { if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)224)+": "+("queryLandmarkData is equal to " + (string)queryLandmarkData)); if (debugLevel >= 6) llOwnerSay( "DEBUG-LANDMARK"+"("+((string)6)+"):"+((string)225)+": "+("queryID is equal to " + (string)queryID)); if (queryID == queryLandmarkData) { rlvTeleport(queryData); llSetTimerEvent(0.0); queryLandmarkData = NULL_KEY; } } } //========== TELEPORT2 ==========
  15. All great ideas. I was able to create a version of StatusRLV.lsl that worked by itself (though with macros included) with the Home landmark in an object. I tested it in the Doll Key on its own with the Home landmark. Both the generic sphere and the Doll Key worked in this way. (I set the teleport to happen on state_entry). Then moving it into the Key with all its scripts, poses, and other landmarks made the script fail to teleport. I've now moved the teleport functions to a new script, and am going towards what Innula mentioned: working until the code has less and less dependencies on macros. The use of debugSay allows me to throw in lots of llOwnerSay and have them all disappear with the resetting of a single macro. It also allows me to have a "level" of debug, so some will be printed and not others. The isLandmarkPresent() converts a strange test for the inventory item's type into what it really is: a test for existance of the landmark. The preprocessor provides for macros, switch/case statements, and array indexing (a[i]). As mentioned, next step is to keep simplifying and removing code until things work: testing all the while in the main fully scripted Key. (Link message data is split apart, using "|" as the divider.)
  16. I moved the code to the StatusRLV script, and it still fails. The dataserver event still gets activated, though never for the llRequestInventoryData() function call. I tested the data server with an llGetSimulatorData() function; worked perfectly. I checked the permissions of the landmark, and its full perm. Would permissions of the prims be involved? I don't know what could be causing this...
  17. I took all the teleport processing out of Avatar.lsl - one of the more complicated scripts - and moved them to StatusRLV.lsl which is one of the simplest scripts. The process still fails. Going to look at the Firestorm post-processed script next.
  18. I was afraid of that. As mentioned before, all code is in the github git repo: https://github.com/emmamei/cdkey/
  19. Yes it is. https://github.com/emmamei/cdkey/ The problem code is in src/Avatar.lsl.
  20. That is correct. I did create a script with just the functions as written, and macros copied, and none of the massive other programming in the original - and it worked (with landmark Home).
  21. When I try to activate the teleport function, this is the resulting debug code: [08:23:31] Dolly Mei's Key: DEBUG-LINKMONITOR(8):199: Link message #INTERNAL_CMD cmd: teleport [ChatHandler] = Home [08:23:32] Dolly Mei's Key: DEBUG-LANDMARK(6):154: queryLandmarkData set to a28a9842-9269-00d9-1fa4-9a4d9663be37 [08:23:32] Dolly Mei's Key: DEBUG-LANDMARK(6):155: Teleporting dolly Lady Mei メイ Mэй Suki to inventory tpLandmark "Home". [08:23:32] Dolly Mei's Key: DEBUG-LANDMARK(6):567: queryLandmarkData now equals a28a9842-9269-00d9-1fa4-9a4d9663be37 After that, a timer times out and I put an error up with llOwner(DEBUG_CHANNEL, ...)
  22. I have something like that already... your code is much cleaner. This is the actual code (with Firestorm macros included): key doTeleport(string tpLandmark) { key queryLandmarkData; if (!isLandmarkPresent(tpLandmark)) { debugSay(6,"DEBUG-LANDMARK","No landmark by the name of \"" + tpLandmark + "\" is present in inventory."); return NULL_KEY; } // This should trigger a dataserver event queryLandmarkData = llRequestInventoryData(tpLandmark); if (queryLandmarkData == NULL_KEY) { llSay(DEBUG_CHANNEL,"Landmark data request failed."); return NULL_KEY; } #ifdef DEVELOPER_MODE debugSay(6,"DEBUG-LANDMARK","queryLandmarkData set to " + (string)queryLandmarkData); debugSay(6,"DEBUG-LANDMARK","Teleporting dolly " + dollName + " to inventory tpLandmark \"" + tpLandmark + "\"."); #endif return queryLandmarkData; } The macro isLandmarkPresent is this: #define isLandmarkPresent(a) (llGetInventoryType(a) == INVENTORY_LANDMARK) debugSay is a macro that displays text with llOwnerSay if the debugLevel variable is larger or equal to the parameter. However, if I change a single macro, every last debugSay vanishes.
  23. In that script, there are no other dataserver events. Otherwise, I have these events in that script: state_entry() on_rez(integer start) attach(key id) changed(integer change) link_message(integer lmSource, integer lmInteger, string lmData, key lmID) timer() run_time_permissions(integer perm) The other scripts perform other functions of the key, as well as generate and respond to menus, handle dressing and undressing the avatar, checking for RLV, handling a chat interface, winding and unwinding the key, and lots more. I'm not sure how the event queue would be exceeding the maximum limit: I have debug statements everywhere, and the only things that happen during resting operation are two timers, and the tracking of time left on the key in seconds. The busiest that the dataserver gets is during the reading of the preferences notecard - that had a delay for reading each line, but now it reads the lines as fast as it can go. In that script, there is only the one dataserver call. I have five other dataserver event blocks: dataserver block in Main.lsl: llRequestSimulatorData() - after teleport dataserver block in Start.lsl: llGetNotecardLine() - at state_entry llRequestDisplayName() - as required dataserver block in Transform.lsl: llGetNotecardLine() - when type phrases are read (doesn't happen often) None of these happen but a very few times during the lifetime of the key. As for the overwriting of the queryLandmarkData variable, that was something I considered - but on exit from the set up function, it has the right value - and the dataserver value never fires at all (seen through testing).
  24. I have a Doll Key with 11 scripts within it, and one of these scripts calls: queryLandmarkData = llRequestInventoryData(landmark); ...where landmark equals "Home" in the standard case. queryLandmarkData is verified to not be NULL_KEY, but the dataserver event never fires: dataserver(key queryID, string queryData) { if (queryID == queryLandmarkData) { rlvTeleport(queryData); llSetTimerEvent(0.0); queryLandmarkData = NULL_KEY; } } (The function rlvTeleport takes queryData, generates the appropriate global position setting, and generates an RLV call to teleport.) Through the use of multiple debug statements it can be determined that the dataserver event never fires for the llRequestInventoryData() call. It does however respond to other dataserver events that happen in other scripts, including processing notecard lines and getting region data and username data. Is it possible that dataserver events in this script get throttled? I can find zero reason for llRequestInventoryData to work and then for data server to fail. There's no documentation in the llRequestInventoryData wiki page or in the dataserver wiki page that explains such a scenario. I'm using Firestorm to compile, along with full usage of all of Firestorm's compile-time enhancements. I also have the code in a git repository. I searched for the possibility that dataserver events were getting throttled or stopped outright due to too many all at once - but I can't find that documented anywhere if it is the case. Help?
  25. And so it has happened: However, the change in groups is actually only a +3 increase for individuals overall - of the 10 groups added to premium accounts, 7 were taken from the allotment given to basic accounts. Thus, basic (free) accounts will actually *lose* 7 slots. I can see how that hurts - and I'm not talking about shopping, or blogging - but working in clubs. Each club requires its staff to have two groups, maybe three - and in one notable and very popular club, I had to have six. This doesnt include general groups for posting notices about upcoming events in, and doesnt include special events which may also have groups. Some of us can use more groups.
  • Create New...