Jump to content

Script causing issue when value are store in notecard


Mindy2174
 Share

You are about to reply to a thread that has been inactive for 206 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

umh hi ! seem like i still need help to figure out why whats writen in the notecard cannot be red. The script can be save and every found fuction does work but the sound. If I leave the UUID in the script no problem but as soon as i try make it in a notecard its problem time.

Sorry its is a long script (didn't find a spoiler button so...) :

and the notecard is named Settings, the UUID of sounds does match with what is written in the notecard yes it says in the error window when i click on Red (or any other color) : [11:46] Could not find sound ''.

 

Settings :

//// Change these settings to what you like !
//OwnerUUID should be the UUID of your owner
//MaxArousal is the level which it will stop going higher. (Between 0-1)
//Red, Yellow and Green level are the force of the vibration. ////

[Settings]
OwnerUUID = "0"
MaxArousal = 0.5
RedLevel = 35.0
RedSound = "728b5bbe-f910-94ea-28b2-327696cf9d6b" // UUID of Red vibration sound
YellowLevel = 25.0
YellowSound = "a0b41909-f15e-a692-c5d2-078d9a2678fc" // UUID of Yellow vibration sound
GreenLevel = 15.0
GreenSound = "ec0cf6ac-b031-c8ed-cb25-10b11d23d7f0" // UUID of Green vibration sound

 

list buttons = ["Vibe level", "Denial"];
list vibrationButtons = ["OFF", "Red", "Yellow", "Green", "Back"]; // Added "Back" button
list denialButtons = ["OFF", "ON", "Back"]; // Added "Back" button
string dialogInfo = "\nChoose the vibration level :";
string denialInfo = "\nChoose if you want the denial option:";
string dialogMenu = "\nChoose your options.";
integer denialON;
integer menuMaxCounter = 60;
integer menuCounter;
integer menuOpen = FALSE;
key owner;
integer RATE = 7; // Animation rate (speed)
integer FRAMES_X = 4; // Number of frames horisontally
integer FRAMES_Y = 4; // Number of frames vertically
integer ALL_FRAMES = 16; // Number of all frames
integer FACE = ALL_SIDES; // Animation face (ALL_SIDES or Face number)
string currentsound ="";
float currentvolume = 0.0;
float currentanimspeed;

integer dialogChannel;
integer listenHandle;
float currentPAamount = 0.0; // We all start from zero arousal
float closeness; //avatar arousal state
float maxArousal; // Maximum arousal level (default value)
integer menuPage = 0;

// Parameters for vibration levels
float RedLevel;
float YellowLevel;
float GreenLevel;

//Parameters for vibration sounds
string RedSound;
string YellowSound;
string GreenSound;

// Owner's UUID
string OwnerUUID;

CloseMenu()
{
    llListenRemove(listenHandle);
    menuOpen = FALSE;
    menuPage = 0;
}

ShowMenu(integer page)
{
    menuCounter = menuMaxCounter;
    llListenRemove(listenHandle);
    listenHandle = llListen(dialogChannel, "", OwnerUUID, "");

    if (page == 0) //main
    {
        llDialog(OwnerUUID, dialogMenu, buttons, dialogChannel);
    }
    else if (page == 1) //vibes
    {
        llDialog(OwnerUUID, dialogInfo, vibrationButtons, dialogChannel);
    }
    else if (page == 2) //denial
    {
        llDialog(OwnerUUID, denialInfo, denialButtons, dialogChannel);
    }
}

default
{
    changed(integer change)
    {
        if (change == CHANGED_OWNER || change == CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    state_entry()
    {
        owner = llGetOwner();
        llSetTimerEvent(1.0);
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );

  
llSetLinkTextureAnim (LINK_SET, ANIM_ON | LOOP,
        FACE,
        FRAMES_X, 
        FRAMES_Y,
        0.0, 
        ALL_FRAMES, 
        RATE);
        llScaleTexture(0.5, 0.5, ALL_SIDES);
        llOffsetTexture(0.25, 0.25, ALL_SIDES);
        llStopSound();

       // Read parameters from the notecard
OwnerUUID = llList2String(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 0);
maxArousal = llList2Float(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 2); // Updated index

// Read vibration level settings from the notecard
RedLevel = llList2Float(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 3); // Updated index
RedSound = llList2String(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 4);

YellowLevel = llList2Float(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 5); // Updated index
YellowSound = llList2String(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 6);

GreenLevel = llList2Float(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 7); // Updated index
GreenSound = llList2String(llGetObjectDetails(llGetKey(), [OBJECT_TOTAL_INVENTORY_COUNT]), 8);
    }

touch_start(integer total_number)
{
    OwnerUUID = llDetectedKey(0);
    // Check if the ownerUUID matches the UUID specified in the notecard
    if (OwnerUUID != OwnerUUID)
    {
        llOwnerSay("You are not authorized to use this menu.");
        return;
    }

    if (!menuOpen)
    {
        ShowMenu(0);
        llSetTimerEvent(1.0); // Start the timer when the menu is opened
    }
    else
    {
        ShowMenu(menuPage);
    }
}


    link_message(integer sender_num, integer num, string str, key id)
    {
        list re_list = llParseString2List(str, ["|"], [""]);
        string preParseTask = llList2String(re_list, 0);
        integer i = llSubStringIndex(preParseTask, (string)owner);
        string task = llDeleteSubString(str, i, -1);
        
        if (task == "arousal")
        {
            closeness = llList2Float(re_list, 2);
        }
    }

    listen(integer channel, string name, key id, string message)
    {
        if (menuPage == 0)
        {
            if (message == "Vibe level")
            {
                menuPage = 1; // Show vibration level buttons
                ShowMenu(menuPage);
            }
            else if (message == "Denial")
            {
                menuPage = 2; // Show denial level buttons
                ShowMenu(menuPage);
            }
        }
        else if (menuPage == 1)
        {
            if (message == "Back")
            {
                menuPage = 0;
                ShowMenu(menuPage);
            }
            else
            {
                if (message == "OFF")
                {
                    currentPAamount = 0.0;
llSetLinkTextureAnim (LINK_SET, ANIM_ON | LOOP,
        FACE,
        FRAMES_X, 
        FRAMES_Y,
        0.0, 
        ALL_FRAMES, 
        RATE);
            llStopSound();
            llScaleTexture(0.5, 0.5, ALL_SIDES);
            llOffsetTexture(0.25, 0.25, ALL_SIDES);
                }
                else if (message == "Red")
                {
                    currentPAamount = RedLevel;
   llLoopSound(RedSound, 0.75);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4, 75);
                }
                else if (message == "Yellow")
                {
                    currentPAamount = YellowLevel;
   llLoopSound(YellowSound, 0.50);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4,50);
                }
                else if (message == "Green")
                {
                    currentPAamount = GreenLevel;
   llLoopSound(GreenSound, 0.25);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4,25);
                }
                CloseMenu();
            }
        }
        else if (menuPage == 2)
        {
            if (message == "Back") // Added condition to go back to menuPage 0
            {
                menuPage = 0;
                ShowMenu(menuPage);
            }
            else
            {
                CloseMenu();
                if (message == "ON")
                {
                    denialON = 1; // Set denial to ON
                    llSay(0, "The Denial function is activated!");
                }
                else if (message == "OFF")
                {
                    denialON = 0; // Set denial to OFF
                    llSay(0, "The Denial function is deactivated!");
                }
            }
        }
    }

    timer()
    {
        if (menuOpen)
        {
            menuCounter--;
            if (menuCounter <= 0)
            {
                llOwnerSay("Menu has timed out.");
                CloseMenu();
            }
        }

        // Apply denial if enabled
        if (closeness >= maxArousal)
        {
            llMessageLinked(LINK_SET, 0, "caeilarousalup|" + (string)llGetOwner() + "|" + (string)(currentPAamount * !denialON) + "|*****nosound", "");
        }
        else
        {
            llMessageLinked(LINK_SET, 0, "caeilarousalup|" + (string)llGetOwner() + "|" + (string)(currentPAamount) + "|*****nosound", "");
        }
    }
}

 

