vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
GUILDADSCOMM_DEBUG = false;             -- Is debug printf enabled?

GUILDADS_MSG_TYPE_ANNONCE = 0;
GUILDADS_MSG_TYPE_REQUEST = 1;
GUILDADS_MSG_TYPE_AVAILABLE = 2;
GUILDADS_MSG_TYPE_SKILL = 3;
GUILDADS_MSG_TYPE_EVENT = 4;
GUILDADS_MSG_TYPE_INVENTORY = 5;
GUILDADS_MSG_TYPE_NOTE = 6;
GUILDADS_MSG_TYPE_EVENT_SUBSCRIPTION = 7;
GUILDADS_MSG_TYPE_IGNORE = "i";

GUILDADS_VERSION_PROTOCOL = "26";

GUILDADS_MSG_PREFIX = "<GA"..GUILDADS_VERSION_PROTOCOL..">";
GUILDADS_MSG_PREFIX_NOVERSION = "<GA";
GUILDADS_MSG_PREFIX_TOKEN = '\29';
GUILDADS_MSG_PREFIX_CHATCOMM = '\29'.."AD"..'\29'..GUILDADS_VERSION_PROTOCOL..'>';

GUILDADS_MSG_ADD = "a";
GUILDADS_MSG_REMOVE = "r";
GUILDADS_MSG_REMOVE_ALL = "R";
GUILDADS_MSG_REQUEST_ADS = "?";
GUILDADS_MSG_REQUEST_INSPECT = "?i";
GUILDADS_MSG_REQUEST_OFFLINES = "?o";
GUILDADS_MSG_SENDING_UPDATE = "U";
GUILDADS_MSG_SENDING_ALL = "S";
GUILDADS_MSG_SENDING_ALL_END = "E";
GUILDADS_MSG_LASTSEEN = "l";
GUILDADS_MSG_LASTSEEN_END = "le";
GUILDADS_MSG_META = "m";
GUILDADS_MSG_CHATFLAG = "chatFlag";

GUILDADS_STATE_UNKNOW       = "unknow";
GUILDADS_STATE_SYNC_ONLINE  = "s_online";
GUILDADS_STATE_SYNC_OFFLINE = "s_offline";
GUILDADS_STATE_OK            = "ok";

local playerName = "";
local MonitorAds = {};                  -- record updated ads (GUILDADS_MSG_SENDING_ALL)
local MetaPlayers = {};                 -- state, onlineSince, version
local MyState = GUILDADS_STATE_UNKNOW;
local LastSeens = {};                   -- Players we are listen to give theirs offline players.
local WaitingOfflinesAds = { }; -- Players are we waiting for offlines ads to be GUILDADS_STATE_OK
local StartTime;
local OnMessageCommand = { };
local OnMessageAd = {};
local WatingForUpdate = { };

local function DEBUG_MSG(msg)
        if (GUILDADSCOMM_DEBUG)
        then
                ChatFrame1:AddMessage("GAC: "..msg, 1.0, 1.0, 0.5);
        end
end

local function GAC_GetGuildChatFrame()
        for i=1,NUM_CHAT_WINDOWS,1 do
                local DefaultMessages = { GetChatWindowMessages(i) };
                for k, channel in DefaultMessages do
                        if channel == "GUILD" then
                                return getglobal("ChatFrame"..i);
                        end
                end
        end
        return DEFAULT_CHAT_FRAME;
end

function GAC_GetMeta(player)
        return MetaPlayers[player];
end

function GAC_GetMetas()
        return MetaPlayers;
end

GAC_GetFlag = SimpleComm_GetFlag;

function GAC_AddChatMessage(msg)
        local info = ChatTypeInfo["CHANNEL"..GetChannelName( SimpleComm_Channel )];
        SimpleComm_ChatFrame:AddMessage(msg, info.r, info.g, info.b);
end

function GAC_InitVariablesLoaded()
        SimpleComm_PreInit(GuildAds_FilterText);
end

function GAC_Init(playername, channel, password)
        DEBUG_MSG("GAC_Init("..playername..","..channel..")");
        
        playerName = playername;
        if (not StartTime) then
                StartTime = GAS_currentTime();
        end
        
        SimpleComm_Init(
                channel,
                password,
                GAC_GetGuildChatFrame(),
                GAC_Synchronize,
                GAC_OnChannelLeave,
                GAC_OnMessage,
                GuildAds_Serialize,
                GuildAds_Unserialize,
                GuildAds_FilterText
                );
        
        local command, alias = GuildAdsConfig_GetChannelAlias()
        SimpleComm_InitAlias(command, alias);
        
        SimpleComm_SetFlagListener(GAC_OnChatFlagChange);
        
        -- Init after the channel is joined (GAC_Synchronize called by SimpleComm)
end

function GAC_Reinit(channel, password)
        -- Reset internal variables
        MonitorAds = {};
        LastSeens = {};
        WaitingOfflinesAds = { };
        WatingForUpdate = { };
        MyState = GUILDADS_STATE_UNKNOW;
        GuildAdsSystem.SynchronizeOfflinesTimer = nil;
        GuildAdsSystem.SynchronizeOfflinesTimerEnd = nil;
        
        -- Reinit GuildAdsComm
        SimpleComm_SetChannel(channel, password);
        
        -- Init after the channel is joined (GAC_Synchronize called by SimpleComm)
end

function GAC_OnChannelLeave()
        GuildAdsPlugin_OnChannelLeave();
end

function GAC_Synchronize()
        DEBUG_MSG("GAC_Synchronize");
        
        -- call plugin init
        GuildAdsPlugin_OnChannelJoin();
        
        -- reset local variables
        MonitorAds = {};
        MetaPlayers = {};
        LastSeens = {};
        WaitingOfflinesAds = {};
        WatingForUpdate = { };
        
        -- Send status
        MyState = GUILDADS_STATE_SYNC_ONLINE;
        GAC_SendMeta(nil);
        
        -- Send chat status : detected by SimpleComm
        GAC_SendChatFlag(playerName);
        
        -- Now, send to all my ads
        GAC_SendAllAdsType(nil, nil, nil);
        
        -- Ask everyone to send me their ads
        GAC_SendRequestAds(nil);
        
        -- Wait 30 seconds and synchronize offlines
        GuildAdsSystem.SynchronizeOfflinesCount = 0;
        GuildAdsSystem.SynchronizeOfflinesTimer = 30;
        GuildAdsSystem.SynchronizeOfflinesTimerEnd = false;
