diff --git a/.gitignore b/.gitignore
index 8f242ff..38a19dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,9 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
+# vim swap files
+*.swp
+
# Package Files #
*.jar
!gradle-wrapper.jar
diff --git a/.gradle/6.3/executionHistory/executionHistory.lock b/.gradle/6.3/executionHistory/executionHistory.lock
deleted file mode 100644
index a7604be..0000000
Binary files a/.gradle/6.3/executionHistory/executionHistory.lock and /dev/null differ
diff --git a/.gradle/6.3/fileChanges/last-build.bin b/.gradle/6.3/fileChanges/last-build.bin
deleted file mode 100644
index f76dd23..0000000
Binary files a/.gradle/6.3/fileChanges/last-build.bin and /dev/null differ
diff --git a/.gradle/6.3/fileHashes/fileHashes.lock b/.gradle/6.3/fileHashes/fileHashes.lock
deleted file mode 100644
index 2b22044..0000000
Binary files a/.gradle/6.3/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/.gradle/6.3/gc.properties b/.gradle/6.3/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/.gradle/6.5/executionHistory/executionHistory.bin b/.gradle/6.5/executionHistory/executionHistory.bin
deleted file mode 100644
index ca60313..0000000
Binary files a/.gradle/6.5/executionHistory/executionHistory.bin and /dev/null differ
diff --git a/.gradle/6.5/executionHistory/executionHistory.lock b/.gradle/6.5/executionHistory/executionHistory.lock
deleted file mode 100644
index 7ae781a..0000000
Binary files a/.gradle/6.5/executionHistory/executionHistory.lock and /dev/null differ
diff --git a/.gradle/6.5/fileChanges/last-build.bin b/.gradle/6.5/fileChanges/last-build.bin
deleted file mode 100644
index f76dd23..0000000
Binary files a/.gradle/6.5/fileChanges/last-build.bin and /dev/null differ
diff --git a/.gradle/6.5/fileHashes/fileHashes.bin b/.gradle/6.5/fileHashes/fileHashes.bin
deleted file mode 100644
index adb536e..0000000
Binary files a/.gradle/6.5/fileHashes/fileHashes.bin and /dev/null differ
diff --git a/.gradle/6.5/fileHashes/fileHashes.lock b/.gradle/6.5/fileHashes/fileHashes.lock
deleted file mode 100644
index b89035b..0000000
Binary files a/.gradle/6.5/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/.gradle/6.5/gc.properties b/.gradle/6.5/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
deleted file mode 100644
index 125640c..0000000
Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
deleted file mode 100644
index b774acd..0000000
--- a/.gradle/buildOutputCleanup/cache.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-#Thu Oct 08 23:16:29 MSK 2020
-gradle.version=6.3
diff --git a/.gradle/checksums/checksums.lock b/.gradle/checksums/checksums.lock
deleted file mode 100644
index 2cf264e..0000000
Binary files a/.gradle/checksums/checksums.lock and /dev/null differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index c8b5c9a..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 87ca0fc..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index fdc392f..0000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index b0ec460..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index c29a8be..bbb4aac 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,14 @@
-# Примеры для курса "Разработчик Java" в OTUS
+
+Разработайте такой функционал: метод класса можно пометить самодельной аннотацией @Log, например, так:
-Группа 2020-09
+class TestLogging { @Log public void calculation(int param) {}; }
-### Преподаватели
-Сергей Петрелевич
-Стрекалов Павел
-Александр Оруджев
-Вячеслав Лапин
-Виталий Куценко
-Дмитрий Коган
+При вызове этого метода "автомагически" в консоль должны логироваться значения параметров. Например так.
-Студент:
-Kashapov Renat (Кашапов Ренат)
-renat.kashapov@gmail.com
\ No newline at end of file
+class Demo { public void action() { new TestLogging().calculation(6); } }
+
+В консоле дожно быть: executed method: calculation, param: 6
+
+Обратите внимание: явного вызова логирования быть не должно.
+
+Учтите, что аннотацию можно поставить, например, на такие методы: public void calculation(int param1) public void calculation(int param1, int param2) public void calculation(int param1, int param2, String param3)
diff --git a/hw05-AOPprincipes/build.gradle b/hw05-AOPprincipes/build.gradle
new file mode 100644
index 0000000..d252df3
--- /dev/null
+++ b/hw05-AOPprincipes/build.gradle
@@ -0,0 +1,26 @@
+plugins {
+ id 'java'
+ id 'application'
+}
+
+group 'ru.otus'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testCompile group: 'junit', name: 'junit', version: '4.12'
+// implementation 'com.google.guava:guava'
+ // https://mvnrepository.com/artifact/com.google.guava/guava
+ compile group: 'com.google.guava', name: 'guava', version: '30.0-jre'
+// https://mvnrepository.com/artifact/cglib/cglib
+ compile group: 'cglib', name: 'cglib', version: '3.3.0'
+// https://mvnrepository.com/artifact/org.ow2.asm/asm
+ compile group: 'org.ow2.asm', name: 'asm', version: '9.0'
+// https://mvnrepository.com/artifact/org.ow2.asm/asm-util
+ compile group: 'org.ow2.asm', name: 'asm-util', version: '9.0'
+}
+
+mainClassName = 'aop.App'
diff --git a/hw05-AOPprincipes/src/main/java/aop/AOPClassLoader.java b/hw05-AOPprincipes/src/main/java/aop/AOPClassLoader.java
new file mode 100644
index 0000000..8592640
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/AOPClassLoader.java
@@ -0,0 +1,43 @@
+package aop;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import java.io.IOException;
+import java.util.*;
+
+import static org.objectweb.asm.Opcodes.ASM9;
+
+public class AOPClassLoader extends ClassLoader {
+ protected Map loggedMethods = new HashMap<>();
+
+ @Override
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ Class> resultClass = null;
+ if (!name.startsWith("java.")) {
+ try {
+ ClassReader cr = new ClassReader(name);
+ ClassWriter cw = new ClassWriter(0);
+ ClassWriter cw1 = new ClassWriter(0);
+ byte[] b2;
+ AOPLoggedMethodsNamesClassVisitor aopLoggedMethodsNamesClassVisitor = new AOPLoggedMethodsNamesClassVisitor(ASM9, cw, loggedMethods);
+ cr.accept(aopLoggedMethodsNamesClassVisitor, 0);
+ b2 = cw.toByteArray();
+ ClassReader c2 = new ClassReader(b2);
+ AOPLoggedMethodsCodeClassVisitor aopLoggedMethodsCodeClassVisitor = new AOPLoggedMethodsCodeClassVisitor(ASM9, cw1, loggedMethods);
+ c2.accept(aopLoggedMethodsCodeClassVisitor, 0);
+ b2 = cw1.toByteArray();
+ resultClass = defineClass(name, b2, 0, b2.length);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ resultClass = super.loadClass(name, resolve);
+ }
+ return resultClass;
+ }
+
+ @Override
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ return super.loadClass(name);
+ }
+}
\ No newline at end of file
diff --git a/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeClassVisitor.java b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeClassVisitor.java
new file mode 100644
index 0000000..36fcf53
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeClassVisitor.java
@@ -0,0 +1,25 @@
+package aop;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import java.util.Map;
+import static org.objectweb.asm.Opcodes.ASM9;
+
+public class AOPLoggedMethodsCodeClassVisitor extends ClassVisitor {
+
+ protected Map loggedMethods;
+
+ public AOPLoggedMethodsCodeClassVisitor(int asmVersion, ClassVisitor classVisitor, Map loggedMethods) {
+ super(asmVersion, classVisitor);
+ this.loggedMethods = loggedMethods;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
+ MethodVisitor superMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
+ if (loggedMethods.get(name + descriptor) != null) {
+ return new AOPLoggedMethodsCodeMethodVisitor(ASM9, superMethodVisitor, loggedMethods.get(name + descriptor));
+ }
+ return superMethodVisitor;
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeMethodVisitor.java b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeMethodVisitor.java
new file mode 100644
index 0000000..e6fc758
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsCodeMethodVisitor.java
@@ -0,0 +1,38 @@
+package aop;
+
+import org.objectweb.asm.MethodVisitor;
+import static org.objectweb.asm.Opcodes.*;
+import java.util.Map;
+
+public class AOPLoggedMethodsCodeMethodVisitor extends MethodVisitor {
+
+ protected SomeMethodAttributes someMethodAttributes;
+
+ public AOPLoggedMethodsCodeMethodVisitor(int api, MethodVisitor methodVisitor, SomeMethodAttributes someMethodAttributes) {
+ super(api, methodVisitor);
+ this.someMethodAttributes = someMethodAttributes;
+ }
+
+ @Override
+ public void visitCode() {
+ mv.visitCode();
+ mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ mv.visitLdcInsn("Method: \"" + someMethodAttributes.getName() + "\"");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+ for (Map.Entry parameter : someMethodAttributes.getMethodVariablesHashMap().entrySet()) {
+ mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ mv.visitLdcInsn("Argument \"" + parameter.getKey() + "\": ");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V", false);
+ mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ mv.visitVarInsn(parameter.getValue().getType().getOpcode(ILOAD), parameter.getValue().getIndex());
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(" + transformToPrintlnArg(parameter.getValue().getType().getDescriptor()) + ")V", false);
+ }
+ }
+
+ private String transformToPrintlnArg(String arg){
+ if(arg.matches("[BSI]{1}")){
+ return "I";
+ }
+ return arg;
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesClassVisitor.java b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesClassVisitor.java
new file mode 100644
index 0000000..f2bc445
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesClassVisitor.java
@@ -0,0 +1,24 @@
+package aop;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.Map;
+import static org.objectweb.asm.Opcodes.*;
+
+public class AOPLoggedMethodsNamesClassVisitor extends ClassVisitor {
+
+ protected Map loggedMethods;
+
+ public AOPLoggedMethodsNamesClassVisitor(int asmVersion, ClassVisitor classVisitor, Map loggedMethods) {
+ super(asmVersion, classVisitor);
+ this.loggedMethods = loggedMethods;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
+ MethodVisitor aopLoggedMethodsNamesMethodVisitor = new AOPLoggedMethodsNamesMethodVisitor(ASM9, super.visitMethod(access, name, descriptor, signature, exceptions), loggedMethods, new SomeMethodAttributes(descriptor, access, name, signature, exceptions, new MethodVariablesHashMap()));
+ return aopLoggedMethodsNamesMethodVisitor;
+ }
+
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesMethodVisitor.java b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesMethodVisitor.java
new file mode 100644
index 0000000..90f6126
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/AOPLoggedMethodsNamesMethodVisitor.java
@@ -0,0 +1,73 @@
+package aop;
+
+import org.objectweb.asm.*;
+import java.util.Map;
+
+public class AOPLoggedMethodsNamesMethodVisitor extends MethodVisitor {
+ protected boolean isLogPresent;
+ protected SomeMethodAttributes someMethodAttributes;
+ protected Map loggedMethods;
+
+ public AOPLoggedMethodsNamesMethodVisitor(int api, MethodVisitor methodVisitor, Map loggedMethods, SomeMethodAttributes someMethodAttributes) {
+ super(api, methodVisitor);
+ this.loggedMethods = loggedMethods;
+ this.someMethodAttributes = someMethodAttributes;
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ isLogPresent = Type.getDescriptor(Log.class).equals(descriptor);
+ if(isLogPresent){
+ loggedMethods.put(someMethodAttributes.getName() + someMethodAttributes.getDescription(), someMethodAttributes);
+ }
+ return super.visitAnnotation(descriptor, visible);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv.visitMaxs(maxStack + 3, maxLocals + 4);
+ }
+
+ @Override
+ public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
+ String methodParameters = someMethodAttributes.getDescription().replaceFirst(".*\\(","").replaceFirst("\\).*", "");
+ if (isLogPresent & index > 0) {
+ someMethodAttributes.getMethodVariablesHashMap().put(name,new TypeIndex(index, parseParameters(methodParameters, index)));
+ }
+ super.visitLocalVariable(name, descriptor, signature, start, end, index);
+ }
+
+ private Type parseParameters(String parameters, int index) {
+ if (index == 1) {
+ if (parameters.startsWith("L")) {
+ return Type.getType(parameters.substring(0,parameters.indexOf(';')+1));
+ } else {
+ return Type.getType(parameters.substring(0, 1));
+ }
+ } else {
+ if (parameters.startsWith("L")){
+ return parseParameters(parameters.substring(parameters.indexOf(';')+1),index-1);
+ } else {
+ return parseParameters(parameters.substring(1),index-1);
+ }
+ }
+ }
+
+ final protected class TypeIndex {
+ private int index;
+ private Type type;
+
+ TypeIndex(int index, Type type) {
+ this.index = index;
+ this.type = type;
+ }
+
+ protected int getIndex() {
+ return index;
+ }
+
+ protected Type getType() {
+ return type;
+ }
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/App.java b/hw05-AOPprincipes/src/main/java/aop/App.java
new file mode 100644
index 0000000..8dfb753
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/App.java
@@ -0,0 +1,27 @@
+package aop;
+
+import java.lang.reflect.Method;
+
+public class App {
+ static public void main(String ... args) {
+ var classLoaderClass = App.class.getClassLoader().getClass();
+ if( !classLoaderClass.getName().equals(AOPClassLoader.class.getName())) { //иначе сравнивать классы невозможно, так как это различные объекты
+ AOPClassLoader aopClassLoader = new AOPClassLoader();
+ try {
+ Class> loadClass = aopClassLoader.loadClass("aop.App", false);
+ Method method = loadClass.getMethod("main", new Class[]{String[].class});
+ method.invoke(null, new Object[]{args});
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else{// классы с AOP писать в этом блоке.
+ try {
+ new UsefulImpl().sayHelloTo("bb");
+ new UsefulImpl().sayHelloTo("cc", (short) 23);
+ }
+ catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/Log.java b/hw05-AOPprincipes/src/main/java/aop/Log.java
new file mode 100644
index 0000000..691d2fe
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/Log.java
@@ -0,0 +1,8 @@
+package aop;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log {
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/MethodVariablesHashMap.java b/hw05-AOPprincipes/src/main/java/aop/MethodVariablesHashMap.java
new file mode 100644
index 0000000..f5a8622
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/MethodVariablesHashMap.java
@@ -0,0 +1,15 @@
+package aop;
+
+import java.util.HashMap;
+
+public class MethodVariablesHashMap extends HashMap {
+ @Override
+ public AOPLoggedMethodsNamesMethodVisitor.TypeIndex put(String name, AOPLoggedMethodsNamesMethodVisitor.TypeIndex typeIndex) {
+ for (AOPLoggedMethodsNamesMethodVisitor.TypeIndex existingTypeIndex : this.values()) {
+ if (typeIndex.getIndex() == existingTypeIndex.getIndex()) {
+ throw new IllegalArgumentException();
+ }
+ }
+ return super.put(name, typeIndex);
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/SomeMethodAttributes.java b/hw05-AOPprincipes/src/main/java/aop/SomeMethodAttributes.java
new file mode 100644
index 0000000..1d74930
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/SomeMethodAttributes.java
@@ -0,0 +1,44 @@
+package aop;
+
+public class SomeMethodAttributes {
+ private String description;
+ private int access;
+ private String name;
+ private String signature;
+ private String[] exceptions;
+ private MethodVariablesHashMap methodVariablesHashMap;
+
+ SomeMethodAttributes(String description, int access, String name, String signature, String[] exceptions,
+ MethodVariablesHashMap methodVariablesHashMap) {
+ this.description = description;
+ this.access = access;
+ this.name = name;
+ this.signature = signature;
+ this.exceptions = exceptions;
+ this.methodVariablesHashMap = methodVariablesHashMap;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public int getAccess() {
+ return this.access;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getSignature() {
+ return this.signature;
+ }
+
+ public String[] getExceptions() {
+ return this.exceptions;
+ }
+
+ public MethodVariablesHashMap getMethodVariablesHashMap(){
+ return this.methodVariablesHashMap;
+ }
+}
diff --git a/hw05-AOPprincipes/src/main/java/aop/Useful.java b/hw05-AOPprincipes/src/main/java/aop/Useful.java
new file mode 100644
index 0000000..88debc4
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/Useful.java
@@ -0,0 +1,8 @@
+package aop;
+
+public interface Useful {
+ public void sayHelloTo();
+ public void sayHelloTo(String name);
+ public void sayHelloTo(String name, double howMany);
+}
+
diff --git a/hw05-AOPprincipes/src/main/java/aop/UsefulImpl.java b/hw05-AOPprincipes/src/main/java/aop/UsefulImpl.java
new file mode 100644
index 0000000..5c17e91
--- /dev/null
+++ b/hw05-AOPprincipes/src/main/java/aop/UsefulImpl.java
@@ -0,0 +1,24 @@
+package aop;
+
+public class UsefulImpl implements Useful {
+ public UsefulImpl() {
+ }
+
+ @Override
+ public void sayHelloTo() {
+// return "Hello!";
+ }
+
+ @Log
+ @Override
+ public void sayHelloTo(String name) {
+// return "Hello, " + name +"!";
+ }
+
+ @Log
+ @Override
+ public void sayHelloTo(String name, double howMany) {
+// return "Hello, " + name + "! " + howMany + " times.";
+ }
+
+}
diff --git a/settings.gradle b/settings.gradle
index 9a32c0b..5b43c31 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,3 @@
rootProject.name = 'otus_hw'
+include 'hw05-AOPprincipes'
diff --git a/src/main/java/A.java b/src/main/java/A.java
deleted file mode 100644
index 6be5562..0000000
--- a/src/main/java/A.java
+++ /dev/null
@@ -1,5 +0,0 @@
-public class A {
- public static void main(String ... args){
- System.out.println("Hello, gradle + git!");
- }
-}