Link to comment
Share on other sites

  • 2 weeks later...

Ok i tought i rewrote it ok but it still doesn't work. Tough this time it seem to at least be able to read OwnerID as in I can access the menu and i'm the UUID provide here .

 

//These are the setting that you could change if need be. //


float maxArousal;  // Denial level value

// Parameters for vibration levels
float RedLevel;
float YellowLevel;
float GreenLevel;

// Parameters for vibration sounds
string RedSound;
string YellowSound;
string GreenSound;

key OwnerID;



//===== Do not change !! ====//

string notecardName = "Config"; // Put name of notecard to process in quotes.

// Put all the headings for your config notecard here:
list listNotecardHeadings=[
    "[Vibration]",
    "[Sounds]",
    "[General]"
];

// Leave the rest of these glabal varibles alone.

// script-wise, the first notecard line is line 0, the second line is line 1, etc.
integer notecardLine=0;

key dataQueryId;
key headingQueryId;

list listNotecardData=[];
string strNotecardHeading="";
integer bDataserverReady=TRUE;
string strTimerReason; // The reason the timer is being used.

integer iNotecardHeadingNo=0;

list buttons = ["Vibe level", "Denial"];
list vibrationButtons = ["OFF", "Red", "Yellow", "Green", "Back"]; // Added "Back" button
list denialButtons = ["OFF", "ON", "Back"]; // Added "Back" button
string dialogInfo = "\nChoose the vibration level :";
string denialInfo = "\nChoose if you want the denial option:";
string dialogMenu = "\nChoose your options.";
integer denialON;
integer menuMaxCounter = 60;
integer menuCounter;
integer menuOpen = FALSE;
key owner;
key ToucherID;
string currentsound ="";
float currentvolume = 0.0;
float currentanimspeed;
integer RATE = 7; // Animation rate (speed)
integer FRAMES_X = 4; // Number of frames horisontally
integer FRAMES_Y = 4; // Number of frames vertically
integer ALL_FRAMES = 16; // Number of all frames
integer FACE = ALL_SIDES; // Animation face (ALL_SIDES or Face number)
 