end

function GAC_SynchronizeOfflines(numberOfTries)
        DEBUG_MSG("GAC_SynchronizeOfflines("..numberOfTries..")");
        
        --[[
                moi à player> envois de GUILDADS_MSG_REQUEST_OFFLINES
                player à moi> envois de GUILDADS_MSG_LASTSEEN pour chacun de ses offlines
                moi> pour chaque GUILDADS_MSG_LASTSEEN reçu : 
                        si plus ancien -> envois de mes annonces
                        si plus récent -> demande les annonces à player
                player à moi> envois de GUILDADS_MSG_LASTSEEN_END
                        envois de ses offlines non mis à jour
        ]]

        -- Ask offlines to someone who is online
        local oneOnlinePlayer, canTryLater = GAC_GetRandomOnline();
        if (oneOnlinePlayer) then
                -- Il y au moins un autre joueur
                if (canTryLater) and (numberOfTries<=20) then
                        --[[ aucun joueur connecté n'est synchronisé
                        attends à nouveau 30 secondes
                        sauf s'il y a plus de 20 essais (donc 10 minutes)
                        nombre d'essais limité pour éviter  le deadlock si 
                        deux joueurs se connectent au même moment
                        onelinePlayer = true
                        ]]
                        GuildAdsSystem.SynchronizeOfflinesTimerEnd = false;
                        GuildAdsSystem.SynchronizeOfflinesCount = numberOfTries+1;
                        GuildAdsSystem.SynchronizeOfflinesTimer = 30;
                else
                        -- Changement d'état
                        MyState = GUILDADS_STATE_SYNC_OFFLINE;
                        GAC_SendMeta(nil);
                        
                        -- Il y a au moins un autre joueur connecté
                        GAC_SendRequestOfflines(oneOnlinePlayer);
                        -- 10 minutes avant d'être déclaré synchronisé
                        GuildAdsSystem.SynchronizeOfflinesTimer = 60*10;
                        GuildAdsSystem.SynchronizeOfflinesCount = 0;
                        GuildAdsSystem.SynchronizeOfflinesTimerEnd = true;
                end
        else
                -- Aucun online
                -- Synchronisation terminée
                MyState = GUILDADS_STATE_OK;
                GAC_SendMeta(nil);
        end
end

function GAC_SynchronizeOfflinesEnd()
        MyState = GUILDADS_STATE_OK;
        GAC_SendMeta(nil);
end

function GAC_OnChatFlagChange(flag, message)
        SimpleComm_SendMessage(
                nil,
                {
                        command = GUILDADS_MSG_CHATFLAG;
                        flag = flag;
                        text = message;
                }
        );
end

--[[
        Retourne le nom d'un joueur connecté et synchronisé.
        Si aucun joueur connecté n'est synchronisé, retourne true
        Si aucun joueur n'est connecté, retourne nil
]]
function GAC_GetRandomOnline()
        local canTryLater = false;
        local ready = {};
        for name, metainfo in MetaPlayers do
                if (name ~= playerName) then
                        if (metainfo.state == GUILDADS_STATE_OK) then
                                tinsert(ready, name);
                        elseif (metainfo.state == GUILDADS_STATE_SYNC_OFFLINE) or (metainfo.state == GUILDADS_STATE_SYNC_ONLINE) then
                                canTryLater = true;
                        end
                end
        end
        local s = table.getn(ready);
        if (s > 0) then
                return ready[math.random(s)], false;
        else
                if (canTryLater) then
                        return nil, true;
                else
                        return nil, false;
                end
        end
end

function GAC_SendAd(who, ad_type ,ad, delay)
        if (ad.m_Enabled == false) then
                return;
        end
        SimpleComm_SendMessage(
                who,
                {
                        command = GUILDADS_MSG_ADD;
                        adtype = ad_type;
                        id = ad.id;
                        text = ad.text;
                        texture = ad.texture;
                        count = ad.count;
                        itemRef = ad.itemRef;
                        itemName = ad.itemName;
                        itemColor = ad.itemColor;
                        skillRank = ad.skillRank;
                        skillMaxRank = ad.skillMaxRank;
                        creationtime = ad.creationtime;
                        owner = ad.owner
                },
                delay
        );
end

function GAC_SendSkill(who, id, skillRank, skillMaxRank, delay)
        SimpleComm_SendMessage(
                who,
                {
                        command = GUILDADS_MSG_ADD;
                        adtype = GUILDADS_MSG_TYPE_SKILL;
                        id = id;
                        skillRank = skillRank;
                        skillMaxRank = skillMaxRank;
                        creationtime = GAS_currentTime()
                },
                delay
        );
end

function GAC_SendSkills(who, delay)
        local grp = "";
        for i = 1, GetNumSkillLines(), 1 do     
                local skillName, header, isExpanded, skillRank, numTempPoints, skillModifier, skillMaxRank, isAbandonable, stepCost, rankCost, minLevel, skillCostType = GetSkillLineInfo(i);
                if (header == 1) then
                        grp = skillName;
                else 
                        local id = GAS_GetSkillId(skillName);
                        if (id > 0) then
                                GAC_SendSkill(who, id, skillRank, skillMaxRank, delay)
                        end
                end
        end
end

function GAC_SendInventory(who, slot, texture, color, ref, name, count)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_ADD;
                                adtype = GUILDADS_MSG_TYPE_INVENTORY;
                                id = slot;
                                itemRef = ref;
                                itemName = name;
                                itemColor = color;
                                count = count;
                                texture = texture;
                                creationtime = GAS_currentTime()
                        }
                );
