Merged upstream/master
This commit is contained in:
@@ -100,7 +100,9 @@ extern AIEngine gMainThreadEngine;
|
||||
extern AIEngine gStateMachineThreadEngine;
|
||||
|
||||
#ifndef STATE_MACHINE_PROFILING
|
||||
#define STATE_MACHINE_PROFILING (LL_RELEASE_FOR_DOWNLOAD)
|
||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||
#define STATE_MACHINE_PROFILING 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class AIStateMachine : public LLThreadSafeRefCount
|
||||
@@ -133,10 +135,10 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
static TimeData sRoot;
|
||||
#endif
|
||||
};
|
||||
protected:
|
||||
#if !STATE_MACHINE_PROFILING
|
||||
StateTimerBase(const std::string& name) : mData(name) {}
|
||||
~StateTimerBase() {}
|
||||
protected:
|
||||
TimeData mData;
|
||||
// Return a copy of the underlying timer data.
|
||||
// This allows the data live beyond the scope of the state timer.
|
||||
@@ -147,6 +149,7 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
return mData;
|
||||
}
|
||||
#else
|
||||
protected:
|
||||
// Ctors/dtors are hidden. Only StateTimerRoot and StateTimer are permitted to access them.
|
||||
StateTimerBase() : mData(NULL) {}
|
||||
~StateTimerBase()
|
||||
|
||||
@@ -221,6 +221,7 @@ class UnixSetup(PlatformSetup):
|
||||
exe_suffixes = ('',)
|
||||
|
||||
def __init__(self):
|
||||
PlatformSetup.__init__(self)
|
||||
super(UnixSetup, self).__init__()
|
||||
self.generator = 'Unix Makefiles'
|
||||
|
||||
@@ -263,6 +264,7 @@ class UnixSetup(PlatformSetup):
|
||||
|
||||
class LinuxSetup(UnixSetup):
|
||||
def __init__(self):
|
||||
UnixSetup.__init__(self)
|
||||
super(LinuxSetup, self).__init__()
|
||||
try:
|
||||
self.debian_sarge = open('/etc/debian_version').read().strip() == '3.1'
|
||||
@@ -384,6 +386,7 @@ class LinuxSetup(UnixSetup):
|
||||
|
||||
class DarwinSetup(UnixSetup):
|
||||
def __init__(self):
|
||||
UnixSetup.__init__(self)
|
||||
super(DarwinSetup, self).__init__()
|
||||
self.generator = 'Xcode'
|
||||
|
||||
@@ -457,6 +460,7 @@ class WindowsSetup(PlatformSetup):
|
||||
exe_suffixes = ('.exe', '.bat', '.com')
|
||||
|
||||
def __init__(self):
|
||||
PlatformSetup.__init__(self)
|
||||
super(WindowsSetup, self).__init__()
|
||||
self._generator = None
|
||||
self.incredibuild = False
|
||||
@@ -497,7 +501,10 @@ class WindowsSetup(PlatformSetup):
|
||||
return 'win32'
|
||||
|
||||
def build_dirs(self):
|
||||
return ['build-' + self.generator]
|
||||
if self.word_size == 64:
|
||||
return ['build-' + self.generator + '-Win64']
|
||||
else:
|
||||
return ['build-' + self.generator]
|
||||
|
||||
def cmake_commandline(self, src_dir, build_dir, opts, simple):
|
||||
args = dict(
|
||||
|
||||
@@ -983,19 +983,19 @@ BOOL LLAvatarAppearance::loadSkeletonNode ()
|
||||
mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
|
||||
mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
|
||||
|
||||
LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
|
||||
LLJoint *skull = mRoot->findJoint("mSkull");
|
||||
if (skull)
|
||||
{
|
||||
skull->addChild(mMeshLOD[MESH_ID_HAIR] );
|
||||
}
|
||||
|
||||
LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft");
|
||||
LLJoint *eyeL = mRoot->findJoint("mEyeLeft");
|
||||
if (eyeL)
|
||||
{
|
||||
eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
|
||||
}
|
||||
|
||||
LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight");
|
||||
LLJoint *eyeR = mRoot->findJoint("mEyeRight");
|
||||
if (eyeR)
|
||||
{
|
||||
eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
|
||||
|
||||
@@ -125,7 +125,8 @@ void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive )
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->setSkeletonComponents(comp, recursive);
|
||||
if (joint)
|
||||
joint->setSkeletonComponents(comp, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +153,8 @@ void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pix
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
|
||||
if (joint)
|
||||
joint->updateFaceSizes(num_vertices, num_indices, pixel_area);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +164,8 @@ void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind,
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
|
||||
if (joint)
|
||||
joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +175,8 @@ void LLAvatarJoint::updateJointGeometry()
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->updateJointGeometry();
|
||||
if (joint)
|
||||
joint->updateJointGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +190,9 @@ BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate)
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
if (!joint)
|
||||
continue;
|
||||
|
||||
F32 jointLOD = joint->getLOD();
|
||||
|
||||
if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
|
||||
@@ -215,7 +222,8 @@ void LLAvatarJoint::dump()
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
joint->dump();
|
||||
if (joint)
|
||||
joint->dump();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,30 +83,28 @@ LLSkinJoint::~LLSkinJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLSkinJoint::setupSkinJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
|
||||
void LLSkinJoint::setupSkinJoint( LLJoint *joint)
|
||||
{
|
||||
mRootToJointSkinOffset.clearVec();
|
||||
mRootToParentJointSkinOffset.clearVec();
|
||||
|
||||
// find the named joint
|
||||
mJoint = joint;
|
||||
if ( !mJoint )
|
||||
if (!(mJoint = joint))
|
||||
{
|
||||
llinfos << "Can't find joint" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the inverse root skin matrix
|
||||
mRootToJointSkinOffset.clearVec();
|
||||
|
||||
LLVector3 rootSkinOffset;
|
||||
while (joint)
|
||||
do
|
||||
{
|
||||
rootSkinOffset += joint->getSkinOffset();
|
||||
joint = (LLAvatarJoint*)joint->getParent();
|
||||
}
|
||||
mRootToJointSkinOffset -= joint->getSkinOffset();
|
||||
} while (joint = joint->getParent());
|
||||
|
||||
mRootToJointSkinOffset = -rootSkinOffset;
|
||||
mRootToParentJointSkinOffset = mRootToJointSkinOffset;
|
||||
mRootToParentJointSkinOffset += mJoint->getSkinOffset();
|
||||
|
||||
return TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -307,15 +305,14 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
|
||||
for (jn = 0; jn < numJointNames; jn++)
|
||||
{
|
||||
//llinfos << "Setting up joint " << jointNames[jn] << llendl;
|
||||
LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
|
||||
mSkinJoints[jn].setupSkinJoint( joint );
|
||||
mSkinJoints[jn].setupSkinJoint( getRoot()->findJoint(jointNames[jn]) );
|
||||
}
|
||||
}
|
||||
|
||||
// setup joint array
|
||||
if (!mMesh->isLOD())
|
||||
{
|
||||
setupJoint((LLAvatarJoint*)getRoot());
|
||||
setupJoint(getRoot());
|
||||
}
|
||||
|
||||
// llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl;
|
||||
@@ -324,7 +321,7 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
|
||||
//-----------------------------------------------------------------------------
|
||||
// setupJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
|
||||
void LLAvatarJointMesh::setupJoint(LLJoint* current_joint)
|
||||
{
|
||||
// llinfos << "Mesh: " << getName() << llendl;
|
||||
|
||||
@@ -345,7 +342,7 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
|
||||
if(mMesh->mJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix())
|
||||
{
|
||||
// ...then just add ourselves
|
||||
LLAvatarJoint* jointp = js.mJoint;
|
||||
LLJoint* jointp = js.mJoint;
|
||||
mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
|
||||
// llinfos << "joint " << joint_count << js.mJoint->getName() << llendl;
|
||||
// joint_count++;
|
||||
|
||||
@@ -49,9 +49,9 @@ class LLSkinJoint
|
||||
public:
|
||||
LLSkinJoint();
|
||||
~LLSkinJoint();
|
||||
BOOL setupSkinJoint( LLAvatarJoint *joint);
|
||||
void setupSkinJoint( LLJoint *joint);
|
||||
|
||||
LLAvatarJoint *mJoint;
|
||||
LLJoint* mJoint;
|
||||
LLVector3 mRootToJointSkinOffset;
|
||||
LLVector3 mRootToParentJointSkinOffset;
|
||||
};
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
void setMesh( LLPolyMesh *mesh );
|
||||
|
||||
// Sets up joint matrix data for rendering
|
||||
void setupJoint(LLAvatarJoint* current_joint);
|
||||
void setupJoint(LLJoint* current_joint);
|
||||
|
||||
// Sets ID for picking
|
||||
void setMeshID( S32 id ) {mMeshID = id;}
|
||||
|
||||
@@ -78,7 +78,7 @@ const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f;
|
||||
const F32 RAD_TO_DEG = 57.295779513082320876798154814105f;
|
||||
const F32 F_APPROXIMATELY_ZERO = 0.00001f;
|
||||
const F32 F_LN10 = 2.3025850929940456840179914546844f;
|
||||
const F32 OO_LN10 = 0.4342944819032518276511289189166f;
|
||||
const F32 OO_LN10 = 0.43429448190325182765112891891661f;
|
||||
const F32 F_LN2 = 0.69314718056f;
|
||||
const F32 OO_LN2 = 1.4426950408889634073599246810019f;
|
||||
|
||||
|
||||
@@ -610,7 +610,7 @@ void AIPerService::purge(void)
|
||||
per_service_w->mCapabilityType[i].mQueuedRequests.clear();
|
||||
if (is_approved((AICapabilityType)i))
|
||||
{
|
||||
llassert(total_queued_w->approved >= s);
|
||||
llassert(total_queued_w->approved >= (S32)s);
|
||||
total_queued_w->approved -= s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,12 +447,12 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
|
||||
createRect(child, item_rect, radio_group, rect);
|
||||
|
||||
std::string item_label = child->getTextContents();
|
||||
node->getAttributeString("label", item_label);
|
||||
child->getAttributeString("label", item_label);
|
||||
std::string item_name("radio");
|
||||
node->getAttributeString("name", item_name);
|
||||
child->getAttributeString("name", item_name);
|
||||
std::string payload(item_name); // Support old-style name as payload
|
||||
node->getAttributeString("value", payload);
|
||||
node->getAttributeString("initial_value", payload); // Synonym
|
||||
child->getAttributeString("value", payload);
|
||||
child->getAttributeString("initial_value", payload); // Synonym
|
||||
LLRadioCtrl* radio = radio_group->addRadioButton(item_name, item_label, item_rect, font, payload);
|
||||
|
||||
radio->initFromXML(child, radio_group);
|
||||
|
||||
@@ -281,7 +281,7 @@ void LLDrawPoolAlpha::render(S32 pass)
|
||||
gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
|
||||
}
|
||||
|
||||
gGL.diffuseColor4f(0.9,0,0,0.4);
|
||||
gGL.diffuseColor4f(0.9f,0.f,0.f,0.4f);
|
||||
|
||||
LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
|
||||
gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ;
|
||||
|
||||
@@ -154,10 +154,10 @@ void LLFloaterRegionRestarting::draw()
|
||||
if (!alchemyRegionShake || isMinimized()) // If we're minimized, leave the user alone
|
||||
return;
|
||||
|
||||
const F32 SHAKE_INTERVAL = 0.025;
|
||||
const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this
|
||||
const F32 SHAKE_INITIAL_MAGNITUDE = 1.5;
|
||||
const F32 SHAKE_HORIZONTAL_BIAS = 0.25;
|
||||
const F32 SHAKE_INTERVAL = 0.025f;
|
||||
const F32 SHAKE_TOTAL_DURATION = 1.8f; // the length of the default alert tone for this
|
||||
const F32 SHAKE_INITIAL_MAGNITUDE = 1.5f;
|
||||
const F32 SHAKE_HORIZONTAL_BIAS = 0.25f;
|
||||
F32 time_shaking;
|
||||
|
||||
if (SHAKE_START == sShakeState)
|
||||
|
||||
@@ -2049,20 +2049,23 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
|
||||
|
||||
S32 data_size = buffer->countAfter(channels.in(), NULL);
|
||||
|
||||
static U8 data[16384];
|
||||
llassert_always(data_size <= sizeof(data));
|
||||
memset(data + data_size, 0, sizeof(data)-data_size);
|
||||
static const U32 BUFF_MAX_STATIC_SIZE = 16384; //If we exceed this size just bump the vector back to BUFF_MAX_STATIC_SIZE after we're done.
|
||||
static std::vector<U8> data(BUFF_MAX_STATIC_SIZE);
|
||||
if (data_size > (S32)data.size())
|
||||
data.resize(data_size);
|
||||
else
|
||||
memset(&data[0] + data_size, 0, data.size() - data_size);
|
||||
|
||||
if (data_size > 0)
|
||||
{
|
||||
AIStateMachine::StateTimer timer("readAfter");
|
||||
buffer->readAfter(channels.in(), NULL, data, data_size);
|
||||
buffer->readAfter(channels.in(), NULL, &data[0], data_size);
|
||||
}
|
||||
|
||||
LLMeshRepository::sBytesReceived += llmin(data_size, 4096);
|
||||
|
||||
AIStateMachine::StateTimer timer("headerReceived");
|
||||
bool success = gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size);
|
||||
bool success = gMeshRepo.mThread->headerReceived(mMeshParams, &data[0], data_size);
|
||||
|
||||
llassert(success);
|
||||
|
||||
@@ -2114,17 +2117,20 @@ void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels,
|
||||
S32 bytes_remaining = bytes;
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
const S32 bytes_written = llmin(bytes_remaining, (S32)sizeof(data));
|
||||
file.write(data, bytes_written);
|
||||
if (bytes_remaining == bytes && bytes_written < bytes_remaining)
|
||||
const S32 bytes_to_write = llmin(bytes_remaining, data_size);
|
||||
file.write(&data[0], bytes_to_write);
|
||||
if (bytes_remaining == bytes && bytes_to_write < bytes_remaining)
|
||||
{
|
||||
memset(data, 0, data_size);
|
||||
memset(&data[0], 0, data.size());
|
||||
}
|
||||
bytes_remaining -= llmin(bytes_remaining, bytes_written);
|
||||
bytes_remaining -= llmin(bytes_remaining, bytes_to_write);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.size() > BUFF_MAX_STATIC_SIZE)
|
||||
data.resize(BUFF_MAX_STATIC_SIZE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -146,6 +146,8 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy )
|
||||
iter != mChildren.end(); ++iter)
|
||||
{
|
||||
LLAvatarJoint* joint = dynamic_cast<LLAvatarJoint*>(*iter);
|
||||
if (!joint)
|
||||
continue;
|
||||
F32 jointLOD = joint->getLOD();
|
||||
if (pixelArea >= jointLOD || sDisableLOD)
|
||||
{
|
||||
|
||||
@@ -579,7 +579,7 @@ void LLViewerJoystick::cursorSlide(F32 inc)
|
||||
void LLViewerJoystick::cursorPush(F32 inc)
|
||||
{
|
||||
static F32 prev_inc = 0.f; // Smooth a little.
|
||||
if (!is_approx_zero(0.001))
|
||||
if (!is_approx_zero(inc))
|
||||
{
|
||||
S32 x, y;
|
||||
LLUI::getMousePositionScreen(&x, &y);
|
||||
|
||||
@@ -757,8 +757,8 @@ void LLViewerTexture::removeFace(U32 ch, LLFace* facep)
|
||||
if(mNumFaces[ch] > 1)
|
||||
{
|
||||
S32 index = facep->getIndexInTex(ch) ;
|
||||
llassert(index < mFaceList[ch].size());
|
||||
llassert(index < mNumFaces[ch]);
|
||||
llassert(index < (S32)mFaceList[ch].size());
|
||||
llassert(index < (S32)mNumFaces[ch]);
|
||||
mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]] ;
|
||||
mFaceList[ch][index]->setIndexInTex(ch, index) ;
|
||||
}
|
||||
@@ -808,8 +808,8 @@ void LLViewerTexture::removeVolume(LLVOVolume* volumep)
|
||||
if(mNumVolumes > 1)
|
||||
{
|
||||
S32 index = volumep->getIndexInTex() ;
|
||||
llassert(index < mVolumeList.size());
|
||||
llassert(index < mNumVolumes);
|
||||
llassert(index < (S32)mVolumeList.size());
|
||||
llassert(index < (S32)mNumVolumes);
|
||||
mVolumeList[index] = mVolumeList[--mNumVolumes] ;
|
||||
mVolumeList[index]->setIndexInTex(index) ;
|
||||
}
|
||||
|
||||
@@ -7324,9 +7324,9 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
|
||||
|
||||
if (!LLViewerCamera::getInstance()->cameraUnderWater())
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2);
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2f);
|
||||
} else {
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0);
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0f);
|
||||
}
|
||||
|
||||
shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
|
||||
@@ -7362,9 +7362,9 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
|
||||
|
||||
if (!LLViewerCamera::getInstance()->cameraUnderWater())
|
||||
{
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2);
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2f);
|
||||
} else {
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0);
|
||||
shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0f);
|
||||
}
|
||||
|
||||
drawFullScreenRect(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="floater_about" title="Über Singularity">
|
||||
<floater name="floater_about" title="Über [SHORT_APP_NAME]">
|
||||
<tab_container name="about_tab">
|
||||
<panel label="Info" name="support_panel">
|
||||
<button label="In Zwischenablage kopieren" name="copy_btn"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="floater_about" title="A propos de Singularity">
|
||||
<floater name="floater_about" title="A propos de [SHORT_APP_NAME]">
|
||||
<tab_container name="about_tab">
|
||||
<panel label="Info" help_topic="about_support_tab" name="support_panel">
|
||||
<button label="Copier dans le presse-papier" name="copy_btn"/>
|
||||
|
||||
Reference in New Issue
Block a user