integer dialogChannel;
integer listenHandle;
float currentPAamount = 0.0; // We all start from zero arousal
float closeness; //avatar arousal state

integer menuPage = 0;

CloseMenu()
{
    llListenRemove(listenHandle);
    menuOpen = FALSE;
    menuPage = 0;
}

ShowMenu(integer page)
{
    menuCounter = menuMaxCounter;
    llListenRemove(listenHandle);
    listenHandle = llListen(dialogChannel, "", ToucherID, "");

    if (page == 0) //main
    {
        llDialog(ToucherID, dialogMenu, buttons, dialogChannel);
    }
    else if (page == 1) //vibes
    {
        llDialog(ToucherID, dialogInfo, vibrationButtons, dialogChannel);
    }
    else if (page == 2) //denial
    {
        llDialog(ToucherID, denialInfo, denialButtons, dialogChannel);
    }
}

// bool fnCheckNotecard()
integer fnCheckNotecard() // You can leave this function alone.
{
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
            return FALSE;
        }
        else
            return TRUE;
}

// this is called from dataserver
fnProcessData() // Put your own code in this function to process the notecard code.
{
    
    llSay(0, "Processing lines from " + notecardName + " " + "section " + strNotecardHeading);
    
    // use if else statments to seperate code for processing diffrent sections of the notecard:
    if (strNotecardHeading=="[General]")
    {
        llSay(0, "Processing General!");
    }
    else
    {
        llSay(0, "Not processing General.");
    }
    
    // while loops can be used to go through all the lines of data in your section.
    integer i = 0;
    integer length = llGetListLength(listNotecardData);
    while (length > i)
    {
        llOwnerSay( "Line: " + (string)i + " " + llList2String(listNotecardData, i) );
        ++i;
    }
}

