Difference between revisions of "User talk:Perry Mizin"

From Second Life Wiki
Jump to navigation Jump to search
(→‎welcome: new section)
Line 28: Line 28:
The next step will be to try to divide the script in 2, or 3 if is possible, so we can spread the memory usage. Also I would like to test a trick i use often for to translate languages that i dont understand, what I do first is to translate that language into English, and then from English to Spanish, it seems a nonsense and unnecesary waste, but if i do it is becouse so i usually understand the translations better.
The next step will be to try to divide the script in 2, or 3 if is possible, so we can spread the memory usage. Also I would like to test a trick i use often for to translate languages that i dont understand, what I do first is to translate that language into English, and then from English to Spanish, it seems a nonsense and unnecesary waste, but if i do it is becouse so i usually understand the translations better.
I want by one part the translators communications and evaluation system, and by other the translation system between avatars, is it very difficult? I doný know , we will see...
I want by one part the translators communications and evaluation system, and by other the translation system between avatars, is it very difficult? I doný know , we will see...
== welcome ==
<lsl>
//Universal Translator
//Version 1.9.0
//November 12, 2009
//LSL Script copyright 2006-2009 by Hank Ramos
//Web Server Services powered by Google
//Variables
list agentsInTranslation;
list agentsInTranslationOptions;
list requestList;
integer listenID;
integer isMaster = 1;
integer autoLanguage = TRUE;
integer enabled = FALSE;
integer showTranslation = FALSE;
integer tranObjects = TRUE;
integer lastHeartBeat;
list    languageCodes = [
"zh-CN", "zh-TW", "hr", 
"bg", "be", "ca",
"af", "sq", "ar", 
"tl", "fr", "gl",   
"fi", "en", "et",   
"cs", "da", "nl", 
"id", "ga", "it",     
"hi", "hu", "is",
"de", "el", "iw",   
"mt", "no", "fa", 
"lt", "mk", "ms", 
"ja", "ko", "lv", 
"sl", "es", "sw",
"ru", "sr", "sk",
"pl", "pt-PT", "ro",
"yi", "", "",
"uk", "vi", "cy",
"sv","th", "tr"];
list    translators;
list    sayCache;
list    sayCachePrivate;
integer priorityNumber;
integer priorityNumListenID;
integer isInitialized = FALSE;
string  options;
//Options
//integer debug = TRUE;
integer broadcastChannel = -9999999; //note this is not the channel used by the HR Universal Translator
string  password = "password"; //note this is not the password used to encrypt comms of the HR Universal Translator
integer version = 190;
//
sendIM(key imid, string imstr)
{
    if (llGetParcelFlags(llGetPos()) & PARCEL_FLAG_ALLOW_SCRIPTS)
    {
        llMessageLinked(LINK_ALL_CHILDREN, 85234119, imstr, imid);
    }
    else
    {
        llMessageLinked(LINK_THIS, 85304563, imstr, imid);
    }
}
//txTxtLot() = sendTextBatch()
txTxtLot(integer txch, string txtxt)
{
    txtxt = llXorBase64StringsCorrect(llStringToBase64(txtxt), llStringToBase64(password));
    while (llStringLength(txtxt) > 508) //If string is 509 characters or longer
    {
        llSay(txch, llGetSubString(txtxt, 0, 507)); //send 508 character chunk
        txtxt = llGetSubString(txtxt, 508, -1);  //delete 508 character chunk
    }
    llSay(txch, txtxt);  //send out any remainder chunk or original chunk
    //Perry Mizin Comment: I don´t understand the aim of the following if.   
    //Hank Ramos Comment: this line serves to "trigger" the receiver not to wait for another batch.  If the
    //message length is exactly 508 characters, the receiver things that another chunk of the message is coming.
    //This message serves to tell the receiver that the last chunk was the last chunk, not another regular chunk.
    if (llStringLength(txtxt) == 508)
        llSay(txch, (string)(txch*4958654));
    //Hank Ramos Comment: this just flashes the color of the bottom prim to show a message was sent
    llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0, 0.25>, "");