end

function GAC_SendInspect(who)
        local buffer = {};
        for slot=1, 19, 1 do
                local link = GetInventoryItemLink("player", slot);
                if (link) then
                        -- local title = TEXT(getglobal(strupper(SlotIdText[slot])));
                        local texture = GetInventoryItemTexture("player", slot);
                        local count = GetInventoryItemCount("player", slot);
                        local color, ref, name = GAS_UnpackLink(link);  
                        tinsert(buffer, {
                                        slot = slot,
                                        texture = texture,
                                        color = color,
                                        ref = ref,
                                        name = name,
                                        count = count
                                }
                        );
                end
        end
        
        GAC_SendingUpdate(who, table.getn(buffer));
        local index = 1;
        while buffer[index] do
                GAC_SendInventory(who, buffer[index].slot, buffer[index].texture, buffer[index].color, buffer[index].ref, buffer[index].name, buffer[index].count);
                index = index + 1;
        end
end

function GAC_SendRequestInspect(who)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_REQUEST_INSPECT
                        }
                );
end

function GAC_SendRequestOfflines(who)
        DEBUG_MSG("GAC_SendRequestOfflines("..NoNil(who)..")");
        LastSeens[who] = {};
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_REQUEST_OFFLINES
                        }
                );
end

function GAC_SendRequestAds(who, owner)
        DEBUG_MSG("GAC_SendRequestAds("..NoNil(who)..")");
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_REQUEST_ADS;
                                owner = owner
                        }
                );
end


function GAC_SendAnnonce(who, owner)
        local powner, level, race, class, name, guildName, guildRankName, guildRankIndex, creationtime;
        if (owner) then
                powner = GAS_ProfileGet(owner);
                level = powner.level;
                race = powner.race;
                class = powner.class;
                name = owner;
                guildName = powner.guild;
                creationtime = powner.creationtime;
                accountid = powner.accountid;
        else
                level = UnitLevel("player");
                race = GAS_GetRaceId(UnitRace("player"));
                class = GAS_GetClassId(UnitClass("player"));
                name = playerName;
                guildName, guildRankName, guildRankIndex = GetGuildInfo("player");
                creationtime = GAS_currentTime();
                accountid = GAS_GetAccountId();
        end
        
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_ADD;
                                adtype = GUILDADS_MSG_TYPE_ANNONCE;
                                accountId = accountid;
                                class = class;
                                race = race;
                                level = level;
                                guild = guildName;
                                creationtime = creationtime;
                                owner = owner
                        }
                );
end

function GAC_SendRemove(who, adtype, id)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_REMOVE;
                                adtype = adtype;
                                id = id
                        }
                );
end

function GAC_SendRemoveAll(who)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_REMOVE_ALL;
                        }
                );
end

function GAC_SendingUpdate(who, count, owner, delay)
        SimpleComm_SendMessage(
                who,
                { 
                        command = GUILDADS_MSG_SENDING_UPDATE,
                        owner = owner,
                        count = count
                },
                delay
        );
end

function GAC_SendingAll(who, owner)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_SENDING_ALL;
                                owner = owner
                        }
                );
end

function GAC_SendingAllEnd(who, owner, delay)
        local creationtime = 0;
        if (owner) then
                creationtime = GAS_ProfileGetUpdatedDate(owner);
        else
                creationtime = GAS_ProfileGetUpdatedDate(playerName);
        end
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_SENDING_ALL_END;
                                creationtime = creationtime;
                                owner = owner;
                        },
                        delay
                );
end

function GAC_SendLastSeen(who, owner, time)
        DEBUG_MSG("GAC_SendLastSeen("..NoNil(who)..")");
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_LASTSEEN;
                                creationtime = time;
                                owner = owner
                        }
                );
end

function GAC_SendLastSeenEnd(who)
        DEBUG_MSG("GAC_SendLastSeenEnd("..NoNil(who)..")");
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_LASTSEEN_END;
                        }
                );
end

function GAC_SendAllAds(who, owner, adTable, ad_type, delay)
        local size = table.getn(adTable);
        if owner then
                for i = 1, size, 1 do
                        if adTable[i].owner == owner then
                                GAC_SendAd(who, ad_type, adTable[i], delay);
                        end
                end
        else
                for i = 1, size, 1 do
                        GAC_SendAd(who, ad_type, adTable[i], delay);
                end
        end
end

function GAC_SendAllAdsType(who, owner, delay)
        DEBUG_MSG("GAC_SendAllAdsType("..NoNil(who)..","..NoNil(owner)..")");
        
        -- On n'envois pas à who ses annonces
        -- sauf si c'est nous même, ou si c'est à tout le monde
        if (who == owner) and (who ~= playerName) and (who ~= nil) then
                return;
        end
        
        -- Ads->Start
        GAC_SendingAll(who, owner);
        
        -- Ads : Guild
        GAC_SendAnnonce(who, owner);
        
        -- Ads : Ask/Have/Event
        local adTables = {};
        if (owner) then
                adTables = GAS_GetAds();
        else
                adTables = GAS_GetMyAds();
        end
        
        GAC_SendAllAds(who, owner, adTables[GUILDADS_MSG_TYPE_REQUEST], GUILDADS_MSG_TYPE_REQUEST, delay);
        GAC_SendAllAds(who, owner, adTables[GUILDADS_MSG_TYPE_AVAILABLE], GUILDADS_MSG_TYPE_AVAILABLE, delay);
        GAC_SendAllAds(who, owner, adTables[GUILDADS_MSG_TYPE_EVENT], GUILDADS_MSG_TYPE_EVENT, delay);
        
        -- Ads : Skills
        if owner then
                GAC_SendAllAds(who, owner, adTables[GUILDADS_MSG_TYPE_SKILL], GUILDADS_MSG_TYPE_SKILL, delay);
        else
                GAC_SendSkills(who, delay);
        end
        
        -- Ads->End
        GAC_SendingAllEnd(who, owner, delay);
end