// This is the function that starts the reading and processing of the notecard.
fnInitReadData()
{
    // Cleanup:
    notecardLine=0;
    listNotecardData=[];
    strNotecardHeading="";
    
    integer length = llGetListLength(listNotecardHeadings);
    if (length > iNotecardHeadingNo)
    {
        strNotecardHeading = llList2String(listNotecardHeadings, iNotecardHeadingNo);
        ++iNotecardHeadingNo;
        
        headingQueryId = llGetNotecardLine(notecardName, notecardLine); // this line runs asynchronously
    }
    else
    {
                
        iNotecardHeadingNo=0;
        
        bDataserverReady=TRUE;
        
        // for testing, you can comment out.
        llSay(0, "Dataserver done");
    }
}


default
{
    changed(integer change)
    {
        if (change == CHANGED_OWNER || change == CHANGED_INVENTORY)
        {
              if ( fnCheckNotecard() )
            {
                llSay(0, "reading notecard named '" + notecardName + "'.");
                
                if (bDataserverReady==FALSE)
                {
                    llSay(0, "to bad. Dataserver not ready. Try again.");
                }
                else
                {
                    fnInitReadData();
                }
                
            }
            else
            {
                llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
            }
        }

    }
    state_entry()
    {
        OwnerID = llGetOwner();
        llSetTimerEvent(1.0);
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );

  
llSetLinkTextureAnim (LINK_SET, ANIM_ON | LOOP,
        FACE,
        FRAMES_X, 
        FRAMES_Y,
        0.0, 
        ALL_FRAMES, 
        RATE);
        llScaleTexture(0.5, 0.5, ALL_SIDES);
        llOffsetTexture(0.25, 0.25, ALL_SIDES);
        llStopSound(); 
    
  // Read values from the notecard
        integer lineNum;
        string lineData;
        string notecardName = "Config"; // Specify the notecard name here
        integer numLines = 0;
        for (lineNum = 0; lineNum < numLines; ++lineNum)
        {
            lineData = llGetNotecardLine(notecardName, lineNum);
            list tokens = llParseString2List(lineData, ["="], []);
            string paramName = llList2String(tokens, 0);
            string paramValue = llList2String(tokens, 1);

            // Process the notecard parameters
            if (paramName == "maxArousal")
            {
                maxArousal;
            }
            else if (paramName == "RedLevel")
            {
                RedLevel;
            }
            else if (paramName == "YellowLevel")
            {
                YellowLevel;
            }
            else if (paramName == "GreenLevel")
            {
                GreenLevel;
            }
            else if (paramName == "RedSound")
            {
                RedSound;
            }
            else if (paramName == "YellowSound")
            {
                YellowSound;
            }
            else if (paramName == "GreenSound")
            {
                GreenSound;
            }
            else if (paramName == "OwnerID")
            {
                OwnerID;
            }
        }
    }    
    


     touch_start(integer total_number)
    {
        ToucherID = llDetectedKey(0);
        if (ToucherID != OwnerID)
        {
            llOwnerSay("You are not the owner!");
        }
        else if (!menuOpen)
        {
            ShowMenu(0);
        }
        else
        {
            ShowMenu(menuPage);
        }
    }

    link_message(integer sender_num, integer num, string str, key id)
    {
        list re_list = llParseString2List(str, ["|"], [""]);
        string preParseTask = llList2String(re_list, 0);
        integer i = llSubStringIndex(preParseTask, (string)owner);
        string task = llDeleteSubString(str, i, -1);
        
        if (task == "arousal")
        {
            closeness = llList2Float(re_list, 2);
        }
    }

    listen(integer channel, string name, key id, string message)
    {
        if (menuPage == 0)
        {
            if (message == "Vibe level")
            {
                menuPage = 1; // Show vibration level buttons
                ShowMenu(menuPage);
            }
            else if (message == "Denial")
            {
                menuPage = 2; // Show denial level buttons
                ShowMenu(menuPage);
            }
        }
        else if (menuPage == 1)
        {
            if (message == "Back")
            {
                menuPage = 0;
                ShowMenu(menuPage);
            }
            else
            {
                if (message == "OFF")
                {
  currentPAamount = 0.0;
llSetLinkTextureAnim (LINK_SET, ANIM_ON | LOOP,
        FACE,
        FRAMES_X, 
        FRAMES_Y,
        0.0, 
        ALL_FRAMES, 
        RATE);
            llStopSound();
            llScaleTexture(0.5, 0.5, ALL_SIDES);
            llOffsetTexture(0.25, 0.25, ALL_SIDES);                }
                else if (message == "Red")
                {
 currentPAamount = RedLevel;
   llLoopSound(RedSound, 0.75);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4, 75);                }
                else if (message == "Yellow")
                {
  currentPAamount = YellowLevel;
   llLoopSound(YellowSound, 0.50);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4,50);                }
                else if (message == "Green")
                {
          currentPAamount = GreenLevel;
   llLoopSound(GreenSound, 0.25);
llSetLinkTextureAnim (LINK_SET, ANIM_ON|PING_PONG|LOOP,ALL_SIDES,2, 2,0, 4,25);                }
                CloseMenu();
            }
        }
        else if (menuPage == 2)
        {
            if (message == "Back") // Added condition to go back to menuPage 0
            {
                menuPage = 0;
                ShowMenu(menuPage);
            }
            else
            {
                CloseMenu();
                if (message == "ON")
                {
                    denialON = 1; // Set denial to ON
                    llSay(0, "The Denial function is activated!");
                }
                else if (message == "OFF")
                {
                    denialON = 0; // Set denial to OFF
                    llSay(0, "The Denial function is deactivated!");
                }
            }
        }
    }

    timer()
    {
        if (menuOpen)
        {
            menuCounter--;
            if (menuCounter <= 0)
            {
                llOwnerSay("Menu has timed out.");
                CloseMenu();
            }
        }

        // Apply denial if enabled
        if (closeness >= maxArousal)
        {
            llMessageLinked(LINK_SET, 0, "caeilarousalup|" + (string)llGetOwner() + "|" + (string)(currentPAamount * !denialON) + "|noanim", "");
        }
        else
        {
            llMessageLinked(LINK_SET, 0, "caeilarousalup|" + (string)llGetOwner() + "|" + (string)(currentPAamount) + "|noanim", "");
        }  }
        
  // you should leave this code alone, (except you can comment out the testing lines).
    
    dataserver(key query_id, string data)
    {
        bDataserverReady=FALSE;
        
        if (query_id == headingQueryId)
        {
            if ( data == strNotecardHeading )
            {
                // we found it
                ++notecardLine; // goto first line in section
                
                // Get the data from the section
                dataQueryId = llGetNotecardLine(notecardName, notecardLine);
            }
            else if ( data == EOF )
            {
                // it doesn't exist
                
                llSay(0, "Section " + strNotecardHeading + " not found.");
                
                fnInitReadData();
            }
            else
            {
                // keep looking
                ++notecardLine;
                headingQueryId = llGetNotecardLine(notecardName, notecardLine);
            }
        }
        else if (query_id == dataQueryId)
        {
            if ( data == EOF || llGetSubString(data, 0, 0) == "[" )
            {
                // End of section
                
                fnProcessData();
                
                fnInitReadData();
                
                // bDataserverReady=TRUE;
            }
            else if ( data == "" || llGetSubString(data, 0, 0) == ";" )
            {
                // skip line
                ++notecardLine;
                dataQueryId = llGetNotecardLine(notecardName, notecardLine);
            }
            else
            {
                // for testing (you can comment this line out)
                llOwnerSay( "Line: " + (string) notecardLine + " " + data);
                
                listNotecardData += data;
                ++notecardLine;
                dataQueryId = llGetNotecardLine(notecardName, notecardLine);
            }
        }
    }

}

