Difference between revisions of "User talk:Perry Mizin"

From Second Life Wiki
Jump to navigation Jump to search
Line 13: Line 13:
----
----


== THE CODE BELOW IS NOT TESTED ==
''Universal Translator Engine''
Que exagerado
<lsl>
<lsl>
//Universal Translator
//Universal Translator

Revision as of 01:49, 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 <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))
   {
       avliPos = llListFindList(agentsInTranslation, [avid]);
       agentsInTranslation = llListReplaceList(agentsInTranslation, [avlan, chklan], avliPos + 1, avliPos + 2);
   }
   else
   {
       @at;
       idNum = llRound(llFrand(2000000)) + 1;
       if(~llListFindList(agentsInTranslation, (list)idNum))
       {//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
                   }
                   lstliPos = llListFindList(translators, [id]);
                   if (lstliPos < 0) 
                   {
                       translators = (translators=[]) + translators + [(integer)Imessage, id];
                       if ((isMaster > 0) && (isInitialized))
                       {
                           txTxtLot((integer)Imessage, llList2CSV([1002, llList2CSV(agentsInTranslation)]));
                           txTxtLot((integer)Imessage, llList2CSV([1004, options]));
                       }
                   }
                   else
                   {
                       translators = llListReplaceList(translators, [(integer)Imessage], lstliPos - 1, lstliPos - 1);
                   }
               }
               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;
       } 
       lstliPos = llListFindList(agentsInTranslation, [id]);
       if (lstliPos >= 0)
       {            
           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;

               lstliPos = llListFindList(translationCache, [lanpair]);
               if (lstliPos < 0)
               {
                 translationCache = (translationCache=[]) + translationCache + [lanpair, recepID];
               }
               else
               {
                 translationCache = llListReplaceList(translationCache, [llList2String(translationCache, lstliPos + 1) + "@" + (string)recepID], lstliPos + 1, lstliPos + 1);
               }
           }
       } 
       //Process Requests
       if (llGetListLength(translationCache) > 0)
       {
           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>