function GAC_SendMeta(who)
        SimpleComm_SendMessage(
                        who,
                        {
                                command = GUILDADS_MSG_META;
                                text = GUILDADS_VERSION;
                                creationtime = StartTime;
                                id = MyState;
                        }
                );
end

function GAC_SendChatFlag(who)
        local flag, message = SimpleComm_GetFlag(playerName);
        SimpleComm_SendMessage(
                nil,
                {
                        command = GUILDADS_MSG_CHATFLAG;
                        flag = flag;
                        text = message;
                }
        );
end

--------------------------------------------------------------------------------
--
-- OnMessage
-- 
---------------------------------------------------------------------------------
function GAC_OnMessage(author, message)
        if (GUILDADSCOMM_DEBUG) then
                DEBUG_MSG("[OnMessage,"..author.."]: "..GuildAds_Serialize(message));
        end
        
        -- Ignore this author ?
        if GAS_ProfileIsIgnored(author) then
                return;
        end
        
        -- Set online
        GAS_SetOnlineStatus(author, true);
        
        -- A propos de quelle personne : l'auteur du message (author) ou une autre (message.owner)
        local owner = author;
        if (message.owner) then
                owner = message.owner;
        end
        
        -- Mise à jour du dernier message de author
        if (owner==author) and ((message.command == GUILDADS_MSG_ADD) or (message.command == GUILDADS_MSG_REMOVE)) then
                GAS_ProfileSetUpdatedDate(author, message.creationtime);
        end
        
        --
        -- Process all the messages we know about
        --
        if (message.command == GUILDADS_MSG_ADD) then
                -- Accept only if :
                --      this owner isn't ignored
                --   AND ( this owner has sent GUILDADS_MSG_SENDING_ALL which was accepted.
                --         OR this owner has sent a GUILDADS_MSG_SENDING_UPDATE )
                if not GAS_ProfileIsIgnored(owner) and (MonitorAds[owner] or WatingForUpdate[owner]) then
                        -- 
                        local adtype = message.adtype;
                        
                        -- Use this update
                        if WatingForUpdate[owner] then
                                WatingForUpdate[owner] = WatingForUpdate[owner] - 1;
                                if WatingForUpdate[owner]==0 then
                                        WatingForUpdate[owner] = nil;
                                end
                                DEBUG_MSG("Count"..NoNil(WatingForUpdate[owner]));
                        end
                
                        -- Call onMessageAd
                        if OnMessageAd[adtype] then
                                if not OnMessageAd[adtype](author, message) then
                                        return;
                                end
                        end
                
                        -- Inventory
                        if (adtype == GUILDADS_MSG_TYPE_INVENTORY) then
                                GAS_ProfileSetInventorySlot(message.creationtime, owner, message.id, message.itemColor, message.itemRef, message.itemName, message.texture, message.count);
                                return false;
                        end
                
                        -- Mise à jour du profile
                        if (adtype == GUILDADS_MSG_TYPE_ANNONCE) then
                                GAS_ProfileSetGeneral(message.creationtime, owner, message.race, message.class, message.level, message.guild);
                                GAS_ProfileSetAccountId(owner, message.accountId);
                                message.guild = nil;
                                message.level = nil;
                                message.class = nil;
                                message.race = nil;
                                message.accountId = nil;
                                message.id = owner;
                        end
                
                        -- Monitor : l'annonce a été mise à jour
                        -- cf GUILDADS_MSG_SENDING_ALL et GUILDADS_MSG_SENDING_ALL_END
                        if adtype and owner and MonitorAds[owner] then
                                if (MonitorAds[owner][adtype] == nil) then
                                        MonitorAds[owner][adtype] = {};
                                end
                                MonitorAds[owner][adtype][message.id] = true;
                        end
                
                        -- Scan for dupes
                        if ((adtype == GUILDADS_MSG_TYPE_REQUEST) or (adtype == GUILDADS_MSG_TYPE_AVAILABLE) or (adtype == GUILDADS_MSG_TYPE_EVENT)) then
                                local ads = GAS_GetAds();
                                for k,v in ads[adtype] do
                                        if ( v.owner == owner and v.id == message.id and v.text == message.text and v.itemName == message.itemName and v.count == message.count ) then
                                                -- DONT ADD IT AGAIN
                                                DEBUG_MSG("GuildAds_OnMessage: Already in DB");
                                                return false;
                                        end
                                end
                        end
                
                
                        -- Effacer le précédent Id 
                        GAS_RemoveByOwnerAndId(owner, adtype, message.id);
                
                        -- Efface les donnees inutiles
                        message.adtype = nil;
                        message.command = nil;
                        message.owner = owner;
                        message.currenttime = nil;
                        
                        -- Traduction du nom si necessaire
                        if message.itemName and message.itemRef then
                                local info = GAS_GetItemInfo(message.itemRef);
                                if (info.name) then
                                        message.itemName = info.name;
                                end
                        end
                
                        -- Ajout de l'annonce
                        GAS_AddAd(owner, adtype, message);
                end
                
        elseif (message.command == GUILDADS_MSG_REMOVE) then
                -- Ignore this owner ?
                if not GAS_ProfileIsIgnored(owner) then
                        -- A previously placed add is being removed
                        GAS_RemoveByOwnerAndId(owner, message.adtype, message.id);
                end
                
        elseif (message.command == GUILDADS_MSG_REQUEST_INSPECT) then   
                if not GAS_ProfileIsIgnored(owner) then
                        -- Send inspect to the author
                        -- Always my inventory
                        GAC_SendInspect(author);
                end
                
        elseif (message.command == GUILDADS_MSG_REQUEST_OFFLINES) then
                if not GAS_ProfileIsIgnored(owner) then
                        -- Pour chaque personne offline
                        -- -> envois la date du dernier message
                        local ads = GAS_GetAds();
                        for i, ad in ads[GUILDADS_MSG_TYPE_ANNONCE] do
                                if (not GAS_IsOnline(ad.owner)) and (not GAS_ProfileIsIgnored(ad.owner)) then
                                        GAC_SendLastSeen(author, ad.owner, GAS_ProfileGetUpdatedDate(ad.owner));
                                end
                        end
                        GAC_SendLastSeenEnd(author);
                end
                
        elseif (message.command == GUILDADS_MSG_LASTSEEN) then
                if (owner ~= playerName) and (LastSeens[author]) and (not GAS_ProfileIsIgnored(owner)) then
                        LastSeens[author][owner] = true;
                        local myUpdate = GAS_ProfileGetUpdatedDate(owner);
                        if (message.creationtime ~= myUpdate) then
                                if (myUpdate) then
                                        if (message.creationtime==nil or message.creationtime < myUpdate) then
                                                DEBUG_MSG("LastSeen("..owner..")="..NoNil(message.creationtime).."<"..NoNil(myUpdate));
                                                -- on doit faire la mise à jour pour tout le monde
                                                GAC_SendAllAdsType(nil, owner);
                                        elseif (message.creationtime > myUpdate) then
                                                DEBUG_MSG("LastSeen("..owner..")="..NoNil(message.creationtime)..">"..NoNil(myUpdate));
                                                -- on doit récupérer la mise à jour
                                                tinsert(WaitingOfflinesAds, owner);
                                        end
                                else
                                        DEBUG_MSG("LastSeen("..owner..")="..NoNil(message.creationtime).."/"..NoNil(myUpdate));
                                        -- on doit récupérer la mise à jour
                                        tinsert(WaitingOfflinesAds, owner);
                                end
                        end
                end
                
        elseif (message.command == GUILDADS_MSG_LASTSEEN_END) then
                if LastSeens[author] and not GAS_ProfileIsIgnored(author) then
                        -- envois les annonces des joueurs non connus.
                        local ads = GAS_GetAds();
                        for i, ad in ads[GUILDADS_MSG_TYPE_ANNONCE] do
                                -- si ad.owner est offline et non connu par author
                                -- alors on envois ses informations à propos de ad.owner
                                if (not GAS_IsOnline(ad.owner) and LastSeens[author][ad.owner]==nil) then
                                        GAC_SendAllAdsType(nil, ad.owner);
                                end
                        end
                        
                        -- Dernier message de author à propos des offlines
                        -- Donc on n'écoute plus les message de author
                        LastSeens[author] = nil;
                        
                        --
                        if (table.getn(WaitingOfflinesAds) > 0) then
                                -- demande de mise à jour pour soi.
                                for _, owner in WaitingOfflinesAds do
                                        GAC_SendRequestAds(author, owner);
                                end
                        else
                                -- aucune demande de offlines
                                -- on est donc synchro : passage a l'etat OK
                                GuildAdsSystem.SynchronizeOfflinesTimer = nil;
                                MyState = GUILDADS_STATE_OK;
                                GAC_SendMeta(nil);
                        end
                end
                
        elseif (message.command == GUILDADS_MSG_REQUEST_ADS) then
                -- Someone is requesting ads, probably just arrived in the channel
                -- if message.owner is set : owner's ads
                -- if message.owner is nil : my ads (send my ads in few seconds)
                -- owner is meaningless
                if GuildAds.Config.PublishMyAds and not GAS_ProfileIsIgnored(owner) then
                        if (author ~= playerName) then
                                if message.owner then
                                        GAC_SendAllAdsType(author, message.owner);
                                else
                                        GAC_SendMeta(author);
                                        GAC_SendChatFlag(author);
                                        GAC_SendAllAdsType(author, nil, math.random(20));
                                end
                        end
                end
                
        elseif (message.command == GUILDADS_MSG_SENDING_UPDATE) then
        
                WatingForUpdate[owner] = (WatingForUpdate[owner] or 0) + message.count;
                
        elseif (message.command == GUILDADS_MSG_SENDING_ALL) then
                if not GAS_ProfileIsIgnored(owner) then
                        -- Start recording each update ads
                        if message.owner then
                                -- Accept offline ads from owner we need. (see GUILDADS_MSG_LASTSEEN)
                                i = 1;
                                while WaitingOfflinesAds[i] and WaitingOfflinesAds[i]~=owner do
                                        i = i+1;
                                end
                                if  WaitingOfflinesAds[i] and WaitingOfflinesAds[i]==owner then
                                        MonitorAds[owner] = {};
                                end
                                
                                -- accept new ads from author who are in GUILDADS_STATE_SYNC_OFFLINE state.
                                if MetaPlayers[author] and MetaPlayers[author].state==GUILDADS_STATE_SYNC_OFFLINE then
                                        MonitorAds[owner] = {};
                                end
                        else
                                -- online synchronization : ok
                                MonitorAds[owner] = {};
                        end
                end
                
        elseif (message.command == GUILDADS_MSG_SENDING_ALL_END) then
                if MonitorAds[owner] and not GAS_ProfileIsIgnored(owner) then
                
                        -- Update profile date
                        if owner then
                                GAS_ProfileSetUpdatedDate(owner, message.creationtime);
                        end

                        -- for each owner's ads
                        -- if not updated (ie in MonitorAds), we delete it
                        local ads = GAS_GetAds();
                        for adtype, tads in ads do
                                if (MonitorAds[owner][adtype] == nil) then
                                        GAS_RemoveByOwner(owner, adtype);
                                else
                                        for i, ad in tads do
                                                if (owner==ad.owner and MonitorAds[owner][adtype][ad.id] == nil) then
                                                        GAS_RemoveByOwnerAndId(owner, adtype, ad.id);
                                                end
                                        end
                                end
                        end

                        -- stop monitoring
                        MonitorAds[owner] = nil;
                        
                        -- Unstack owner in WatingOfflineAds
                        -- if this is the last, we are sync
                        -- so set state to GUILDADS_STATE_OK
                        i = 1;
                        while WaitingOfflinesAds[i] and WaitingOfflinesAds[i]~=owner do
                                i = i+1;
                        end
                        if WaitingOfflinesAds[i] and WaitingOfflinesAds[i]==owner then
                                table.remove(WaitingOfflinesAds, i);
                                if (table.getn(WaitingOfflinesAds)==0) then
                                        GuildAdsSystem.SynchronizeOfflinesTimer = nil;
                                        MyState = GUILDADS_STATE_OK;
                                        GAC_SendMeta(nil);
                                end
                        end
                        
                end
                
        elseif (message.command == GUILDADS_MSG_REMOVE_ALL) then
        
                if not GAS_ProfileIsIgnored(owner) then
                        -- Remove all the ads from the owner
                        GAS_RemoveByOwner(owner, GUILDADS_MSG_TYPE_ANNONCE);
                        GAS_RemoveByOwner(owner, GUILDADS_MSG_TYPE_REQUEST);
                        GAS_RemoveByOwner(owner, GUILDADS_MSG_TYPE_AVAILABLE);
                        GAS_RemoveByOwner(owner, GUILDADS_MSG_TYPE_SKILL);
                        GAS_RemoveByOwner(owner, GUILDADS_MSG_TYPE_EVENT);
                end
                
        elseif (message.command == GUILDADS_MSG_META) then
        
                if not GAS_ProfileIsIgnored(author) then
                        MetaPlayers[author] = {
                                state = message.id;
                                onlineSince = message.creationtime;
                                version = message.text;
                        };
                end
                
        elseif (message.command == GUILDADS_MSG_CHATFLAG) then
                
                if author~=playerName then
                        SimpleComm_SetFlag(author, message.flag, message.text);
                end
                
        elseif OnMessageCommand[message.command] then
                OnMessageCommand[message.command](author, message);
        else
                -- This message was unknown
        end