//string rxTxtLot() = string receiveTextBatch()
string rxTxtLot(key rxid, string rxmsg)
{
    integer rxliPos;
    string  rxtmpStr = "";
    while (~llListFindList(sayCache, (list)rxid))
    {
        rxliPos = llListFindList(sayCache, [rxid]);
        rxtmpStr = (rxtmpStr="") + rxtmpStr + llList2String(sayCache, rxliPos + 1);
        sayCache = llDeleteSubList(sayCache, rxliPos, rxliPos + 1);
    }
    rxmsg = rxtmpStr + rxmsg;
    rxmsg = llBase64ToString(llXorBase64StringsCorrect(rxmsg, llStringToBase64(password)));
    return rxmsg;
}
//string rxTxtLot() = string receiveTextBatch() (Another way)
integer rxTxtLotBusy = FALSE; //Perry Mizin: added Busy Mode, this could fail or prevent fail
string rxTxtLot(key rxid, string rxmsg)
{
    if (rxTxtLotBusy == FALSE)
    {
        rxTxtLotBusy = TRUE;
        integer rxliPos;
        string  rxtmpStr = "";
        if(~llListFindList(sayCache, (list)rxid))
        {
            @rxin;
            rxliPos = llListFindList(sayCache, [rxid]);
            rxtmpStr = (rxtmpStr="") + rxtmpStr + llList2String(sayCache, rxliPos + 1);
            sayCache = llDeleteSubList(sayCache, rxliPos, rxliPos + 1);
            if(~llListFindList(sayCache, (list)rxid))
            {
                jump rxin;
            }
        }
        rxmsg = rxtmpStr + rxmsg;
        rxmsg = llBase64ToString(llXorBase64StringsCorrect(rxmsg, llStringToBase64(password)));
        rxTxtLotBusy = FALSE;
        return rxmsg;
    }
    else
    {
        //Perry Mizin: llSaySomething?
        return "";       
    }
}
//string rxTxtLotPrv() = string receiveTextBatchPrivate()
string rxTxtLotPrv(key prxid, string prxmsg)
{
    integer prxliPos;
    string  prxtmpStr = "";
    while (~llListFindList(sayCachePrivate, (list)prxid))
    {
        prxliPos = llListFindList(sayCachePrivate, [prxid]);
        prxtmpStr = (prxtmpStr="") + prxtmpStr + llList2String(sayCachePrivate, prxliPos + 1);
        sayCachePrivate = llDeleteSubList(sayCachePrivate, prxliPos, prxliPos + 1);
    }
    prxmsg = prxtmpStr + prxmsg;
    prxmsg = llBase64ToString(llXorBase64StringsCorrect(prxmsg, llStringToBase64(password)));
    return prxmsg;
}
//updateTranslatorList()
updateTranslatorList()
{
    integer nx;
    integer xliLng;
    list    newList;
    string  tmpStrPos;
    integer newMaster;
    //Scan and remove translators not in the area
    xliLng = llGetListLength(translators);
    for (nx = 0; nx < xliLng; nx += 2)
    {
        tmpStrPos = llList2String(llGetObjectDetails(llList2Key(translators, nx + 1), [OBJECT_POS]), 0);
        if ((llVecDist(llGetPos(), (vector)tmpStrPos) <= 20.0) && (tmpStrPos != ""))
        {
            newList = (newList=[]) + newList +  llList2List(translators, nx, nx + 1);
        }
    }
    translators = newList;
    //llMessageLinked(LINK_THIS,65635544,(string)xliLng,""); Perry Mizin: what is this necesary for?
    if (translators == [])
    {
        newMaster = 1;
    }
    else
    {
        if (enabled)
        {
            xliLng = llGetListLength(translators);
            newMaster = 2;
            for (nx = 0; nx < xliLng; nx += 2)
            {
                //llOwnerSay("Checking Priority Number(" +  (string)priorityNumber + "): " + (string)llList2Integer(translators, x));
                if (llList2Integer(translators, nx) > priorityNumber)
                {
                    newMaster = 0;
                }
            }
        }
        else
        {
            newMaster = 0;
        }
    }
    if ((isMaster > 0) && (newMaster == 0))
    {
        //We are being demoted from master to slave
        //Flush agentsInTranslation to master
        if (agentsInTranslation != [])
        {
            //Demotion Dump of agentsInTranslation to Master
            txTxtLot(broadcastChannel, llList2CSV([1003, llList2CSV(agentsInTranslation)]));
            if (isInitialized == FALSE)
            {
                return;
            }
            txTxtLot(broadcastChannel, llList2CSV([1004, options])); //error
        }
        llListenRemove(listenID);
    }
    if ((isMaster == 0) && (newMaster > 0))
    {
        llListenRemove(listenID);
        listenID = llListen(0, "", "", "");
    }
    isMaster = newMaster;
    llMessageLinked(LINK_THIS, 34829304, (string)isMaster, "");
}
//sendHeartbeat()
sendHeartbeat()
{
    updateTranslatorList();
    txTxtLot(broadcastChannel, llList2CSV([1001, priorityNumber]));
    //Broadcast agentList to Slaves
    if (isMaster == 2)
    {
        txTxtLot(broadcastChannel, llList2CSV([1002, llList2CSV(agentsInTranslation)]));
    }
}
//checkThrottle()
checkThrottle(integer chkn, string chkmsg, list chkli)
{
    integer y;
    integer maxCount;
    float  chkoldTime;
    float  sleepTime;
    list    chknewli;
    key    returnValue;
    integer channelToSpeak;
    //loop though list and remove items older than 25 seconds
    for (y = 0; y < llGetListLength(requestList); y += 1)
    {
        chkoldTime = llList2Float(requestList, y);
        //Construct new list with only times less than 25 seconds
        if ((llGetTime() - chkoldTime) <= 25.0)
        {
            chknewli = (chknewli=[]) + chknewli + [chkoldTime];
        }
    }
    requestList = chknewli;
    y = llGetListLength(requestList);
    //Shunt all translations to linked translators if master
    if (isMaster == 2)
    {
        if (chkn == 0)
        {
            //Send HTTP request to other translator
            //Send out Request to Random Translator Channel
            channelToSpeak = llList2Integer(llListRandomize(llList2ListStrided(translators, 0, -1, 2), 1), 0);
            if (channelToSpeak > 0)
            {
                txTxtLot(channelToSpeak, llList2CSV([chkn, llList2CSV(chkli)]) + "~" + chkmsg);
                return;
            }
        }
    }
    if (y == 19)
    {
        sleepTime =  25.0 - (llGetTime() - llList2Float(requestList, 0));
        if (sleepTime > 0)
        {
            llSleep(sleepTime);
        }
        requestList = llDeleteSubList(requestList, 0, 0);
    }
    if (chkn == 0)
    {
        chkmsg = "translate?v=1.0&q=" + chkmsg;
    }
    else
    {
        chkmsg = "detect?v=1.0&q=" + chkmsg;
    }
    requestList = (requestList=[]) + requestList + (list)llGetTime();
    returnValue = llHTTPRequest("http://ajax.googleapis.com/ajax/services/language/" + chkmsg, [HTTP_METHOD, "GET", HTTP_MIMETYPE, "plain/text;charset=utf-8"], " ");
    if (returnValue != NULL_KEY)
    {
        if (chkn == 0)
        {
            llMessageLinked(LINK_THIS, 235365342, llList2CSV(chkli), returnValue);
        }
        else
        {
            llMessageLinked(LINK_THIS, 235365343, llList2CSV(chkli), returnValue);
        }
    }
    else
    {
        llSleep(40.0); //Something has gone horribly wrong, sleep 40 seconds to clear throttle
    }
}
//string checkLanguage()
string checkLanguage(string chklantmpStr)
{
    if (llGetSubString(chklantmpStr, 0, 1) == "zh")
    {
        chklantmpStr = "zh-CN";
    }
    else if (chklantmpStr == "und")
    {
        chklantmpStr = "el";
    }
    if (~llListFindList(languageCodes, [chklantmpStr]))
    {
    } else {
        chklantmpStr = "";
    }
    chklantmpStr = llGetSubString(chklantmpStr, 0, 1);
    return chklantmpStr;
}
//addAgent()
addAgent(key avid, string avlan, integer chklan)
{
    integer avliPos;
    integer idNum;
    if (llListFindList(agentsInTranslation, (list)avid) != 911)
    {
        avliPos = llListFindList(agentsInTranslation, [avid]);
        agentsInTranslation = llListReplaceList(agentsInTranslation, [avlan, chklan], avliPos + 1, avliPos + 2);
    }
    else
    {
        @yes;
        idNum = llRound(llFrand(2000000)) + 1;
        if(llListFindList(agentsInTranslation, (list)idNum) != 911)
        {//it exists     
            jump at;
        }
        agentsInTranslation = (agentsInTranslation=[]) + agentsInTranslation + [avid, avlan, chklan, idNum];
        llMessageLinked(LINK_THIS, 64562349, avlan, avid);       
    }
}
//string addNewAgent()
string addNewAgent(key newavid)
{
    string speakerLan;
    if (llGetAgentSize(newavid) != ZERO_VECTOR)
    {
        speakerLan  = checkLanguage(llGetAgentLanguage(newavid));
        if (speakerLan == "")
        {
            speakerLan = "en";
            addAgent(newavid, speakerLan, TRUE);
        }
        else
        {
            addAgent(newavid, speakerLan, FALSE);
        }
    }
    return speakerLan;
}
//key getAgentKey()
key getAgentKey(integer agentID)
{
    if(~llListFindList(agentsInTranslation, (list)agentID))
    {
        integer gkliPos = llListFindList(agentsInTranslation, [agentID]);
        return llList2Key(agentsInTranslation, gkliPos - 3);
    }
    else
    {
        return "";
    }
}
//processHTTPResponse()
processHTTPResponse(integer ntype, string bodyStr, list paramsli)
{
    integer spkliPos;
    list    recepientList;
    key    recepientID;
    string  recepientLanguage;
    string  languagePair;
    key    speakerID;
    string  speakerName;
    string  speakerLanguage;
    string  translatedText;
    string  lantmpStr;
    integer z;
    integer speakerLanguageReliable;
    float  speakerLanguageConfidence;
    list    paramtmpli;
    //===================
    //Process Translation
    //===================
    if (ntype == 0)
    {
        speakerID  = llList2Key(paramsli, 1);
        speakerName = llKey2Name(speakerID);
        if (speakerName == "")
        {
            speakerName = llList2String(llGetObjectDetails(speakerID, [OBJECT_NAME]), 0);
        }
        recepientList = llParseString2List(llList2String(paramsli, 2), ["@"], []);
        paramtmpli = llParseStringKeepNulls(llList2String(paramsli, 3), ["|"],[]);
        recepientLanguage = llList2String(paramtmpli, 1);
        languagePair = llDumpList2String(paramtmpli, ">>");
        //Perform Text Cleanup
        z = llSubStringIndex(bodyStr, "\",\"detectedSourceLanguage\":\"");
        if (z != -1)
        {
            translatedText  = llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"translatedText\":\"") + 18, z);
            speakerLanguage = checkLanguage(llGetSubString(bodyStr, z + 28, llSubStringIndex(bodyStr, "\"}, \"responseDetails\":") - 1));
            spkliPos = llListFindList(agentsInTranslation, [speakerID]);
            if (spkliPos >= 0)
            {
                if (speakerLanguage != llList2String(agentsInTranslation, spkliPos + 1))
                {
                    agentsInTranslation = llListReplaceList(agentsInTranslation, [TRUE], spkliPos + 2, spkliPos + 2);  //Mark for recheck of actual spoken language.
                }
            }                 
        }
        else if (z == -1)
        {
            translatedText = llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"translatedText\":\"") + 18, llSubStringIndex(bodyStr, "\"}, \"responseDetails\""));
        }
        //Reverse order if Recepient Language is Hebrew or Arabic
        if ((recepientLanguage == "iw") || (recepientLanguage == "ar"))
        {
            lantmpStr = "";
            //Perry Mizin Comment: Probably I guess this is wrong, maybe I am wrong
            //Perry Mizin Comment: alternative reverse order: "Hello World" could be "World Hello"
            //Perry Mizin Comment: reverse order: "Hello World" is "dlroW olleH" or ,,pl^ºM ºllªH,,
            for(z = llStringLength(translatedText);z >= 0; z--)
            {
                lantmpStr = (lantmpStr="") + lantmpStr + llGetSubString(translatedText, z, z);
            }
            translatedText = lantmpStr;
        } 
        lantmpStr = speakerName + "(" + languagePair + "): " + translatedText;
        if (showTranslation)
        {
            sendIM(speakerID, lantmpStr);
        }
        for (z = 0; z < llGetListLength(recepientList); z += 1)
        {
            recepientID = getAgentKey(llList2Integer(recepientList, z));
            if (recepientID != "")
            {
                recepientLanguage = llList2String(agentsInTranslation, llListFindList(agentsInTranslation, [recepientID]) + 1);
                if (recepientLanguage != speakerLanguage)
                {
                    sendIM(recepientID, lantmpStr);
                }
            } 
        }
        return;
    }
    //===========================
    //Process Language Detection
    //===========================
    if (ntype == 1)
    {
        speakerID = llList2Key(paramsli, 1);
        speakerLanguageReliable = llToLower(llGetSubString(bodyStr, llSubStringIndex(bodyStr, "\",\"isReliable\":") + 15, llSubStringIndex(bodyStr, ",\"confidence\":") - 1)) == "true";
        speakerLanguageConfidence = (float)llGetSubString(bodyStr, llSubStringIndex(bodyStr, ",\"confidence\":") + 14, llSubStringIndex(bodyStr, "}, \"responseDetails\":") - 1);
        spkliPos = llListFindList(agentsInTranslation, [speakerID]);
        if (((spkliPos < 0) && (speakerLanguageReliable) || (speakerLanguageConfidence >= 0.08)))
        {
            //Analyze Data
            lantmpStr = checkLanguage(llToLower(llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"language\":\"") + 13, llSubStringIndex(bodyStr, "\",\"isReliable\":") - 1)));
            if (lantmpStr == "")
            {
                return;
            }
            if (speakerLanguageConfidence < 0.14)
            {
                addAgent(speakerID, lantmpStr, TRUE);
            }
            else
            {
                addAgent(speakerID, lantmpStr, FALSE);
            }
        }
    }   
}
default
{
    state_entry()
    {
        //Multiplexor Initialization
        priorityNumber = version*1000000 + llRound(llFrand(499999) + 50000);
        llListen(broadcastChannel, "", NULL_KEY, "");
        priorityNumListenID = llListen(priorityNumber, "", NULL_KEY, "");
        //Send out initial heartbeat
        lastHeartBeat = llGetUnixTime();
        txTxtLot(broadcastChannel, llList2CSV([1001, priorityNumber]));
        //Wait for the network to settle down
        llSetTimerEvent(5.0);
        //llSetTimerEvent(10 + ((1-llGetRegionTimeDilation()) * 1));     
    }
    link_message(integer sender_num, integer num, string lstr, key lid)
    {
        list    ltmpli;
        //Old Multiplexor
        if (num == 8434532)
        {
            enabled = (integer)lstr;
        }
        else if (num == 3342976)
        {
            //Send Preferences
            options = lstr;
            if (isInitialized == FALSE) return;
            ltmpli = llCSV2List(options);
            showTranslation = llList2Integer(ltmpli, 0);
            tranObjects = llList2Integer(ltmpli, 1);
            autoLanguage = llList2Integer(ltmpli, 2);
            txTxtLot(broadcastChannel, llList2CSV([1004, options]));
        }
        else if (num == 9384610)
        {
            if (isMaster == 0) //markering
                //llMessageLinked(LINK_THIS, 5598321, llList2CSV([id, str, FALSE]), "");
                txTxtLot(broadcastChannel, llList2CSV([1003, lid, lstr, FALSE]));
            else
                addAgent(lid, lstr, TRUE);
        }
        else if (num == 345149625)
        {
            //Return Translation
            processHTTPResponse(0, lstr, llCSV2List(lid));
        }
        else if (num == 345149626)
        {
            //Return Detection
            processHTTPResponse(1, lstr, llCSV2List(lid));
        }
    }
    sensor(integer num_detected)
    {
        integer s;
        key    sid;
        for (s = 0; s < num_detected; s += 1)
        {
            sid = llDetectedKey(s);
            if (~llListFindList(agentsInTranslation, (list)sid))
            {               
            }else{
                addNewAgent(sid);
            }
        }
    }
       
    listen(integer channel, string name, key id, string message)
    {
        integer w;
        string  spkrLan;
        string  recepLan;
        integer recepID;
        integer lstliPos;
        string  lanpair;
        list    translationCache;
        list    lsttmpli;
        integer ImessageType;
        string  Imessage;
        string  lsttmpStr;
        string  lst2tmpStr;
        //Multiplexor Code
        if ((channel == broadcastChannel) || (channel == priorityNumber))
        {
            //==========================
            //Process Proxy HTTP Request
            //==========================
            if (channel == priorityNumber)
            {
                if (llStringLength(message) >= 508)
                {
                    if (((integer)message/channel) != 4958654)
                    {
                        sayCachePrivate = (sayCachePrivate=[]) + sayCachePrivate + [id, message];
                        return;
                    }
                    message = "";
                }
                message = rxTxtLotPrv(id, message);
                //Received packet to translate
                llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0.05, 0.25>, "");
                lsttmpli = llParseString2List(message, ["~"], []);
                lsttmpStr = llList2String(lsttmpli, 0);
                lsttmpli = llDeleteSubList(lsttmpli, 0, 0);
                lst2tmpStr = llDumpList2String(lsttmpli, "|");
                lsttmpli = llCSV2List(lsttmpStr);
                lstliPos = llList2Integer(lsttmpli, 0);
                lsttmpli = llDeleteSubList(lsttmpli, 0, 0);
                checkThrottle(lstliPos, lst2tmpStr, lsttmpli);
                return;
            }
            //=======================
            //Process Global Messages
            //=======================
            if (llStringLength(message) >= 508)
            {
                if (((integer)message/channel) != 4958654)
                {
                    sayCache = (sayCache=[]) + sayCache + [id, message];
                    return;
                }
                message = "";
            }
            message = rxTxtLot(id, message);
            lsttmpli = llCSV2List(message);
            if (llGetListLength(lsttmpli) >= 2)   
            {
                ImessageType = llList2Integer(lsttmpli, 0);
                lsttmpli = llDeleteSubList(lsttmpli, 0, 0);
                Imessage = llList2CSV(lsttmpli);       
                llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0, 0.25>, "");
                //Process Message Here
                if (ImessageType == 1001)
                {
                    //Incoming Heartbeat
                    if ((integer)Imessage == priorityNumber)
                    {
                        llOwnerSay("Priority Number Conflict!  Resetting Script...");
                        llResetScript(); //Reset if conflicting priority number
                    }
                   
                    if (~llListFindList(translators, (list)id)  //lstliPos < 0)
                    {
                        lstliPos = llListFindList(translators, [id]);
                        translators = llListReplaceList(translators, [(integer)Imessage], lstliPos - 1, lstliPos - 1);                       
                    }
                    else
                    {
                      translators = (translators=[]) + translators + [(integer)Imessage, id];
                        if ((isMaster > 0) && (isInitialized))
                        {
                            txTxtLot((integer)Imessage, llList2CSV([1002, llList2CSV(agentsInTranslation)]));
                            txTxtLot((integer)Imessage, llList2CSV([1004, options]));
                        }
                    }
                }
                else if (ImessageType == 1002)
                {
                    //Incoming agentsInTranslation Master Broadcast
                    if (isMaster == 0)
                    {
                        //llMessageLinked(LINK_THIS, 9458021, Imessage, ""); 
                        lsttmpli = llCSV2List(Imessage);
                        agentsInTranslation = [];
                        for (w = 0; w < llGetListLength(lsttmpli); w += 4)
                        {
                            agentsInTranslation = (agentsInTranslation=[]) + agentsInTranslation + [llList2Key(lsttmpli, w), llList2String(lsttmpli, w + 1), llList2Integer(lsttmpli, w + 2), llList2Integer(lsttmpli, w + 3)];
                        }
                    }
                }
                else if (ImessageType == 1003)
                {
                    //Incoming agentsInTranslation dump from Slave
                    lsttmpli = llCSV2List(Imessage);
                    for (w = 0; w < llGetListLength(lsttmpli); w += 4)
                    {
                        addAgent(llList2Key(lsttmpli, w), llList2String(lsttmpli, w + 1), llList2Integer(lsttmpli, w + 2));
                    }
                }
                else if (ImessageType == 1004)
                {
                    //Incoming Preferences
                    options = Imessage;
                    lsttmpli = llCSV2List(options);
                    showTranslation = llList2Integer(lsttmpli, 0);
                    tranObjects = llList2Integer(lsttmpli, 1);
                    autoLanguage = llList2Integer(lsttmpli, 2);
                    llMessageLinked(LINK_THIS, 3342977, Imessage, ""); 
                }
            }           
            return;
        }
        //Translator Engine Code
        if ((llToLower(message) == "translator") && (isMaster > 0))
        {
            llMessageLinked(LINK_THIS, 2540664, message, id);
            return;
        }
        if ((!enabled) && (isMaster == 1)) return;
        if (!tranObjects)
        {
            if (llGetAgentSize(id) == ZERO_VECTOR) return;
        }
       
        if (~llListFindList(agentsInTranslation, (list)id)) //lstliPos >= 0)
        {
            lstliPos = llListFindList(agentsInTranslation, (list)id);           
            spkrLan = llList2String(agentsInTranslation, lstliPos + 1);
        }
        else
        {
            spkrLan = addNewAgent(id);
        }
        if (spkrLan == "xx") return;  //Agent Opt-Out
       
        llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 1, 0>, "");
        //===============================
        //Formulate Translation Requests
        //===============================
        for (w = 0; w < llGetListLength(agentsInTranslation); w += 4)
        {
            //Loop through translation group and do appropriate translations as needed
            recepID = llList2Integer(agentsInTranslation, w + 3);
            recepLan =  checkLanguage(llList2Key(agentsInTranslation, w + 1));
            if ((spkrLan != recepLan) && (recepLan != "") && (recepLan != "xx"))
            {
                lanpair = spkrLan + "|" + recepLan;
               
                if (~llListFindList(translationCache, (list)lanpair)) //lstliPos < 0)
                {
                  lstliPos = llListFindList(translationCache, [lanpair]);
                  translationCache = llListReplaceList(translationCache, [llList2String(translationCache, lstliPos + 1) + "@" + (string)recepID], lstliPos + 1, lstliPos + 1);
                 
                }
                else
                {
                  translationCache = (translationCache=[]) + translationCache + [lanpair, recepID];
                }
            }
        }
        //Process Requests
        if (translationCache != [])
        {
            for (w = 0; w < llGetListLength(translationCache); w += 2)
            {
                //====================================
                //Translation
                //====================================
                //Forumulate and Send Translation Request
                lanpair = "|" + llList2String(llParseStringKeepNulls(llList2String(translationCache, w), ["|"],[]), 1);
                checkThrottle(0, llEscapeURL(message) + "&langpair=" + llEscapeURL(lanpair), [llGetTime(), id , llList2String(translationCache, w + 1), llList2String(translationCache, w)]);
            }
        }
        else
            spkrLan = "";
        //====================================
        //Language Detection
        //====================================
        if (llGetAgentSize(id) != ZERO_VECTOR) //llList2Key(llGetObjectDetails(id, [OBJECT_CREATOR]), 0) == NULL_KEY)
        {
            if (((spkrLan == "") || (llList2Integer(agentsInTranslation, llListFindList(agentsInTranslation, [id]) + 2) == TRUE)) || (isMaster == 2))
            {
                //Forumulate and Send Language Detect Request
                checkThrottle(1, llEscapeURL(message), [llGetTime(), id]);
            }     
        }
    }
   
    http_response(key request_id, integer status, list metadata, string body)
    {
        string  htttmpStr;
        if (status != 200)
        {
            //llOwnerSay("WWW Error:" + (string)status);
            llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 0, 0>, "");
            //llOwnerSay(body);
            return;
        }
        //Process Resonse Code
        htttmpStr = llGetSubString(body, llSubStringIndex(body, "\"responseStatus\":"), -1);
        status = (integer)llGetSubString(htttmpStr, 17, llSubStringIndex(htttmpStr, "}") - 1);
        if (status != 200)
        {
            //llOwnerSay("Language Server Returned Error Code: " + (string)status);
            //llOwnerSay(body);
            llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 0, 0>, "");
            return;
        }
        llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0, 0, 1>, "");
        llMessageLinked(LINK_THIS, 345149624, body, request_id);
    }
    timer()
    {
        llSetTimerEvent(0.0);  // timer reset
        integer r;
        string  tmrtmpStr;
        list    tmrnewli;
        integer translatorCount = llGetListLength(translators)/2;
        if (isInitialized == FALSE)
        {
            enabled = TRUE;
            listenID = llListen(0, "", "", "");
            llListen(777, "", NULL_KEY, "");
            llMessageLinked(LINK_THIS, 6877259, (string)enabled, NULL_KEY);
            isInitialized = TRUE;
        }
        llMessageLinked(LINK_THIS, 94558323, llList2CSV(agentsInTranslation), "");
        if (isMaster > 0)
        {
            for (r = 0; r < llGetListLength(agentsInTranslation); r += 4)
            {
                tmrtmpStr = llList2String(llGetObjectDetails(llList2Key(agentsInTranslation, r), [OBJECT_POS]), 0);
                if ((llVecDist(llGetPos(), (vector)tmrtmpStr) <= 20.0) && (tmrtmpStr != ""))
                {
                    tmrnewli = (tmrnewli=[]) + tmrnewli + llList2List(agentsInTranslation, r, r + 3);
                }
            }
            agentsInTranslation = tmrnewli;
            if ((llGetUnixTime() - lastHeartBeat) >= 5)
            {
                //Send heartbeat
                sendHeartbeat();
                lastHeartBeat = llGetUnixTime();
            }
        }
        else
        {
            if ((llGetUnixTime() - lastHeartBeat) >= `0 + llGetListLength(agentsInTranslation)*2 + llPow(translatorCount, 1.4) + translatorCount + ((1-llGetRegionTimeDilation()) * 5))
            {
                //Send heartbeat
                sendHeartbeat();
                lastHeartBeat = llGetUnixTime();
            }
        }
        //turn on and off scanner
        if ((autoLanguage) && isMaster > 0)
        {
            llSensor("", NULL_KEY, AGENT, 20.0, PI);
        }
        llSetTimerEvent(4.0); // restart timer
        //llSetTimerEvent(4 + ((1-llGetRegionTimeDilation()) * 5));
    }
}
</lsl>

Revision as of 14:50, 15 December 2009

Bienvenid@

Hola, soy Perry Mizin y este será mi humilde intento de contribucion al proyecto "Traductor Universal de Google" creado por Hank Ramos.

El siguiente codigo fué originalmente creado por Hank Ramos, empezaré modificando algunas funciones a mi manera... No os riais

Welcome

Hello, I am Perry Mizin and this will be my humble try to contribute with the project "Universal Google Translator" created by Hank Ramos.

The next code was originally created by Hank Ramos, I will start modifiying some functions on my way... Don´t laugh


Universal Translator Engine

Bueno, despues de respiñar todo lo que he podido, creo que el uso de memoria y la velocidad estan practicamente igual que en la version original pero bueno... en la variedad está el gusto no? Ya he probado un poco el codigo, y parece que funciona aunque estoy teniendo algunos problemas... Por ejemplo creo que el sistema de traduccion no funciona correctamente, y no me refiero al sistema de traduccion de Google (en mi opinion, si no es el mejor, es uno de los mejores del mundo), sino a que aun queda mucho trabajo por hacer en el script...

El siguiente paso sera intentar dividir el script en dos, o si es posible en tres para repartir el uso de memoria. Tambien me gustaria probar un truco que uso a menudo para traducir paginas en un idioma que no entiendo, lo que hago es que en vez de traducir directamente al español, primero lo traduzco a inglés, y luego desde inglés al español, parece una tonteria y un gasto innecesario, pero si lo hago es porque así suelo entender mejor las traducciones. Quiero por un lado el sistema de comunicacion y evaluacion entre traductores, y por otro el sistema de traduccion entre avatares, ¿es muy dificil? no se ya lo veremos...

Well, after saving as much as I could, I think the memory usage and the speed are technically the same as in the original script, but well, in the variety is the taste, isnt it?. I have tested a bit the code above already, and it seems to work altought i´m having some problems... For instance i think the translation system is not working properly, and i dont mean the Google´s translation system (in my opinion, if is not the best, one of the bests), but that there is still much work to do in the script...

The next step will be to try to divide the script in 2, or 3 if is possible, so we can spread the memory usage. Also I would like to test a trick i use often for to translate languages that i dont understand, what I do first is to translate that language into English, and then from English to Spanish, it seems a nonsense and unnecesary waste, but if i do it is becouse so i usually understand the translations better. I want by one part the translators communications and evaluation system, and by other the translation system between avatars, is it very difficult? I doný know , we will see...

welcome

<lsl> //Universal Translator //Version 1.9.0 //November 12, 2009 //LSL Script copyright 2006-2009 by Hank Ramos //Web Server Services powered by Google //Variables list agentsInTranslation; list agentsInTranslationOptions; list requestList; integer listenID; integer isMaster = 1; integer autoLanguage = TRUE; integer enabled = FALSE; integer showTranslation = FALSE; integer tranObjects = TRUE; integer lastHeartBeat; list languageCodes = [ "zh-CN", "zh-TW", "hr", "bg", "be", "ca", "af", "sq", "ar", "tl", "fr", "gl", "fi", "en", "et", "cs", "da", "nl", "id", "ga", "it", "hi", "hu", "is", "de", "el", "iw", "mt", "no", "fa", "lt", "mk", "ms", "ja", "ko", "lv", "sl", "es", "sw", "ru", "sr", "sk", "pl", "pt-PT", "ro", "yi", "", "", "uk", "vi", "cy", "sv","th", "tr"];

list translators; list sayCache; list sayCachePrivate; integer priorityNumber; integer priorityNumListenID; integer isInitialized = FALSE; string options; //Options //integer debug = TRUE; integer broadcastChannel = -9999999; //note this is not the channel used by the HR Universal Translator string password = "password"; //note this is not the password used to encrypt comms of the HR Universal Translator integer version = 190; // sendIM(key imid, string imstr) {

   if (llGetParcelFlags(llGetPos()) & PARCEL_FLAG_ALLOW_SCRIPTS)
   {
       llMessageLinked(LINK_ALL_CHILDREN, 85234119, imstr, imid); 
   }
   else
   {
       llMessageLinked(LINK_THIS, 85304563, imstr, imid);
   }

} //txTxtLot() = sendTextBatch() txTxtLot(integer txch, string txtxt) {

   txtxt = llXorBase64StringsCorrect(llStringToBase64(txtxt), llStringToBase64(password));
   while (llStringLength(txtxt) > 508) //If string is 509 characters or longer 
   {
       llSay(txch, llGetSubString(txtxt, 0, 507)); //send 508 character chunk
       txtxt = llGetSubString(txtxt, 508, -1);  //delete 508 character chunk
   }
   llSay(txch, txtxt);  //send out any remainder chunk or original chunk
   //Perry Mizin Comment: I don´t understand the aim of the following if.    
   //Hank Ramos Comment: this line serves to "trigger" the receiver not to wait for another batch.  If the
   //message length is exactly 508 characters, the receiver things that another chunk of the message is coming.
   //This message serves to tell the receiver that the last chunk was the last chunk, not another regular chunk.
   if (llStringLength(txtxt) == 508)
       llSay(txch, (string)(txch*4958654));
   //Hank Ramos Comment: this just flashes the color of the bottom prim to show a message was sent
   llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0, 0.25>, ""); 

} //string rxTxtLot() = string receiveTextBatch() string rxTxtLot(key rxid, string rxmsg) {

   integer rxliPos;
   string  rxtmpStr = "";
   while (~llListFindList(sayCache, (list)rxid))
   {
       rxliPos = llListFindList(sayCache, [rxid]);
       rxtmpStr = (rxtmpStr="") + rxtmpStr + llList2String(sayCache, rxliPos + 1);
       sayCache = llDeleteSubList(sayCache, rxliPos, rxliPos + 1);
   }
   rxmsg = rxtmpStr + rxmsg;
   rxmsg = llBase64ToString(llXorBase64StringsCorrect(rxmsg, llStringToBase64(password)));
   return rxmsg;

} //string rxTxtLot() = string receiveTextBatch() (Another way) integer rxTxtLotBusy = FALSE; //Perry Mizin: added Busy Mode, this could fail or prevent fail string rxTxtLot(key rxid, string rxmsg) {

   if (rxTxtLotBusy == FALSE)
   {
       rxTxtLotBusy = TRUE;
       integer rxliPos;
       string  rxtmpStr = "";
       if(~llListFindList(sayCache, (list)rxid))
       {
           @rxin;
           rxliPos = llListFindList(sayCache, [rxid]);
           rxtmpStr = (rxtmpStr="") + rxtmpStr + llList2String(sayCache, rxliPos + 1);
           sayCache = llDeleteSubList(sayCache, rxliPos, rxliPos + 1);
           if(~llListFindList(sayCache, (list)rxid))
           {
                jump rxin;
           }
       }
       rxmsg = rxtmpStr + rxmsg;
       rxmsg = llBase64ToString(llXorBase64StringsCorrect(rxmsg, llStringToBase64(password)));
       rxTxtLotBusy = FALSE;
       return rxmsg;
   }
   else
   {
       //Perry Mizin: llSaySomething?
       return "";        
   }

} //string rxTxtLotPrv() = string receiveTextBatchPrivate() string rxTxtLotPrv(key prxid, string prxmsg) {

   integer prxliPos;
   string  prxtmpStr = "";
   while (~llListFindList(sayCachePrivate, (list)prxid))
   {
       prxliPos = llListFindList(sayCachePrivate, [prxid]);
       prxtmpStr = (prxtmpStr="") + prxtmpStr + llList2String(sayCachePrivate, prxliPos + 1);
       sayCachePrivate = llDeleteSubList(sayCachePrivate, prxliPos, prxliPos + 1);
   }
   prxmsg = prxtmpStr + prxmsg;
   prxmsg = llBase64ToString(llXorBase64StringsCorrect(prxmsg, llStringToBase64(password)));
   return prxmsg;

} //updateTranslatorList() updateTranslatorList() {

   integer nx;
   integer xliLng;
   list    newList;
   string  tmpStrPos;
   integer newMaster;
   //Scan and remove translators not in the area
   xliLng = llGetListLength(translators);
   for (nx = 0; nx < xliLng; nx += 2)
   {
       tmpStrPos = llList2String(llGetObjectDetails(llList2Key(translators, nx + 1), [OBJECT_POS]), 0);
       if ((llVecDist(llGetPos(), (vector)tmpStrPos) <= 20.0) && (tmpStrPos != ""))
       {
           newList = (newList=[]) + newList +  llList2List(translators, nx, nx + 1);
       }
   }
   translators = newList;
   //llMessageLinked(LINK_THIS,65635544,(string)xliLng,""); Perry Mizin: what is this necesary for?
   if (translators == [])
   {
       newMaster = 1;
   }
   else
   {
       if (enabled)
       {
           xliLng = llGetListLength(translators);
           newMaster = 2;
           for (nx = 0; nx < xliLng; nx += 2)
           {
               //llOwnerSay("Checking Priority Number(" +  (string)priorityNumber + "): " + (string)llList2Integer(translators, x));
               if (llList2Integer(translators, nx) > priorityNumber)
               {
                   newMaster = 0;
               }
           }
       }
       else
       {
           newMaster = 0;
       }
   }
   if ((isMaster > 0) && (newMaster == 0))
   {
       //We are being demoted from master to slave
       //Flush agentsInTranslation to master
       if (agentsInTranslation != [])
       {
           //Demotion Dump of agentsInTranslation to Master
           txTxtLot(broadcastChannel, llList2CSV([1003, llList2CSV(agentsInTranslation)]));
           if (isInitialized == FALSE)
           {
               return;
           }
           txTxtLot(broadcastChannel, llList2CSV([1004, options])); //error
       }
       llListenRemove(listenID);
   }
   if ((isMaster == 0) && (newMaster > 0))
   {
       llListenRemove(listenID);
       listenID = llListen(0, "", "", ""); 
   }
   isMaster = newMaster;
   llMessageLinked(LINK_THIS, 34829304, (string)isMaster, "");

} //sendHeartbeat() sendHeartbeat() {

   updateTranslatorList();
   txTxtLot(broadcastChannel, llList2CSV([1001, priorityNumber]));
   //Broadcast agentList to Slaves
   if (isMaster == 2)
   {
       txTxtLot(broadcastChannel, llList2CSV([1002, llList2CSV(agentsInTranslation)]));
   }

} //checkThrottle() checkThrottle(integer chkn, string chkmsg, list chkli) {

   integer y;
   integer maxCount;
   float   chkoldTime;
   float   sleepTime;
   list    chknewli;
   key     returnValue;
   integer channelToSpeak; 
   //loop though list and remove items older than 25 seconds
   for (y = 0; y < llGetListLength(requestList); y += 1)
   {
       chkoldTime = llList2Float(requestList, y);
       //Construct new list with only times less than 25 seconds
       if ((llGetTime() - chkoldTime) <= 25.0)
       { 
           chknewli = (chknewli=[]) + chknewli + [chkoldTime];
       }
   }
   requestList = chknewli; 
   y = llGetListLength(requestList);
   //Shunt all translations to linked translators if master
   if (isMaster == 2)
   {
       if (chkn == 0)
       {
           //Send HTTP request to other translator
           //Send out Request to Random Translator Channel
           channelToSpeak = llList2Integer(llListRandomize(llList2ListStrided(translators, 0, -1, 2), 1), 0);
           if (channelToSpeak > 0) 
           {
               txTxtLot(channelToSpeak, llList2CSV([chkn, llList2CSV(chkli)]) + "~" + chkmsg);
               return;
           }
       }
   }
   if (y == 19)
   {
       sleepTime =  25.0 - (llGetTime() - llList2Float(requestList, 0));
       if (sleepTime > 0) 
       {
           llSleep(sleepTime);
       }
       requestList = llDeleteSubList(requestList, 0, 0);
   }
   if (chkn == 0)
   {
       chkmsg = "translate?v=1.0&q=" + chkmsg;
   }
   else
   {
       chkmsg = "detect?v=1.0&q=" + chkmsg;
   }

   requestList = (requestList=[]) + requestList + (list)llGetTime();
   returnValue = llHTTPRequest("http://ajax.googleapis.com/ajax/services/language/" + chkmsg, [HTTP_METHOD, "GET", HTTP_MIMETYPE, "plain/text;charset=utf-8"], " ");

   if (returnValue != NULL_KEY)
   {
       if (chkn == 0)
       {
           llMessageLinked(LINK_THIS, 235365342, llList2CSV(chkli), returnValue); 
       }
       else
       {
           llMessageLinked(LINK_THIS, 235365343, llList2CSV(chkli), returnValue); 
       }
   }
   else
   {
       llSleep(40.0); //Something has gone horribly wrong, sleep 40 seconds to clear throttle
   }

} //string checkLanguage() string checkLanguage(string chklantmpStr) {

   if (llGetSubString(chklantmpStr, 0, 1) == "zh")
   {
       chklantmpStr = "zh-CN";
   }
   else if (chklantmpStr == "und")
   {
       chklantmpStr = "el";
   }
   if (~llListFindList(languageCodes, [chklantmpStr]))
   {

   } else {
       chklantmpStr = "";
   }
   chklantmpStr = llGetSubString(chklantmpStr, 0, 1);
   return chklantmpStr;

} //addAgent() addAgent(key avid, string avlan, integer chklan) {

   integer avliPos;
   integer idNum;
   if (llListFindList(agentsInTranslation, (list)avid) != 911)
   {
       avliPos = llListFindList(agentsInTranslation, [avid]);
       agentsInTranslation = llListReplaceList(agentsInTranslation, [avlan, chklan], avliPos + 1, avliPos + 2);
   }
   else
   {
       @yes;
       idNum = llRound(llFrand(2000000)) + 1;
       if(llListFindList(agentsInTranslation, (list)idNum) != 911)
       {//it exists       
           jump at;
       }
       agentsInTranslation = (agentsInTranslation=[]) + agentsInTranslation + [avid, avlan, chklan, idNum];
       llMessageLinked(LINK_THIS, 64562349, avlan, avid);        
   }

} //string addNewAgent() string addNewAgent(key newavid) {

   string speakerLan;

   if (llGetAgentSize(newavid) != ZERO_VECTOR)
   {
       speakerLan  = checkLanguage(llGetAgentLanguage(newavid));
       if (speakerLan == "")
       {
           speakerLan = "en";
           addAgent(newavid, speakerLan, TRUE);
       }
       else
       {
           addAgent(newavid, speakerLan, FALSE);
       }
   }
   return speakerLan;

} //key getAgentKey() key getAgentKey(integer agentID) {

   if(~llListFindList(agentsInTranslation, (list)agentID))
   {
       integer gkliPos = llListFindList(agentsInTranslation, [agentID]);
       return llList2Key(agentsInTranslation, gkliPos - 3);
   }
   else
   {
       return "";
   }

} //processHTTPResponse() processHTTPResponse(integer ntype, string bodyStr, list paramsli) {

   integer spkliPos;
   list    recepientList;
   key     recepientID;
   string  recepientLanguage;
   string  languagePair;
   key     speakerID;
   string  speakerName;
   string  speakerLanguage;
   string  translatedText;
   string  lantmpStr;
   integer z;
   integer speakerLanguageReliable;
   float   speakerLanguageConfidence;
   list    paramtmpli;
   //===================
   //Process Translation
   //===================
   if (ntype == 0)
   {
       speakerID  = llList2Key(paramsli, 1);
       speakerName = llKey2Name(speakerID);
       if (speakerName == "")
       {
           speakerName = llList2String(llGetObjectDetails(speakerID, [OBJECT_NAME]), 0);
       }
       recepientList = llParseString2List(llList2String(paramsli, 2), ["@"], []);
       paramtmpli = llParseStringKeepNulls(llList2String(paramsli, 3), ["|"],[]);
       recepientLanguage = llList2String(paramtmpli, 1);
       languagePair = llDumpList2String(paramtmpli, ">>"); 
       //Perform Text Cleanup
       z = llSubStringIndex(bodyStr, "\",\"detectedSourceLanguage\":\""); 
       if (z != -1)
       {
           translatedText  = llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"translatedText\":\"") + 18, z);
           speakerLanguage = checkLanguage(llGetSubString(bodyStr, z + 28, llSubStringIndex(bodyStr, "\"}, \"responseDetails\":") - 1));
           spkliPos = llListFindList(agentsInTranslation, [speakerID]);
           if (spkliPos >= 0)
           {
               if (speakerLanguage != llList2String(agentsInTranslation, spkliPos + 1))
               {
                   agentsInTranslation = llListReplaceList(agentsInTranslation, [TRUE], spkliPos + 2, spkliPos + 2);  //Mark for recheck of actual spoken language.
               }
           }                   
       }
       else if (z == -1)
       {
           translatedText = llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"translatedText\":\"") + 18, llSubStringIndex(bodyStr, "\"}, \"responseDetails\""));
       }
       //Reverse order if Recepient Language is Hebrew or Arabic
       if ((recepientLanguage == "iw") || (recepientLanguage == "ar"))
       {
           lantmpStr = "";
           //Perry Mizin Comment: Probably I guess this is wrong, maybe I am wrong
           //Perry Mizin Comment: alternative reverse order: "Hello World" could be "World Hello"
           //Perry Mizin Comment: reverse order: "Hello World" is "dlroW olleH" or ,,pl^ºM ºllªH,,
           for(z = llStringLength(translatedText);z >= 0; z--)
           {
               lantmpStr = (lantmpStr="") + lantmpStr + llGetSubString(translatedText, z, z); 
           }
           translatedText = lantmpStr;
       }   
       lantmpStr = speakerName + "(" + languagePair + "): " + translatedText;
       if (showTranslation)
       {
           sendIM(speakerID, lantmpStr);
       } 
       for (z = 0; z < llGetListLength(recepientList); z += 1)
       {
           recepientID = getAgentKey(llList2Integer(recepientList, z));
           if (recepientID != "")
           {
               recepientLanguage = llList2String(agentsInTranslation, llListFindList(agentsInTranslation, [recepientID]) + 1);
               if (recepientLanguage != speakerLanguage)
               {
                   sendIM(recepientID, lantmpStr);
               }
           }  
       }
       return;
   }
   //===========================
   //Process Language Detection
   //===========================
   if (ntype == 1)
   {
       speakerID = llList2Key(paramsli, 1);
       speakerLanguageReliable = llToLower(llGetSubString(bodyStr, llSubStringIndex(bodyStr, "\",\"isReliable\":") + 15, llSubStringIndex(bodyStr, ",\"confidence\":") - 1)) == "true";
       speakerLanguageConfidence = (float)llGetSubString(bodyStr, llSubStringIndex(bodyStr, ",\"confidence\":") + 14, llSubStringIndex(bodyStr, "}, \"responseDetails\":") - 1);

       spkliPos = llListFindList(agentsInTranslation, [speakerID]);
       if (((spkliPos < 0) && (speakerLanguageReliable) || (speakerLanguageConfidence >= 0.08)))
       {
           //Analyze Data
           lantmpStr = checkLanguage(llToLower(llGetSubString(bodyStr, llSubStringIndex(bodyStr, "{\"language\":\"") + 13, llSubStringIndex(bodyStr, "\",\"isReliable\":") - 1)));
           if (lantmpStr == "")
           {
               return;
           } 
           if (speakerLanguageConfidence < 0.14)
           {
               addAgent(speakerID, lantmpStr, TRUE);
           }
           else
           {
               addAgent(speakerID, lantmpStr, FALSE);
           }
       }
   }    

}

default {

   state_entry()
   {
       //Multiplexor Initialization
       priorityNumber = version*1000000 + llRound(llFrand(499999) + 50000);
       llListen(broadcastChannel, "", NULL_KEY, "");
       priorityNumListenID = llListen(priorityNumber, "", NULL_KEY, "");

       //Send out initial heartbeat
       lastHeartBeat = llGetUnixTime();
       txTxtLot(broadcastChannel, llList2CSV([1001, priorityNumber]));

       //Wait for the network to settle down
       llSetTimerEvent(5.0); 
       //llSetTimerEvent(10 + ((1-llGetRegionTimeDilation()) * 1));       
   }
   link_message(integer sender_num, integer num, string lstr, key lid)
   {
       list    ltmpli;
       //Old Multiplexor
       if (num == 8434532)
       {
           enabled = (integer)lstr;
       }
       else if (num == 3342976)
       {
           //Send Preferences
           options = lstr;
           if (isInitialized == FALSE) return;
           ltmpli = llCSV2List(options);
           showTranslation = llList2Integer(ltmpli, 0);
           tranObjects = llList2Integer(ltmpli, 1);
           autoLanguage = llList2Integer(ltmpli, 2);
           txTxtLot(broadcastChannel, llList2CSV([1004, options]));

       }
       else if (num == 9384610)
       {
           if (isMaster == 0) //markering
               //llMessageLinked(LINK_THIS, 5598321, llList2CSV([id, str, FALSE]), "");
               txTxtLot(broadcastChannel, llList2CSV([1003, lid, lstr, FALSE]));
           else
               addAgent(lid, lstr, TRUE);
       }
       else if (num == 345149625)
       {
           //Return Translation
           processHTTPResponse(0, lstr, llCSV2List(lid));
       }
       else if (num == 345149626)
       {
           //Return Detection
           processHTTPResponse(1, lstr, llCSV2List(lid));
       }
   }

   sensor(integer num_detected)
   {
       integer s;
       key     sid;

       for (s = 0; s < num_detected; s += 1)
       {
           sid = llDetectedKey(s);
           if (~llListFindList(agentsInTranslation, (list)sid))
           {                
           }else{
               addNewAgent(sid);
           }
       }
   }
       
   listen(integer channel, string name, key id, string message)
   {
       integer w;
       string  spkrLan;
       string  recepLan;
       integer recepID;
       integer lstliPos;
       string  lanpair;
       list    translationCache;
       list    lsttmpli;
       integer ImessageType;
       string  Imessage;
       string  lsttmpStr;
       string  lst2tmpStr;

       //Multiplexor Code
       if ((channel == broadcastChannel) || (channel == priorityNumber))
       {
           //==========================
           //Process Proxy HTTP Request
           //==========================

           if (channel == priorityNumber)
           {
               if (llStringLength(message) >= 508)
               {
                   if (((integer)message/channel) != 4958654)
                   {
                       sayCachePrivate = (sayCachePrivate=[]) + sayCachePrivate + [id, message];
                       return; 
                   }
                   message = "";
               }
               message = rxTxtLotPrv(id, message);
               //Received packet to translate
               llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0.05, 0.25>, "");

               lsttmpli = llParseString2List(message, ["~"], []);
               lsttmpStr = llList2String(lsttmpli, 0);
               lsttmpli = llDeleteSubList(lsttmpli, 0, 0);

               lst2tmpStr = llDumpList2String(lsttmpli, "|");
               lsttmpli = llCSV2List(lsttmpStr);
               lstliPos = llList2Integer(lsttmpli, 0);
               lsttmpli = llDeleteSubList(lsttmpli, 0, 0);

               checkThrottle(lstliPos, lst2tmpStr, lsttmpli);

               return;
           }

           //=======================
           //Process Global Messages
           //=======================
           if (llStringLength(message) >= 508)
           {
               if (((integer)message/channel) != 4958654)
               {
                   sayCache = (sayCache=[]) + sayCache + [id, message];
                   return; 
               }
               message = "";
           }
           message = rxTxtLot(id, message);

           lsttmpli = llCSV2List(message);

           if (llGetListLength(lsttmpli) >= 2)    
           {
               ImessageType = llList2Integer(lsttmpli, 0);
               lsttmpli = llDeleteSubList(lsttmpli, 0, 0);
               Imessage = llList2CSV(lsttmpli);        

               llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0.25, 0, 0.25>, "");
               //Process Message Here
               if (ImessageType == 1001)
               {
                   //Incoming Heartbeat
                   if ((integer)Imessage == priorityNumber)
                   {
                       llOwnerSay("Priority Number Conflict!  Resetting Script...");
                       llResetScript(); //Reset if conflicting priority number
                   }
                   
                   if (~llListFindList(translators, (list)id)  //lstliPos < 0) 
                   {
                       lstliPos = llListFindList(translators, [id]);
                       translators = llListReplaceList(translators, [(integer)Imessage], lstliPos - 1, lstliPos - 1);                        
                   }
                   else
                   {
                      translators = (translators=[]) + translators + [(integer)Imessage, id];
                       if ((isMaster > 0) && (isInitialized))
                       {
                           txTxtLot((integer)Imessage, llList2CSV([1002, llList2CSV(agentsInTranslation)]));
                           txTxtLot((integer)Imessage, llList2CSV([1004, options]));
                       } 
                   }
               }
               else if (ImessageType == 1002)
               {
                   //Incoming agentsInTranslation Master Broadcast
                   if (isMaster == 0)
                   {
                       //llMessageLinked(LINK_THIS, 9458021, Imessage, "");  
                       lsttmpli = llCSV2List(Imessage);
                       agentsInTranslation = [];
                       for (w = 0; w < llGetListLength(lsttmpli); w += 4)
                       {
                           agentsInTranslation = (agentsInTranslation=[]) + agentsInTranslation + [llList2Key(lsttmpli, w), llList2String(lsttmpli, w + 1), llList2Integer(lsttmpli, w + 2), llList2Integer(lsttmpli, w + 3)];
                       }
                   }
               }
               else if (ImessageType == 1003)
               {
                   //Incoming agentsInTranslation dump from Slave
                   lsttmpli = llCSV2List(Imessage);
                   for (w = 0; w < llGetListLength(lsttmpli); w += 4)
                   {
                       addAgent(llList2Key(lsttmpli, w), llList2String(lsttmpli, w + 1), llList2Integer(lsttmpli, w + 2));
                   }
               }
               else if (ImessageType == 1004)
               {
                   //Incoming Preferences
                   options = Imessage;
                   lsttmpli = llCSV2List(options);
                   showTranslation = llList2Integer(lsttmpli, 0);
                   tranObjects = llList2Integer(lsttmpli, 1);
                   autoLanguage = llList2Integer(lsttmpli, 2);

                   llMessageLinked(LINK_THIS, 3342977, Imessage, "");  
               }
           }            
           return;
       }

       //Translator Engine Code
       if ((llToLower(message) == "translator") && (isMaster > 0)) 
       {
           llMessageLinked(LINK_THIS, 2540664, message, id);
           return;
       }
       if ((!enabled) && (isMaster == 1)) return;

       if (!tranObjects)
       {
           if (llGetAgentSize(id) == ZERO_VECTOR) return;
       } 
       
       if (~llListFindList(agentsInTranslation, (list)id)) //lstliPos >= 0)
       {
           lstliPos = llListFindList(agentsInTranslation, (list)id);            
           spkrLan = llList2String(agentsInTranslation, lstliPos + 1);
       }
       else
       {
           spkrLan = addNewAgent(id);
       } 
       if (spkrLan == "xx") return;  //Agent Opt-Out
        
       llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 1, 0>, "");
       //===============================
       //Formulate Translation Requests
       //===============================
       for (w = 0; w < llGetListLength(agentsInTranslation); w += 4)
       {
           //Loop through translation group and do appropriate translations as needed
           recepID = llList2Integer(agentsInTranslation, w + 3);
           recepLan =  checkLanguage(llList2Key(agentsInTranslation, w + 1)); 
           if ((spkrLan != recepLan) && (recepLan != "") && (recepLan != "xx"))
           {
               lanpair = spkrLan + "|" + recepLan;

               
               if (~llListFindList(translationCache, (list)lanpair)) //lstliPos < 0)
               {
                 lstliPos = llListFindList(translationCache, [lanpair]);
                 translationCache = llListReplaceList(translationCache, [llList2String(translationCache, lstliPos + 1) + "@" + (string)recepID], lstliPos + 1, lstliPos + 1);
                 
               }
               else
               {
                 translationCache = (translationCache=[]) + translationCache + [lanpair, recepID];
               }
           }
       } 
       //Process Requests
       if (translationCache != [])
       {
           for (w = 0; w < llGetListLength(translationCache); w += 2)
           {
               //====================================
               //Translation
               //====================================
               //Forumulate and Send Translation Request
               lanpair = "|" + llList2String(llParseStringKeepNulls(llList2String(translationCache, w), ["|"],[]), 1); 
               checkThrottle(0, llEscapeURL(message) + "&langpair=" + llEscapeURL(lanpair), [llGetTime(), id , llList2String(translationCache, w + 1), llList2String(translationCache, w)]);
           } 
       }
       else
           spkrLan = ""; 
       //====================================
       //Language Detection
       //====================================
       if (llGetAgentSize(id) != ZERO_VECTOR) //llList2Key(llGetObjectDetails(id, [OBJECT_CREATOR]), 0) == NULL_KEY)
       {
           if (((spkrLan == "") || (llList2Integer(agentsInTranslation, llListFindList(agentsInTranslation, [id]) + 2) == TRUE)) || (isMaster == 2))
           {
               //Forumulate and Send Language Detect Request
               checkThrottle(1, llEscapeURL(message), [llGetTime(), id]);
           }       
       }
   }
   
   http_response(key request_id, integer status, list metadata, string body)
   {
       string  htttmpStr; 
       if (status != 200) 
       {
           //llOwnerSay("WWW Error:" + (string)status);
           llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 0, 0>, "");
           //llOwnerSay(body);
           return;
       } 
       //Process Resonse Code
       htttmpStr = llGetSubString(body, llSubStringIndex(body, "\"responseStatus\":"), -1);
       status = (integer)llGetSubString(htttmpStr, 17, llSubStringIndex(htttmpStr, "}") - 1);
       if (status != 200)
       {
           //llOwnerSay("Language Server Returned Error Code: " + (string)status);
           //llOwnerSay(body);
           llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<1, 0, 0>, "");
           return;
       }
       llMessageLinked(LINK_ALL_CHILDREN, 6634934, (string)<0, 0, 1>, "");
       llMessageLinked(LINK_THIS, 345149624, body, request_id);
   }
   timer()
   {
       llSetTimerEvent(0.0);  // timer reset
       integer r;
       string  tmrtmpStr;
       list    tmrnewli;
       integer translatorCount = llGetListLength(translators)/2; 
       if (isInitialized == FALSE)
       {
           enabled = TRUE;
           listenID = llListen(0, "", "", ""); 
           llListen(777, "", NULL_KEY, "");
           llMessageLinked(LINK_THIS, 6877259, (string)enabled, NULL_KEY);
           isInitialized = TRUE;
       } 
       llMessageLinked(LINK_THIS, 94558323, llList2CSV(agentsInTranslation), "");
       if (isMaster > 0)
       {
           for (r = 0; r < llGetListLength(agentsInTranslation); r += 4)
           {
               tmrtmpStr = llList2String(llGetObjectDetails(llList2Key(agentsInTranslation, r), [OBJECT_POS]), 0);
               if ((llVecDist(llGetPos(), (vector)tmrtmpStr) <= 20.0) && (tmrtmpStr != ""))
               {
                   tmrnewli = (tmrnewli=[]) + tmrnewli + llList2List(agentsInTranslation, r, r + 3);
               }
           }
           agentsInTranslation = tmrnewli;
           if ((llGetUnixTime() - lastHeartBeat) >= 5)
           {
               //Send heartbeat
               sendHeartbeat();
               lastHeartBeat = llGetUnixTime();
           }
       }
       else
       {
           if ((llGetUnixTime() - lastHeartBeat) >= `0 + llGetListLength(agentsInTranslation)*2 + llPow(translatorCount, 1.4) + translatorCount + ((1-llGetRegionTimeDilation()) * 5))
           {
               //Send heartbeat
               sendHeartbeat();
               lastHeartBeat = llGetUnixTime();
           }
       } 
       //turn on and off scanner
       if ((autoLanguage) && isMaster > 0)
       {
           llSensor("", NULL_KEY, AGENT, 20.0, PI);
       }
       llSetTimerEvent(4.0); // restart timer
       //llSetTimerEvent(4 + ((1-llGetRegionTimeDilation()) * 5));
   }

}

</lsl>