From b416dcb73b1f405ebf5260cc588b07fde7ad1604 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Tue, 18 May 2010 10:20:44 -0400 Subject: adding verbose logging around your own avatar rez time. Documents load times for each component texture at each discard level, as well as baked texture upload times, and reports the timing of each texture to the console when your avatar sends out its appearance data to the server. Reviewed by Seraph, will be removed before release. -Nyx --- indra/newview/llvoavatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llvoavatar.cpp') diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 2ec8ced543..c64f7b5a3e 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5869,14 +5869,14 @@ void LLVOAvatar::updateRuthTimer(bool loading) const F32 LOADING_TIMEOUT = 120.f; if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT) { - /* + llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." << llendl; - */ + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); } -- cgit v1.3 From 955473266e511d5bb155be1645a7ec464b1ce0a7 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 18 May 2010 15:15:08 -0400 Subject: AVP-72 FIXED Debug settings for gathering Welcome Island Rez time statistics Fixed memory leak. Prettied up formatting for debug readouts. Added more notifications for rez and cloud time. --- indra/newview/lltexturectrl.cpp | 29 +++++++------ indra/newview/llvoavatar.cpp | 49 +++++++++++++++++++++- indra/newview/llvoavatarself.cpp | 37 ++++++++++++---- .../newview/skins/default/xui/en/notifications.xml | 28 +++++++++++++ 4 files changed, 121 insertions(+), 22 deletions(-) (limited to 'indra/newview/llvoavatar.cpp') diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 07db3e0cef..9aebc264a2 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1267,22 +1267,25 @@ void LLTextureCtrl::draw() // fully loaded. if (mTexturep.notNull() && (!mTexturep->isFullyLoaded()) && - (mShowLoadingPlaceholder == TRUE) && - (mTexturep->getDiscardLevel() != 1) && - (mTexturep->getDiscardLevel() != 0)) + (mShowLoadingPlaceholder == TRUE)) { U32 v_offset = 25; LLFontGL* font = LLFontGL::getFontSansSerif(); - font->renderUTF8( - mLoadingPlaceholderString, - 0, - llfloor(interior.mLeft+3), - llfloor(interior.mTop-v_offset), - LLColor4::white, - LLFontGL::LEFT, - LLFontGL::BASELINE, - LLFontGL::DROP_SHADOW); - + + // Don't show as loaded if the texture is almost fully loaded (i.e. discard1) unless god + if ((mTexturep->getDiscardLevel() > 1) || gAgent.isGodlike()) + { + font->renderUTF8( + mLoadingPlaceholderString, + 0, + llfloor(interior.mLeft+3), + llfloor(interior.mTop-v_offset), + LLColor4::white, + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::DROP_SHADOW); + } + // Show more detailed information if this agent is god. if (gAgent.isGodlike()) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c64f7b5a3e..f95017b658 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -667,6 +667,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mTexEyeColor( NULL ), mNeedsSkin(FALSE), mUpdatePeriod(1), + mFullyLoaded(FALSE), + mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), mSupportsAlphaLayers(FALSE) { @@ -746,8 +748,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mOohMorph = NULL; mAahMorph = NULL; - mCurrentGesticulationLevel = 0; + mCurrentGesticulationLevel = 0; + mRuthTimer.reset(); + mRuthDebugTimer.reset(); } //------------------------------------------------------------------------ @@ -755,6 +759,25 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, //------------------------------------------------------------------------ LLVOAvatar::~LLVOAvatar() { + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (!mFullyLoaded) + { + llinfos << "AVATARREZTIME: Avatar '" << getFullname() << " left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; + LLSD args; + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); + } + else + { + llinfos << "AVATARREZTIME: Avatar '" << getFullname() << " left." << llendl; + LLSD args; + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftNotification",args); + } + + } lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; mRoot.removeAllChildren(); @@ -1269,6 +1292,7 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + } const LLVector3 LLVOAvatar::getRenderPosition() const @@ -2076,9 +2100,22 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, LLMemType mt(LLMemType::MTYPE_AVATAR); LLVector3 old_vel = getVelocity(); + const BOOL has_name = !getNVPair("FirstName"); + // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); + // Print out arrival information once we have name of avatar. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (has_name && getNVPair("FirstName")) + { + LLSD args; + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezArrivedNotification",args); + llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' arrived." << llendl; + } + } if(retval & LLViewerObject::INVALID_UPDATE) { if (isSelf()) @@ -5863,6 +5900,14 @@ void LLVOAvatar::updateRuthTimer(bool loading) if (mPreviousFullyLoaded) { mRuthTimer.reset(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' became cloud." << llendl; + LLSD args; + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezCloudNotification",args); + } mRuthDebugTimer.reset(); } @@ -5896,7 +5941,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) { if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { - llinfos << "Avatar '" << getFullname() << "' resolved in " << mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; + llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; LLSD args; args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 739c021311..e8f42178a1 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1772,6 +1772,7 @@ void LLVOAvatarSelf::timingLocalTexLoaded(BOOL success, LLViewerFetchedTexture * { mTextureLoadTimes[(U32)index][(U32)discard_level] = mSelfLoadTimer.getElapsedTimeF32(); } + delete data; } void LLVOAvatarSelf::bakedTextureUpload(EBakedTextureIndex index, BOOL finished) @@ -1956,18 +1957,40 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) { gAgent.sendAgentSetAppearance(); F32 final_time = mSelfLoadTimer.getElapsedTimeF32(); - llinfos << "time from avatar creation to load wearables: " << mTimeWearablesLoaded << llendl; - llinfos << "time from avatar creation to de-cloud: " << mTimeAvatarVisible << llendl; - llinfos << "time from avatar creation to de-cloud for others: " << final_time << llendl; - llinfos << "load time for each texture: " << llendl; + llinfos << "AVATARREZTIME: Myself rez stats:" << llendl; + llinfos << "\t Time from avatar creation to load wearables: " << (S32)mTimeWearablesLoaded << llendl; + llinfos << "\t Time from avatar creation to de-cloud: " << (S32)mTimeAvatarVisible << llendl; + llinfos << "\t Time from avatar creation to de-cloud for others: " << (S32)final_time << llendl; + llinfos << "\t Load time for each texture: " << llendl; for (U32 i = 0; i < LLVOAvatarDefines::TEX_NUM_INDICES; ++i) { - llinfos << "(" << i << "): " << (S32)mTextureLoadTimes[i][0] << "\t" << (S32)mTextureLoadTimes[i][1] << "\t" << (S32)mTextureLoadTimes[i][2] << "\t" << (S32)mTextureLoadTimes[i][3] << "\t" << (S32)mTextureLoadTimes[i][4] << "\t" << (S32)mTextureLoadTimes[i][5] << llendl; + std::stringstream out; + out << "\t\t (" << i << ") "; + U32 j=0; + for (j=0; j <= MAX_DISCARD_LEVEL; j++) + { + out << "\t"; + S32 load_time = (S32)mTextureLoadTimes[i][j]; + if (load_time == -1) + { + out << "*"; + if (j == 0) + break; + } + else + { + out << load_time; + } + } + + // Don't print out non-existent textures. + if (j != 0) + llinfos << out.str() << llendl; } - llinfos << "Time points for each upload (start / finish)" << llendl; + llinfos << "\t Time points for each upload (start / finish)" << llendl; for (U32 i = 0; i < LLVOAvatarDefines::BAKED_NUM_INDICES; ++i) { - llinfos << "(" << i << "): " << (S32)mBakedTextureTimes[i][0] << " / " << (S32)mBakedTextureTimes[i][1] << llendl; + llinfos << "\t\t (" << i << ") \t" << (S32)mBakedTextureTimes[i][0] << " / " << (S32)mBakedTextureTimes[i][1] << llendl; } } } diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a2acb8100f..6b486a91c5 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6126,6 +6126,34 @@ Drag items from inventory onto a person in the resident picker Avatar '[NAME]' rezzed in [TIME] seconds. + +Avatar '[NAME]' became cloud. + + + +Avatar '[NAME]' appeared. + + + +Avatar '[NAME]' left after [TIME] seconds as cloud. + + + +Avatar '[NAME]' left as fully loaded. + + Date: Tue, 18 May 2010 17:10:44 -0400 Subject: AVP-72 FIXED Debug settings for gathering Welcome Island Rez time statistics Added timestamp for avatar rez messages. Added messaging when entering/leaving Edit Appearance Mode. --- indra/newview/llvoavatar.cpp | 40 +++++++++++++++++++--- indra/newview/llvoavatar.h | 1 + .../newview/skins/default/xui/en/notifications.xml | 21 ++++++++++++ 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'indra/newview/llvoavatar.cpp') diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f95017b658..46d10b0fe6 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -752,6 +752,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mRuthTimer.reset(); mRuthDebugTimer.reset(); + mDebugExistenceTimer.reset(); } //------------------------------------------------------------------------ @@ -763,16 +764,18 @@ LLVOAvatar::~LLVOAvatar() { if (!mFullyLoaded) { - llinfos << "AVATARREZTIME: Avatar '" << getFullname() << " left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); } else { - llinfos << "AVATARREZTIME: Avatar '" << getFullname() << " left." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left." << llendl; LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezLeftNotification",args); } @@ -2110,10 +2113,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, { if (has_name && getNVPair("FirstName")) { + mDebugExistenceTimer.reset(); LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezArrivedNotification",args); - llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' arrived." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; } } if(retval & LLViewerObject::INVALID_UPDATE) @@ -2809,6 +2814,29 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) const BOOL is_muted = isSelf() ? FALSE : LLMuteList::getInstance()->isMuted(getID()); const BOOL is_cloud = getIsCloud(); + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + if (is_appearance != mNameAppearance) + { + if (is_appearance) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " entered appearance mode." << llendl; + } + else + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left appearance mode." << llendl; + } + } + } + if (mNameString.empty() || new_name || (!title && !mTitle.empty()) || @@ -5902,8 +5930,9 @@ void LLVOAvatar::updateRuthTimer(bool loading) mRuthTimer.reset(); if (gSavedSettings.getBOOL("DebugAvatarRezTime")) { - llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' became cloud." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezCloudNotification",args); @@ -5941,8 +5970,9 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) { if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { - llinfos << "AVATARREZTIME: Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezNotification",args); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 24bd2739f7..d74b4fe7b2 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -261,6 +261,7 @@ private: LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez + LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. /** State ** ** diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6b486a91c5..4b31a1a0ad 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6123,6 +6123,7 @@ Drag items from inventory onto a person in the resident picker icon="notifytip.tga" name="AvatarRezNotification" type="notifytip"> +( [EXISTENCE] seconds ) Avatar '[NAME]' rezzed in [TIME] seconds. @@ -6130,6 +6131,7 @@ Avatar '[NAME]' rezzed in [TIME] seconds. icon="notifytip.tga" name="AvatarRezCloudNotification" type="notifytip"> +( [EXISTENCE] seconds ) Avatar '[NAME]' became cloud. @@ -6137,6 +6139,7 @@ Avatar '[NAME]' became cloud. icon="notifytip.tga" name="AvatarRezArrivedNotification" type="notifytip"> +( [EXISTENCE] seconds ) Avatar '[NAME]' appeared. @@ -6144,13 +6147,31 @@ Avatar '[NAME]' appeared. icon="notifytip.tga" name="AvatarRezLeftCloudNotification" type="notifytip"> +( [EXISTENCE] seconds ) Avatar '[NAME]' left after [TIME] seconds as cloud. + +( [EXISTENCE] seconds ) +Avatar '[NAME]' entered appearance mode. + + + +( [EXISTENCE] seconds ) +Avatar '[NAME]' left appearance mode. + + +( [EXISTENCE] seconds ) Avatar '[NAME]' left as fully loaded. -- cgit v1.3 From 529a88458ac774932a61e2e41bded3079520a73b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 18 May 2010 17:30:31 -0400 Subject: AVP-72 FIXED Debug settings for gathering Welcome Island Rez time statistics Superficial improvements to llinfos messaging. --- indra/newview/llvoavatar.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llvoavatar.cpp') diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 46d10b0fe6..0f4623c678 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -764,7 +764,7 @@ LLVOAvatar::~LLVOAvatar() { if (!mFullyLoaded) { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; LLSD args; args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); @@ -773,7 +773,7 @@ LLVOAvatar::~LLVOAvatar() } else { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; LLSD args; args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); @@ -2824,7 +2824,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " entered appearance mode." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; } else { @@ -2832,7 +2832,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); args["NAME"] = getFullname(); LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << " left appearance mode." << llendl; + llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; } } } -- cgit v1.3