end


--------------------------------------------------------------------------------
--
-- Serialize/Unserialize 
-- 
---------------------------------------------------------------------------------
function SerializeId(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                return obj
        end
end

function UnserializeId(str)
        return str;
end

function SerializeString(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                return obj
        end
end

function UnserializeString(str)
        if (str == "") then
                return nil;
        else
                return str
        end
end

function SerializeTexture(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                return string.gsub(obj, "Interface\\Icons\\", "\@");
        end
end

function UnserializeTexture(str)
        if (str == "") then
                return nil;
        else
                return string.gsub(str, "\@", "Interface\\Icons\\");
        end
end

function SerializeItemRef(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                return string.gsub(string.gsub(obj, "item\:", "\@"), ":0:0:0", "\*");
        end
end

function UnserializeItemRef(str)
        if (str == "") then
                return nil;
        else
                return string.gsub(string.gsub(str, "\@", "item\:"), "\*", ":0:0:0");
        end
end

function SerializeColor(obj)
        if obj==nil then
                return "";
        elseif obj=="ffa335ee" then
                return "E"; -- epic
        elseif obj=="ff0070dd" then
                return "R"; -- rare
        elseif obj=="ff1eff00" then
                return "U" -- uncommun
        elseif obj=="ffffffff" then
                return "C" -- common
        elseif obj=="ff9d9d9d" then
                return "P" -- poor
        else
                return obj;
        end
end

function UnserializeColor(str)
        if str==nil then
                return nil
        elseif str=="E" then
                return "ffa335ee";
        elseif str=="R" then
                return "ff0070dd";
        elseif str=="U" then
                return "ff1eff00";
        elseif str=="C" then
                return "ffffffff";
        elseif str=="P" then
                return "ff9d9d9d";
        else
                return str;
        end
end

function SerializeInteger(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                return obj;
        end
end

function UnserializeInteger(str)
        return tonumber(str);
end

function SerializeTime(obj)
        if (type(obj) == "nil" ) then
                return "";
        else
                -- convertion en base 52
                value = "";
                while (obj ~= 0) do
                        i = floor(obj / 52);
                        j = obj - i*52;
                        if (j>=26) then
                                value = string.char(65+j-26)..value;
                        else
                                value = string.char(96+j)..value;
                        end
                        obj = i;
                end
                return value;
        end
end

function UnserializeTime(str)
        if (str == "") then
                return nil;
        else
                number = 0;
                for i=1, string.len(str),1  do
                        o = string.byte(str, i);
                        if (o> 95) then
                                j = o-96;
                        else
                                j = o-65+26;
                        end
                        number = number*52 + j;
                end
                return number;
        end
end

function SerializeObj(obj)
        if (type(obj) == "nil" ) then 
                return "";
        elseif ( type(obj) == "string" ) then
                return "s"..string.gsub(string.gsub(string.gsub(obj, ">", "&gt;"), "|([cHhr])", "&%1;"), "|", "&p;");
        elseif ( type(obj) == "number" ) then
                return "n"..obj;
        elseif ( type(obj) == "boolean" ) then
                if  (value) then
                        return "1";
                else
                        return "0";
                end
        elseif ( type(obj) == "function" ) then
                return ""; -- nil
        elseif ( type(obj) == "table" ) then
                return ""; -- nil
        end
        return "";
end

function UnserializeObj(str)
        if (str == "") then
                return nil;
        else
                typeString = string.sub(str, 0, 1);
                valueString = string.sub(str, 2);
                if (typeString == "s") then
                        return string.gsub(string.gsub(string.gsub(valueString, "&gt;", ">"), "&(%w);", "|%1"), "&p;", "|");
                elseif (typeString == "n") then
                        return tonumber(valueString);
                elseif (typeString == "1") then
                        return true;
                elseif (typeString == "0") then
                        return false;
                else
                        DEBUG_MSG("GuildAds_Unserialize: Type non reconnu:"..str);
                        return nil;
                end
        end
end

local SerializeMeta = {
                [1]  = { ["key"] ="command",    ["fout"]=SerializeId,           ["fin"]=UnserializeId }
        };
        
local SerializeCommand = {
                [GUILDADS_MSG_ADD] = {
                                [1] = { ["key"]="owner",                        ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [2] = { ["key"]="adtype",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [3] = { ["key"]="id",                           ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                                [4] = { ["key"]="currenttime",          ["fout"]=SerializeTime,         ["fin"]=UnserializeTime},
                                [5] = { ["key"]="creationtime",         ["fout"]=SerializeTime,         ["fin"]=UnserializeTime},
                        },
                [GUILDADS_MSG_REMOVE] = {
                                [1] = { ["key"] ="owner",                       ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [2] = { ["key"] ="adtype",                      ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [3] = { ["key"] ="id",                          ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                        },
                [GUILDADS_MSG_REMOVE_ALL] = {
                                [1]  = { ["key"] ="owner",                      ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                        },
                [GUILDADS_MSG_REQUEST_ADS] = {
                                [1]  = { ["key"] ="owner",                      ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                        },
                [GUILDADS_MSG_REQUEST_OFFLINES] = {},
                [GUILDADS_MSG_REQUEST_INSPECT] = {},
                [GUILDADS_MSG_SENDING_UPDATE] = {
                                [1] = { ["key"] ="owner",                       ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [2] = { ["key"] ="count",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                        },
                [GUILDADS_MSG_SENDING_ALL] = {
                                [1] = { ["key"] ="owner",                       ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                        },
                [GUILDADS_MSG_SENDING_ALL_END] = { -- currenttime, profiletime
                                [1] = { ["key"] ="owner",                       ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [2] = { ["key"] ="currenttime",         ["fout"]=SerializeTime,         ["fin"]=UnserializeTime},
                                [3] = { ["key"] ="creationtime",        ["fout"]=SerializeTime,         ["fin"]=UnserializeTime },
                        },
                [GUILDADS_MSG_LASTSEEN] = {  -- currenttime, profiletime
                                [1] = { ["key"] ="owner",                       ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [2] = { ["key"] ="currenttime",         ["fout"]=SerializeTime,         ["fin"]=UnserializeTime},
                                [3] = { ["key"] ="creationtime",        ["fout"]=SerializeTime,         ["fin"]=UnserializeTime },
                        },
                [GUILDADS_MSG_LASTSEEN_END] = {},
                [GUILDADS_MSG_META] = { -- currenttime, version, starttime, id
                                [1] = { ["key"] ="currenttime",         ["fout"]=SerializeTime,         ["fin"]=UnserializeTime},
                                [2] = { ["key"] ="text",                        ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [3] = { ["key"] ="creationtime",        ["fout"]=SerializeTime,         ["fin"]=UnserializeTime },
                                [4] = { ["key"] ="id",                          ["fout"]=SerializeId,           ["fin"]=UnserializeId },
                        },
                [GUILDADS_MSG_CHATFLAG] = { -- flag, text
                                [1] = { ["key"] ="flag",                    ["fout"]=SerializeString,   ["fin"]=UnserializeString},
                                [2] = { ["key"] ="text",                        ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                        },
        };


local SerializeAd = {
                [GUILDADS_MSG_TYPE_ANNONCE] = { -- accountId, class, race, level, guild
                                [1]  = { ["key"] ="accountId",          ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                                [2]  = { ["key"] ="class",                      ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [3]  = { ["key"] ="race",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [4]  = { ["key"] ="level",                      ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [5]  = { ["key"] ="guild",                      ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                        },
                [GUILDADS_MSG_TYPE_INVENTORY] = { -- itemRef, itemName, itemColor, count, texture
                                [1] = { ["key"] ="itemColor",           ["fout"]=SerializeColor,        ["fin"]=UnserializeColor },
                                [2] = { ["key"] ="itemRef",             ["fout"]=SerializeItemRef,      ["fin"]=UnserializeItemRef },
                                [3] = { ["key"] ="itemName",            ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [4] = { ["key"] ="count",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [5] = { ["key"] ="texture",             ["fout"]=SerializeTexture,      ["fin"]=UnserializeTexture },                           
                        },
                [GUILDADS_MSG_TYPE_SKILL] = { -- skillRank , skillMaxRank
                                [1] = { ["key"] ="skillRank",           ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [2] = { ["key"] ="skillMaxRank",        ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },                           
                        },
                [GUILDADS_MSG_TYPE_REQUEST] = { -- text, itemRef, itemName, itemColor, count, texture
                                [1] = { ["key"] ="text",                        ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                                [2] = { ["key"] ="itemColor",           ["fout"]=SerializeColor,        ["fin"]=UnserializeColor },
                                [3] = { ["key"] ="itemRef",             ["fout"]=SerializeItemRef,      ["fin"]=UnserializeItemRef },
                                [4] = { ["key"] ="itemName",            ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [5] = { ["key"] ="count",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [6] = { ["key"] ="texture",             ["fout"]=SerializeTexture,      ["fin"]=UnserializeTexture },
                        },
                [GUILDADS_MSG_TYPE_AVAILABLE] ={ -- text, itemRef, itemName, itemColor, count, texture
                                [1] = { ["key"] ="text",                        ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                                [2] = { ["key"] ="itemColor",           ["fout"]=SerializeColor,        ["fin"]=UnserializeColor },
                                [3] = { ["key"] ="itemRef",             ["fout"]=SerializeItemRef,      ["fin"]=UnserializeItemRef },
                                [4] = { ["key"] ="itemName",            ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [5] = { ["key"] ="count",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [6] = { ["key"] ="texture",             ["fout"]=SerializeTexture,      ["fin"]=UnserializeTexture },
                        },
                [GUILDADS_MSG_TYPE_EVENT] = { -- text
                                [1] = { ["key"] ="text",                        ["fout"]=SerializeObj,          ["fin"]=UnserializeObj },
                                [2] = { ["key"] ="eventtime",           ["fout"]=SerializeTime,         ["fin"]=UnserializeTime },
                                [3] = { ["key"] ="note",                        ["fout"]=SerializeString,       ["fin"]=UnserializeString },
                                [4] = { ["key"] ="count",                       ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [5] = { ["key"] ="minlevel",            ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                                [6] = { ["key"] ="maxlevel",            ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                        },
                [GUILDADS_MSG_TYPE_EVENT_SUBSCRIPTION] = {
                                [1] = { ["key"] ="eventid",             ["fout"]=SerializeInteger,      ["fin"]=UnserializeInteger },
                }
        };

                                                
function SerializeTable(spec, obj)
        local tmp = "";
        local index = table.getn(spec);
        while (index > 0) do
                local info = spec[index];
                local result = info.fout(obj[info.key]);
                
                if (tmp ~= "") or (result ~= "") then
                        tmp = result..">"..tmp;
                end;
                
                index = index -1;
        end
        return tmp;
end

function GuildAds_SerializeCommand(obj)
        local result = SerializeTable(SerializeMeta, obj)
        if SerializeCommand[obj.command] then
                result = result .. SerializeTable(SerializeCommand[obj.command], obj);
                if obj.command == GUILDADS_MSG_ADD then
                        result = result .. SerializeTable(SerializeAd[obj.adtype], obj);
                end
        end
        return result;
end

function GuildAds_UnserializeCommand(text)
        local obj= { };
        
        local spec=SerializeMeta;
        local index=1;
        local size= table.getn(spec);
        local step=1;
        
        for str in string.gfind(text, "([^\>]*)>") do
                info = spec[index];
                obj[info.key] = info.fin(str);
                
                index = index + 1;
                if index>size then
                        
                        step=step+1;
                        
                        if step==2 then
                                if obj.command and SerializeCommand[obj.command] then
                                        spec=SerializeCommand[obj.command];
                                else
                                        spec=nil;
                                end
                        elseif step==3 then
                                if obj.adtype and SerializeAd[obj.adtype] then
                                        spec=SerializeAd[obj.adtype];
                                else
                                        spec=nil;
                                end
                        else
                                return obj;
                        end
                        
                        if spec then
                                index=1;
                                size=table.getn(spec);
                        else
                                return obj
                        end
                end
        end
        
        return obj;
end

function GuildAds_Serialize(obj)
        obj["currenttime"] = GAS_currentTime();
        return GUILDADS_MSG_PREFIX..GuildAds_SerializeCommand(obj);
end

function GuildAds_Unserialize(str)
        local iStart, iEnd, msg, params;
        iStart, iEnd, params = string.find(str, GUILDADS_MSG_PREFIX.."(.*)");
        if (iStart) then
                return GuildAds_UnserializeCommand(params);
        else
                iStart, iEnd, params = string.find(str, GUILDADS_MSG_PREFIX_CHATCOMM.."(.*)");
                if (iStart) then
                        return GuildAds_UnserializeCommand(params);
                else
                        return nil
                end
        end
end

function GuildAds_FilterText(text)
        return string.sub(text, 1, string.len(GUILDADS_MSG_PREFIX_NOVERSION)) == GUILDADS_MSG_PREFIX_NOVERSION 
                or string.sub(text, 1, string.len(GUILDADS_MSG_PREFIX_TOKEN)) == GUILDADS_MSG_PREFIX_TOKEN;
end


--------------------------------------------------------------------------------
--
-- Register/Unregister new command
-- 
---------------------------------------------------------------------------------
function GAC_RegisterCommand(command, serializeInfo, onMessage)
        if SerializeCommand[command] then
                return false, "command("..command..") already registered";
        else
                if  type(onMessage) == "function" then
                        if type(serializeInfo) == "table" then
                                for _, spec in serializeInfo do
                                        if type(spec.key)~="string" or type(spec.fin)~="function" or type(spec.fout)~="function" then
                                                if type(spec.key)=="string" then
                                                        return false, "serializeInfo["..spec.key.."]="..type(spec.fin)..","..type(spec.fout);
                                                else
                                                        return false, "serializeInfo[??]="..type(spec.fin)..","..type(spec.fout);
                                                end
                                        end
                                end
                                SerializeCommand[command] = serializeInfo;
                                OnMessageCommand[command] = onMessage;
                                return true;
                        else
                                return false, "type(serializeInfo)="..type(serializeInfo);
                        end
                else
                        return false, "type(onMessage)="..type(onMessage);
                end
        end
end

function GAC_UnregisterCommand(command)
        SerializeCommand[command] = nil;
        OnMessageCommand[command] = nil;
end

function GAC_IsRegisteredCommand(command)
        if SerializeCommand[command] then
                return true, SerializeCommand[command], OnMessageCommand[command];
        else
                return false;
        end
end

--------------------------------------------------------------------------------
--
-- Register/Unregister new ad type
-- 
---------------------------------------------------------------------------------
function GAC_RegisterAdtype(adtype, serializeInfo, onMessage)
        if SerializeAd[adtype] then
                return false, "adtype("..command..") already registered";
        else
                if type(onMessage) == "function" then
                        if type(serializeInfo) == "table" then
                                for _, spec in serializeInfo do
                                        if type(spec.key)~="string" or type(spec.fin)~="function" or type(spec.fout)~="function" then
                                                return false, "serializeInfo["..spec.key.."]="..type(spec.fin)..","..type(spec.fout);
                                        end
                                end
                                SerializeAd[adtype] = serializeInfo;
                                OnMessageAd[adtype] = onMessage;
                                return true;
                        else
                                return false, "type(serializeInfo)="..type(serializeInfo);
                        end
                else
                        return false, "type(onMessage)="..type(onMessage);
                end
        end
end

function GAC_UnregisterAdtype(adtype)
        SerializeAd[adtype] = nil;
        OnMessageAd[adtype] = nil;
end

function GAC_IsRegisteredAdtype(adtype)
        if SerializeCommand[adtype] then
                return true, SerializeAd[adtype], OnMessageAd[adtype];
        else
                return false;
        end
end

-- export
GAC_SerializeObj = SerializeObj;
GAC_UnserializeObj = UnserializeObj;

GAC_SerializeString = SerializeString;
GAC_UnserializeString = UnserializeString;

GAC_SerializeInteger = SerializeInteger;
GAC_UnserializeInteger = UnserializeInteger;

GAC_SerializeColor = SerializeColor;
GAC_UnserializeColor = UnserializeColor;

Generated by GNU Enscript 1.6.5.90.