diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Recipes.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Recipes.xml
index 0d5287f111..90f4bd8dd7 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Recipes.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Recipes.xml
@@ -7,17214 +7,30899 @@
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/EffectMasterHandler.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/EffectMasterHandler.java
index 07d2f9cf70..980dbf1447 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/EffectMasterHandler.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/EffectMasterHandler.java
@@ -90,12 +90,16 @@ public final class EffectMasterHandler
EffectHandler.getInstance().registerHandler("CpHealOverTime", CpHealOverTime::new);
EffectHandler.getInstance().registerHandler("CpHealPercent", CpHealPercent::new);
EffectHandler.getInstance().registerHandler("CpRegen", CpRegen::new);
+ EffectHandler.getInstance().registerHandler("CraftingCritical", CraftingCritical::new);
+ EffectHandler.getInstance().registerHandler("CreateCommonItem", CreateCommonItem::new);
+ EffectHandler.getInstance().registerHandler("CreateItem", CreateItem::new);
EffectHandler.getInstance().registerHandler("CreateItemRandom", CreateItemRandom::new);
EffectHandler.getInstance().registerHandler("CriticalDamage", CriticalDamage::new);
EffectHandler.getInstance().registerHandler("CriticalDamagePosition", CriticalDamagePosition::new);
EffectHandler.getInstance().registerHandler("CriticalRate", CriticalRate::new);
EffectHandler.getInstance().registerHandler("CriticalRatePositionBonus", CriticalRatePositionBonus::new);
EffectHandler.getInstance().registerHandler("CrystalGradeModify", CrystalGradeModify::new);
+ EffectHandler.getInstance().registerHandler("Crystallize", Crystallize::new);
EffectHandler.getInstance().registerHandler("CubicMastery", CubicMastery::new);
EffectHandler.getInstance().registerHandler("DamageBlock", DamageBlock::new);
EffectHandler.getInstance().registerHandler("DamageShield", DamageShield::new);
@@ -265,6 +269,7 @@ public final class EffectMasterHandler
EffectHandler.getInstance().registerHandler("ReflectSkill", ReflectSkill::new);
EffectHandler.getInstance().registerHandler("RefuelAirship", RefuelAirship::new);
EffectHandler.getInstance().registerHandler("Relax", Relax::new);
+ EffectHandler.getInstance().registerHandler("RemoveEquipPenalty", RemoveEquipPenalty::new);
EffectHandler.getInstance().registerHandler("ResetInstanceEntry", ResetInstanceEntry::new);
EffectHandler.getInstance().registerHandler("ResistAbnormalByCategory", ResistAbnormalByCategory::new);
EffectHandler.getInstance().registerHandler("ResistDDMagic", ResistDDMagic::new);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2ManufactureItem.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CraftingCritical.java
similarity index 56%
rename from L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2ManufactureItem.java
rename to L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CraftingCritical.java
index 96d3dd2776..861ca9f57a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2ManufactureItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CraftingCritical.java
@@ -1,48 +1,31 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver.model;
-
-import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
-
-public class L2ManufactureItem
-{
- private final int _recipeId;
- private final long _cost;
- private final boolean _isDwarven;
-
- public L2ManufactureItem(int recipeId, long cost)
- {
- _recipeId = recipeId;
- _cost = cost;
- _isDwarven = RecipeData.getInstance().getRecipeList(_recipeId).isDwarvenRecipe();
- }
-
- public int getRecipeId()
- {
- return _recipeId;
- }
-
- public long getCost()
- {
- return _cost;
- }
-
- public boolean isDwarven()
- {
- return _isDwarven;
- }
-}
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.effecthandlers;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.stats.Stats;
+
+/**
+ * @author Nik
+ */
+public class CraftingCritical extends AbstractStatAddEffect
+{
+ public CraftingCritical(StatsSet params)
+ {
+ super(params, Stats.CRAFTING_CRITICAL);
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateCommonItem.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateCommonItem.java
new file mode 100644
index 0000000000..d189eb6f48
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateCommonItem.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.effecthandlers;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.effects.AbstractEffect;
+import com.l2jmobius.gameserver.model.skills.BuffInfo;
+import com.l2jmobius.gameserver.model.skills.Skill;
+
+/**
+ * An effect that allows the player to create common recipe items up to a certain level.
+ * @author Nik
+ */
+public final class CreateCommonItem extends AbstractEffect
+{
+ private final int _recipeLevel;
+
+ public CreateCommonItem(StatsSet params)
+ {
+ _recipeLevel = params.getInt("value");
+ }
+
+ @Override
+ public boolean canStart(BuffInfo info)
+ {
+ return info.getEffected().isPlayer();
+ }
+
+ @Override
+ public void onStart(L2Character effector, L2Character effected, Skill skill)
+ {
+ final L2PcInstance player = effected.getActingPlayer();
+ if (player != null)
+ {
+ player.setCreateCommonItemLevel(_recipeLevel);
+ }
+ }
+
+ @Override
+ public void onExit(BuffInfo info)
+ {
+ final L2PcInstance player = info.getEffected().getActingPlayer();
+ if (player != null)
+ {
+ player.setCreateCommonItemLevel(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateItem.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateItem.java
new file mode 100644
index 0000000000..a18650feb0
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CreateItem.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.effecthandlers;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.effects.AbstractEffect;
+import com.l2jmobius.gameserver.model.skills.BuffInfo;
+import com.l2jmobius.gameserver.model.skills.Skill;
+
+/**
+ * An effect that allows the player to create dwarven recipe items up to a certain level.
+ * @author Nik
+ */
+public final class CreateItem extends AbstractEffect
+{
+ private final int _recipeLevel;
+
+ public CreateItem(StatsSet params)
+ {
+ _recipeLevel = params.getInt("value");
+ }
+
+ @Override
+ public boolean canStart(BuffInfo info)
+ {
+ return info.getEffected().isPlayer();
+ }
+
+ @Override
+ public void onStart(L2Character effector, L2Character effected, Skill skill)
+ {
+ final L2PcInstance player = effected.getActingPlayer();
+ if (player != null)
+ {
+ player.setCreateItemLevel(_recipeLevel);
+ }
+ }
+
+ @Override
+ public void onExit(BuffInfo info)
+ {
+ final L2PcInstance player = info.getEffected().getActingPlayer();
+ if (player != null)
+ {
+ player.setCreateItemLevel(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CrystalGradeModify.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CrystalGradeModify.java
index 248727ab7d..49807b42a7 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CrystalGradeModify.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/CrystalGradeModify.java
@@ -29,11 +29,11 @@ import com.l2jmobius.gameserver.model.skills.Skill;
*/
public final class CrystalGradeModify extends AbstractEffect
{
- private final int _grade;
+ private final int _amount;
public CrystalGradeModify(StatsSet params)
{
- _grade = params.getInt("grade", 0);
+ _amount = params.getInt("_amount", 0);
}
@Override
@@ -45,7 +45,7 @@ public final class CrystalGradeModify extends AbstractEffect
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
- effected.getActingPlayer().setExpertisePenaltyBonus(_grade);
+ effected.getActingPlayer().setExpertisePenaltyBonus(_amount);
}
@Override
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/Crystallize.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/Crystallize.java
new file mode 100644
index 0000000000..070fbd5193
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/Crystallize.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.effecthandlers;
+
+import com.l2jmobius.gameserver.enums.ItemGrade;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.effects.AbstractEffect;
+import com.l2jmobius.gameserver.model.skills.BuffInfo;
+import com.l2jmobius.gameserver.model.skills.Skill;
+
+/**
+ * An effect that allows the player to crystallize items up to a certain grade.
+ * @author Nik
+ */
+public final class Crystallize extends AbstractEffect
+{
+ private final ItemGrade _grade;
+
+ public Crystallize(StatsSet params)
+ {
+ _grade = params.getEnum("grade", ItemGrade.class);
+ }
+
+ @Override
+ public boolean canStart(BuffInfo info)
+ {
+ return info.getEffected().isPlayer();
+ }
+
+ @Override
+ public void onStart(L2Character effector, L2Character effected, Skill skill)
+ {
+ final L2PcInstance player = effected.getActingPlayer();
+ if (player != null)
+ {
+ player.setCrystallizeGrade(_grade);
+ }
+ }
+
+ @Override
+ public void onExit(BuffInfo info)
+ {
+ final L2PcInstance player = info.getEffected().getActingPlayer();
+ if (player != null)
+ {
+ player.setCrystallizeGrade(null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenCommonRecipeBook.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenCommonRecipeBook.java
index 78280f5bd8..a353ce45d2 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenCommonRecipeBook.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenCommonRecipeBook.java
@@ -16,7 +16,6 @@
*/
package handlers.effecthandlers;
-import com.l2jmobius.gameserver.RecipeController;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -25,6 +24,7 @@ import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
/**
* Open Common Recipe Book effect implementation.
@@ -45,18 +45,24 @@ public final class OpenCommonRecipeBook extends AbstractEffect
@Override
public void instant(L2Character effector, L2Character effected, Skill skill, L2ItemInstance item)
{
- if (!effector.isPlayer())
+ final L2PcInstance casterPlayer = effector.getActingPlayer();
+ if (casterPlayer == null)
{
return;
}
- final L2PcInstance player = effector.getActingPlayer();
- if (player.getPrivateStoreType() != PrivateStoreType.NONE)
+ if (casterPlayer.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
{
- player.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ casterPlayer.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return;
}
- RecipeController.getInstance().requestBookOpen(player, false);
+ if (casterPlayer.isProcessingTransaction())
+ {
+ casterPlayer.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ return;
+ }
+
+ casterPlayer.sendPacket(new RecipeBookItemList(casterPlayer, false));
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenDwarfRecipeBook.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenDwarfRecipeBook.java
index d781e6d6cb..68493ad7cc 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenDwarfRecipeBook.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/OpenDwarfRecipeBook.java
@@ -16,7 +16,6 @@
*/
package handlers.effecthandlers;
-import com.l2jmobius.gameserver.RecipeController;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -25,6 +24,7 @@ import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
/**
* Open Dwarf Recipe Book effect implementation.
@@ -45,18 +45,24 @@ public final class OpenDwarfRecipeBook extends AbstractEffect
@Override
public void instant(L2Character effector, L2Character effected, Skill skill, L2ItemInstance item)
{
- if (!effector.isPlayer())
+ final L2PcInstance casterPlayer = effector.getActingPlayer();
+ if (casterPlayer == null)
{
return;
}
- final L2PcInstance player = effector.getActingPlayer();
- if (player.getPrivateStoreType() != PrivateStoreType.NONE)
+ if (casterPlayer.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
{
- player.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ casterPlayer.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return;
}
- RecipeController.getInstance().requestBookOpen(player, true);
+ if (casterPlayer.isProcessingTransaction())
+ {
+ casterPlayer.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ return;
+ }
+
+ casterPlayer.sendPacket(new RecipeBookItemList(casterPlayer, true));
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/RemoveEquipPenalty.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/RemoveEquipPenalty.java
new file mode 100644
index 0000000000..4841f0a023
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/effecthandlers/RemoveEquipPenalty.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.effecthandlers;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.effects.AbstractEffect;
+import com.l2jmobius.gameserver.model.items.type.CrystalType;
+import com.l2jmobius.gameserver.model.skills.BuffInfo;
+import com.l2jmobius.gameserver.model.skills.Skill;
+
+/**
+ * An effect that removes equipment grade penalty. Its the base effect for the grade penalty mechanics.
+ * @author Nik
+ */
+public final class RemoveEquipPenalty extends AbstractEffect
+{
+ private final CrystalType _grade;
+
+ public RemoveEquipPenalty(StatsSet params)
+ {
+ _grade = params.getEnum("grade", CrystalType.class);
+ }
+
+ @Override
+ public boolean canStart(BuffInfo info)
+ {
+ return info.getEffected().isPlayer();
+ }
+
+ @Override
+ public void onStart(L2Character effector, L2Character effected, Skill skill)
+ {
+ final L2PcInstance player = effected.getActingPlayer();
+ if (player != null)
+ {
+ player.setExpertiseLevel(_grade);
+ }
+ }
+
+ @Override
+ public void onExit(BuffInfo info)
+ {
+ final L2PcInstance player = info.getEffected().getActingPlayer();
+ if (player != null)
+ {
+ player.setExpertiseLevel(null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/CharmOfCourage.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/CharmOfCourage.java
index 4b7b0b246d..eef7f6bb11 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/CharmOfCourage.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/CharmOfCourage.java
@@ -42,7 +42,7 @@ public class CharmOfCourage implements IItemHandler
final L2PcInstance activeChar = playable.getActingPlayer();
int level = activeChar.getLevel();
- final int itemLevel = item.getItem().getCrystalType().getId();
+ final int itemLevel = item.getItem().getCrystalType().getLevel();
if (level < 20)
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/Recipes.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/Recipes.java
index 59ca8fcc83..19bc984f6f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/Recipes.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/itemhandlers/Recipes.java
@@ -18,9 +18,9 @@ package handlers.itemhandlers;
import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.handler.IItemHandler;
-import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
@@ -40,15 +40,16 @@ public class Recipes implements IItemHandler
}
final L2PcInstance activeChar = playable.getActingPlayer();
- if (activeChar.isInCraftMode())
+ if (activeChar.isCrafting())
{
activeChar.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return false;
}
- final L2RecipeList rp = RecipeData.getInstance().getRecipeByItemId(item.getId());
+ final RecipeHolder rp = RecipeData.getInstance().getRecipeByRecipeItemId(item.getId());
if (rp == null)
{
+ activeChar.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
return false;
}
@@ -63,15 +64,15 @@ public class Recipes implements IItemHandler
boolean recipeLimit = false;
if (rp.isDwarvenRecipe())
{
- canCraft = activeChar.hasDwarvenCraft();
- recipeLevel = (rp.getLevel() > activeChar.getDwarvenCraft());
- recipeLimit = (activeChar.getDwarvenRecipeBook().length >= activeChar.getDwarfRecipeLimit());
+ canCraft = activeChar.getCreateItemLevel() > 0;
+ recipeLevel = (rp.getLevel() > activeChar.getCreateItemLevel());
+ recipeLimit = (activeChar.getDwarvenRecipeBook().size() >= activeChar.getDwarfRecipeLimit());
}
else
{
- canCraft = activeChar.hasCommonCraft();
- recipeLevel = (rp.getLevel() > activeChar.getCommonCraft());
- recipeLimit = (activeChar.getCommonRecipeBook().length >= activeChar.getCommonRecipeLimit());
+ canCraft = activeChar.getCreateCommonItemLevel() > 0;
+ recipeLevel = (rp.getLevel() > activeChar.getCreateCommonItemLevel());
+ recipeLimit = (activeChar.getCommonRecipeBook().size() >= activeChar.getCommonRecipeLimit());
}
if (!canCraft)
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 1e34a0d148..766844c759 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -119,7 +119,7 @@ public final class SocialAction implements IPlayerActionHandler
}
SystemMessage sm;
- if (player.isInStoreMode() || player.isInCraftMode())
+ if (player.isInStoreMode() || player.isCrafting())
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_PRIVATE_STORE_MODE_OR_IN_A_BATTLE_AND_CANNOT_BE_REQUESTED_FOR_A_COUPLE_ACTION);
sm.addPcName(player);
@@ -198,7 +198,7 @@ public final class SocialAction implements IPlayerActionHandler
// Checks for partner.
final L2PcInstance partner = target.getActingPlayer();
- if (partner.isInStoreMode() || partner.isInCraftMode())
+ if (partner.isInStoreMode() || partner.isCrafting())
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_PRIVATE_STORE_MODE_OR_IN_A_BATTLE_AND_CANNOT_BE_REQUESTED_FOR_A_COUPLE_ACTION);
sm.addPcName(partner);
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00100-00199.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00100-00199.xml
index 4c6466021c..f84f600ad1 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00100-00199.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00100-00199.xml
@@ -2727,6 +2727,27 @@
P
5
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00200-00299.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00200-00299.xml
index 78e7b47318..ef9977ac2f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00200-00299.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/00200-00299.xml
@@ -2434,6 +2434,22 @@
P
5
+
+
+
+ D
+ C
+ B
+ A
+ S
+ S80
+ S80
+ R
+ R95
+ R99
+
+
+
@@ -2615,6 +2631,18 @@
P
5
+
+
+
+ D
+ C
+ B
+ A
+ S
+ R
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/01300-01399.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/01300-01399.xml
index 60f0c36643..490d054c7e 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/01300-01399.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/01300-01399.xml
@@ -666,6 +666,22 @@
P
5
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/10300-10399.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/10300-10399.xml
index b752c643f4..1b64d26c36 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/10300-10399.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/10300-10399.xml
@@ -509,10 +509,25 @@
-
icon.skill10312
+
+ 85
+ 90
+ 95
+ 99
+
P
+
+
+
+ 2.4
+ 3.8
+ 4.2
+ 5.4
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/22000-22099.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/22000-22099.xml
index 9b757cf870..d0c88e95f3 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/22000-22099.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/22000-22099.xml
@@ -1268,10 +1268,10 @@
-
+
3
5
-
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/26000-26099.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/26000-26099.xml
index c4badadcad..3ab9f257c0 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/26000-26099.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/26000-26099.xml
@@ -1320,13 +1320,13 @@
-
+
1
2
3
4
5
-
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/documentation.txt b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/documentation.txt
index c4f6ad75ed..a9b94b0bf3 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/documentation.txt
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/skills/documentation.txt
@@ -59,12 +59,16 @@ CpHealOverTime: Increases current CP by a given amount over time.
CpHealPercent: Increases current CP by a given percentage amount.
Cp: Increases current CP by a static amount.
CpRegen: CP Regeneration stat.
+CraftingCritical: Crafting critical stat.
+CreateCommonItem: Allows the player to create common recipe items up to a certain level.
+CreateItem: Allows the player to create dwarven recipe items up to a certain level.
CreateItemRandom: Creates an item randomly from a given list. All extractable items with chances to get different items are using this effect.
CriticalDamage: Critical Damage stat.
CriticalDamagePosition: Critical Damage depending on position stat.
CriticalRate: Critical Rate stat.
CriticalRatePositionBonus: Critical Rate depending on position stat. Ignores the critical rate cap of 500.
CrystalGradeModify: Sets your Expertise Grade level. With this effect you can make lv. 40 player (C Grade) to wear S grade.
+Crystallize: Allows the player to crystallize items up to a certain grade.
CubicMastery: Max cubics stat.
DamageBlock: Blocks Hp or Mp damage/heal.
DamageShield: Reflect damage percentage stat.
@@ -233,6 +237,7 @@ ReflectMagic: Deflects magical damage back to the attacker.
ReflectSkill: Deflects physical/magical debuffs back to the attacker.
RefuelAirship: Increases Airship's fuel.
Relax: Sits down and increases HP regeneration until full.
+RemoveEquipPenalty: Removes equipment grade penalty. Its the base effect for the grade penalty mechanics.
ResetInstanceEntry: Resets instance re-entry time. (l2jmobius)
ResistAbnormalByCategory: Buff/debuff resist stat.
ResistDDMagic: Magic resist stat (magic attack 50% effective or 1 damage)
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/Recipes.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/Recipes.xsd
index 52c9af31ff..ffa4478bef 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/Recipes.xsd
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/Recipes.xsd
@@ -2,88 +2,68 @@
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/skills.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/skills.xsd
index 2b9bb3042d..24f4246eb5 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/skills.xsd
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/skills.xsd
@@ -1197,6 +1197,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2037,21 +2052,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/RecipeController.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/RecipeController.java
deleted file mode 100644
index 0bd69dc604..0000000000
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/RecipeController.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Logger;
-
-import com.l2jmobius.Config;
-import com.l2jmobius.commons.util.Rnd;
-import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
-import com.l2jmobius.gameserver.datatables.ItemTable;
-import com.l2jmobius.gameserver.enums.StatType;
-import com.l2jmobius.gameserver.enums.StatusUpdateType;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
-import com.l2jmobius.gameserver.model.L2RecipeInstance;
-import com.l2jmobius.gameserver.model.L2RecipeList;
-import com.l2jmobius.gameserver.model.L2RecipeStatInstance;
-import com.l2jmobius.gameserver.model.TempItem;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
-import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
-import com.l2jmobius.gameserver.model.items.L2Item;
-import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
-import com.l2jmobius.gameserver.model.skills.CommonSkill;
-import com.l2jmobius.gameserver.model.skills.Skill;
-import com.l2jmobius.gameserver.model.stats.Stats;
-import com.l2jmobius.gameserver.network.SystemMessageId;
-import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
-import com.l2jmobius.gameserver.network.serverpackets.ExUserInfoInvenWeight;
-import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
-import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
-import com.l2jmobius.gameserver.network.serverpackets.RecipeItemMakeInfo;
-import com.l2jmobius.gameserver.network.serverpackets.RecipeShopItemInfo;
-import com.l2jmobius.gameserver.network.serverpackets.SetupGauge;
-import com.l2jmobius.gameserver.network.serverpackets.StatusUpdate;
-import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
-import com.l2jmobius.gameserver.util.Util;
-
-public class RecipeController
-{
- protected static final Map _activeMakers = new ConcurrentHashMap<>();
-
- protected RecipeController()
- {
- }
-
- public void requestBookOpen(L2PcInstance player, boolean isDwarvenCraft)
- {
- // Check if player is trying to alter recipe book while engaged in manufacturing.
- if (!_activeMakers.containsKey(player.getObjectId()))
- {
- final RecipeBookItemList response = new RecipeBookItemList(isDwarvenCraft, player.getMaxMp());
- response.addRecipes(isDwarvenCraft ? player.getDwarvenRecipeBook() : player.getCommonRecipeBook());
- player.sendPacket(response);
- return;
- }
- player.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
- }
-
- public void requestMakeItemAbort(L2PcInstance player)
- {
- _activeMakers.remove(player.getObjectId()); // TODO: anything else here?
- }
-
- public void requestManufactureItem(L2PcInstance manufacturer, int recipeListId, L2PcInstance player)
- {
- final L2RecipeList recipeList = RecipeData.getInstance().getValidRecipeList(player, recipeListId);
- if (recipeList == null)
- {
- return;
- }
-
- final List dwarfRecipes = Arrays.asList(manufacturer.getDwarvenRecipeBook());
- final List commonRecipes = Arrays.asList(manufacturer.getCommonRecipeBook());
-
- if (!dwarfRecipes.contains(recipeList) && !commonRecipes.contains(recipeList))
- {
- Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
- return;
- }
-
- // Check if manufacturer is under manufacturing store or private store.
- if (Config.ALT_GAME_CREATION && _activeMakers.containsKey(manufacturer.getObjectId()))
- {
- player.sendPacket(SystemMessageId.PLEASE_CLOSE_THE_SETUP_WINDOW_FOR_YOUR_PRIVATE_WORKSHOP_OR_PRIVATE_STORE_AND_TRY_AGAIN);
- return;
- }
-
- final RecipeItemMaker maker = new RecipeItemMaker(manufacturer, recipeList, player);
- if (maker._isValid)
- {
- if (Config.ALT_GAME_CREATION)
- {
- _activeMakers.put(manufacturer.getObjectId(), maker);
- ThreadPoolManager.schedule(maker, 100);
- }
- else
- {
- maker.run();
- }
- }
- }
-
- public void requestMakeItem(L2PcInstance player, int recipeListId)
- {
- // Check if player is trying to operate a private store or private workshop while engaged in combat.
- if (player.isInCombat() || player.isInDuel())
- {
- player.sendPacket(SystemMessageId.WHILE_YOU_ARE_ENGAGED_IN_COMBAT_YOU_CANNOT_OPERATE_A_PRIVATE_STORE_OR_PRIVATE_WORKSHOP);
- return;
- }
-
- final L2RecipeList recipeList = RecipeData.getInstance().getValidRecipeList(player, recipeListId);
- if (recipeList == null)
- {
- return;
- }
-
- final List dwarfRecipes = Arrays.asList(player.getDwarvenRecipeBook());
- final List commonRecipes = Arrays.asList(player.getCommonRecipeBook());
-
- if (!dwarfRecipes.contains(recipeList) && !commonRecipes.contains(recipeList))
- {
- Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
- return;
- }
-
- // Check if player is busy (possible if alt game creation is enabled)
- if (Config.ALT_GAME_CREATION && _activeMakers.containsKey(player.getObjectId()))
- {
- final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1);
- sm.addItemName(recipeList.getItemId());
- sm.addString("You are busy creating.");
- player.sendPacket(sm);
- return;
- }
-
- final RecipeItemMaker maker = new RecipeItemMaker(player, recipeList, player);
- if (maker._isValid)
- {
- if (Config.ALT_GAME_CREATION)
- {
- _activeMakers.put(player.getObjectId(), maker);
- ThreadPoolManager.schedule(maker, 100);
- }
- else
- {
- maker.run();
- }
- }
- }
-
- private static class RecipeItemMaker implements Runnable
- {
- private static final Logger LOGGER = Logger.getLogger(RecipeItemMaker.class.getName());
- protected boolean _isValid;
- protected List _items = null;
- protected final L2RecipeList _recipeList;
- protected final L2PcInstance _player; // "crafter"
- protected final L2PcInstance _target; // "customer"
- protected final Skill _skill;
- protected final int _skillId;
- protected final int _skillLevel;
- protected int _creationPasses = 1;
- protected int _itemGrab;
- protected int _exp = -1;
- protected int _sp = -1;
- protected long _price;
- protected int _totalItems;
- protected int _delay;
-
- public RecipeItemMaker(L2PcInstance pPlayer, L2RecipeList pRecipeList, L2PcInstance pTarget)
- {
- _player = pPlayer;
- _target = pTarget;
- _recipeList = pRecipeList;
-
- _isValid = false;
- _skillId = _recipeList.isDwarvenRecipe() ? CommonSkill.CREATE_DWARVEN.getId() : CommonSkill.CREATE_COMMON.getId();
- _skillLevel = _player.getSkillLevel(_skillId);
- _skill = _player.getKnownSkill(_skillId);
-
- _player.isInCraftMode(true);
-
- if (_player.isAlikeDead())
- {
- _player.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- if (_target.isAlikeDead())
- {
- _target.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- if (_target.isProcessingTransaction())
- {
- _target.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- if (_player.isProcessingTransaction())
- {
- _player.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- // validate recipe list
- if (_recipeList.getRecipes().length == 0)
- {
- _player.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- // validate skill level
- if (_recipeList.getLevel() > _skillLevel)
- {
- _player.sendPacket(ActionFailed.STATIC_PACKET);
- abort();
- return;
- }
-
- // check that customer can afford to pay for creation services
- if (_player != _target)
- {
- final L2ManufactureItem item = _player.getManufactureItems().get(_recipeList.getId());
- if (item != null)
- {
- _price = item.getCost();
- if (_target.getAdena() < _price) // check price
- {
- _target.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
- abort();
- return;
- }
- }
- }
-
- // make temporary items
- _items = listItems(false);
- if (_items == null)
- {
- abort();
- return;
- }
-
- for (TempItem i : _items)
- {
- _totalItems += i.getQuantity();
- }
-
- // initial statUse checks
- if (!calculateStatUse(false, false))
- {
- abort();
- return;
- }
-
- // initial AltStatChange checks
- if (Config.ALT_GAME_CREATION)
- {
- calculateAltStatChange();
- }
-
- updateMakeInfo(true);
- updateCurMp();
- updateCurLoad();
-
- _player.isInCraftMode(false);
- _isValid = true;
- }
-
- @Override
- public void run()
- {
- if (!Config.IS_CRAFTING_ENABLED)
- {
- _target.sendMessage("Item creation is currently disabled.");
- abort();
- return;
- }
-
- if ((_player == null) || (_target == null))
- {
- LOGGER.warning("player or target == null (disconnected?), aborting" + _target + _player);
- abort();
- return;
- }
-
- if (!_player.isOnline() || !_target.isOnline())
- {
- LOGGER.warning("player or target is not online, aborting " + _target + _player);
- abort();
- return;
- }
-
- if (Config.ALT_GAME_CREATION && !_activeMakers.containsKey(_player.getObjectId()))
- {
- if (_target != _player)
- {
- _target.sendMessage("Manufacture aborted");
- _player.sendMessage("Manufacture aborted");
- }
- else
- {
- _player.sendMessage("Item creation aborted");
- }
-
- abort();
- return;
- }
-
- if (Config.ALT_GAME_CREATION && !_items.isEmpty())
- {
-
- if (!calculateStatUse(true, true))
- {
- return; // check stat use
- }
- updateCurMp(); // update craft window mp bar
-
- grabSomeItems(); // grab (equip) some more items with a nice msg to player
-
- // if still not empty, schedule another pass
- if (!_items.isEmpty())
- {
- _delay = (int) (Config.ALT_GAME_CREATION_SPEED * _player.getStat().getReuseTime(_skill) * GameTimeController.TICKS_PER_SECOND * GameTimeController.MILLIS_IN_TICK);
-
- // FIXME: please fix this packet to show crafting animation (somebody)
- final MagicSkillUse msk = new MagicSkillUse(_player, _skillId, _skillLevel, _delay, 0);
- _player.broadcastPacket(msk);
-
- _player.sendPacket(new SetupGauge(_player.getObjectId(), 0, _delay));
- ThreadPoolManager.schedule(this, 100 + _delay);
- }
- else
- {
- // for alt mode, sleep delay msec before finishing
- _player.sendPacket(new SetupGauge(_player.getObjectId(), 0, _delay));
-
- try
- {
- Thread.sleep(_delay);
- }
- catch (InterruptedException e)
- {
- }
- finally
- {
- finishCrafting();
- }
- }
- } // for old craft mode just finish
- else
- {
- finishCrafting();
- }
- }
-
- private void finishCrafting()
- {
- if (!Config.ALT_GAME_CREATION)
- {
- calculateStatUse(false, true);
- }
-
- // first take adena for manufacture
- if ((_target != _player) && (_price > 0)) // customer must pay for services
- {
- // attempt to pay for item
- final L2ItemInstance adenatransfer = _target.transferItem("PayManufacture", _target.getInventory().getAdenaInstance().getObjectId(), _price, _player.getInventory(), _player);
-
- if (adenatransfer == null)
- {
- _target.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
- abort();
- return;
- }
- }
-
- _items = listItems(true); // this line actually takes materials from inventory
- if (_items == null)
- {
- // handle possible cheaters here
- // (they click craft then try to get rid of items in order to get free craft)
- }
- else if ((Rnd.get(100) < _recipeList.getSuccessRate()) || _target.tryLuck())
- {
- rewardPlayer(_target); // and immediately puts created item in its place
- updateMakeInfo(true);
- }
- else
- {
- if (_target != _player)
- {
- SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.YOU_FAILED_TO_CREATE_S2_FOR_C1_AT_THE_PRICE_OF_S3_ADENA);
- msg.addString(_target.getName());
- msg.addItemName(_recipeList.getItemId());
- msg.addLong(_price);
- _player.sendPacket(msg);
-
- msg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_FAILED_TO_CREATE_S2_AT_THE_PRICE_OF_S3_ADENA);
- msg.addString(_player.getName());
- msg.addItemName(_recipeList.getItemId());
- msg.addLong(_price);
- _target.sendPacket(msg);
- }
- else
- {
- _target.sendPacket(SystemMessageId.YOU_FAILED_AT_MIXING_THE_ITEM);
- }
- updateMakeInfo(false);
- }
- // update load and mana bar of craft window
- updateCurMp();
- _activeMakers.remove(_player.getObjectId());
- _player.isInCraftMode(false);
- _target.sendItemList(false);
- }
-
- private void updateMakeInfo(boolean success)
- {
- if (_target == _player)
- {
- _target.sendPacket(new RecipeItemMakeInfo(_recipeList.getId(), _target, success));
- }
- else
- {
- _target.sendPacket(new RecipeShopItemInfo(_player, _recipeList.getId()));
- }
- }
-
- private void updateCurLoad()
- {
- _target.sendPacket(new ExUserInfoInvenWeight(_target));
- }
-
- private void updateCurMp()
- {
- final StatusUpdate su = new StatusUpdate(_target);
- su.addUpdate(StatusUpdateType.CUR_MP, (int) _target.getCurrentMp());
- _target.sendPacket(su);
- }
-
- private void grabSomeItems()
- {
- int grabItems = _itemGrab;
- while ((grabItems > 0) && !_items.isEmpty())
- {
- final TempItem item = _items.get(0);
-
- int count = item.getQuantity();
- if (count >= grabItems)
- {
- count = grabItems;
- }
-
- item.setQuantity(item.getQuantity() - count);
- if (item.getQuantity() <= 0)
- {
- _items.remove(0);
- }
- else
- {
- _items.set(0, item);
- }
-
- grabItems -= count;
-
- if (_target == _player)
- {
- final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EQUIPPED_S1_S2); // you equipped ...
- sm.addLong(count);
- sm.addItemName(item.getItemId());
- _player.sendPacket(sm);
- }
- else
- {
- _target.sendMessage("Manufacturer " + _player.getName() + " used " + count + " " + item.getItemName());
- }
- }
- }
-
- // AltStatChange parameters make their effect here
- private void calculateAltStatChange()
- {
- _itemGrab = _skillLevel;
-
- for (L2RecipeStatInstance altStatChange : _recipeList.getAltStatChange())
- {
- if (altStatChange.getType() == StatType.XP)
- {
- _exp = altStatChange.getValue();
- }
- else if (altStatChange.getType() == StatType.SP)
- {
- _sp = altStatChange.getValue();
- }
- else if (altStatChange.getType() == StatType.GIM)
- {
- _itemGrab *= altStatChange.getValue();
- }
- }
- // determine number of creation passes needed
- _creationPasses = (_totalItems / _itemGrab) + ((_totalItems % _itemGrab) != 0 ? 1 : 0);
- if (_creationPasses < 1)
- {
- _creationPasses = 1;
- }
- }
-
- // StatUse
- private boolean calculateStatUse(boolean isWait, boolean isReduce)
- {
- boolean ret = true;
- for (L2RecipeStatInstance statUse : _recipeList.getStatUse())
- {
- final double modifiedValue = statUse.getValue() / _creationPasses;
- if (statUse.getType() == StatType.HP)
- {
- // we do not want to kill the player, so its CurrentHP must be greater than the reduce value
- if (_player.getCurrentHp() <= modifiedValue)
- {
- // rest (wait for HP)
- if (Config.ALT_GAME_CREATION && isWait)
- {
- _player.sendPacket(new SetupGauge(_player.getObjectId(), 0, _delay));
- ThreadPoolManager.schedule(this, 100 + _delay);
- }
- else
- {
- _target.sendPacket(SystemMessageId.NOT_ENOUGH_HP);
- abort();
- }
- ret = false;
- }
- else if (isReduce)
- {
- _player.reduceCurrentHp(modifiedValue, _player, _skill);
- }
- }
- else if (statUse.getType() == StatType.MP)
- {
- if (_player.getCurrentMp() < modifiedValue)
- {
- // rest (wait for MP)
- if (Config.ALT_GAME_CREATION && isWait)
- {
- _player.sendPacket(new SetupGauge(_player.getObjectId(), 0, _delay));
- ThreadPoolManager.schedule(this, 100 + _delay);
- }
- else
- {
- _target.sendPacket(SystemMessageId.NOT_ENOUGH_MP);
- abort();
- }
- ret = false;
- }
- else if (isReduce)
- {
- _player.reduceCurrentMp(modifiedValue);
- }
- }
- else
- {
- // there is an unknown StatUse value
- _target.sendMessage("Recipe error!!!, please tell this to your GM.");
- ret = false;
- abort();
- }
- }
- return ret;
- }
-
- private List listItems(boolean remove)
- {
- final L2RecipeInstance[] recipes = _recipeList.getRecipes();
- final Inventory inv = _target.getInventory();
- final List materials = new ArrayList<>();
- SystemMessage sm;
-
- for (L2RecipeInstance recipe : recipes)
- {
- if (recipe.getQuantity() > 0)
- {
- final L2ItemInstance item = inv.getItemByItemId(recipe.getItemId());
- final long itemQuantityAmount = item == null ? 0 : item.getCount();
-
- // check materials
- if (itemQuantityAmount < recipe.getQuantity())
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_S2_MORE_S1_S);
- sm.addItemName(recipe.getItemId());
- sm.addLong(recipe.getQuantity() - itemQuantityAmount);
- _target.sendPacket(sm);
-
- abort();
- return null;
- }
-
- // make new temporary object, just for counting purposes
- materials.add(new TempItem(item, recipe.getQuantity()));
- }
- }
-
- if (remove)
- {
- for (TempItem tmp : materials)
- {
- inv.destroyItemByItemId("Manufacture", tmp.getItemId(), tmp.getQuantity(), _target, _player);
-
- if (tmp.getQuantity() > 1)
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_S_DISAPPEARED);
- sm.addItemName(tmp.getItemId());
- sm.addLong(tmp.getQuantity());
- _target.sendPacket(sm);
- }
- else
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DISAPPEARED);
- sm.addItemName(tmp.getItemId());
- _target.sendPacket(sm);
- }
- }
- }
- return materials;
- }
-
- private void abort()
- {
- updateMakeInfo(false);
- _player.isInCraftMode(false);
- _activeMakers.remove(_player.getObjectId());
- }
-
- private void rewardPlayer(L2PcInstance player)
- {
- final int rareProdId = _recipeList.getRareItemId();
- int itemId = _recipeList.getItemId();
- int itemCount = _recipeList.getCount();
- final L2Item template = ItemTable.getInstance().getTemplate(itemId);
-
- // check that the current recipe has a rare production or not
- if ((rareProdId != -1) && ((rareProdId == itemId) || Config.CRAFT_MASTERWORK))
- {
- if (Rnd.get(100) < _recipeList.getRarity())
- {
- itemId = rareProdId;
- itemCount = _recipeList.getRareCount();
- }
- }
-
- if (player.tryLuck())
- {
- itemCount *= 2;
- }
-
- _target.getInventory().addItem("Manufacture", itemId, itemCount, _target, _player);
-
- // inform customer of earned item
- SystemMessage sm = null;
- if (_target != _player)
- {
- // inform manufacturer of earned profit
- if (itemCount == 1)
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.S2_HAS_BEEN_CREATED_FOR_C1_AFTER_THE_PAYMENT_OF_S3_ADENA_WAS_RECEIVED);
- sm.addString(_target.getName());
- sm.addItemName(itemId);
- sm.addLong(_price);
- _player.sendPacket(sm);
-
- sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CREATED_S2_AFTER_RECEIVING_S3_ADENA);
- sm.addString(_player.getName());
- sm.addItemName(itemId);
- sm.addLong(_price);
- _target.sendPacket(sm);
- }
- else
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.S3_S2_S_HAVE_BEEN_CREATED_FOR_C1_AT_THE_PRICE_OF_S4_ADENA);
- sm.addString(_target.getName());
- sm.addInt(itemCount);
- sm.addItemName(itemId);
- sm.addLong(_price);
- _player.sendPacket(sm);
-
- sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CREATED_S3_S2_S_AT_THE_PRICE_OF_S4_ADENA);
- sm.addString(_player.getName());
- sm.addInt(itemCount);
- sm.addItemName(itemId);
- sm.addLong(_price);
- _target.sendPacket(sm);
- }
- }
-
- if (itemCount > 1)
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_S2_S1_S);
- sm.addItemName(itemId);
- sm.addLong(itemCount);
- _target.sendPacket(sm);
- }
- else
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1);
- sm.addItemName(itemId);
- _target.sendPacket(sm);
- }
-
- if (Config.ALT_GAME_CREATION)
- {
- final int recipeLevel = _recipeList.getLevel();
- if (_exp < 0)
- {
- _exp = template.getReferencePrice() * itemCount;
- _exp /= recipeLevel;
- }
- if (_sp < 0)
- {
- _sp = _exp / 10;
- }
- if (itemId == rareProdId)
- {
- _exp *= Config.ALT_GAME_CREATION_RARE_XPSP_RATE;
- _sp *= Config.ALT_GAME_CREATION_RARE_XPSP_RATE;
- }
-
- if (_exp < 0)
- {
- _exp = 0;
- }
- if (_sp < 0)
- {
- _sp = 0;
- }
-
- for (int i = _skillLevel; i > recipeLevel; i--)
- {
- _exp /= 4;
- _sp /= 4;
- }
-
- // Added multiplication of Creation speed with XP/SP gain slower crafting -> more XP,
- // faster crafting -> less XP you can use ALT_GAME_CREATION_XP_RATE/SP to modify XP/SP gained (default = 1)
- _player.addExpAndSp((int) _player.getStat().getValue(Stats.EXPSP_RATE, _exp * Config.ALT_GAME_CREATION_XP_RATE * Config.ALT_GAME_CREATION_SPEED), (int) _player.getStat().getValue(Stats.EXPSP_RATE, _sp * Config.ALT_GAME_CREATION_SP_RATE * Config.ALT_GAME_CREATION_SPEED));
- }
- updateMakeInfo(true); // success
- }
- }
-
- public static RecipeController getInstance()
- {
- return SingletonHolder._instance;
- }
-
- private static class SingletonHolder
- {
- protected static final RecipeController _instance = new RecipeController();
- }
-}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java
index f88260f46a..d34129376f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/sql/impl/OfflineTradersTable.java
@@ -21,6 +21,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -28,7 +31,6 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.TradeItem;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -133,12 +135,12 @@ public class OfflineTradersTable
continue;
}
title = pc.getStoreName();
- for (L2ManufactureItem i : pc.getManufactureItems().values())
+ for (Entry entry : pc.getManufactureItems().entrySet())
{
stm_items.setInt(1, pc.getObjectId());
- stm_items.setInt(2, i.getRecipeId());
+ stm_items.setInt(2, entry.getKey());
stm_items.setLong(3, 0);
- stm_items.setLong(4, i.getCost());
+ stm_items.setLong(4, entry.getValue());
stm_items.executeUpdate();
stm_items.clearParameters();
}
@@ -274,10 +276,12 @@ public class OfflineTradersTable
}
case MANUFACTURE:
{
+ final Map manufactureItems = new HashMap<>();
while (items.next())
{
- player.getManufactureItems().put(items.getInt(2), new L2ManufactureItem(items.getInt(2), items.getLong(4)));
+ manufactureItems.put(items.getInt(2), items.getLong(4));
}
+ player.setManufactureItems(manufactureItems);
player.setStoreName(rs.getString("title"));
break;
}
@@ -407,12 +411,12 @@ public class OfflineTradersTable
{
title = trader.getStoreName();
}
- for (L2ManufactureItem i : trader.getManufactureItems().values())
+ for (Entry entry : trader.getManufactureItems().entrySet())
{
stm3.setInt(1, trader.getObjectId());
- stm3.setInt(2, i.getRecipeId());
+ stm3.setInt(2, entry.getKey());
stm3.setLong(3, 0);
- stm3.setLong(4, i.getCost());
+ stm3.setLong(4, entry.getValue());
stm3.executeUpdate();
stm3.clearParameters();
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/RecipeData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/RecipeData.java
index b0b755ac92..80d9297e84 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/RecipeData.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/RecipeData.java
@@ -18,35 +18,33 @@ package com.l2jmobius.gameserver.data.xml.impl;
import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.commons.util.IGameXmlReader;
-import com.l2jmobius.gameserver.model.L2RecipeInstance;
-import com.l2jmobius.gameserver.model.L2RecipeList;
-import com.l2jmobius.gameserver.model.L2RecipeStatInstance;
+import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.model.StatsSet;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
+import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
/**
- * The Class RecipeData.
- * @author Zoey76
+ * @author Nik
*/
public class RecipeData implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(RecipeData.class.getName());
- private final Map _recipes = new HashMap<>();
+ private final Map _recipes = new HashMap<>();
- /**
- * Instantiates a new recipe data.
- */
protected RecipeData()
{
load();
@@ -63,205 +61,108 @@ public class RecipeData implements IGameXmlReader
@Override
public void parseDocument(Document doc, File f)
{
- // TODO: Cleanup checks enforced by XSD.
- final List recipePartList = new ArrayList<>();
- final List recipeStatUseList = new ArrayList<>();
- final List recipeAltStatChangeList = new ArrayList<>();
+ StatsSet set;
+ Node att;
+ NamedNodeMap attrs;
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
- RECIPES_FILE: for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
+ for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
- if ("item".equalsIgnoreCase(d.getNodeName()))
+ if ("recipe".equalsIgnoreCase(d.getNodeName()))
{
- recipePartList.clear();
- recipeStatUseList.clear();
- recipeAltStatChangeList.clear();
- final NamedNodeMap attrs = d.getAttributes();
- Node att;
- int id = -1;
- boolean haveRare = false;
- final StatsSet set = new StatsSet();
-
- att = attrs.getNamedItem("id");
- if (att == null)
+ attrs = d.getAttributes();
+ set = new StatsSet();
+ for (int i = 0; i < attrs.getLength(); i++)
{
- LOGGER.severe(getClass().getSimpleName() + ": Missing id for recipe item, skipping");
- continue;
+ att = attrs.item(i);
+ set.set(att.getNodeName(), att.getNodeValue());
}
- id = Integer.parseInt(att.getNodeValue());
- set.set("id", id);
- att = attrs.getNamedItem("recipeId");
- if (att == null)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Missing recipeId for recipe item id: " + id + ", skipping");
- continue;
- }
- set.set("recipeId", Integer.parseInt(att.getNodeValue()));
-
- att = attrs.getNamedItem("name");
- if (att == null)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Missing name for recipe item id: " + id + ", skipping");
- continue;
- }
- set.set("recipeName", att.getNodeValue());
-
- att = attrs.getNamedItem("craftLevel");
- if (att == null)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Missing level for recipe item id: " + id + ", skipping");
- continue;
- }
- set.set("craftLevel", Integer.parseInt(att.getNodeValue()));
-
- att = attrs.getNamedItem("type");
- if (att == null)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Missing type for recipe item id: " + id + ", skipping");
- continue;
- }
- set.set("isDwarvenRecipe", att.getNodeValue().equalsIgnoreCase("dwarven"));
-
- att = attrs.getNamedItem("successRate");
- if (att == null)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Missing successRate for recipe item id: " + id + ", skipping");
- continue;
- }
- set.set("successRate", Integer.parseInt(att.getNodeValue()));
+ final int recipeId = set.getInt("id");
+ List materials = Collections.emptyList();
+ List productGroup = Collections.emptyList();
+ List npcFee = Collections.emptyList();
+ final Map statUse = new HashMap<>();
for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling())
{
- if ("statUse".equalsIgnoreCase(c.getNodeName()))
+ if ("materials".equalsIgnoreCase(c.getNodeName()))
{
- final String statName = c.getAttributes().getNamedItem("name").getNodeValue();
- final int value = Integer.parseInt(c.getAttributes().getNamedItem("value").getNodeValue());
- try
- {
- recipeStatUseList.add(new L2RecipeStatInstance(statName, value));
- }
- catch (Exception e)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Error in StatUse parameter for recipe item id: " + id + ", skipping");
- continue RECIPES_FILE;
- }
+ materials = getItemList(c);
}
- else if ("altStatChange".equalsIgnoreCase(c.getNodeName()))
+ else if ("product".equalsIgnoreCase(c.getNodeName()))
{
- final String statName = c.getAttributes().getNamedItem("name").getNodeValue();
- final int value = Integer.parseInt(c.getAttributes().getNamedItem("value").getNodeValue());
- try
+ productGroup = getItemList(c).stream().map(ItemChanceHolder.class::cast).collect(Collectors.toList());
+ }
+ else if ("npcFee".equalsIgnoreCase(c.getNodeName()))
+ {
+ npcFee = getItemList(c);
+ }
+ else if ("statUse".equalsIgnoreCase(c.getNodeName()))
+ {
+ for (Node b = c.getFirstChild(); b != null; b = b.getNextSibling())
{
- recipeAltStatChangeList.add(new L2RecipeStatInstance(statName, value));
+ if ("stat".equalsIgnoreCase(b.getNodeName()))
+ {
+ StatusUpdateType stat = StatusUpdateType.valueOf(b.getAttributes().getNamedItem("name").getNodeValue());
+ double value = Double.parseDouble(b.getAttributes().getNamedItem("val").getNodeValue());
+ statUse.put(stat, value);
+ }
}
- catch (Exception e)
- {
- LOGGER.severe(getClass().getSimpleName() + ": Error in AltStatChange parameter for recipe item id: " + id + ", skipping");
- continue RECIPES_FILE;
- }
- }
- else if ("ingredient".equalsIgnoreCase(c.getNodeName()))
- {
- final int ingId = Integer.parseInt(c.getAttributes().getNamedItem("id").getNodeValue());
- final int ingCount = Integer.parseInt(c.getAttributes().getNamedItem("count").getNodeValue());
- recipePartList.add(new L2RecipeInstance(ingId, ingCount));
- }
- else if ("production".equalsIgnoreCase(c.getNodeName()))
- {
- set.set("itemId", Integer.parseInt(c.getAttributes().getNamedItem("id").getNodeValue()));
- set.set("count", Integer.parseInt(c.getAttributes().getNamedItem("count").getNodeValue()));
- }
- else if ("productionRare".equalsIgnoreCase(c.getNodeName()))
- {
- set.set("rareItemId", Integer.parseInt(c.getAttributes().getNamedItem("id").getNodeValue()));
- set.set("rareCount", Integer.parseInt(c.getAttributes().getNamedItem("count").getNodeValue()));
- set.set("rarity", Integer.parseInt(c.getAttributes().getNamedItem("rarity").getNodeValue()));
- haveRare = true;
}
}
- final L2RecipeList recipeList = new L2RecipeList(set, haveRare);
- for (L2RecipeInstance recipePart : recipePartList)
- {
- recipeList.addRecipe(recipePart);
- }
- for (L2RecipeStatInstance recipeStatUse : recipeStatUseList)
- {
- recipeList.addStatUse(recipeStatUse);
- }
- for (L2RecipeStatInstance recipeAltStatChange : recipeAltStatChangeList)
- {
- recipeList.addAltStatChange(recipeAltStatChange);
- }
-
- _recipes.put(id, recipeList);
+ _recipes.put(recipeId, new RecipeHolder(set, materials, productGroup, npcFee, statUse));
}
}
}
}
}
- /**
- * Gets the recipe list.
- * @param listId the list id
- * @return the recipe list
- */
- public L2RecipeList getRecipeList(int listId)
+ private List getItemList(Node c)
{
- return _recipes.get(listId);
- }
-
- /**
- * Gets the recipe by item id.
- * @param itemId the item id
- * @return the recipe by item id
- */
- public L2RecipeList getRecipeByItemId(int itemId)
- {
- for (L2RecipeList find : _recipes.values())
+ final List items = new ArrayList<>();
+ for (Node b = c.getFirstChild(); b != null; b = b.getNextSibling())
{
- if (find.getRecipeId() == itemId)
+ if ("item".equalsIgnoreCase(b.getNodeName()))
{
- return find;
+ int itemId = Integer.parseInt(b.getAttributes().getNamedItem("id").getNodeValue());
+ long itemCount = Long.parseLong(b.getAttributes().getNamedItem("count").getNodeValue());
+
+ if (b.getAttributes().getNamedItem("chance") != null)
+ {
+ double chance = Double.parseDouble(b.getAttributes().getNamedItem("chance").getNodeValue());
+ items.add(new ItemChanceHolder(itemId, chance, itemCount));
+ }
+ else
+ {
+ items.add(new ItemHolder(itemId, itemCount));
+ }
}
}
- return null;
+
+ return items;
}
/**
- * Gets the all item ids.
- * @return the all item ids
+ * Gets the recipe by recipe item id.
+ * @param itemId the recipe's item id
+ * @return {@code RecipeHolder} for the given recipe item id {@code null} if there is no recipe data connected with this recipe item id.
*/
- public int[] getAllItemIds()
+ public RecipeHolder getRecipeByRecipeItemId(int itemId)
{
- final int[] idList = new int[_recipes.size()];
- int i = 0;
- for (L2RecipeList rec : _recipes.values())
- {
- idList[i++] = rec.getRecipeId();
- }
- return idList;
+ return _recipes.values().stream().filter(r -> r.getItemId() == itemId).findAny().orElse(null);
}
/**
- * Gets the valid recipe list.
- * @param player the player
- * @param id the recipe list id
- * @return the valid recipe list
+ * @param recipeId the id of the recipe, NOT the recipe item id.
+ * @return {@code RecipeHolder} containing all the info necessary for crafting a recipe or {@code null} if there is no data for this recipeId.
*/
- public L2RecipeList getValidRecipeList(L2PcInstance player, int id)
+ public RecipeHolder getRecipe(int recipeId)
{
- final L2RecipeList recipeList = _recipes.get(id);
- if ((recipeList == null) || (recipeList.getRecipes().length == 0))
- {
- player.sendMessage("No recipe for: " + id);
- player.isInCraftMode(false);
- return null;
- }
- return recipeList;
+ return _recipes.get(recipeId);
}
/**
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/engines/DocumentBase.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/engines/DocumentBase.java
index 0050c0a281..6f7ebc5cf9 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/engines/DocumentBase.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/engines/DocumentBase.java
@@ -74,7 +74,6 @@ import com.l2jmobius.gameserver.model.conditions.ConditionPlayerCloakStatus;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerCp;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerDualclass;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerFlyMounted;
-import com.l2jmobius.gameserver.model.conditions.ConditionPlayerGrade;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerHasCastle;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerHasClanHall;
import com.l2jmobius.gameserver.model.conditions.ConditionPlayerHasFort;
@@ -511,12 +510,6 @@ public abstract class DocumentBase
cond = joinAnd(cond, new ConditionPlayerCp(cp));
break;
}
- case "grade":
- {
- final int expIndex = Integer.decode(getValue(a.getNodeValue(), template));
- cond = joinAnd(cond, new ConditionPlayerGrade(expIndex));
- break;
- }
case "pkcount":
{
final int expIndex = Integer.decode(getValue(a.getNodeValue(), template));
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/Fishing.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/Fishing.java
index edbfe1412c..157a085fb2 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/Fishing.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/Fishing.java
@@ -182,7 +182,7 @@ public class Fishing
return;
}
- if (_player.isInCraftMode() || _player.isInStoreMode())
+ if (_player.isCrafting() || _player.isInStoreMode())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHILE_USING_A_RECIPE_BOOK_PRIVATE_WORKSHOP_OR_PRIVATE_STORE);
_player.sendPacket(ActionFailed.STATIC_PACKET);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeInstance.java
deleted file mode 100644
index 469b9843cc..0000000000
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeInstance.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver.model;
-
-/**
- * This class describes a RecipeList component (1 line of the recipe : Item-Quantity needed).
- */
-public class L2RecipeInstance
-{
- /** The Identifier of the item needed in the L2RecipeInstance */
- private final int _itemId;
-
- /** The item quantity needed in the L2RecipeInstance */
- private final int _quantity;
-
- /**
- * Constructor of L2RecipeInstance (create a new line in a RecipeList).
- * @param itemId
- * @param quantity
- */
- public L2RecipeInstance(int itemId, int quantity)
- {
- _itemId = itemId;
- _quantity = quantity;
- }
-
- /**
- * @return the Identifier of the L2RecipeInstance Item needed.
- */
- public int getItemId()
- {
- return _itemId;
- }
-
- /**
- * @return the Item quantity needed of the L2RecipeInstance.
- */
- public int getQuantity()
- {
- return _quantity;
- }
-
-}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeList.java
deleted file mode 100644
index 672503228f..0000000000
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeList.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver.model;
-
-/**
- * This class describes a Recipe used by Dwarf to craft Item. All L2RecipeList are made of L2RecipeInstance (1 line of the recipe : Item-Quantity needed).
- */
-public class L2RecipeList
-{
- /** The table containing all L2RecipeInstance (1 line of the recipe : Item-Quantity needed) of the L2RecipeList */
- private L2RecipeInstance[] _recipes;
-
- /** The table containing all L2RecipeStatInstance for the statUse parameter of the L2RecipeList */
- private L2RecipeStatInstance[] _statUse;
-
- /** The table containing all L2RecipeStatInstance for the altStatChange parameter of the L2RecipeList */
- private L2RecipeStatInstance[] _altStatChange;
-
- /** The Identifier of the Instance */
- private final int _id;
-
- /** The crafting level needed to use this L2RecipeList */
- private final int _level;
-
- /** The Identifier of the L2RecipeList */
- private final int _recipeId;
-
- /** The name of the L2RecipeList */
- private final String _recipeName;
-
- /** The crafting success rate when using the L2RecipeList */
- private final int _successRate;
-
- /** The Identifier of the Item crafted with this L2RecipeList */
- private final int _itemId;
-
- /** The quantity of Item crafted when using this L2RecipeList */
- private final int _count;
-
- /** The Identifier of the Rare Item crafted with this L2RecipeList */
- private int _rareItemId;
-
- /** The quantity of Rare Item crafted when using this L2RecipeList */
- private int _rareCount;
-
- /** The chance of Rare Item crafted when using this L2RecipeList */
- private int _rarity;
-
- /** If this a common or a dwarven recipe */
- private final boolean _isDwarvenRecipe;
-
- /**
- * Constructor of L2RecipeList (create a new Recipe).
- * @param set
- * @param haveRare
- */
- public L2RecipeList(StatsSet set, boolean haveRare)
- {
- _recipes = new L2RecipeInstance[0];
- _statUse = new L2RecipeStatInstance[0];
- _altStatChange = new L2RecipeStatInstance[0];
- _id = set.getInt("id");
- _level = set.getInt("craftLevel");
- _recipeId = set.getInt("recipeId");
- _recipeName = set.getString("recipeName");
- _successRate = set.getInt("successRate");
- _itemId = set.getInt("itemId");
- _count = set.getInt("count");
- if (haveRare)
- {
- _rareItemId = set.getInt("rareItemId");
- _rareCount = set.getInt("rareCount");
- _rarity = set.getInt("rarity");
- }
- _isDwarvenRecipe = set.getBoolean("isDwarvenRecipe");
- }
-
- /**
- * Add a L2RecipeInstance to the L2RecipeList (add a line Item-Quantity needed to the Recipe).
- * @param recipe
- */
- public void addRecipe(L2RecipeInstance recipe)
- {
- final int len = _recipes.length;
- final L2RecipeInstance[] tmp = new L2RecipeInstance[len + 1];
- System.arraycopy(_recipes, 0, tmp, 0, len);
- tmp[len] = recipe;
- _recipes = tmp;
- }
-
- /**
- * Add a L2RecipeStatInstance of the statUse parameter to the L2RecipeList.
- * @param statUse
- */
- public void addStatUse(L2RecipeStatInstance statUse)
- {
- final int len = _statUse.length;
- final L2RecipeStatInstance[] tmp = new L2RecipeStatInstance[len + 1];
- System.arraycopy(_statUse, 0, tmp, 0, len);
- tmp[len] = statUse;
- _statUse = tmp;
- }
-
- /**
- * Add a L2RecipeStatInstance of the altStatChange parameter to the L2RecipeList.
- * @param statChange
- */
- public void addAltStatChange(L2RecipeStatInstance statChange)
- {
- final int len = _altStatChange.length;
- final L2RecipeStatInstance[] tmp = new L2RecipeStatInstance[len + 1];
- System.arraycopy(_altStatChange, 0, tmp, 0, len);
- tmp[len] = statChange;
- _altStatChange = tmp;
- }
-
- /**
- * @return the Identifier of the Instance.
- */
- public int getId()
- {
- return _id;
- }
-
- /**
- * @return the crafting level needed to use this L2RecipeList.
- */
- public int getLevel()
- {
- return _level;
- }
-
- /**
- * @return the Identifier of the L2RecipeList.
- */
- public int getRecipeId()
- {
- return _recipeId;
- }
-
- /**
- * @return the name of the L2RecipeList.
- */
- public String getRecipeName()
- {
- return _recipeName;
- }
-
- /**
- * @return the crafting success rate when using the L2RecipeList.
- */
- public int getSuccessRate()
- {
- return _successRate;
- }
-
- /**
- * @return the Identifier of the Item crafted with this L2RecipeList.
- */
- public int getItemId()
- {
- return _itemId;
- }
-
- /**
- * @return the quantity of Item crafted when using this L2RecipeList.
- */
- public int getCount()
- {
- return _count;
- }
-
- /**
- * @return the Identifier of the Rare Item crafted with this L2RecipeList.
- */
- public int getRareItemId()
- {
- return _rareItemId;
- }
-
- /**
- * @return the quantity of Rare Item crafted when using this L2RecipeList.
- */
- public int getRareCount()
- {
- return _rareCount;
- }
-
- /**
- * @return the chance of Rare Item crafted when using this L2RecipeList.
- */
- public int getRarity()
- {
- return _rarity;
- }
-
- /**
- * @return {@code true} if this a Dwarven recipe or {@code false} if its a Common recipe
- */
- public boolean isDwarvenRecipe()
- {
- return _isDwarvenRecipe;
- }
-
- /**
- * @return the table containing all L2RecipeInstance (1 line of the recipe : Item-Quantity needed) of the L2RecipeList.
- */
- public L2RecipeInstance[] getRecipes()
- {
- return _recipes;
- }
-
- /**
- * @return the table containing all L2RecipeStatInstance of the statUse parameter of the L2RecipeList.
- */
- public L2RecipeStatInstance[] getStatUse()
- {
- return _statUse;
- }
-
- /**
- * @return the table containing all L2RecipeStatInstance of the AltStatChange parameter of the L2RecipeList.
- */
- public L2RecipeStatInstance[] getAltStatChange()
- {
- return _altStatChange;
- }
-}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeStatInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeStatInstance.java
deleted file mode 100644
index ae06fa8c1b..0000000000
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2RecipeStatInstance.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver.model;
-
-import com.l2jmobius.gameserver.enums.StatType;
-
-/**
- * This class describes a RecipeList statUse and altStatChange component.
- */
-public class L2RecipeStatInstance
-{
- /** The Identifier of the statType */
- private final StatType _type;
-
- /** The value of the statType */
- private final int _value;
-
- /**
- * Constructor of L2RecipeStatInstance.
- * @param type
- * @param value
- */
- public L2RecipeStatInstance(String type, int value)
- {
- _type = Enum.valueOf(StatType.class, type);
- _value = value;
- }
-
- /**
- * @return the the type of the L2RecipeStatInstance.
- */
- public StatType getType()
- {
- return _type;
- }
-
- /**
- * @return the value of the L2RecipeStatInstance.
- */
- public int getValue()
- {
- return _value;
- }
-
-}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Seed.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Seed.java
index ced8554e47..e099179153 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Seed.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Seed.java
@@ -32,8 +32,8 @@ public final class L2Seed
private final boolean _isAlternative;
private final int _limitSeeds;
private final int _limitCrops;
- private final int _seedReferencePrice;
- private final int _cropReferencePrice;
+ private final long _seedReferencePrice;
+ private final long _cropReferencePrice;
public L2Seed(StatsSet set)
{
@@ -99,27 +99,27 @@ public final class L2Seed
return _limitCrops * Config.RATE_DROP_MANOR;
}
- public final int getSeedReferencePrice()
+ public final long getSeedReferencePrice()
{
return _seedReferencePrice;
}
- public final int getSeedMaxPrice()
+ public final long getSeedMaxPrice()
{
return _seedReferencePrice * 10;
}
- public final int getSeedMinPrice()
+ public final long getSeedMinPrice()
{
return (int) (_seedReferencePrice * 0.6);
}
- public final int getCropReferencePrice()
+ public final long getCropReferencePrice()
{
return _cropReferencePrice;
}
- public final int getCropMaxPrice()
+ public final long getCropMaxPrice()
{
return _cropReferencePrice * 10;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/TempItem.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/TempItem.java
index fa918cfc55..db4b2f817f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/TempItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/TempItem.java
@@ -28,7 +28,7 @@ public final class TempItem
{
private final int _itemId;
private int _quantity;
- private final int _referencePrice;
+ private final long _referencePrice;
private final String _itemName;
/**
@@ -60,7 +60,7 @@ public final class TempItem
_quantity = quantity;
}
- public int getReferencePrice()
+ public long getReferencePrice()
{
return _referencePrice;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index 77605ef09b..32f9b286f2 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -27,7 +27,6 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -46,11 +45,11 @@ import java.util.stream.Collectors;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
+import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ItemsAutoDestroy;
import com.l2jmobius.gameserver.LoginServerThread;
-import com.l2jmobius.gameserver.RecipeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.L2CharacterAI;
@@ -63,6 +62,7 @@ import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.sql.impl.CharSummonTable;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.CategoryData;
import com.l2jmobius.gameserver.data.xml.impl.ClassListData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
@@ -85,6 +85,7 @@ import com.l2jmobius.gameserver.enums.GroupType;
import com.l2jmobius.gameserver.enums.HtmlActionScope;
import com.l2jmobius.gameserver.enums.IllegalActionPunishmentType;
import com.l2jmobius.gameserver.enums.InstanceType;
+import com.l2jmobius.gameserver.enums.ItemGrade;
import com.l2jmobius.gameserver.enums.MountType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
@@ -116,6 +117,7 @@ import com.l2jmobius.gameserver.instancemanager.MatchingRoomManager;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
import com.l2jmobius.gameserver.instancemanager.PunishmentManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
+import com.l2jmobius.gameserver.instancemanager.SellBuffsManager;
import com.l2jmobius.gameserver.instancemanager.SiegeManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.ArenaParticipantsHolder;
@@ -128,7 +130,6 @@ import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.L2CommandChannel;
import com.l2jmobius.gameserver.model.L2ContactList;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2Party.MessageType;
@@ -136,7 +137,6 @@ import com.l2jmobius.gameserver.model.L2PetData;
import com.l2jmobius.gameserver.model.L2PetLevelData;
import com.l2jmobius.gameserver.model.L2PremiumItem;
import com.l2jmobius.gameserver.model.L2Radar;
-import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.L2Request;
import com.l2jmobius.gameserver.model.L2SkillLearn;
import com.l2jmobius.gameserver.model.L2World;
@@ -163,7 +163,6 @@ import com.l2jmobius.gameserver.model.actor.stat.PcStat;
import com.l2jmobius.gameserver.model.actor.status.PcStatus;
import com.l2jmobius.gameserver.model.actor.tasks.player.DismountTask;
import com.l2jmobius.gameserver.model.actor.tasks.player.FameTask;
-import com.l2jmobius.gameserver.model.actor.tasks.player.GameGuardCheckTask;
import com.l2jmobius.gameserver.model.actor.tasks.player.HennaDurationTask;
import com.l2jmobius.gameserver.model.actor.tasks.player.InventoryEnableTask;
import com.l2jmobius.gameserver.model.actor.tasks.player.PetFeedTask;
@@ -180,8 +179,6 @@ import com.l2jmobius.gameserver.model.actor.tasks.player.WaterTask;
import com.l2jmobius.gameserver.model.actor.templates.L2PcTemplate;
import com.l2jmobius.gameserver.model.actor.transform.Transform;
import com.l2jmobius.gameserver.model.base.ClassId;
-import com.l2jmobius.gameserver.model.base.ClassLevel;
-import com.l2jmobius.gameserver.model.base.PlayerClass;
import com.l2jmobius.gameserver.model.base.SubClass;
import com.l2jmobius.gameserver.model.ceremonyofchaos.CeremonyOfChaosEvent;
import com.l2jmobius.gameserver.model.cubic.CubicInstance;
@@ -215,6 +212,7 @@ import com.l2jmobius.gameserver.model.holders.MonsterBookCardHolder;
import com.l2jmobius.gameserver.model.holders.MonsterBookRewardHolder;
import com.l2jmobius.gameserver.model.holders.MovieHolder;
import com.l2jmobius.gameserver.model.holders.PlayerEventHolder;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.model.holders.SellBuffHolder;
import com.l2jmobius.gameserver.model.holders.SkillUseHolder;
import com.l2jmobius.gameserver.model.holders.TrainingHolder;
@@ -235,6 +233,7 @@ import com.l2jmobius.gameserver.model.items.L2Weapon;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.items.type.ActionType;
import com.l2jmobius.gameserver.model.items.type.ArmorType;
+import com.l2jmobius.gameserver.model.items.type.CrystalType;
import com.l2jmobius.gameserver.model.items.type.EtcItemType;
import com.l2jmobius.gameserver.model.items.type.WeaponType;
import com.l2jmobius.gameserver.model.matching.MatchingRoom;
@@ -293,7 +292,6 @@ import com.l2jmobius.gameserver.network.serverpackets.ExUseSharedGroupItem;
import com.l2jmobius.gameserver.network.serverpackets.ExUserInfoAbnormalVisualEffect;
import com.l2jmobius.gameserver.network.serverpackets.ExUserInfoCubic;
import com.l2jmobius.gameserver.network.serverpackets.ExUserInfoInvenWeight;
-import com.l2jmobius.gameserver.network.serverpackets.GameGuardQuery;
import com.l2jmobius.gameserver.network.serverpackets.GetOnVehicle;
import com.l2jmobius.gameserver.network.serverpackets.HennaInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
@@ -523,13 +521,13 @@ public final class L2PcInstance extends L2Playable
private AdminTeleportType _teleportType = AdminTeleportType.NORMAL;
private boolean _inCrystallize;
- private boolean _inCraftMode;
+ private volatile boolean _isCrafting;
private long _offlineShopStart = 0;
/** The table containing all L2RecipeList of the L2PcInstance */
- private final Map _dwarvenRecipeBook = new ConcurrentSkipListMap<>();
- private final Map _commonRecipeBook = new ConcurrentSkipListMap<>();
+ private final Map _dwarvenRecipeBook = new ConcurrentSkipListMap<>();
+ private final Map _commonRecipeBook = new ConcurrentSkipListMap<>();
/** Premium Items */
private final Map _premiumItems = new ConcurrentSkipListMap<>();
@@ -564,7 +562,7 @@ public final class L2PcInstance extends L2Playable
private TradeList _activeTradeList;
private ItemContainer _activeWarehouse;
- private volatile Map _manufactureItems;
+ private volatile Map _manufactureItems;
private String _storeName = "";
private TradeList _sellList;
private TradeList _buyList;
@@ -619,8 +617,6 @@ public final class L2PcInstance extends L2Playable
// after Freya players can control more than one tamed beast
private volatile Set _tamedBeast = null;
- private boolean _minimapAllowed = false;
-
// client radar
// TODO: This needs to be better integrated and saved/loaded
private final L2Radar _radar;
@@ -712,6 +708,10 @@ public final class L2PcInstance extends L2Playable
// private byte _updateKnownCounter = 0;
+ private int _createItemLevel;
+ private int _createCommonItemLevel;
+ private ItemGrade _crystallizeGrade = ItemGrade.NONE;
+ private CrystalType _expertiseLevel = CrystalType.NONE;
private int _expertiseArmorPenalty = 0;
private int _expertiseWeaponPenalty = 0;
private int _expertisePenaltyBonus = 0;
@@ -1259,14 +1259,14 @@ public final class L2PcInstance extends L2Playable
return getPrivateStoreType() != PrivateStoreType.NONE;
}
- public boolean isInCraftMode()
+ public boolean isCrafting()
{
- return _inCraftMode;
+ return _isCrafting;
}
- public void isInCraftMode(boolean b)
+ public void setIsCrafting(boolean isCrafting)
{
- _inCraftMode = b;
+ _isCrafting = isCrafting;
}
/**
@@ -1304,17 +1304,17 @@ public final class L2PcInstance extends L2Playable
/**
* @return a table containing all Common L2RecipeList of the L2PcInstance.
*/
- public L2RecipeList[] getCommonRecipeBook()
+ public Collection getCommonRecipeBook()
{
- return _commonRecipeBook.values().toArray(new L2RecipeList[_commonRecipeBook.values().size()]);
+ return _commonRecipeBook.values();
}
/**
* @return a table containing all Dwarf L2RecipeList of the L2PcInstance.
*/
- public L2RecipeList[] getDwarvenRecipeBook()
+ public Collection getDwarvenRecipeBook()
{
- return _dwarvenRecipeBook.values().toArray(new L2RecipeList[_dwarvenRecipeBook.values().size()]);
+ return _dwarvenRecipeBook.values();
}
/**
@@ -1322,7 +1322,7 @@ public final class L2PcInstance extends L2Playable
* @param recipe The L2RecipeList to add to the _recipebook
* @param saveToDb
*/
- public void registerCommonRecipeList(L2RecipeList recipe, boolean saveToDb)
+ public void registerCommonRecipeList(RecipeHolder recipe, boolean saveToDb)
{
_commonRecipeBook.put(recipe.getId(), recipe);
@@ -1337,7 +1337,7 @@ public final class L2PcInstance extends L2Playable
* @param recipe The L2RecipeList to add to the _recipebook
* @param saveToDb
*/
- public void registerDwarvenRecipeList(L2RecipeList recipe, boolean saveToDb)
+ public void registerDwarvenRecipeList(RecipeHolder recipe, boolean saveToDb)
{
_dwarvenRecipeBook.put(recipe.getId(), recipe);
@@ -1867,29 +1867,39 @@ public final class L2PcInstance extends L2Playable
}
/**
- * @return True if the L2PcInstance can Craft Dwarven Recipes.
+ * @return the maximum dwarven recipe level this character can craft.
*/
- public boolean hasDwarvenCraft()
+ public int getCreateItemLevel()
{
- return getSkillLevel(CommonSkill.CREATE_DWARVEN.getId()) >= 1;
+ return _createItemLevel;
}
- public int getDwarvenCraft()
+ public void setCreateItemLevel(int createItemLevel)
{
- return getSkillLevel(CommonSkill.CREATE_DWARVEN.getId());
+ _createItemLevel = createItemLevel;
}
/**
- * @return True if the L2PcInstance can Craft Dwarven Recipes.
+ * @return the maximum common recipe level this character can craft.
*/
- public boolean hasCommonCraft()
+ public int getCreateCommonItemLevel()
{
- return getSkillLevel(CommonSkill.CREATE_COMMON.getId()) >= 1;
+ return _createCommonItemLevel;
}
- public int getCommonCraft()
+ public void setCreateCommonItemLevel(int createCommonItemLevel)
{
- return getSkillLevel(CommonSkill.CREATE_COMMON.getId());
+ _createCommonItemLevel = createCommonItemLevel;
+ }
+
+ public ItemGrade getCrystallizeGrade()
+ {
+ return _crystallizeGrade;
+ }
+
+ public void setCrystallizeGrade(ItemGrade crystallizeGrade)
+ {
+ _crystallizeGrade = crystallizeGrade != null ? crystallizeGrade : ItemGrade.NONE;
}
/**
@@ -2073,11 +2083,7 @@ public final class L2PcInstance extends L2Playable
public int getWeightPenalty()
{
- if (_dietMode)
- {
- return 0;
- }
- return _curWeightPenalty;
+ return _dietMode ? 0 : _curWeightPenalty;
}
/**
@@ -2141,37 +2147,26 @@ public final class L2PcInstance extends L2Playable
return;
}
- final int expertiseLevel = getExpertiseLevel();
+ final CrystalType expertiseLevel = getExpertiseLevel().plusLevel(getExpertisePenaltyBonus());
int armorPenalty = 0;
int weaponPenalty = 0;
- int crystaltype;
- for (L2ItemInstance item : getInventory().getItems())
+ for (L2ItemInstance item : getInventory().getPaperdollItems(item -> (item != null) && ((item.getItemType() != EtcItemType.ARROW) && (item.getItemType() != EtcItemType.BOLT)) && item.getItem().getCrystalType().isGreater(expertiseLevel)))
{
- if ((item != null) && item.isEquipped() && ((item.getItemType() != EtcItemType.ARROW) && (item.getItemType() != EtcItemType.BOLT)))
+ if (item.isArmor())
{
- crystaltype = item.getItem().getCrystalType().getId();
- if (crystaltype > expertiseLevel)
- {
- if (item.isWeapon() && (crystaltype > weaponPenalty))
- {
- weaponPenalty = crystaltype;
- }
- else if (crystaltype > armorPenalty)
- {
- armorPenalty = crystaltype;
- }
- }
+ // Armor penalty level increases depending on amount of penalty armors equipped, not grade level difference.
+ armorPenalty = CommonUtil.constrain(armorPenalty + 1, 0, 4);
+ }
+ else
+ {
+ // Weapon penalty level increases based on grade difference.
+ weaponPenalty = CommonUtil.constrain(item.getItem().getCrystalType().getLevel() - expertiseLevel.getLevel(), 0, 4);
}
}
boolean changed = false;
- final int bonus = getExpertisePenaltyBonus();
-
- // calc weapon penalty
- weaponPenalty = weaponPenalty - expertiseLevel - bonus;
- weaponPenalty = Math.min(Math.max(weaponPenalty, 0), 4);
if ((getExpertiseWeaponPenalty() != weaponPenalty) || (getSkillLevel(CommonSkill.WEAPON_GRADE_PENALTY.getId()) != weaponPenalty))
{
@@ -2182,15 +2177,11 @@ public final class L2PcInstance extends L2Playable
}
else
{
- removeSkill(getKnownSkill(CommonSkill.WEAPON_GRADE_PENALTY.getId()), false, true);
+ removeSkill(CommonSkill.WEAPON_GRADE_PENALTY.getId(), true);
}
changed = true;
}
- // calc armor penalty
- armorPenalty = armorPenalty - expertiseLevel - bonus;
- armorPenalty = Math.min(Math.max(armorPenalty, 0), 4);
-
if ((getExpertiseArmorPenalty() != armorPenalty) || (getSkillLevel(CommonSkill.ARMOR_GRADE_PENALTY.getId()) != armorPenalty))
{
_expertiseArmorPenalty = armorPenalty;
@@ -2200,13 +2191,14 @@ public final class L2PcInstance extends L2Playable
}
else
{
- removeSkill(getKnownSkill(CommonSkill.ARMOR_GRADE_PENALTY.getId()), false, true);
+ removeSkill(CommonSkill.ARMOR_GRADE_PENALTY.getId(), true);
}
changed = true;
}
if (changed)
{
+ sendSkillList(); // Update expertise penalty icon in skill list.
sendPacket(new EtcStatusUpdate(this));
}
}
@@ -2383,7 +2375,7 @@ public final class L2PcInstance extends L2Playable
try
{
- if ((getLvlJoinedAcademy() != 0) && (_clan != null) && (PlayerClass.values()[Id].getLevel() == ClassLevel.THIRD))
+ if ((getLvlJoinedAcademy() != 0) && (_clan != null) && CategoryData.getInstance().isInCategory(CategoryType.THIRD_CLASS_GROUP, Id))
{
if (getLvlJoinedAcademy() <= 16)
{
@@ -2416,7 +2408,7 @@ public final class L2PcInstance extends L2Playable
setTarget(this);
broadcastPacket(new MagicSkillUse(this, 5103, 1, 1000, 0));
setClassTemplate(Id);
- if (getClassId().level() == 3)
+ if (isInCategory(CategoryType.FOURTH_CLASS_GROUP))
{
sendPacket(SystemMessageId.CONGRATULATIONS_YOU_VE_COMPLETED_YOUR_THIRD_CLASS_TRANSFER_QUEST);
}
@@ -2710,18 +2702,6 @@ public final class L2PcInstance extends L2Playable
return _radar;
}
- /* Return true if Hellbound minimap allowed */
- public boolean isMinimapAllowed()
- {
- return _minimapAllowed;
- }
-
- /* Enable or disable minimap on Hellbound */
- public void setMinimapAllowed(boolean b)
- {
- _minimapAllowed = b;
- }
-
/**
* @return the SP amount of the L2PcInstance.
*/
@@ -4355,6 +4335,8 @@ public final class L2PcInstance extends L2Playable
return getClan().getAllyCrestId();
}
+ //@formatter:off
+ /*
public void queryGameGuard()
{
if (getClient() != null)
@@ -4364,9 +4346,10 @@ public final class L2PcInstance extends L2Playable
}
if (Config.GAMEGUARD_ENFORCE)
{
- ThreadPoolManager.schedule(new GameGuardCheckTask(this), 30 * 1000);
+ ThreadPool.scheduleGeneral(new GameGuardCheckTask(this), 30 * 1000);
}
- }
+ }*/
+ //@formatter:on
/**
* Send a Server->Client packet StatusUpdate to the L2PcInstance.
@@ -4404,22 +4387,28 @@ public final class L2PcInstance extends L2Playable
{
if (target instanceof L2PcInstance)
{
- final L2PcInstance temp = (L2PcInstance) target;
+ final L2PcInstance targetPlayer = (L2PcInstance) target;
sendPacket(ActionFailed.STATIC_PACKET);
- if ((temp.getPrivateStoreType() == PrivateStoreType.SELL) || (temp.getPrivateStoreType() == PrivateStoreType.PACKAGE_SELL))
+ if ((targetPlayer.getPrivateStoreType() == PrivateStoreType.SELL) || (targetPlayer.getPrivateStoreType() == PrivateStoreType.PACKAGE_SELL))
{
- sendPacket(new PrivateStoreListSell(this, temp));
+ if (isSellingBuffs())
+ {
+ SellBuffsManager.getInstance().sendBuffMenu(this, targetPlayer, 0);
+ }
+ else
+ {
+ sendPacket(new PrivateStoreListSell(this, targetPlayer));
+ }
}
- else if (temp.getPrivateStoreType() == PrivateStoreType.BUY)
+ else if (targetPlayer.getPrivateStoreType() == PrivateStoreType.BUY)
{
- sendPacket(new PrivateStoreListBuy(this, temp));
+ sendPacket(new PrivateStoreListBuy(this, targetPlayer));
}
- else if (temp.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
+ else if (targetPlayer.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
{
- sendPacket(new RecipeShopSellList(this, temp));
+ sendPacket(new RecipeShopSellList(this, targetPlayer));
}
-
}
else if (target != null) // _interactTarget=null should never happen but one never knows ^^;
{
@@ -5057,6 +5046,9 @@ public final class L2PcInstance extends L2Playable
// Clear resurrect xp calculation
setExpBeforeDeath(0);
+ // Calculate Shilen's Breath debuff level. It must happen right before death, because buffs aren't applied on dead characters.
+ calculateShilensBreathDebuffLevel(killer);
+
// Kill the L2PcInstance
if (!super.doDie(killer))
{
@@ -5110,9 +5102,6 @@ public final class L2PcInstance extends L2Playable
}
}
- // calculate Shilen's Breath debuff level
- calculateShilensBreathDebuffLevel(killer);
-
if (isMounted())
{
stopFeed();
@@ -5778,21 +5767,21 @@ public final class L2PcInstance extends L2Playable
* Get the manufacture items map of this player.
* @return the the manufacture items map
*/
- public Map getManufactureItems()
+ public Map getManufactureItems()
{
if (_manufactureItems == null)
{
- synchronized (this)
- {
- if (_manufactureItems == null)
- {
- _manufactureItems = Collections.synchronizedMap(new LinkedHashMap<>());
- }
- }
+ return Collections.emptyMap();
}
+
return _manufactureItems;
}
+ public void setManufactureItems(Map manufactureItems)
+ {
+ _manufactureItems = manufactureItems;
+ }
+
/**
* Get the store name, if any.
* @return the store name
@@ -6524,7 +6513,7 @@ public final class L2PcInstance extends L2Playable
statement.setInt(23, getRace().ordinal());
statement.setInt(24, getClassId().getId());
statement.setLong(25, getDeleteTimer());
- statement.setInt(26, hasDwarvenCraft() ? 1 : 0);
+ statement.setInt(26, getCreateItemLevel() > 0 ? 1 : 0);
statement.setString(27, getTitle());
statement.setInt(28, getAppearance().getTitleColor());
statement.setInt(29, isOnlineInt());
@@ -6994,11 +6983,11 @@ public final class L2PcInstance extends L2Playable
{
_dwarvenRecipeBook.clear();
- L2RecipeList recipe;
- final RecipeData rd = RecipeData.getInstance();
+ RecipeHolder recipe;
+ RecipeData rd = RecipeData.getInstance();
while (rset.next())
{
- recipe = rd.getRecipeList(rset.getInt("id"));
+ recipe = rd.getRecipe(rset.getInt("id"));
if (loadCommon)
{
if (rset.getInt(2) == 1)
@@ -8770,7 +8759,7 @@ public final class L2PcInstance extends L2Playable
{
for (int itemId : _activeSoulShots)
{
- if (ItemTable.getInstance().getTemplate(itemId).getCrystalType().getId() == crystalType)
+ if (ItemTable.getInstance().getTemplate(itemId).getCrystalType().getLevel() == crystalType)
{
disableAutoShot(itemId);
}
@@ -10290,17 +10279,17 @@ public final class L2PcInstance extends L2Playable
}
/**
- * Expertise of the L2PcInstance (None=0, D=1, C=2, B=3, A=4, S=5, S80=6, S84=7)
- * @return int Expertise skill level.
+ * Expertise of the L2PcInstance (None=0, D=1, C=2, B=3, A=4, S=5, S80=6, S84=7, R=8, R95=9, R99=10)
+ * @return CrystalTyperepresenting expertise level..
*/
- public int getExpertiseLevel()
+ public CrystalType getExpertiseLevel()
{
- int level = getSkillLevel(239);
- if (level < 0)
- {
- level = 0;
- }
- return level;
+ return _expertiseLevel;
+ }
+
+ public void setExpertiseLevel(CrystalType crystalType)
+ {
+ _expertiseLevel = crystalType != null ? crystalType : CrystalType.NONE;
}
@Override
@@ -10864,16 +10853,6 @@ public final class L2PcInstance extends L2Playable
_log.log(Level.SEVERE, "deleteMe()", e);
}
- // Stop crafting, if in progress
- try
- {
- RecipeController.getInstance().requestMakeItemAbort(this);
- }
- catch (Exception e)
- {
- _log.log(Level.SEVERE, "deleteMe()", e);
- }
-
// Cancel Attak or Cast
try
{
@@ -12501,11 +12480,11 @@ public final class L2PcInstance extends L2Playable
{
final AtomicInteger slot = new AtomicInteger(1);
con.setAutoCommit(false);
- for (L2ManufactureItem item : _manufactureItems.values())
+ for (Entry entry : _manufactureItems.entrySet())
{
st.setInt(1, getObjectId());
- st.setInt(2, item.getRecipeId());
- st.setLong(3, item.getCost());
+ st.setInt(2, entry.getKey());
+ st.setLong(3, entry.getValue());
st.setInt(4, slot.getAndIncrement());
st.addBatch();
}
@@ -12522,10 +12501,7 @@ public final class L2PcInstance extends L2Playable
private void restoreRecipeShopList()
{
- if (_manufactureItems != null)
- {
- _manufactureItems.clear();
- }
+ final Map manufactureItems = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(RESTORE_CHAR_RECIPE_SHOP))
@@ -12535,7 +12511,7 @@ public final class L2PcInstance extends L2Playable
{
while (rset.next())
{
- getManufactureItems().put(rset.getInt("recipeId"), new L2ManufactureItem(rset.getInt("recipeId"), rset.getLong("price")));
+ manufactureItems.put(rset.getInt("recipeId"), rset.getLong("price"));
}
}
}
@@ -12543,6 +12519,8 @@ public final class L2PcInstance extends L2Playable
{
_log.log(Level.SEVERE, "Could not restore recipe shop list data for playerId: " + getObjectId(), e);
}
+
+ _manufactureItems = manufactureItems;
}
@Override
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index a97eab382d..dcb3ab34da 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -78,7 +78,7 @@ public class PcStatus extends PlayableStatus
}
// If OFFLINE_MODE_NO_DAMAGE is enabled and player is offline and he is in store/craft mode, no damage is taken.
- if (Config.OFFLINE_MODE_NO_DAMAGE && (getActiveChar().getClient() != null) && getActiveChar().getClient().isDetached() && ((Config.OFFLINE_TRADE_ENABLE && ((getActiveChar().getPrivateStoreType() == PrivateStoreType.SELL) || (getActiveChar().getPrivateStoreType() == PrivateStoreType.BUY))) || (Config.OFFLINE_CRAFT_ENABLE && (getActiveChar().isInCraftMode() || (getActiveChar().getPrivateStoreType() == PrivateStoreType.MANUFACTURE)))))
+ if (Config.OFFLINE_MODE_NO_DAMAGE && (getActiveChar().getClient() != null) && getActiveChar().getClient().isDetached() && ((Config.OFFLINE_TRADE_ENABLE && ((getActiveChar().getPrivateStoreType() == PrivateStoreType.SELL) || (getActiveChar().getPrivateStoreType() == PrivateStoreType.BUY))) || (Config.OFFLINE_CRAFT_ENABLE && (getActiveChar().isCrafting() || (getActiveChar().getPrivateStoreType() == PrivateStoreType.MANUFACTURE)))))
{
return;
}
@@ -100,7 +100,7 @@ public class PcStatus extends PlayableStatus
getActiveChar().stopEffectsOnDamage();
}
// Attacked players in craft/shops stand up.
- if (getActiveChar().isInCraftMode() || getActiveChar().isInStoreMode())
+ if (getActiveChar().isCrafting() || getActiveChar().isInStoreMode())
{
getActiveChar().setPrivateStoreType(PrivateStoreType.NONE);
getActiveChar().standUp();
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/conditions/ConditionPlayerGrade.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/conditions/ConditionPlayerGrade.java
deleted file mode 100644
index 8d2e52b55c..0000000000
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/conditions/ConditionPlayerGrade.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This file is part of the L2J Mobius project.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.l2jmobius.gameserver.model.conditions;
-
-import java.util.logging.Logger;
-
-import com.l2jmobius.gameserver.model.actor.L2Character;
-import com.l2jmobius.gameserver.model.items.L2Item;
-import com.l2jmobius.gameserver.model.skills.Skill;
-
-/**
- * The Class ConditionPlayerGrade.
- * @author Gigiikun
- */
-public final class ConditionPlayerGrade extends Condition
-{
- protected static final Logger _log = Logger.getLogger(ConditionPlayerGrade.class.getName());
- // conditional values
- public static final int COND_NO_GRADE = 0x0001;
- public static final int COND_D_GRADE = 0x0002;
- public static final int COND_C_GRADE = 0x0004;
- public static final int COND_B_GRADE = 0x0008;
- public static final int COND_A_GRADE = 0x0010;
- public static final int COND_S_GRADE = 0x0020;
- public static final int COND_S80_GRADE = 0x0040;
- public static final int COND_S84_GRADE = 0x0080;
-
- private final int _value;
-
- /**
- * Instantiates a new condition player grade.
- * @param value the value
- */
- public ConditionPlayerGrade(int value)
- {
- _value = value;
- }
-
- /**
- *
- */
- @Override
- public boolean testImpl(L2Character effector, L2Character effected, Skill skill, L2Item item)
- {
- return (effector.getActingPlayer() != null) && (_value == (byte) effector.getActingPlayer().getExpertiseLevel());
- }
-}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/RecipeHolder.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/RecipeHolder.java
new file mode 100644
index 0000000000..5e33d6f797
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/RecipeHolder.java
@@ -0,0 +1,336 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.enums.StatusUpdateType;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.interfaces.IIdentifiable;
+import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+
+/**
+ * A holder representing a craftable recipe based on the former L2RecipeList.
+ * It contains all the recipe data and methods required for crafting this recipe.
+ * @author Nik
+ */
+public class RecipeHolder implements IIdentifiable
+{
+ /** List of materials required to craft this recipe. */
+ private final List _materials;
+
+ /** Group of products where a single product will randomly be selected upon crafting. */
+ private final List _productGroup;
+
+ private final List _npcFee;
+
+ /** Stats and amount required to perform the craft. */
+ private final Map _statUse;
+
+ private final int _id;
+ private final int _level;
+ private final int _itemId;
+ private final String _name;
+ private final double _successRate;
+ private final boolean _isCommonRecipe;
+ private final double _maxOfferingBonus;
+ private final long _maxOffering;
+
+ public RecipeHolder(StatsSet set, List ingredients, List productGroup, List npcFee, Map statUse)
+ {
+ _id = set.getInt("id");
+ _level = set.getInt("level");
+ _itemId = set.getInt("itemId");
+ _name = set.getString("name");
+ _successRate = set.getDouble("successRate");
+ _isCommonRecipe = set.getBoolean("isCommonRecipe");
+ _maxOfferingBonus = set.getDouble("maxOfferingBonus", Math.max(0, 100 - _successRate));
+ _maxOffering = set.getLong("maxOffering", 0);
+
+ _materials = Collections.unmodifiableList(ingredients);
+ _productGroup = Collections.unmodifiableList(productGroup);
+ _npcFee = Collections.unmodifiableList(npcFee);
+ _statUse = Collections.unmodifiableMap(statUse);
+ }
+
+ /**
+ * @return the recipe id, NOT the recipe's item id
+ */
+ @Override
+ public int getId()
+ {
+ return _id;
+ }
+
+ /**
+ * @return the crafting level needed to use this L2RecipeList.
+ */
+ public int getLevel()
+ {
+ return _level;
+ }
+
+ /**
+ * @return the recipe's item id.
+ */
+ public int getItemId()
+ {
+ return _itemId;
+ }
+
+ /**
+ * @return the name of the L2RecipeList.
+ */
+ public String getName()
+ {
+ return _name;
+ }
+
+ /**
+ * @return the crafting success rate when using the L2RecipeList.
+ */
+ public double getSuccessRate()
+ {
+ return _successRate;
+ }
+
+ /**
+ * @return {@code true} if this a Dwarven recipe or {@code false} if its a Common recipe
+ */
+ public boolean isDwarvenRecipe()
+ {
+ return !_isCommonRecipe;
+ }
+
+ /**
+ * @return list of materials required to complete the recipe.
+ */
+ public List getMaterials()
+ {
+ return _materials;
+ }
+
+ /**
+ * @return the whole group of products from which one random item will result in being crafted.
+ */
+ public List getProductGroup()
+ {
+ return _productGroup;
+ }
+
+ /**
+ * @return list of items that NPCs take for crafting this recipe.
+ */
+ public List getNpcFee()
+ {
+ return _npcFee;
+ }
+
+ /**
+ * @return the table containing all L2RecipeStatInstance of the statUse parameter of the L2RecipeList.
+ */
+ public Map getStatUse()
+ {
+ return _statUse;
+ }
+
+ /**
+ * @return Maximum bonus success rate when maximum offering is reached. Default is the rate needed to reach 100% success rate.
+ */
+ public double getMaxOfferingBonus()
+ {
+ return _maxOfferingBonus;
+ }
+
+ /**
+ * @return Maximum amount of items' adena worth offering. {@code 0} if this recipe does not allow offering.
+ */
+ public long getMaxOffering()
+ {
+ return _maxOffering;
+ }
+
+ /**
+ * Picks a random number then attempts to get a product from the group based on it.
+ * @return {@code ItemChanceHolder} that is the randomly picked product from the group,
+ * or {@code null} if the whole chance sum of the products in the group didn't manage to outnumber the random.
+ */
+ public ItemChanceHolder getRandomProduct()
+ {
+ double random = Rnd.get(100);
+ for (ItemChanceHolder product : _productGroup)
+ {
+ if (product.getChance() > random)
+ {
+ return product;
+ }
+
+ random -= product.getChance();
+ }
+
+ return null;
+ }
+
+ public boolean checkNecessaryStats(L2PcInstance player, L2PcInstance manufacturer, boolean sendMessage)
+ {
+ for (Entry entry : _statUse.entrySet())
+ {
+ final StatusUpdateType stat = entry.getKey();
+ final double requiredAmount = entry.getValue();
+
+ // Less than or equals to because some stats bad interraction - like HP could kill the player if its taken all.
+ if (stat.getValue(manufacturer) <= requiredAmount)
+ {
+ if (sendMessage)
+ {
+ switch (stat)
+ {
+ case CUR_HP:
+ {
+ player.sendPacket(SystemMessageId.NOT_ENOUGH_HP);
+ break;
+ }
+ case CUR_MP:
+ {
+ player.sendPacket(SystemMessageId.NOT_ENOUGH_MP);
+ break;
+ }
+ default:
+ {
+ player.sendMessage("You need " + requiredAmount + " " + stat.toString().toLowerCase() + " to perform this craft.");
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @param player the player's inventory to check.
+ * @param sendMessage send system messages for item requirements if there is missing ingredient.
+ * @return {@code true} if all necessary ingredients are met, {@code false} if there are missing ingredients.
+ */
+ public boolean checkNecessaryIngredients(L2PcInstance player, boolean sendMessage)
+ {
+ for (ItemHolder ingredient : getMaterials())
+ {
+ final long count = player.getInventory().getInventoryItemCount(ingredient.getId(), -1);
+ if (count < ingredient.getCount())
+ {
+ if (sendMessage)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_S2_MORE_S1_S);
+ sm.addItemName(ingredient.getId());
+ sm.addLong(ingredient.getCount() - count);
+ player.sendPacket(sm);
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param player the player requesting the craft.
+ * @param manufacturer the player doing the craft (either the same player or manufacture shop).
+ * @param success {@code true} to give the product item to the player, {@code false} otherwise.
+ * @param craftingCritical {@code true} to give double of the product (if success), {@code false} otherwise.
+ * @param sendMessage send system messages of the process.
+ * @return {@code ItemHolder} of the randomly created product (even if its failing craft), {@code null} if the item creation was not performed due to failed checks.
+ */
+ public ItemHolder doCraft(L2PcInstance player, L2PcInstance manufacturer, boolean success, boolean craftingCritical, boolean sendMessage)
+ {
+ if (!checkNecessaryStats(player, manufacturer, sendMessage))
+ {
+ return null;
+ }
+
+ if (!checkNecessaryIngredients(player, sendMessage))
+ {
+ return null;
+ }
+
+ // Take necessary stats.
+ for (Entry entry : _statUse.entrySet())
+ {
+ final StatusUpdateType stat = entry.getKey();
+ final double requiredAmount = entry.getValue();
+
+ switch (stat)
+ {
+ case CUR_HP:
+ {
+ manufacturer.reduceCurrentHp(requiredAmount, manufacturer, null);
+ break;
+ }
+ case CUR_MP:
+ {
+ manufacturer.reduceCurrentMp(requiredAmount);
+ break;
+ }
+ case CUR_CP:
+ {
+ manufacturer.getStatus().reduceCp((int) requiredAmount);
+ break;
+ }
+ case EXP:
+ {
+ manufacturer.getStat().removeExp((long) requiredAmount);
+ break;
+ }
+ case REPUTATION:
+ {
+ manufacturer.setReputation((int) (manufacturer.getReputation() - requiredAmount));
+ break;
+ }
+ }
+ }
+
+ // Take necessary ingredients. If there was problem destroying item, return null to insicate that process didn't go well.
+ if (getMaterials().stream().anyMatch(i -> !player.destroyItemByItemId("Recipe " + getId(), i.getId(), i.getCount(), manufacturer, sendMessage)))
+ {
+ return null;
+ }
+
+ // Check if success. Luck triggers no matter the success rate - even with 100% craft. Luck chance is taken from your stat and not manufacturer's stat.
+ final ItemHolder result = getRandomProduct();
+ if (success)
+ {
+ player.addItem("Craft", result, manufacturer, true);
+
+ // Award another item if its crafting critical. Double blessed items is very, very rare, but still possible.
+ if (craftingCritical)
+ {
+ player.addItem("CraftCritical", result, manufacturer, true);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/itemcontainer/Inventory.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/itemcontainer/Inventory.java
index 88575164db..c5f33c86df 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/itemcontainer/Inventory.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/itemcontainer/Inventory.java
@@ -401,7 +401,7 @@ public abstract class Inventory extends ItemContainer
final L2PcInstance player = (L2PcInstance) inventory.getOwner();
// Any items equipped that result in expertise penalty do not give any skills at all.
- if (item.getItem().getCrystalType().getId() > player.getExpertiseLevel())
+ if (item.getItem().getCrystalType().isGreater(player.getExpertiseLevel()))
{
return;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/L2Item.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/L2Item.java
index 2f590854f8..0f672fa66d 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/L2Item.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/L2Item.java
@@ -134,7 +134,7 @@ public abstract class L2Item extends ListenersContainer implements IIdentifiable
private int _time;
private int _autoDestroyTime;
private int _bodyPart;
- private int _referencePrice;
+ private long _referencePrice;
private int _crystalCount;
private boolean _sellable;
private boolean _dropable;
@@ -200,7 +200,7 @@ public abstract class L2Item extends ListenersContainer implements IIdentifiable
_time = set.getInt("time", -1);
_autoDestroyTime = set.getInt("auto_destroy_time", -1) * 1000;
_bodyPart = ItemTable.SLOTS.get(set.getString("bodypart", "none"));
- _referencePrice = set.getInt("price", 0);
+ _referencePrice = set.getLong("price", 0);
_crystalType = set.getEnum("crystal_type", CrystalType.class, CrystalType.NONE);
_crystalCount = set.getInt("crystal_count", 0);
@@ -538,7 +538,7 @@ public abstract class L2Item extends ListenersContainer implements IIdentifiable
/**
* @return the price of reference of the item.
*/
- public final int getReferencePrice()
+ public final long getReferencePrice()
{
return _referencePrice;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index ebd3c44be4..fb63011022 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -731,7 +731,7 @@ public final class L2ItemInstance extends L2Object
/**
* @return the reference price of the item.
*/
- public int getReferencePrice()
+ public long getReferencePrice()
{
return _item.getReferencePrice();
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/type/CrystalType.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/type/CrystalType.java
index 6f0351fc9e..f87f2ec4a0 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/type/CrystalType.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/type/CrystalType.java
@@ -35,14 +35,14 @@ public enum CrystalType
R99(10, 17371, 30, 500),
EVENT(11, 0, 0, 0);
- private final int _id;
+ private final int _level;
private final int _crystalId;
private final int _crystalEnchantBonusArmor;
private final int _crystalEnchantBonusWeapon;
- CrystalType(int id, int crystalId, int crystalEnchantBonusArmor, int crystalEnchantBonusWeapon)
+ CrystalType(int level, int crystalId, int crystalEnchantBonusArmor, int crystalEnchantBonusWeapon)
{
- _id = id;
+ _level = level;
_crystalId = crystalId;
_crystalEnchantBonusArmor = crystalEnchantBonusArmor;
_crystalEnchantBonusWeapon = crystalEnchantBonusWeapon;
@@ -52,9 +52,9 @@ public enum CrystalType
* Gets the crystal type ID.
* @return the crystal type ID
*/
- public int getId()
+ public int getLevel()
{
- return _id;
+ return _level;
}
/**
@@ -78,11 +78,41 @@ public enum CrystalType
public boolean isGreater(CrystalType crystalType)
{
- return getId() > crystalType.getId();
+ return getLevel() > crystalType.getLevel();
}
public boolean isLesser(CrystalType crystalType)
{
- return getId() < crystalType.getId();
+ return getLevel() < crystalType.getLevel();
+ }
+
+ public CrystalType plusLevel(int level)
+ {
+ level += getLevel();
+
+ if (level >= CrystalType.R99.getLevel())
+ {
+ return CrystalType.R99;
+ }
+
+ if (level <= CrystalType.NONE.getLevel())
+ {
+ return CrystalType.NONE;
+ }
+
+ return getByLevel(level);
+ }
+
+ public static CrystalType getByLevel(int level)
+ {
+ for (CrystalType crystalType : values())
+ {
+ if (crystalType.getLevel() == level)
+ {
+ return crystalType;
+ }
+ }
+
+ return null;
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/stats/Stats.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/stats/Stats.java
index 3eb0a2828c..5d43bf448a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/stats/Stats.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/stats/Stats.java
@@ -266,6 +266,7 @@ public enum Stats
// Which base stat ordinal should alter skill critical formula.
STAT_BONUS_SKILL_CRITICAL("statSkillCritical"),
STAT_BONUS_SPEED("statSpeed"),
+ CRAFTING_CRITICAL("craftingCritical"),
SHOTS_BONUS("shotBonus", new ShotsBonusFinalizer());
static final Logger LOGGER = Logger.getLogger(Stats.class.getName());
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/L2GameClient.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/L2GameClient.java
index f0fc7726d3..629b0afc09 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/L2GameClient.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/L2GameClient.java
@@ -790,7 +790,7 @@ public final class L2GameClient extends ChannelInboundHandler
}
default:
{
- canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
+ canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isCrafting();
break;
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookDestroy.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookDestroy.java
index c84bf256a2..bed25678de 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookDestroy.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookDestroy.java
@@ -18,9 +18,11 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
-import com.l2jmobius.gameserver.model.L2RecipeList;
+import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
public final class RequestRecipeBookDestroy implements IClientIncomingPacket
@@ -48,23 +50,24 @@ public final class RequestRecipeBookDestroy implements IClientIncomingPacket
return;
}
- final L2RecipeList rp = RecipeData.getInstance().getRecipeList(_recipeID);
- if (rp == null)
+ if ((activeChar.getPrivateStoreType() == PrivateStoreType.MANUFACTURE) || activeChar.isCrafting())
{
+ activeChar.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return;
}
+
+ final RecipeHolder rp = RecipeData.getInstance().getRecipe(_recipeID);
+ if (rp == null)
+ {
+ client.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+
+ // Remove the recipe from the list.
activeChar.unregisterRecipeList(_recipeID);
- final RecipeBookItemList response = new RecipeBookItemList(rp.isDwarvenRecipe(), activeChar.getMaxMp());
- if (rp.isDwarvenRecipe())
- {
- response.addRecipes(activeChar.getDwarvenRecipeBook());
- }
- else
- {
- response.addRecipes(activeChar.getCommonRecipeBook());
- }
-
+ // Send the new recipe book.
+ final RecipeBookItemList response = new RecipeBookItemList(activeChar, rp.isDwarvenRecipe());
activeChar.sendPacket(response);
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookOpen.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookOpen.java
index 26a453d3ff..01a8faf4f7 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookOpen.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeBookOpen.java
@@ -17,10 +17,11 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
-import com.l2jmobius.gameserver.RecipeController;
+import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.RecipeBookItemList;
public final class RequestRecipeBookOpen implements IClientIncomingPacket
{
@@ -48,12 +49,19 @@ public final class RequestRecipeBookOpen implements IClientIncomingPacket
return;
}
- if (activeChar.getActiveRequester() != null)
+ if (activeChar.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
{
- activeChar.sendMessage("You may not alter your recipe book while trading.");
+ client.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return;
}
- RecipeController.getInstance().requestBookOpen(activeChar, _isDwarvenCraft);
+ if (activeChar.isProcessingTransaction())
+ {
+ client.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ return;
+ }
+
+ final RecipeBookItemList response = new RecipeBookItemList(activeChar, _isDwarvenCraft);
+ activeChar.sendPacket(response);
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeInfo.java
index 64f44c07f2..e393db0631 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeInfo.java
@@ -17,8 +17,11 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.RecipeItemMakeInfo;
public final class RequestRecipeItemMakeInfo implements IClientIncomingPacket
@@ -41,6 +44,13 @@ public final class RequestRecipeItemMakeInfo implements IClientIncomingPacket
return;
}
- client.sendPacket(new RecipeItemMakeInfo(_id, player));
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(_id);
+ if (recipe == null)
+ {
+ player.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+
+ client.sendPacket(new RecipeItemMakeInfo(_id, player, recipe.getMaxOffering()));
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeSelf.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeSelf.java
index 8aa642c02a..a2415834ec 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeSelf.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeItemMakeSelf.java
@@ -16,23 +16,45 @@
*/
package com.l2jmobius.gameserver.network.clientpackets;
+import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
-import com.l2jmobius.gameserver.RecipeController;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
+import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
+import com.l2jmobius.gameserver.model.stats.Stats;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.RecipeItemMakeInfo;
+import com.l2jmobius.gameserver.util.Util;
/**
- * @author Administrator
+ * @author Nik
*/
public final class RequestRecipeItemMakeSelf implements IClientIncomingPacket
{
private int _id;
+ private ItemHolder[] _offeredItems;
@Override
public boolean read(L2GameClient client, PacketReader packet)
{
_id = packet.readD();
+
+ final int offeringsCount = packet.readD();
+ if (offeringsCount > 0)
+ {
+ _offeredItems = new ItemHolder[offeringsCount];
+ for (int i = 0; i < offeringsCount; i++)
+ {
+ final int objectId = packet.readD();
+ final long count = packet.readQ();
+ _offeredItems[i] = new ItemHolder(objectId, count);
+ }
+ }
return true;
}
@@ -45,23 +67,122 @@ public final class RequestRecipeItemMakeSelf implements IClientIncomingPacket
return;
}
+ if (!Config.IS_CRAFTING_ENABLED)
+ {
+ activeChar.sendMessage("Item creation is currently disabled.");
+ return;
+ }
+
if (!client.getFloodProtectors().getManufacture().tryPerformAction("RecipeMakeSelf"))
{
return;
}
- if (activeChar.getPrivateStoreType() != PrivateStoreType.NONE)
+ if (activeChar.isCastingNow())
{
- activeChar.sendMessage("You cannot create items while trading.");
+ activeChar.sendPacket(SystemMessageId.YOUR_RECIPE_BOOK_MAY_NOT_BE_ACCESSED_WHILE_USING_A_SKILL);
return;
}
- if (activeChar.isInCraftMode())
+ if (activeChar.getPrivateStoreType() == PrivateStoreType.MANUFACTURE)
{
- activeChar.sendMessage("You are currently in Craft Mode.");
+ activeChar.sendPacket(SystemMessageId.YOU_MAY_NOT_ALTER_YOUR_RECIPE_BOOK_WHILE_ENGAGED_IN_MANUFACTURING);
return;
}
- RecipeController.getInstance().requestMakeItem(activeChar, _id);
+ if (activeChar.isProcessingTransaction())
+ {
+ activeChar.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
+ return;
+ }
+
+ // TODO: Check if its a retail-like check.
+ if (activeChar.isAlikeDead())
+ {
+ return;
+ }
+
+ // On retail if player is requesting trade, it is instantly canceled.
+ activeChar.cancelActiveTrade();
+
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(_id);
+ if (recipe == null)
+ {
+ activeChar.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+
+ if (!activeChar.hasRecipeList(recipe.getId()))
+ {
+ Util.handleIllegalPlayerAction(activeChar, "Warning!! Character " + activeChar.getName() + " of account " + activeChar.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
+ return;
+ }
+
+ // Check if stats or ingredients are met.
+ if (!recipe.checkNecessaryStats(activeChar, activeChar, true) || !recipe.checkNecessaryIngredients(activeChar, true))
+ {
+ return;
+ }
+
+ // Check if all offerings are legit.
+ if ((_offeredItems != null) && (recipe.getMaxOffering() > 0) && (recipe.getMaxOfferingBonus() > 0))
+ {
+ for (ItemHolder offer : _offeredItems)
+ {
+ final L2ItemInstance item = activeChar.getInventory().getItemByObjectId(offer.getId());
+ if ((item == null) || (item.getCount() < offer.getCount()) || !item.isDestroyable())
+ {
+ return;
+ }
+ }
+ }
+
+ if (activeChar.isCrafting())
+ {
+ activeChar.sendPacket(SystemMessageId.CURRENTLY_CRAFTING_AN_ITEM_PLEASE_WAIT);
+ return;
+ }
+
+ activeChar.setIsCrafting(true);
+
+ // Take offerings to increase chance
+ double offeringBonus = 0;
+ if ((_offeredItems != null) && (recipe.getMaxOffering() > 0) && (recipe.getMaxOfferingBonus() > 0))
+ {
+ long offeredAdenaWorth = 0;
+ for (ItemHolder offer : _offeredItems)
+ {
+ final L2ItemInstance item = activeChar.getInventory().getItemByObjectId(offer.getId());
+ if (activeChar.destroyItem("CraftOffering", item, offer.getCount(), null, true))
+ {
+ offeredAdenaWorth += (item.getItem().getReferencePrice() * offer.getCount());
+ }
+ }
+
+ offeringBonus = Math.min((offeredAdenaWorth / recipe.getMaxOffering()) * recipe.getMaxOfferingBonus(), recipe.getMaxOfferingBonus());
+ }
+
+ final boolean success = activeChar.tryLuck() || ((recipe.getSuccessRate() + offeringBonus) > Rnd.get(100));
+ final boolean craftingCritical = success && (activeChar.getStat().getValue(Stats.CRAFTING_CRITICAL) > Rnd.get(100));
+
+ if (success) // Successful craft.
+ {
+ if (craftingCritical)
+ {
+ activeChar.sendPacket(SystemMessageId.CRAFTING_CRITICAL);
+ }
+ }
+ else // Failed craft.
+ {
+ activeChar.sendPacket(SystemMessageId.YOU_FAILED_AT_MIXING_THE_ITEM);
+ }
+
+ // Perform the crafting: take the items and give reward if success.
+ recipe.doCraft(activeChar, activeChar, success, craftingCritical, true);
+
+ // Send craft window. Must be sent after crafting so it properly counts the items.
+ activeChar.sendPacket(new RecipeItemMakeInfo(recipe.getId(), activeChar, success, recipe.getMaxOffering()));
+
+ activeChar.setIsCrafting(false);
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopListSet.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopListSet.java
index 2c7aaa9a84..d4385ae32c 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopListSet.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopListSet.java
@@ -18,16 +18,17 @@ package com.l2jmobius.gameserver.network.clientpackets;
import static com.l2jmobius.gameserver.model.itemcontainer.Inventory.MAX_ADENA;
-import java.util.Arrays;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
+import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
-import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
@@ -44,28 +45,28 @@ public final class RequestRecipeShopListSet implements IClientIncomingPacket
{
private static final int BATCH_LENGTH = 12;
- private L2ManufactureItem[] _items = null;
+ private Map _manufactureRecipes = null;
@Override
public boolean read(L2GameClient client, PacketReader packet)
{
- final int count = packet.readD();
+ int count = packet.readD();
if ((count <= 0) || (count > Config.MAX_ITEM_IN_PACKET) || ((count * BATCH_LENGTH) != packet.getReadableBytes()))
{
return false;
}
- _items = new L2ManufactureItem[count];
+ _manufactureRecipes = new HashMap<>(count);
for (int i = 0; i < count; i++)
{
- final int id = packet.readD();
- final long cost = packet.readQ();
+ int id = packet.readD();
+ long cost = packet.readQ();
if (cost < 0)
{
- _items = null;
+ _manufactureRecipes = null;
return false;
}
- _items[i] = new L2ManufactureItem(id, cost);
+ _manufactureRecipes.put(id, cost);
}
return true;
}
@@ -79,13 +80,26 @@ public final class RequestRecipeShopListSet implements IClientIncomingPacket
return;
}
- if (_items == null)
+ if (_manufactureRecipes == null)
{
+ player.sendPacket(SystemMessageId.ITEMS_ARE_NOT_AVAILABLE_FOR_A_PRIVATE_STORE_OR_PRIVATE_WORKSHOP);
player.setPrivateStoreType(PrivateStoreType.NONE);
player.broadcastUserInfo();
return;
}
+ if (player.isCastingNow())
+ {
+ player.sendPacket(SystemMessageId.A_PRIVATE_STORE_MAY_NOT_BE_OPENED_WHILE_USING_A_SKILL);
+ return;
+ }
+
+ if (player.isCrafting())
+ {
+ player.sendPacket(SystemMessageId.CURRENTLY_CRAFTING_AN_ITEM_PLEASE_WAIT);
+ return;
+ }
+
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player) || player.isInDuel())
{
client.sendPacket(SystemMessageId.WHILE_YOU_ARE_ENGAGED_IN_COMBAT_YOU_CANNOT_OPERATE_A_PRIVATE_STORE_OR_PRIVATE_WORKSHOP);
@@ -100,29 +114,36 @@ public final class RequestRecipeShopListSet implements IClientIncomingPacket
return;
}
- final List dwarfRecipes = Arrays.asList(player.getDwarvenRecipeBook());
- final List commonRecipes = Arrays.asList(player.getCommonRecipeBook());
-
- player.getManufactureItems().clear();
-
- for (L2ManufactureItem i : _items)
+ for (Entry item : _manufactureRecipes.entrySet())
{
- final L2RecipeList list = RecipeData.getInstance().getRecipeList(i.getRecipeId());
- if (!dwarfRecipes.contains(list) && !commonRecipes.contains(list))
+ final int recipeId = item.getKey();
+ final long recipeCost = item.getValue();
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(recipeId);
+ if (recipe == null)
+ {
+ player.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+ if (ItemTable.getInstance().getTemplate(recipe.getItemId()).isQuestItem())
+ {
+ player.sendPacket(SystemMessageId.QUEST_RECIPES_CAN_NOT_BE_REGISTERED);
+ return;
+ }
+ if (!player.hasRecipeList(recipe.getId()))
{
Util.handleIllegalPlayerAction(player, "Warning!! Player " + player.getName() + " of account " + player.getAccountName() + " tried to set recipe which he dont have.", Config.DEFAULT_PUNISH);
return;
}
- if (i.getCost() > MAX_ADENA)
+ if (recipeCost > MAX_ADENA)
{
- Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " tried to set price more than " + MAX_ADENA + " adena in Private Manufacture.", Config.DEFAULT_PUNISH);
+ Util.handleIllegalPlayerAction(player, "Warning!! Character " + player.getName() + " of account " + player.getAccountName() + " tried to set price of " + recipeCost + " adena in Private Manufacture.", Config.DEFAULT_PUNISH);
return;
}
-
- player.getManufactureItems().put(i.getRecipeId(), i);
}
+ player.setManufactureItems(_manufactureRecipes);
+
player.setStoreName(!player.hasManufactureShop() ? "" : player.getStoreName());
player.setPrivateStoreType(PrivateStoreType.MANUFACTURE);
player.sitDown();
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeInfo.java
index 12f915819f..4e6a68fdc4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeInfo.java
@@ -17,10 +17,13 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopItemInfo;
/**
@@ -49,12 +52,25 @@ public final class RequestRecipeShopMakeInfo implements IClientIncomingPacket
return;
}
- final L2PcInstance shop = L2World.getInstance().getPlayer(_playerObjectId);
- if ((shop == null) || (shop.getPrivateStoreType() != PrivateStoreType.MANUFACTURE))
+ final L2PcInstance manufacturer = L2World.getInstance().getPlayer(_playerObjectId);
+ if ((manufacturer == null) || (manufacturer.getPrivateStoreType() != PrivateStoreType.MANUFACTURE))
{
return;
}
- client.sendPacket(new RecipeShopItemInfo(shop, _recipeId));
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(_recipeId);
+ if (recipe == null)
+ {
+ player.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+
+ final Long manufactureRecipeCost = manufacturer.getManufactureItems().get(_recipeId);
+ if (manufactureRecipeCost == null)
+ {
+ return;
+ }
+
+ client.sendPacket(new RecipeShopItemInfo(manufacturer, _recipeId, manufactureRecipeCost, recipe.getMaxOffering()));
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeItem.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeItem.java
index ba40366a3e..38401cb4ae 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopMakeItem.java
@@ -16,30 +16,53 @@
*/
package com.l2jmobius.gameserver.network.clientpackets;
+import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
-import com.l2jmobius.gameserver.RecipeController;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
+import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
+import com.l2jmobius.gameserver.model.stats.Stats;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.RecipeShopItemInfo;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.util.Util;
/**
- * @author Administrator
+ * It appears you are able to successfully create from manufacture store while casting, while in manufacture store and within 250 range. So basic checks
+ * from your own recipe list crafting are skipped. With the exception of trading, if you request trade, it is cancelled, if you are already trading, you get message.
+ * @author Nik
*/
public final class RequestRecipeShopMakeItem implements IClientIncomingPacket
{
- private int _id;
+ private int _objectId;
private int _recipeId;
- @SuppressWarnings("unused")
- private long _unknown;
+ private long _manufacturePrice;
+ private ItemHolder[] _offeredItems;
@Override
public boolean read(L2GameClient client, PacketReader packet)
{
- _id = packet.readD();
+ _objectId = packet.readD();
_recipeId = packet.readD();
- _unknown = packet.readQ();
+ _manufacturePrice = packet.readQ();
+
+ final int offeringsCount = packet.readD();
+ if (offeringsCount > 0)
+ {
+ _offeredItems = new ItemHolder[offeringsCount];
+ for (int i = 0; i < offeringsCount; i++)
+ {
+ final int objectId = packet.readD();
+ final long count = packet.readQ();
+ _offeredItems[i] = new ItemHolder(objectId, count);
+ }
+ }
return true;
}
@@ -52,41 +75,197 @@ public final class RequestRecipeShopMakeItem implements IClientIncomingPacket
return;
}
+ if (!Config.IS_CRAFTING_ENABLED)
+ {
+ activeChar.sendMessage("Item creation is currently disabled.");
+ return;
+ }
+
if (!client.getFloodProtectors().getManufacture().tryPerformAction("RecipeShopMake"))
{
return;
}
- final L2PcInstance manufacturer = L2World.getInstance().getPlayer(_id);
+ final L2PcInstance manufacturer = L2World.getInstance().getPlayer(_objectId);
if (manufacturer == null)
{
return;
}
- if (manufacturer.getInstanceWorld() != activeChar.getInstanceWorld())
+ if ((manufacturer.getInstanceWorld() != activeChar.getInstanceWorld()) || (activeChar.calculateDistance(manufacturer, false, false) > 250))
{
return;
}
- if (activeChar.getPrivateStoreType() != PrivateStoreType.NONE)
- {
- activeChar.sendMessage("You cannot create items while trading.");
- return;
- }
if (manufacturer.getPrivateStoreType() != PrivateStoreType.MANUFACTURE)
{
- // activeChar.sendMessage("You cannot create items while trading.");
return;
}
- if (activeChar.isInCraftMode() || manufacturer.isInCraftMode())
+ if (activeChar.isProcessingTransaction() || manufacturer.isProcessingTransaction())
{
- activeChar.sendMessage("You are currently in Craft Mode.");
+ activeChar.sendPacket(SystemMessageId.ITEM_CREATION_IS_NOT_POSSIBLE_WHILE_ENGAGED_IN_A_TRADE);
return;
}
- if (Util.checkIfInRange(150, activeChar, manufacturer, true))
+
+ // TODO: Check if its a retail-like check.
+ if (activeChar.isAlikeDead() || manufacturer.isAlikeDead())
{
- RecipeController.getInstance().requestManufactureItem(manufacturer, _recipeId, activeChar);
+ return;
}
+
+ // On retail if player is requesting trade, it is instantly canceled.
+ activeChar.cancelActiveTrade();
+
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(_recipeId);
+ if (recipe == null)
+ {
+ activeChar.sendPacket(SystemMessageId.THE_RECIPE_IS_INCORRECT);
+ return;
+ }
+
+ if (!manufacturer.hasRecipeList(recipe.getId()))
+ {
+ Util.handleIllegalPlayerAction(activeChar, "Warning!! Character " + activeChar.getName() + " of account " + activeChar.getAccountName() + " sent a false recipe id.", Config.DEFAULT_PUNISH);
+ return;
+ }
+
+ final Long manufactureRecipeCost = manufacturer.getManufactureItems().get(_recipeId);
+ if (manufactureRecipeCost == null)
+ {
+ return;
+ }
+
+ // Check if the price is the same as requested price.
+ if (_manufacturePrice != manufactureRecipeCost)
+ {
+ return;
+ }
+
+ // Check if player can pay.
+ if (activeChar.getAdena() < manufactureRecipeCost)
+ {
+ activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
+ return;
+ }
+
+ // Check if stats or ingredients are met.
+ if (!recipe.checkNecessaryStats(activeChar, manufacturer, true) || !recipe.checkNecessaryIngredients(activeChar, true))
+ {
+ return;
+ }
+
+ // Check if all offerings are legit.
+ if ((_offeredItems != null) && (recipe.getMaxOffering() > 0) && (recipe.getMaxOfferingBonus() > 0))
+ {
+ for (ItemHolder offer : _offeredItems)
+ {
+ final L2ItemInstance item = activeChar.getInventory().getItemByObjectId(offer.getId());
+ if ((item == null) || (item.getCount() < offer.getCount()) || !item.isDestroyable())
+ {
+ return;
+ }
+ }
+ }
+
+ if (manufacturer.isCrafting())
+ {
+ activeChar.sendPacket(SystemMessageId.CURRENTLY_CRAFTING_AN_ITEM_PLEASE_WAIT);
+ return;
+ }
+
+ manufacturer.setIsCrafting(true);
+
+ // First you must pay for the manufacturing service of the other player.
+ if (manufactureRecipeCost > 0)
+ {
+ // Attempt to pay the required manufacturing price by the manufacturer.
+ L2ItemInstance paidAdena = activeChar.transferItem("PayManufacture", activeChar.getInventory().getAdenaInstance().getObjectId(), manufactureRecipeCost, manufacturer.getInventory(), manufacturer);
+
+ if (paidAdena == null)
+ {
+ activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
+ return;
+ }
+ }
+
+ // Take offerings to increase chance
+ double offeringBonus = 0;
+ if ((_offeredItems != null) && (recipe.getMaxOffering() > 0) && (recipe.getMaxOfferingBonus() > 0))
+ {
+ long offeredAdenaWorth = 0;
+ for (ItemHolder offer : _offeredItems)
+ {
+ final L2ItemInstance item = activeChar.getInventory().getItemByObjectId(offer.getId());
+ if (activeChar.destroyItem("CraftOffering", item, offer.getCount(), manufacturer, true))
+ {
+ offeredAdenaWorth += (item.getItem().getReferencePrice() * offer.getCount());
+ }
+ }
+
+ offeringBonus = Math.min((offeredAdenaWorth / recipe.getMaxOffering()) * recipe.getMaxOfferingBonus(), recipe.getMaxOfferingBonus());
+ }
+
+ final boolean success = activeChar.tryLuck() || ((recipe.getSuccessRate() + offeringBonus) > Rnd.get(100));
+ final boolean craftingCritical = success && (activeChar.getStat().getValue(Stats.CRAFTING_CRITICAL) > Rnd.get(100));
+
+ final ItemHolder craftedItem = recipe.doCraft(activeChar, manufacturer, success, craftingCritical, true);
+ if (success)
+ {
+ if (craftingCritical)
+ {
+ activeChar.sendPacket(SystemMessageId.CRAFTING_CRITICAL);
+ }
+ if (craftedItem.getCount() > 1)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S3_S2_S_HAVE_BEEN_CREATED_FOR_C1_AT_THE_PRICE_OF_S4_ADENA);
+ sm.addString(activeChar.getName());
+ sm.addInt((int) craftedItem.getCount());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ manufacturer.sendPacket(sm);
+
+ sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CREATED_S3_S2_S_AT_THE_PRICE_OF_S4_ADENA);
+ sm.addString(manufacturer.getName());
+ sm.addInt((int) craftedItem.getCount());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_HAS_BEEN_CREATED_FOR_C1_AFTER_THE_PAYMENT_OF_S3_ADENA_WAS_RECEIVED);
+ sm.addString(activeChar.getName());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ manufacturer.sendPacket(sm);
+
+ sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CREATED_S2_AFTER_RECEIVING_S3_ADENA);
+ sm.addString(manufacturer.getName());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ activeChar.sendPacket(sm);
+ }
+ }
+ else
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_FAILED_TO_CREATE_S2_FOR_C1_AT_THE_PRICE_OF_S3_ADENA);
+ sm.addString(activeChar.getName());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ manufacturer.sendPacket(sm);
+
+ sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_FAILED_TO_CREATE_S2_AT_THE_PRICE_OF_S3_ADENA);
+ sm.addString(manufacturer.getName());
+ sm.addItemName(craftedItem.getId());
+ sm.addLong(manufactureRecipeCost);
+ activeChar.sendPacket(sm);
+ }
+
+ // Show manufacturing window.
+ activeChar.sendPacket(new RecipeShopItemInfo(manufacturer, recipe.getId(), success, _manufacturePrice, recipe.getMaxOffering()));
+
+ manufacturer.setIsCrafting(false);
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManageList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManageList.java
index 59b5957d8e..15ac35b4bf 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManageList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManageList.java
@@ -19,9 +19,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
+import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopManageList;
+import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
public final class RequestRecipeShopManageList implements IClientIncomingPacket
{
@@ -40,6 +43,38 @@ public final class RequestRecipeShopManageList implements IClientIncomingPacket
return;
}
+ if (player.getCommonRecipeBook().isEmpty() && player.getDwarvenRecipeBook().isEmpty())
+ {
+ player.sendPacket(SystemMessageId.NO_RECIPES_HAVE_BEEN_REGISTERED);
+ return;
+ }
+
+ if (player.isCastingNow())
+ {
+ player.sendPacket(SystemMessageId.A_PRIVATE_STORE_MAY_NOT_BE_OPENED_WHILE_USING_A_SKILL);
+ return;
+ }
+
+ if (player.isCrafting())
+ {
+ player.sendPacket(SystemMessageId.CURRENTLY_CRAFTING_AN_ITEM_PLEASE_WAIT);
+ return;
+ }
+
+ if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player) || player.isInDuel())
+ {
+ client.sendPacket(SystemMessageId.WHILE_YOU_ARE_ENGAGED_IN_COMBAT_YOU_CANNOT_OPERATE_A_PRIVATE_STORE_OR_PRIVATE_WORKSHOP);
+ client.sendPacket(ActionFailed.STATIC_PACKET);
+ return;
+ }
+
+ if (player.isInsideZone(ZoneId.NO_STORE))
+ {
+ client.sendPacket(SystemMessageId.YOU_CANNOT_OPEN_A_PRIVATE_WORKSHOP_HERE);
+ client.sendPacket(ActionFailed.STATIC_PACKET);
+ return;
+ }
+
// Player shouldn't be able to set stores if he/she is alike dead (dead or fake death)
if (player.isAlikeDead())
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManagePrev.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManagePrev.java
index 8b59287b33..52fb7e31b4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManagePrev.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestRecipeShopManagePrev.java
@@ -42,7 +42,14 @@ public final class RequestRecipeShopManagePrev implements IClientIncomingPacket
{
return;
}
- else if (player.isAlikeDead() || (player.getTarget() == null) || !player.getTarget().isPlayer())
+
+ if (player.isAlikeDead() || (player.getTarget() == null) || !player.getTarget().isPlayer())
+ {
+ client.sendPacket(ActionFailed.STATIC_PACKET);
+ return;
+ }
+
+ if (player.calculateDistance(player.getTarget(), false, false) > 250)
{
client.sendPacket(ActionFailed.STATIC_PACKET);
return;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/alchemy/RequestAlchemyTryMixCube.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/alchemy/RequestAlchemyTryMixCube.java
index dad7c7aefa..86324a84a0 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/alchemy/RequestAlchemyTryMixCube.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/alchemy/RequestAlchemyTryMixCube.java
@@ -120,7 +120,7 @@ public class RequestAlchemyTryMixCube implements IClientIncomingPacket
return;
}
- final int price = itemInstance.getReferencePrice();
+ final long price = itemInstance.getReferencePrice();
if (itemInstance.getReferencePrice() == 0)
{
player.sendPacket(SystemMessageId.THIS_ITEM_CANNOT_BE_COMBINED);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingEnchantSupportItem.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingEnchantSupportItem.java
index b3f8a823c8..ad3f971eda 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingEnchantSupportItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingEnchantSupportItem.java
@@ -59,7 +59,7 @@ public class RequestExTryToPutShapeShiftingEnchantSupportItem implements IClient
final ShapeShiftingItemRequest request = player.getRequest(ShapeShiftingItemRequest.class);
- if (player.isInStoreMode() || player.isInCraftMode() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
+ if (player.isInStoreMode() || player.isCrafting() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
{
client.sendPacket(SystemMessageId.YOU_CANNOT_USE_THIS_SYSTEM_DURING_TRADING_PRIVATE_STORE_AND_WORKSHOP_SETUP);
return;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingTargetItem.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingTargetItem.java
index 4fe4ef7d8c..75c44c649d 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingTargetItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestExTryToPutShapeShiftingTargetItem.java
@@ -54,7 +54,7 @@ public class RequestExTryToPutShapeShiftingTargetItem implements IClientIncoming
final ShapeShiftingItemRequest request = player.getRequest(ShapeShiftingItemRequest.class);
- if (player.isInStoreMode() || player.isInCraftMode() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
+ if (player.isInStoreMode() || player.isCrafting() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
{
client.sendPacket(ExPutShapeShiftingTargetItemResult.FAILED);
client.sendPacket(SystemMessageId.YOU_CANNOT_USE_THIS_SYSTEM_DURING_TRADING_PRIVATE_STORE_AND_WORKSHOP_SETUP);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestShapeShiftingItem.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestShapeShiftingItem.java
index 97d035b0f3..1d6ef78348 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestShapeShiftingItem.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/appearance/RequestShapeShiftingItem.java
@@ -62,7 +62,7 @@ public class RequestShapeShiftingItem implements IClientIncomingPacket
final ShapeShiftingItemRequest request = player.getRequest(ShapeShiftingItemRequest.class);
- if (player.isInStoreMode() || player.isInCraftMode() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
+ if (player.isInStoreMode() || player.isCrafting() || player.isProcessingRequest() || player.isProcessingTransaction() || (request == null))
{
client.sendPacket(ExShapeShiftingResult.CLOSE);
client.sendPacket(SystemMessageId.YOU_CANNOT_USE_THIS_SYSTEM_DURING_TRADING_PRIVATE_STORE_AND_WORKSHOP_SETUP);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowCropSetting.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowCropSetting.java
index 8be8b98259..b5dd119973 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowCropSetting.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowCropSetting.java
@@ -77,7 +77,7 @@ public class ExShowCropSetting implements IClientOutgoingPacket
packet.writeD(s.getCropLimit()); // next sale limit
packet.writeD(0); // ???
packet.writeD(s.getCropMinPrice()); // min crop price
- packet.writeD(s.getCropMaxPrice()); // max crop price
+ packet.writeD((int) s.getCropMaxPrice()); // max crop price
// Current period
if (_current.containsKey(s.getCropId()))
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowManorDefaultInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowManorDefaultInfo.java
index 8516330479..52f23f1fca 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowManorDefaultInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowManorDefaultInfo.java
@@ -48,8 +48,8 @@ public final class ExShowManorDefaultInfo implements IClientOutgoingPacket
{
packet.writeD(crop.getCropId()); // crop Id
packet.writeD(crop.getLevel()); // level
- packet.writeD(crop.getSeedReferencePrice()); // seed price
- packet.writeD(crop.getCropReferencePrice()); // crop price
+ packet.writeD((int) crop.getSeedReferencePrice()); // seed price
+ packet.writeD((int) crop.getCropReferencePrice()); // crop price
packet.writeC(1); // Reward 1 type
packet.writeD(crop.getReward(1)); // Reward 1 itemId
packet.writeC(1); // Reward 2 type
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowSeedSetting.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowSeedSetting.java
index 40c0360538..5f76c46f65 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowSeedSetting.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExShowSeedSetting.java
@@ -75,9 +75,9 @@ public class ExShowSeedSetting implements IClientOutgoingPacket
packet.writeC(1);
packet.writeD(s.getReward(2)); // reward 2 id
packet.writeD(s.getSeedLimit()); // next sale limit
- packet.writeD(s.getSeedReferencePrice()); // price for castle to produce 1
- packet.writeD(s.getSeedMinPrice()); // min seed price
- packet.writeD(s.getSeedMaxPrice()); // max seed price
+ packet.writeD((int) s.getSeedReferencePrice()); // price for castle to produce 1
+ packet.writeD((int) s.getSeedMinPrice()); // min seed price
+ packet.writeD((int) s.getSeedMaxPrice()); // max seed price
// Current period
if (_current.containsKey(s.getSeedId()))
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/GMViewCharacterInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/GMViewCharacterInfo.java
index d67302fa42..f376dc11dc 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/GMViewCharacterInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/GMViewCharacterInfo.java
@@ -137,7 +137,7 @@ public class GMViewCharacterInfo implements IClientOutgoingPacket
packet.writeD(_activeChar.getAllyId()); // ally id
packet.writeC(_activeChar.getMountType().ordinal()); // mount type
packet.writeC(_activeChar.getPrivateStoreType().getId());
- packet.writeC(_activeChar.hasDwarvenCraft() ? 1 : 0);
+ packet.writeC(_activeChar.getCreateItemLevel() > 0 ? 1 : 0);
packet.writeD(_activeChar.getPkKills());
packet.writeD(_activeChar.getPvpKills());
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeBookItemList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeBookItemList.java
index e972857e29..5c0dc5c556 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeBookItemList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeBookItemList.java
@@ -16,25 +16,24 @@
*/
package com.l2jmobius.gameserver.network.serverpackets;
+import java.util.Collection;
+
import com.l2jmobius.commons.network.PacketWriter;
-import com.l2jmobius.gameserver.model.L2RecipeList;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.OutgoingPackets;
public class RecipeBookItemList implements IClientOutgoingPacket
{
- private L2RecipeList[] _recipes;
+ private final Collection _recipes;
private final boolean _isDwarvenCraft;
private final int _maxMp;
- public RecipeBookItemList(boolean isDwarvenCraft, int maxMp)
+ public RecipeBookItemList(L2PcInstance player, boolean isDwarvenCraft)
{
_isDwarvenCraft = isDwarvenCraft;
- _maxMp = maxMp;
- }
-
- public void addRecipes(L2RecipeList[] recipeBook)
- {
- _recipes = recipeBook;
+ _maxMp = player.getMaxMp();
+ _recipes = (isDwarvenCraft ? player.getDwarvenRecipeBook() : player.getCommonRecipeBook());
}
@Override
@@ -51,11 +50,12 @@ public class RecipeBookItemList implements IClientOutgoingPacket
}
else
{
- packet.writeD(_recipes.length); // number of items in recipe book
- for (int i = 0; i < _recipes.length; i++)
+ packet.writeD(_recipes.size()); // number of items in recipe book
+ int i = 1;
+ for (RecipeHolder recipe : _recipes)
{
- packet.writeD(_recipes[i].getId());
- packet.writeD(i + 1);
+ packet.writeD(recipe.getId());
+ packet.writeD(i++);
}
}
return true;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeItemMakeInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeItemMakeInfo.java
index 6397e049ac..9a47f0c939 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeItemMakeInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeItemMakeInfo.java
@@ -18,34 +18,53 @@ package com.l2jmobius.gameserver.network.serverpackets;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
-import com.l2jmobius.gameserver.model.L2RecipeList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.OutgoingPackets;
public class RecipeItemMakeInfo implements IClientOutgoingPacket
{
private final int _id;
private final L2PcInstance _activeChar;
- private final boolean _success;
+ private final Boolean _success;
+ private final long _offeringMaximumAdena;
+
+ public RecipeItemMakeInfo(int id, L2PcInstance player, boolean success, long offeringMaximumAdena)
+ {
+ _id = id;
+ _activeChar = player;
+ _success = success;
+ _offeringMaximumAdena = offeringMaximumAdena;
+ }
public RecipeItemMakeInfo(int id, L2PcInstance player, boolean success)
{
_id = id;
_activeChar = player;
_success = success;
+ _offeringMaximumAdena = 0;
+ }
+
+ public RecipeItemMakeInfo(int id, L2PcInstance player, long offeringMaximumAdena)
+ {
+ _id = id;
+ _activeChar = player;
+ _success = null;
+ _offeringMaximumAdena = offeringMaximumAdena;
}
public RecipeItemMakeInfo(int id, L2PcInstance player)
{
_id = id;
_activeChar = player;
- _success = true;
+ _success = null;
+ _offeringMaximumAdena = 0;
}
@Override
public boolean write(PacketWriter packet)
{
- final L2RecipeList recipe = RecipeData.getInstance().getRecipeList(_id);
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(_id);
if (recipe != null)
{
OutgoingPackets.RECIPE_ITEM_MAKE_INFO.writeId(packet);
@@ -53,9 +72,9 @@ public class RecipeItemMakeInfo implements IClientOutgoingPacket
packet.writeD(recipe.isDwarvenRecipe() ? 0 : 1); // 0 = Dwarven - 1 = Common
packet.writeD((int) _activeChar.getCurrentMp());
packet.writeD(_activeChar.getMaxMp());
- packet.writeD(_success ? 1 : 0); // item creation success/failed
- packet.writeC(0x00);
- packet.writeQ(0x00);
+ packet.writeD(_success == null ? -1 : (_success ? 1 : 0)); // item creation none/success/failed
+ packet.writeC(_offeringMaximumAdena > 0 ? 1 : 0); // Show offering window.
+ packet.writeQ(_offeringMaximumAdena); // Adena worth of items for maximum offering.
return true;
}
_log.info("Character: " + _activeChar + ": Requested unexisting recipe with id = " + _id);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopItemInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopItemInfo.java
index 95090c8f30..086f3d6103 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopItemInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopItemInfo.java
@@ -22,13 +22,28 @@ import com.l2jmobius.gameserver.network.OutgoingPackets;
public class RecipeShopItemInfo implements IClientOutgoingPacket
{
- private final L2PcInstance _player;
+ private final L2PcInstance _manufacturer;
private final int _recipeId;
+ private final Boolean _success;
+ private final long _manufacturePrice;
+ private final long _offeringMaximumAdena;
- public RecipeShopItemInfo(L2PcInstance player, int recipeId)
+ public RecipeShopItemInfo(L2PcInstance manufacturer, int recipeId, boolean success, long manufacturePrice, long offeringMaximumAdena)
{
- _player = player;
+ _manufacturer = manufacturer;
_recipeId = recipeId;
+ _success = success;
+ _manufacturePrice = manufacturePrice;
+ _offeringMaximumAdena = offeringMaximumAdena;
+ }
+
+ public RecipeShopItemInfo(L2PcInstance manufacturer, int recipeId, long manufacturePrice, long offeringMaximumAdena)
+ {
+ _manufacturer = manufacturer;
+ _recipeId = recipeId;
+ _success = null;
+ _manufacturePrice = manufacturePrice;
+ _offeringMaximumAdena = offeringMaximumAdena;
}
@Override
@@ -36,14 +51,14 @@ public class RecipeShopItemInfo implements IClientOutgoingPacket
{
OutgoingPackets.RECIPE_SHOP_ITEM_INFO.writeId(packet);
- packet.writeD(_player.getObjectId());
+ packet.writeD(_manufacturer.getObjectId());
packet.writeD(_recipeId);
- packet.writeD((int) _player.getCurrentMp());
- packet.writeD(_player.getMaxMp());
- packet.writeD(0xffffffff);
- packet.writeQ(0x00);
- packet.writeC(0x00); // Trigger offering window if 1
- packet.writeQ(0x00);
+ packet.writeD((int) _manufacturer.getCurrentMp());
+ packet.writeD(_manufacturer.getMaxMp());
+ packet.writeD(_success == null ? -1 : (_success ? 1 : 0)); // item creation none/success/failed
+ packet.writeQ(_manufacturePrice);
+ packet.writeC(_offeringMaximumAdena > 0 ? 1 : 0); // Trigger offering window if 1
+ packet.writeQ(_offeringMaximumAdena);
return true;
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopManageList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopManageList.java
index 3aa7b5c70c..318e490a91 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopManageList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopManageList.java
@@ -16,44 +16,39 @@
*/
package com.l2jmobius.gameserver.network.serverpackets;
-import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
import com.l2jmobius.commons.network.PacketWriter;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
-import com.l2jmobius.gameserver.model.L2RecipeList;
+import com.l2jmobius.gameserver.data.xml.impl.RecipeData;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.RecipeHolder;
import com.l2jmobius.gameserver.network.OutgoingPackets;
public class RecipeShopManageList implements IClientOutgoingPacket
{
private final L2PcInstance _seller;
private final boolean _isDwarven;
- private L2RecipeList[] _recipes;
+ private final Collection _recipes;
+ private List> _manufacture;
public RecipeShopManageList(L2PcInstance seller, boolean isDwarven)
{
_seller = seller;
_isDwarven = isDwarven;
-
- if (_isDwarven && _seller.hasDwarvenCraft())
- {
- _recipes = _seller.getDwarvenRecipeBook();
- }
- else
- {
- _recipes = _seller.getCommonRecipeBook();
- }
+ _recipes = (isDwarven && (_seller.getCreateItemLevel() > 0)) ? _seller.getDwarvenRecipeBook() : _seller.getCommonRecipeBook();
if (_seller.hasManufactureShop())
{
- final Iterator it = _seller.getManufactureItems().values().iterator();
- L2ManufactureItem item;
- while (it.hasNext())
+ _manufacture = new ArrayList<>();
+ for (Entry item : _seller.getManufactureItems().entrySet())
{
- item = it.next();
- if ((item.isDwarven() != _isDwarven) || !seller.hasRecipeList(item.getRecipeId()))
+ final RecipeHolder recipe = RecipeData.getInstance().getRecipe(item.getKey());
+ if (((recipe != null) && (recipe.isDwarvenRecipe() == _isDwarven)) && seller.hasRecipeList(recipe.getId()))
{
- it.remove();
+ _manufacture.add(item);
}
}
}
@@ -68,34 +63,34 @@ public class RecipeShopManageList implements IClientOutgoingPacket
packet.writeD((int) _seller.getAdena());
packet.writeD(_isDwarven ? 0x00 : 0x01);
- if (_recipes == null)
+ if ((_recipes == null) || _recipes.isEmpty())
{
packet.writeD(0);
}
else
{
- packet.writeD(_recipes.length); // number of items in recipe book
+ packet.writeD(_recipes.size());// number of items in recipe book
- for (int i = 0; i < _recipes.length; i++)
+ int i = 1;
+ for (RecipeHolder recipe : _recipes)
{
- final L2RecipeList temp = _recipes[i];
- packet.writeD(temp.getId());
- packet.writeD(i + 1);
+ packet.writeD(recipe.getId());
+ packet.writeD(i++);
}
}
- if (!_seller.hasManufactureShop())
+ if ((_manufacture == null) || _manufacture.isEmpty())
{
packet.writeD(0x00);
}
else
{
- packet.writeD(_seller.getManufactureItems().size());
- for (L2ManufactureItem item : _seller.getManufactureItems().values())
+ packet.writeD(_manufacture.size());
+ for (Entry item : _manufacture)
{
- packet.writeD(item.getRecipeId());
- packet.writeD(0x00);
- packet.writeQ(item.getCost());
+ packet.writeD(item.getKey());
+ packet.writeD(0x00); // CanCraft?
+ packet.writeQ(item.getValue());
}
}
return true;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopSellList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopSellList.java
index 8a6638e153..5788685406 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopSellList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/RecipeShopSellList.java
@@ -16,8 +16,9 @@
*/
package com.l2jmobius.gameserver.network.serverpackets;
+import java.util.Map.Entry;
+
import com.l2jmobius.commons.network.PacketWriter;
-import com.l2jmobius.gameserver.model.L2ManufactureItem;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -47,11 +48,11 @@ public class RecipeShopSellList implements IClientOutgoingPacket
else
{
packet.writeD(_manufacturer.getManufactureItems().size());
- for (L2ManufactureItem temp : _manufacturer.getManufactureItems().values())
+ for (Entry item : _manufacturer.getManufactureItems().entrySet())
{
- packet.writeD(temp.getRecipeId());
- packet.writeD(0x00); // unknown
- packet.writeQ(temp.getCost());
+ packet.writeD(item.getKey());
+ packet.writeD(0x00); // CanCreate?
+ packet.writeQ(item.getValue());
}
}
return true;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/SellList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/SellList.java
index 433eae9095..e10221838e 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/SellList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/SellList.java
@@ -76,7 +76,7 @@ public class SellList implements IClientOutgoingPacket
for (L2ItemInstance item : _sellList)
{
- int price = item.getItem().getReferencePrice() / 2;
+ long price = item.getItem().getReferencePrice() / 2;
if (_merchant != null)
{
price -= (price * _merchant.getTotalTaxRate(TaxType.SELL));
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ShopPreviewList.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ShopPreviewList.java
index 438e259df2..7ecb2ebd18 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ShopPreviewList.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ShopPreviewList.java
@@ -23,6 +23,7 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.buylist.L2BuyList;
import com.l2jmobius.gameserver.model.buylist.Product;
import com.l2jmobius.gameserver.model.items.L2Item;
+import com.l2jmobius.gameserver.model.items.type.CrystalType;
import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ShopPreviewList implements IClientOutgoingPacket
@@ -30,14 +31,14 @@ public class ShopPreviewList implements IClientOutgoingPacket
private final int _listId;
private final Collection _list;
private final long _money;
- private int _expertise;
+ private CrystalType _expertise;
- public ShopPreviewList(L2BuyList list, long currentMoney, int expertiseIndex)
+ public ShopPreviewList(L2BuyList list, long currentMoney, CrystalType expertise)
{
_listId = list.getListId();
_list = list.getProducts();
_money = currentMoney;
- _expertise = expertiseIndex;
+ _expertise = expertise;
}
public ShopPreviewList(Collection lst, int listId, long currentMoney)
@@ -59,7 +60,7 @@ public class ShopPreviewList implements IClientOutgoingPacket
int newlength = 0;
for (Product product : _list)
{
- if ((product.getItem().getCrystalType().getId() <= _expertise) && product.getItem().isEquipable())
+ if (!product.getItem().getCrystalType().isGreater(_expertise) && product.getItem().isEquipable())
{
newlength++;
}
@@ -68,7 +69,7 @@ public class ShopPreviewList implements IClientOutgoingPacket
for (Product product : _list)
{
- if ((product.getItem().getCrystalType().getId() <= _expertise) && product.getItem().isEquipable())
+ if (!product.getItem().getCrystalType().isGreater(_expertise) && product.getItem().isEquipable())
{
packet.writeD(product.getItemId());
packet.writeH(product.getItem().getType2()); // item type2
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/UserInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/UserInfo.java
index 3972277e4c..b9cca5a15e 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/UserInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/UserInfo.java
@@ -20,6 +20,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.enums.AttributeType;
+import com.l2jmobius.gameserver.enums.ItemGrade;
import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.model.L2Clan;
@@ -205,7 +206,7 @@ public class UserInfo extends AbstractMaskPacket
packet.writeH(6);
packet.writeC(_activeChar.getMountType().ordinal());
packet.writeC(_activeChar.getPrivateStoreType().getId());
- packet.writeC(_activeChar.hasDwarvenCraft() || (_activeChar.getSkillLevel(248) > 0) ? 1 : 0);
+ packet.writeC(_activeChar.getCrystallizeGrade() != ItemGrade.NONE ? 1 : 0);
packet.writeC(_activeChar.getAbilityPoints() - _activeChar.getAbilityPointsUsed());
}