forked from 0ad/0ad
Minor JavaScript updates
This was SVN commit r2073.
This commit is contained in:
parent
7a31f202c0
commit
3c99f0f2eb
@ -153,7 +153,7 @@ JSBool JSI_Camera::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* v
|
||||
}
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *d /*, cameraInfo, ( void( IPropertyOwner::* )() )&Camera_Info::Update, ( void( IPropertyOwner::* )() )&Camera_Info::Freshen */ ) );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( d, cameraInfo, ( void( IPropertyOwner::* )() )&Camera_Info::Update, ( void( IPropertyOwner::* )() )&Camera_Info::Freshen ) );
|
||||
*vp = OBJECT_TO_JSVAL( vector3d );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
@ -236,7 +236,7 @@ JSBool JSI_Camera::getFocus( JSContext* cx, JSObject* obj, uintN argc, jsval* ar
|
||||
Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( cameraInfo->m_sv_Target /*, cameraInfo, NULL, ( void( IPropertyOwner::* )() )&Camera_Info::FreshenTarget */ ) );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( &( cameraInfo->m_sv_Target ), cameraInfo, NULL, ( void( IPropertyOwner::* )() )&Camera_Info::FreshenTarget ) );
|
||||
*rval = OBJECT_TO_JSVAL( vector3d );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace JSI_Camera
|
||||
lookat
|
||||
};
|
||||
|
||||
struct Camera_Info
|
||||
struct Camera_Info : public IPropertyOwner
|
||||
{
|
||||
CCamera* m_Data;
|
||||
bool m_EngineOwned;
|
||||
|
@ -1157,7 +1157,7 @@ sle(11340106);
|
||||
if(!g_Quickstart)
|
||||
{
|
||||
WriteSysInfo();
|
||||
vfs_display();
|
||||
// vfs_display();
|
||||
}
|
||||
else
|
||||
// speed up startup by disabling all sound
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "JSInterface_Vector3D.h"
|
||||
#include "scripting/JSConversions.h"
|
||||
#include "scripting/ScriptingHost.h"
|
||||
|
||||
JSClass JSI_Vector3D::JSI_class = {
|
||||
"Vector3D", JSCLASS_HAS_PRIVATE,
|
||||
@ -22,6 +24,17 @@ JSPropertySpec JSI_Vector3D::JSI_props[] =
|
||||
JSFunctionSpec JSI_Vector3D::JSI_methods[] =
|
||||
{
|
||||
{ "toString", JSI_Vector3D::toString, 0, 0, 0 },
|
||||
{ "add", JSI_Vector3D::add, 1, 0, 0 },
|
||||
{ "subtract", JSI_Vector3D::subtract, 1, 0, 0 },
|
||||
{ "minus", JSI_Vector3D::subtract, 1, 0, 0 },
|
||||
{ "negate", JSI_Vector3D::negate, 1, 0, 0 },
|
||||
{ "scale", JSI_Vector3D::scale, 1, 0, 0 },
|
||||
{ "multiply", JSI_Vector3D::scale, 1, 0, 0 },
|
||||
{ "divide", JSI_Vector3D::divide, 1, 0, 0 },
|
||||
{ "dot", JSI_Vector3D::dot, 1, 0, 0 },
|
||||
{ "cross", JSI_Vector3D::cross, 1, 0, 0 },
|
||||
{ "length", JSI_Vector3D::length, 0, 0, 0 },
|
||||
{ "normalize", JSI_Vector3D::normalize, 0, 0, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -188,3 +201,142 @@ JSBool JSI_Vector3D::toString( JSContext* cx, JSObject* obj, uintN argc, jsval*
|
||||
*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
CVector3D* JSI_Vector3D::GetVector( JSContext* cx, JSObject* obj )
|
||||
{
|
||||
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate( cx, obj, &JSI_class, NULL );
|
||||
if( !vectorInfo )
|
||||
{
|
||||
JS_ReportError( cx, "[Vector3D] Invalid reference" );
|
||||
return( NULL );
|
||||
}
|
||||
if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
|
||||
return( vectorInfo->vector );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *a, *b;
|
||||
if( !( a = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) || !( b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) ) ) )
|
||||
{
|
||||
JS_ReportError( cx, "[Vector3D] Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a + *b ) );
|
||||
*rval = OBJECT_TO_JSVAL( vector3d );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *a, *b;
|
||||
if( !( a = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) || !( b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) ) ) )
|
||||
{
|
||||
JS_ReportError( cx, "[Vector3D] Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a - *b ) );
|
||||
*rval = OBJECT_TO_JSVAL( vector3d );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::negate( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *v;
|
||||
if( !( v = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
|
||||
*rval = ToJSVal( -( *v ) );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *v; float f;
|
||||
if( !( v = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !ToPrimitive( cx, argv[0], f ) )
|
||||
{
|
||||
JS_ReportError( cx, "Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * f ) );
|
||||
*rval = OBJECT_TO_JSVAL( vector3d );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *v; float f;
|
||||
if( !( v = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !ToPrimitive( cx, argv[0], f ) )
|
||||
{
|
||||
JS_ReportError( cx, "Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * ( 1.0 / f ) ) );
|
||||
*rval = OBJECT_TO_JSVAL( vector3d );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *a, *b;
|
||||
if( !( a = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) || !( b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) ) ) )
|
||||
{
|
||||
JS_ReportError( cx, "[Vector3D] Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
*rval = ToJSVal( a->Dot( *b ) );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *a, *b;
|
||||
if( !( a = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) || !( b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) ) ) )
|
||||
{
|
||||
JS_ReportError( cx, "[Vector3D] Invalid parameter" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
*rval = ToJSVal( a->Cross( *b ) );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::length( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *v;
|
||||
if( !( v = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
|
||||
*rval = ToJSVal( v->GetLength() );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool JSI_Vector3D::normalize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D *v;
|
||||
if( !( v = GetVector( cx, obj ) ) ) return( JS_TRUE );
|
||||
|
||||
CVector3D r( v->X, v->Y, v->Z );
|
||||
r.Normalize();
|
||||
|
||||
*rval = ToJSVal( r );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
@ -13,8 +13,6 @@
|
||||
#ifndef JSI_VECTOR3_INCLUDED
|
||||
#define JSI_VECTOR3_INCLUDED
|
||||
|
||||
class IPropertyOwner;
|
||||
|
||||
namespace JSI_Vector3D
|
||||
{
|
||||
enum
|
||||
@ -23,7 +21,18 @@ namespace JSI_Vector3D
|
||||
component_y,
|
||||
component_z
|
||||
};
|
||||
static CVector3D* GetVector( JSContext* cx, JSObject* obj );
|
||||
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool negate( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool length( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
JSBool normalize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
|
||||
|
||||
struct Vector3D_Info
|
||||
{
|
||||
IPropertyOwner* owner;
|
||||
@ -41,6 +50,7 @@ namespace JSI_Vector3D
|
||||
extern JSClass JSI_class;
|
||||
extern JSPropertySpec JSI_props[];
|
||||
extern JSFunctionSpec JSI_methods[];
|
||||
|
||||
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
void finalize( JSContext* cx, JSObject* obj );
|
||||
|
@ -36,6 +36,8 @@ private:
|
||||
static JSBool Pop( JSContext* cx, JSObject* obj, uintN argc, jsval* agv, jsval* rval );
|
||||
static JSBool Remove( JSContext* cx, JSObject* obj, uintN argc, jsval* agv, jsval* rval );
|
||||
static JSBool GetLength( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
static JSBool IsEmpty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
static JSBool Clear( JSContext* cx, JSObject* obj, uintN argc, jsval* agv, jsval* rval );
|
||||
static JSBool AddProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
static JSBool RemoveProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
static JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
|
||||
@ -63,6 +65,7 @@ template<typename T, JSClass* ScriptType> JSClass CJSCollection<T, ScriptType>::
|
||||
template<typename T, JSClass* ScriptType> JSPropertySpec CJSCollection<T, ScriptType>::JSI_props[] =
|
||||
{
|
||||
{ "length", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetLength },
|
||||
{ "empty", 0, JSPROP_PERMANENT | JSPROP_READONLY, IsEmpty },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -73,6 +76,7 @@ template<typename T, JSClass* ScriptType> JSFunctionSpec CJSCollection<T, Script
|
||||
{ "push", Push, 1, 0, 0 },
|
||||
{ "pop", Pop, 0, 0, 0 },
|
||||
{ "remove", Remove, 1, 0, 0 },
|
||||
{ "clear", Clear, 0, 0, 0 },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
@ -257,6 +261,17 @@ template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::G
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::IsEmpty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
||||
{
|
||||
std::vector<T>* set = RetrieveSet( cx, obj );
|
||||
|
||||
if( !set )
|
||||
return( JS_FALSE ); // That's odd; we've lost the pointer.
|
||||
|
||||
*vp = BOOLEAN_TO_JSVAL( set->empty() );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::Subset( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
assert( argc > 0 );
|
||||
@ -286,6 +301,19 @@ template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::S
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::Clear( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
std::vector<T>* Set = RetrieveSet( cx, obj );
|
||||
if( !Set )
|
||||
return( JS_FALSE );
|
||||
|
||||
Set->clear();
|
||||
|
||||
*rval = JSVAL_TRUE;
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::Push( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
assert( argc > 0 );
|
||||
@ -357,5 +385,5 @@ template<typename T, JSClass* ScriptType> JSBool CJSCollection<T, ScriptType>::R
|
||||
|
||||
#define EntityCollection CJSCollection<HEntity, &CEntity::JSI_class>
|
||||
#define PlayerCollection CJSCollection<CPlayer*, &CPlayer::JSI_class>
|
||||
|
||||
#define JSObjectCollection
|
||||
#endif
|
||||
|
@ -65,6 +65,12 @@ template<> JSObject* ToScript<CVector3D>( CVector3D* Native )
|
||||
return( Script );
|
||||
}
|
||||
|
||||
template<> jsval ToJSVal<CVector3D>( const CVector3D& Native )
|
||||
{
|
||||
JSObject* Script = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
|
||||
JS_SetPrivate( g_ScriptingHost.GetContext(), Script, new JSI_Vector3D::Vector3D_Info( Native ) );
|
||||
return( OBJECT_TO_JSVAL( Script ) );
|
||||
}
|
||||
|
||||
// CScriptObject
|
||||
|
||||
|
@ -93,6 +93,7 @@ template<typename T> jsval ToJSVal( const T& Native );
|
||||
// CVector3D
|
||||
template<> CVector3D* ToNative<CVector3D>( JSContext* cx, JSObject* obj );
|
||||
template<> JSObject* ToScript<CVector3D>( CVector3D* Native );
|
||||
template<> jsval ToJSVal<CVector3D>( const CVector3D& Native );
|
||||
|
||||
// CBaseEntity
|
||||
template<> bool ToPrimitive<CBaseEntity*>( JSContext* cx, jsval v, CBaseEntity*& Storage );
|
||||
|
@ -57,6 +57,7 @@ JSFunctionSpec ScriptFunctionTable[] =
|
||||
{"getGlobal", getGlobal, 0, 0, 0 },
|
||||
{"getGUIGlobal", getGUIGlobal, 0, 0, 0 },
|
||||
{"setCursor", setCursor, 1, 0, 0 },
|
||||
{"setCameraTarget", setCameraTarget, 1, 0, 0 },
|
||||
{"startGame", startGame, 0, 0, 0 },
|
||||
{"endGame", endGame, 0, 0, 0 },
|
||||
{"createClient", createClient, 0, 0, 0 },
|
||||
@ -91,6 +92,7 @@ JSPropertySpec ScriptGlobalTable[] =
|
||||
{ "console", GLOBAL_CONSOLE, JSPROP_PERMANENT | JSPROP_READONLY, JSI_Console::getConsole, NULL },
|
||||
{ "entities", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetEntitySet, NULL },
|
||||
{ "players", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetPlayerSet, NULL },
|
||||
{ "localPlayer", 0, JSPROP_PERMANENT | JSPROP_READONLY, GetLocalPlayer, NULL },
|
||||
{ 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
@ -195,6 +197,27 @@ JSBool GetPlayerSet( JSContext* cx, JSObject* globalObject, jsval argv, jsval* v
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool GetLocalPlayer( JSContext* cx, JSObject* globalObject, jsval argv, jsval* vp )
|
||||
{
|
||||
*vp = OBJECT_TO_JSVAL( g_Game->GetLocalPlayer()->GetScript() );
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool setCameraTarget( JSContext* context, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
CVector3D* target;
|
||||
if( ( argc == 0 ) || !( target = ToNative<CVector3D>( argv[0] ) ) )
|
||||
{
|
||||
JS_ReportError( context, "Invalid camera target" );
|
||||
return( JS_TRUE );
|
||||
}
|
||||
g_Game->GetView()->SetCameraTarget( *target );
|
||||
|
||||
*rval = JSVAL_TRUE;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool setTimeout( JSContext* context, JSObject* UNUSEDPARAM(globalObject), unsigned int argc, jsval* argv, jsval* UNUSEDPARAM(rval) )
|
||||
{
|
||||
assert( argc >= 2 );
|
||||
|
@ -17,6 +17,10 @@ JSBool GetEntitySet( JSContext* context, JSObject* globalObject, jsval argv, jsv
|
||||
|
||||
// Player
|
||||
JSBool GetPlayerSet( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
|
||||
JSBool GetLocalPlayer( JSContext* context, JSObject* globalObject, jsval argv, jsval* vp );
|
||||
|
||||
// Camera
|
||||
JSFunc setCameraTarget;
|
||||
|
||||
// Timer
|
||||
JSFunc setTimeout;
|
||||
|
@ -41,6 +41,10 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
|
||||
#include "Singleton.h"
|
||||
#include "CStr.h"
|
||||
|
||||
class IPropertyOwner
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
class DelayedScriptExecutor
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user