and the config note card

; General Settings
[General]
maxArousal = 0.5
OwnerID = "d9bc42e0-a217-465c-9872-6a118c953e98"

; Vibration Levels
[Vibration]
RedLevel = 35.0
YellowLevel = 25.0
GreenLevel = 15.0

; Sound Settings
[Sounds]
RedSound = "728b5bbe-f910-94ea-28b2-327696cf9d6b"
YellowSound = "a0b41909-f15e-a692-c5d2-078d9a2678fc"
GreenSound = "ec0cf6ac-b031-c8ed-cb25-10b11d23d7f0"

 

Link to comment
Share on other sites

There's still a deep misunderstanding on how notecard reading is done: you're making requests but not really doing anything with them, and instead treating the requests like they were the data. The attempted processing of the values you actually didn't get also doesn't work: things like "if (paramName == "YellowLevel") { YellowLevel; }" do absolutely nothing, you're not assigning anything to the variable.

Notecard reading crash course:

1) llGetNotecardLine returns a key that identifies a dataserver event; you are NOT given the line you're asking for directly

2) in a dataserver event, check that the dataserver event key matches the key you were given for your request

3) if so, you know this is the line you asked for

4) if the line is EOF, the notecard is over and you can let your script proceed knowing you've finished reading the notecard

5) otherwise, process the line in some manner (read its data directly into variables, or build a global list of notecard lines to be handled in bulk later, but that's potentially memory intensive)

6) you are not given the next line automatically: you must request it with another llGetNotecardLine, store the request key and repeat

