Notecard

All the jokes are contained in the corrade-lsl-templates/eggdrop Subversion respository. You can checkout the repository using any Subversion client.

The jokes have been extracted from Taivo Pungas' joke-dataset GitHub repository by using jsawk. In order to extract the jokes, for each JSON file provided by the joke dataset, the commands:

  • for reddit_jokes.json :
    jsawk -n < reddit_jokes.json 'var j = (this.title.replace(/(\r\n|\n|\r)/gm, " ").trim() + " " + this.body.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s{2,}/gm, " ").trim()); if(j.length <= 255) out(j)' | pbcopy
  • for wocka.json :
    jsawk -n < wocka.json 'var j = (this.body.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s{2,}/gm, " ").trim()); if(j.length <= 255) out(j)' | pbcopy
  • for stupidstuff.json :
    jsawk -n < stupidstuff.json 'var j = (this.body.replace(/(\r\n|\n|\r)/gm, " ").replace(/\s{2,}/gm, " ").trim()); if(j.length <= 255) out(j)' | pbcopy

have been executed.

The commands use jsawk to parse the JSON files and then perform some input sanitization; in particular, accepting only one-line jokes of 255 characters or less in order for LSL to be able to read the notecards.

Script

The LSL script could be repurposed as a limitless notecard reader because it does not load notecards but rather selects a random line from a random notecard. The script just holds in memory a list of notecard lines corresponding to each joke notecard (ie: for $20$ notecards of $65535$ bytes each, the script will remember only $20$ integer values stored within a list).

File: http://svn.grimore.org/corrade-lsl-templates/source/eggdrop/joke-notecard.lsl -

