Names from new runtime
This commit is contained in:
+11
-11
@@ -123,9 +123,9 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
|
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
|
||||||
|
|
||||||
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
|
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
|
||||||
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("KOutput")
|
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("StructureEncoder")
|
||||||
val wBeginFunc = ctx.getNameForDescriptor(
|
val wBeginFunc = ctx.getNameForDescriptor(
|
||||||
kOutputClass.getFuncDesc("writeBegin").single { (it as FunctionDescriptor).valueParameters.size == 2 })
|
kOutputClass.getFuncDesc("beginStructure").single { (it as FunctionDescriptor).valueParameters.size == 2 })
|
||||||
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
|
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
|
||||||
|
|
||||||
// output.writeBegin(desc, [])
|
// output.writeBegin(desc, [])
|
||||||
@@ -151,7 +151,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
|
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
|
||||||
if (innerSerial == null) {
|
if (innerSerial == null) {
|
||||||
val writeFunc =
|
val writeFunc =
|
||||||
kOutputClass.getFuncDesc("write${sti.elementMethodPrefix}ElementValue").single()
|
kOutputClass.getFuncDesc("encode${sti.elementMethodPrefix}ElementValue").single()
|
||||||
.let { ctx.getNameForDescriptor(it) }
|
.let { ctx.getNameForDescriptor(it) }
|
||||||
+JsInvocation(JsNameRef(writeFunc, localOutputRef),
|
+JsInvocation(JsNameRef(writeFunc, localOutputRef),
|
||||||
serialClassDescRef,
|
serialClassDescRef,
|
||||||
@@ -160,7 +160,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val writeFunc =
|
val writeFunc =
|
||||||
kOutputClass.getFuncDesc("write${sti.elementMethodPrefix}SerializableElementValue").single()
|
kOutputClass.getFuncDesc("encode${sti.elementMethodPrefix}SerializableElementValue").single()
|
||||||
.let { ctx.getNameForDescriptor(it) }
|
.let { ctx.getNameForDescriptor(it) }
|
||||||
+JsInvocation(JsNameRef(writeFunc, localOutputRef),
|
+JsInvocation(JsNameRef(writeFunc, localOutputRef),
|
||||||
serialClassDescRef,
|
serialClassDescRef,
|
||||||
@@ -171,7 +171,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// output.writeEnd(serialClassDesc)
|
// output.writeEnd(serialClassDesc)
|
||||||
val wEndFunc = kOutputClass.getFuncDesc("writeEnd").single()
|
val wEndFunc = kOutputClass.getFuncDesc("endStructure").single()
|
||||||
.let { ctx.getNameForDescriptor(it) }
|
.let { ctx.getNameForDescriptor(it) }
|
||||||
+JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt()
|
+JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt()
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
|
|
||||||
|
|
||||||
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
|
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
|
||||||
val inputClass = serializerDescriptor.getClassFromSerializationPackage("KInput")
|
val inputClass = serializerDescriptor.getClassFromSerializationPackage("StructureDecoder")
|
||||||
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
|
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
|
||||||
|
|
||||||
// var index = -1, readAll = false
|
// var index = -1, readAll = false
|
||||||
@@ -237,7 +237,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
JsNameRef(context.scope().declareName("$typeArgPrefix$idx"), JsThisRef())
|
JsNameRef(context.scope().declareName("$typeArgPrefix$idx"), JsThisRef())
|
||||||
}
|
}
|
||||||
val inputVar = JsNameRef(jsFun.scope.declareFreshName("input"))
|
val inputVar = JsNameRef(jsFun.scope.declareFreshName("input"))
|
||||||
val readBeginF = inputClass.getFuncDesc("readBegin").single()
|
val readBeginF = inputClass.getFuncDesc("beginStructure").single()
|
||||||
val call = JsInvocation(JsNameRef(context.getNameForDescriptor(readBeginF), JsNameRef(jsFun.parameters[0].name)),
|
val call = JsInvocation(JsNameRef(context.getNameForDescriptor(readBeginF), JsNameRef(jsFun.parameters[0].name)),
|
||||||
serialClassDescRef, JsArrayLiteral(typeParams))
|
serialClassDescRef, JsArrayLiteral(typeParams))
|
||||||
+JsVars(JsVars.JsVar(inputVar.name, call))
|
+JsVars(JsVars.JsVar(inputVar.name, call))
|
||||||
@@ -247,7 +247,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
val loopRef = JsNameRef(loop.name)
|
val loopRef = JsNameRef(loop.name)
|
||||||
jsWhile(JsBooleanLiteral(true), {
|
jsWhile(JsBooleanLiteral(true), {
|
||||||
// index = input.readElement(classDesc)
|
// index = input.readElement(classDesc)
|
||||||
val readElementF = context.getNameForDescriptor(inputClass.getFuncDesc("readElement").single())
|
val readElementF = context.getNameForDescriptor(inputClass.getFuncDesc("decodeElement").single())
|
||||||
+JsAstUtils.assignment(
|
+JsAstUtils.assignment(
|
||||||
indexVar,
|
indexVar,
|
||||||
JsInvocation(JsNameRef(readElementF, inputVar), serialClassDescRef)
|
JsInvocation(JsNameRef(readElementF, inputVar), serialClassDescRef)
|
||||||
@@ -270,7 +270,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
val call: JsExpression = if (innerSerial == null) {
|
val call: JsExpression = if (innerSerial == null) {
|
||||||
val unknownSer = (sti.elementMethodPrefix.isEmpty())
|
val unknownSer = (sti.elementMethodPrefix.isEmpty())
|
||||||
val readFunc =
|
val readFunc =
|
||||||
inputClass.getFuncDesc("read${sti.elementMethodPrefix}ElementValue")
|
inputClass.getFuncDesc("decode${sti.elementMethodPrefix}ElementValue")
|
||||||
// if readElementValue, must have 3 parameters, if readXXXElementValue - 2
|
// if readElementValue, must have 3 parameters, if readXXXElementValue - 2
|
||||||
.single { !unknownSer || (it is FunctionDescriptor && it.valueParameters.size == 3) }
|
.single { !unknownSer || (it is FunctionDescriptor && it.valueParameters.size == 3) }
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
@@ -281,7 +281,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
else {
|
else {
|
||||||
val notSeenTest = propNotSeenTest(bitMasks[i / 32], i)
|
val notSeenTest = propNotSeenTest(bitMasks[i / 32], i)
|
||||||
val readFunc =
|
val readFunc =
|
||||||
inputClass.getFuncDesc("read${sti.elementMethodPrefix}SerializableElementValue").single()
|
inputClass.getFuncDesc("decode${sti.elementMethodPrefix}SerializableElementValue").single()
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
val updateFunc =
|
val updateFunc =
|
||||||
inputClass.getFuncDesc("update${sti.elementMethodPrefix}SerializableElementValue").single()
|
inputClass.getFuncDesc("update${sti.elementMethodPrefix}SerializableElementValue").single()
|
||||||
@@ -349,7 +349,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
|
|||||||
}, loop)
|
}, loop)
|
||||||
|
|
||||||
// input.readEnd(desc)
|
// input.readEnd(desc)
|
||||||
val readEndF = inputClass.getFuncDesc("readEnd").single()
|
val readEndF = inputClass.getFuncDesc("endStructure").single()
|
||||||
.let { context.getNameForDescriptor(it) }
|
.let { context.getNameForDescriptor(it) }
|
||||||
+JsInvocation(
|
+JsInvocation(
|
||||||
JsNameRef(readEndF, inputVar),
|
JsNameRef(readEndF, inputVar),
|
||||||
|
|||||||
+8
-8
@@ -34,14 +34,14 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescripto
|
|||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
internal val descType = Type.getObjectType("kotlinx/serialization/KSerialClassDesc")
|
internal val descType = Type.getObjectType("kotlinx/serialization/SerialDescriptor")
|
||||||
internal val descImplType = Type.getObjectType("kotlinx/serialization/internal/SerialClassDescImpl")
|
internal val descImplType = Type.getObjectType("kotlinx/serialization/internal/SerialClassDescImpl")
|
||||||
internal val kOutputType = Type.getObjectType("kotlinx/serialization/KOutput")
|
internal val kOutputType = Type.getObjectType("kotlinx/serialization/StructureEncoder")
|
||||||
internal val kInputType = Type.getObjectType("kotlinx/serialization/KInput")
|
internal val kInputType = Type.getObjectType("kotlinx/serialization/StructureDecoder")
|
||||||
|
|
||||||
|
|
||||||
internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/KSerialSaver")
|
internal val kSerialSaverType = Type.getObjectType("kotlinx/serialization/SerializationStrategy")
|
||||||
internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/KSerialLoader")
|
internal val kSerialLoaderType = Type.getObjectType("kotlinx/serialization/DeserializationStrategy")
|
||||||
internal val kSerializerType = Type.getObjectType("kotlinx/serialization/KSerializer")
|
internal val kSerializerType = Type.getObjectType("kotlinx/serialization/KSerializer")
|
||||||
internal val kSerializerArrayType = Type.getObjectType("[Lkotlinx/serialization/KSerializer;")
|
internal val kSerializerArrayType = Type.getObjectType("[Lkotlinx/serialization/KSerializer;")
|
||||||
|
|
||||||
@@ -77,11 +77,11 @@ fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, clas
|
|||||||
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti)
|
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti)
|
||||||
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar)
|
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar)
|
||||||
if (!sti.unit) classCodegen.genPropertyOnStack(this, expressionCodegen.context, property.descriptor, propertyOwnerType, ownerVar)
|
if (!sti.unit) classCodegen.genPropertyOnStack(this, expressionCodegen.context, property.descriptor, propertyOwnerType, ownerVar)
|
||||||
invokevirtual(kOutputType.internalName,
|
invokeinterface(kOutputType.internalName,
|
||||||
"write" + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
|
"encode" + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
|
||||||
"(" + descType.descriptor + "I" +
|
"(" + descType.descriptor + "I" +
|
||||||
(if (useSerializer) kSerialSaverType.descriptor else "") +
|
(if (useSerializer) kSerialSaverType.descriptor else "") +
|
||||||
(if (sti.unit) "" else sti.type.descriptor) + ")V", false)
|
(if (sti.unit) "" else sti.type.descriptor) + ")V")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String {
|
internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String {
|
||||||
|
|||||||
+13
-13
@@ -155,9 +155,9 @@ class SerializerCodegenImpl(
|
|||||||
load(outputVar, kOutputType)
|
load(outputVar, kOutputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
genArrayOfTypeParametersSerializers()
|
genArrayOfTypeParametersSerializers()
|
||||||
invokevirtual(kOutputType.internalName, "writeBegin",
|
invokeinterface(kOutputType.internalName, "beginStructure",
|
||||||
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
||||||
")" + kOutputType.descriptor, false)
|
")" + kOutputType.descriptor)
|
||||||
store(outputVar, kOutputType)
|
store(outputVar, kOutputType)
|
||||||
if (serializableDescriptor.isInternalSerializable) {
|
if (serializableDescriptor.isInternalSerializable) {
|
||||||
val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
|
val sig = StringBuilder("(${kOutputType.descriptor}${descType.descriptor}")
|
||||||
@@ -190,8 +190,8 @@ class SerializerCodegenImpl(
|
|||||||
// output.writeEnd(classDesc)
|
// output.writeEnd(classDesc)
|
||||||
load(outputVar, kOutputType)
|
load(outputVar, kOutputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokevirtual(kOutputType.internalName, "writeEnd",
|
invokeinterface(kOutputType.internalName, "endStructure",
|
||||||
"(" + descType.descriptor + ")V", false)
|
"(" + descType.descriptor + ")V")
|
||||||
// return
|
// return
|
||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
}
|
}
|
||||||
@@ -245,17 +245,17 @@ class SerializerCodegenImpl(
|
|||||||
load(inputVar, kInputType)
|
load(inputVar, kInputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
genArrayOfTypeParametersSerializers()
|
genArrayOfTypeParametersSerializers()
|
||||||
invokevirtual(kInputType.internalName, "readBegin",
|
invokeinterface(kInputType.internalName, "beginStructure",
|
||||||
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
"(" + descType.descriptor + kSerializerArrayType.descriptor +
|
||||||
")" + kInputType.descriptor, false)
|
")" + kInputType.descriptor)
|
||||||
store(inputVar, kInputType)
|
store(inputVar, kInputType)
|
||||||
// readElement: int index = input.readElement(classDesc)
|
// readElement: int index = input.readElement(classDesc)
|
||||||
val readElementLabel = Label()
|
val readElementLabel = Label()
|
||||||
visitLabel(readElementLabel)
|
visitLabel(readElementLabel)
|
||||||
load(inputVar, kInputType)
|
load(inputVar, kInputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokevirtual(kInputType.internalName, "readElement",
|
invokeinterface(kInputType.internalName, "decodeElement",
|
||||||
"(" + descType.descriptor + ")I", false)
|
"(" + descType.descriptor + ")I")
|
||||||
store(indexVar, Type.INT_TYPE)
|
store(indexVar, Type.INT_TYPE)
|
||||||
// switch(index)
|
// switch(index)
|
||||||
val labeledProperties = orderedProperties.filter { !it.transient }
|
val labeledProperties = orderedProperties.filter { !it.transient }
|
||||||
@@ -296,13 +296,13 @@ class SerializerCodegenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun produceCall(update: Boolean) {
|
fun produceCall(update: Boolean) {
|
||||||
invokevirtual(kInputType.internalName,
|
invokeinterface(kInputType.internalName,
|
||||||
(if (update) "update" else "read") + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
|
(if (update) "update" else "decode") + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
|
||||||
"(" + descType.descriptor + "I" +
|
"(" + descType.descriptor + "I" +
|
||||||
(if (useSerializer) kSerialLoaderType.descriptor else "")
|
(if (useSerializer) kSerialLoaderType.descriptor else "")
|
||||||
+ (if (unknownSer) AsmTypes.K_CLASS_TYPE.descriptor else "")
|
+ (if (unknownSer) AsmTypes.K_CLASS_TYPE.descriptor else "")
|
||||||
+ (if (update) sti.type.descriptor else "")
|
+ (if (update) sti.type.descriptor else "")
|
||||||
+ ")" + (if (sti.unit) "V" else sti.type.descriptor), false)
|
+ ")" + (if (sti.unit) "V" else sti.type.descriptor))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useSerializer) {
|
if (useSerializer) {
|
||||||
@@ -351,8 +351,8 @@ class SerializerCodegenImpl(
|
|||||||
visitLabel(readEndLabel)
|
visitLabel(readEndLabel)
|
||||||
load(inputVar, kInputType)
|
load(inputVar, kInputType)
|
||||||
load(descVar, descType)
|
load(descVar, descType)
|
||||||
invokevirtual(kInputType.internalName, "readEnd",
|
invokeinterface(kInputType.internalName, "endStructure",
|
||||||
"(" + descType.descriptor + ")V", false)
|
"(" + descType.descriptor + ")V")
|
||||||
if (!serializableDescriptor.isInternalSerializable) {
|
if (!serializableDescriptor.isInternalSerializable) {
|
||||||
//validate all required (constructor) fields
|
//validate all required (constructor) fields
|
||||||
val nonThrowLabel = Label()
|
val nonThrowLabel = Label()
|
||||||
|
|||||||
+2
-1
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
|||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.descType
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_CLASS_NAME
|
||||||
|
|
||||||
internal val packageFqName = FqName("kotlinx.serialization")
|
internal val packageFqName = FqName("kotlinx.serialization")
|
||||||
@@ -192,7 +193,7 @@ fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescri
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ClassDescriptor.checkSerializableClassPropertyResult(prop: PropertyDescriptor): Boolean =
|
fun ClassDescriptor.checkSerializableClassPropertyResult(prop: PropertyDescriptor): Boolean =
|
||||||
prop.returnType!!.isSubtypeOf(getClassFromSerializationPackage("KSerialClassDesc").toSimpleType(false)) // todo: cache lookup
|
prop.returnType!!.isSubtypeOf(getClassFromSerializationPackage("SerialDescriptor").toSimpleType(false)) // todo: cache lookup
|
||||||
|
|
||||||
// todo: serialization: do an actual check better that just number of parameters
|
// todo: serialization: do an actual check better that just number of parameters
|
||||||
fun ClassDescriptor.checkSaveMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
fun ClassDescriptor.checkSaveMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
||||||
|
|||||||
+4
-4
@@ -39,8 +39,8 @@ import java.util.*
|
|||||||
object KSerializerDescriptorResolver {
|
object KSerializerDescriptorResolver {
|
||||||
|
|
||||||
val SERIAL_DESC_FIELD = "serialClassDesc"
|
val SERIAL_DESC_FIELD = "serialClassDesc"
|
||||||
val SAVE = "save"
|
val SAVE = "serialize"
|
||||||
val LOAD = "load"
|
val LOAD = "deserialize"
|
||||||
val SERIALIZER_CLASS = "\$serializer"
|
val SERIALIZER_CLASS = "\$serializer"
|
||||||
|
|
||||||
internal val typeArgPrefix = "typeSerial"
|
internal val typeArgPrefix = "typeSerial"
|
||||||
@@ -379,7 +379,7 @@ object KSerializerDescriptorResolver {
|
|||||||
i++,
|
i++,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
Name.identifier("output"),
|
Name.identifier("output"),
|
||||||
thisClass.getClassFromSerializationPackage("KOutput").toSimpleType(false),
|
thisClass.getClassFromSerializationPackage("StructureEncoder").toSimpleType(false),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
@@ -393,7 +393,7 @@ object KSerializerDescriptorResolver {
|
|||||||
i++,
|
i++,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
Name.identifier("serialDesc"),
|
Name.identifier("serialDesc"),
|
||||||
thisClass.getClassFromSerializationPackage("KSerialClassDesc").toSimpleType(false),
|
thisClass.getClassFromSerializationPackage("SerialDescriptor").toSimpleType(false),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|||||||
Reference in New Issue
Block a user