Minimal example:

string nc_name = "my notecard";
integer nc_line = 0;
key nc_handle;

default {
	state_entry() {
		nc_handle = llGetNotecardLine(nc_name, nc_line); // start reading from line 0
	}

	dataserver(key id, string data) {
		if(id != nc_handle) // not my request
			return;
		if(data == EOF) { // end of notecard
			llOwnerSay("All done!");
			return;
		}
		llOwnerSay("Read line " +(string)nc_line + ": " + data); // process the data, in this case just say it
		nc_handle = llGetNotecardLine(nc_name, ++nc_line); // read next line, note the pre-increment ++
	}
}

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

  • 1 month later...

You will also need to handle all the # comments and // comments yourself.

A notecard is just a text file. The whole line will be returned via dataserver() event.

For simplification, do not use // inline comments. Only use # whole line comments.

Also, you'll need to trim the double quotes surrounding your values.

I'm still on my way home, but when I arrive home I'll show an example of how to read a notecard, with proper discard of empty lines and # whole-line comments.

Link to comment
Share on other sites

2 hours ago, primerib1 said:

but when I arrive home I'll show an example of how to read a notecard, with proper discard of empty lines and # whole-line comments.

The unseen context of why other people weren't helping more is because it seems pretty clear the OP is just using some sort of AI tool to generate code and hoping it magically works without understanding the underlying logic. IMHO It is not worth the effort to try and explain to this kind of person how things actually work. As helpful as such an example might be, I think it would be better off in its own thread in the LSL library section.

  • Like 2
Link to comment
Share on other sites

3 minutes ago, Quistess Alpha said:

The unseen context of why other people weren't helping more is because it seems pretty clear the OP is just using some sort of AI tool to generate code

Irony, because someone in another thread an "answer" that was generated with AI to someone's question, and talked about how great their AI LSL generation is!

So, if THAT is true..then maybe it all depends on the AI training model, and how well you ask it the question.

(I still don't trust it..because AI gonna take my LSL job!)

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 206 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...