///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0      //
///////////////////////////////////////////////////////////////////////////
//
// A joke module for Corrade Eggdrop.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
    if(llStringLength(data) == 0) return "";
    if(llStringLength(k) == 0) return "";
    list a = llParseString2List(data, ["&", "="], []);
    integer i = llListFindList(a, [ k ]);
    if(i != -1) return llList2String(a, i+1);
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list data) {
    list k = llList2ListStrided(data, 0, -1, 2);
    list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
    data = [];
    do {
        data += llList2String(k, 0) + "=" + llList2String(v, 0);
        k = llDeleteSubList(k, 0, 0);
        v = llDeleteSubList(v, 0, 0);
    } while(llGetListLength(k) != 0);
    return llDumpList2String(data, "&");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
// http://was.fm/secondlife/wanderer
vector wasCirclePoint(float radius) {
    float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
        return <x, y, 0>;
    return wasCirclePoint(radius);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
// escapes a string in conformance with RFC1738
string wasURLEscape(string i) {
    string o = "";
    do {
        string c = llGetSubString(i, 0, 0);
        i = llDeleteSubString(i, 0, 0);
        if(c == "") jump continue;
        if(c == " ") {
            o += "+";
            jump continue;
        }
        if(c == "\n") {
            o += "%0D" + llEscapeURL(c);
            jump continue;
        }
        o += llEscapeURL(c);
@continue;
    } while(i != "");
    return o;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
list wasCSVToList(string csv) {
    list l = [];
    list s = [];
    string m = "";
    do {
        string a = llGetSubString(csv, 0, 0);
        csv = llDeleteSubString(csv, 0, 0);
        if(a == ",") {
            if(llList2String(s, -1) != "\"") {
                l += m;
                m = "";
                jump continue;
            }
            m += a;
            jump continue;
        }
        if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
            m += a;
            csv = llDeleteSubString(csv, 0, 0);
            jump continue;
        }
        if(a == "\"") {
            if(llList2String(s, -1) != a) {
                s += a;
                jump continue;
            }
            s = llDeleteSubList(s, -1, -1);
            jump continue;
        }
        m += a;
@continue;
    } while(csv != "");
    // postcondition: length(s) = 0
    return l + m;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
string wasListToCSV(list l) {
    list v = [];
    do {
        string a = llDumpList2String(
            llParseStringKeepNulls(
                llList2String(
                    l, 
                    0
                ), 
                ["\""], 
                []
            ),
            "\"\""
        );
        if(llParseStringKeepNulls(
            a, 
            [" ", ",", "\n", "\""], []
            ) != 
            (list) a
        ) a = "\"" + a + "\"";
        v += a;
        l = llDeleteSubList(l, 0, 0);
    } while(l != []);
    return llDumpList2String(v, ",");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
// unescapes a string in conformance with RFC1738
string wasURLUnescape(string i) {
    return llUnescapeURL(
        llDumpList2String(
            llParseString2List(
                llDumpList2String(
                    llParseString2List(
                        i, 
                        ["+"], 
                        []
                    ), 
                    " "
                ), 
                ["%0D%0A"], 
                []
            ), 
            "\n"
        )
    );
}
 
// configuration data
string configuration = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
// Notecard reading.
key nQuery = NULL_KEY;
string joke = "";
list q = [ ];
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
// Requires: a limit.
// Provides: true random number between [0, max) or (-max, 0].
//////////////////////////////////////////////////////////
integer wasFPSrand(integer max) {
    integer r = (integer)(llGetRegionFPS() * 10000000.0) % max;
    if(max > 0) return r; else return -r;
}
 
default {
    state_entry() {
        llOwnerSay("[Joke] Starting module...");
        llSetTimerEvent(10);
    }
    link_message(integer sender, integer num, string message, key id) {
        if(id != "configuration") return;
        llOwnerSay("[Joke] Got configuration...");
        configuration = message;
        state count_jokes;
    }
    timer() {
        llOwnerSay("[Joke] Requesting configuration...");
        llMessageLinked(LINK_THIS, 0, "configuration", NULL_KEY);
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || 
            (change & CHANGED_REGION_START) || 
            (change & CHANGED_OWNER)) {
            llResetScript();
        }
    }
    state_exit() {
        llSetTimerEvent(0);
    }
}
 
state count_jokes {
    state_entry() {
        // Build a list of dataserver queries and retrieve the number of lines.
        joke = (string)llGetInventoryNumber(INVENTORY_NOTECARD);
        integer i = (integer)joke - 1;
        do {
            string card = llGetInventoryName(INVENTORY_NOTECARD, i);
            // Filter notecards containing the "jokes" configuration key value.
            if(llSubStringIndex(card, wasKeyValueGet("jokes", configuration)) == -1) {
                joke = (string)((integer)joke - 1);
                jump continue;
            }
            q = llListInsertList(q, [ llGetNumberOfNotecardLines(card) ], 0);
@continue;
        } while(--i >= -1);
        q += NULL_KEY; 
    }
    dataserver(key id, string data) {
        // Find the query in the query list.
        integer i = llListFindList(q, [ id ]);
        if(i == -1) return;
 
        // Replace the query by the number of notecard lines (lists are covariant).
        q = llListReplaceList(q, [ (integer) data ], i, i);
        joke = (string)((integer)joke - 1);
        if((integer)joke == 0)
            state listen_group;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || 
            (change & CHANGED_REGION_START) || 
            (change & CHANGED_OWNER)) {
            llResetScript();
        }
    }
}
 
state listen_group {
    state_entry() {
        // DEBUG
        llOwnerSay("[Joke] Waiting for group messages...");
    }
    link_message(integer sender, integer num, string message, key id) {
        // We only care about notifications now.
        if(id != "notification")
            return;
 
        // This script only processes group notifications.
        if(wasKeyValueGet("type", message) != "group")
            return;
 
        // Get the sent message.
        data = wasURLUnescape(
            wasKeyValueGet(
                "message", 
                message
            )
        );
 
        // Check if this is an eggdrop command.
        if(llGetSubString(data, 0, 0) != 
            wasKeyValueGet("command", configuration))
            return;
 
        // Check if the command matches the current module.
        list command = llParseString2List(data, [" "], []);
        if(llList2String(command, 0) != 
            wasKeyValueGet("command", configuration) + "joke")
            return;
 
        // Remove command.
        command = llDeleteSubList(command, 0, 0);
 
        state read_joke;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || 
            (change & CHANGED_REGION_START) || 
            (change & CHANGED_OWNER)) {
            llResetScript();
        }
    }
}
 
state read_joke {
    state_entry() {
        // DEBUG
        llOwnerSay("[Joke] Reading a joke...");
 
        integer i = llGetInventoryNumber(INVENTORY_NOTECARD) - 1;
        list c = [];
        do {
            string card = llGetInventoryName(INVENTORY_NOTECARD, i);
            if(llSubStringIndex(card, wasKeyValueGet("jokes", configuration)) == -1)
                jump continue;
            c = llListInsertList(c, [ i ], 0);
@continue;
        } while(--i >= -1);
 
        i = (integer)llFrand(llGetListLength(c));
        nQuery = llGetNotecardLine(
            llGetInventoryName(
                INVENTORY_NOTECARD, 
                llList2Integer(c, i)
            ), 
            (integer)
                (
                    llFrand(
                        llList2Integer(
                            q,
                            i
                        )
                    )
                )
        );
    }
    dataserver(key id, string data) {
        if(id != nQuery) return;
        joke = data;
        state tell;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || 
            (change & CHANGED_REGION_START) || 
            (change & CHANGED_OWNER)) {
            llResetScript();
        }
    }
}
 
state tell {
    state_entry() {
        // DEBUG
        llOwnerSay("[Joke] Sending to group.");
        llInstantMessage(
            wasKeyValueGet(
                "corrade", 
                configuration
            ), 
            wasKeyValueEncode(
                [
                    "command", "tell",
                    "group", wasURLEscape(
                        wasKeyValueGet(
                            "group", 
                            configuration
                        )
                    ),
                    "password", wasURLEscape(
                        wasKeyValueGet(
                            "password", 
                            configuration
                        )
                    ),
                    "entity", "group",
                    "message", wasURLEscape(joke)
                ]
            )
        );
 
        // GC
        joke = "";
 
        state listen_group;
    }
}

secondlife/scripted_agents/corrade/projects/in_world/eggdrop/joke/notecard_based.txt ยท Last modified: 2019/01/03 01:36 (external edit)

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the copyright, license, warranty and privacy terms for the usage of this website please see the license, privacy, copyright and the plagiarism pages.