pbesa 4.0.6__tar.gz → 4.0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. {pbesa-4.0.6 → pbesa-4.0.7}/PKG-INFO +1 -1
  2. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/cognitive.py +59 -12
  3. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-39.pyc +0 -0
  4. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/util.py +0 -0
  5. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/mas.py +0 -0
  6. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/models.py +0 -0
  7. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/delegator.py +0 -0
  8. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/dialog.py +10 -2
  9. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/prompts.py +0 -0
  10. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/templates.py +0 -0
  11. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa.egg-info/PKG-INFO +1 -1
  12. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa.egg-info/requires.txt +0 -0
  13. {pbesa-4.0.6 → pbesa-4.0.7}/setup.py +1 -1
  14. {pbesa-4.0.6 → pbesa-4.0.7}/.gitignore +0 -0
  15. {pbesa-4.0.6 → pbesa-4.0.7}/LICENSE +0 -0
  16. {pbesa-4.0.6 → pbesa-4.0.7}/LICENSE.txt +0 -0
  17. {pbesa-4.0.6 → pbesa-4.0.7}/MANIFEST +0 -0
  18. {pbesa-4.0.6 → pbesa-4.0.7}/README.md +0 -0
  19. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/db.sqlite3 +0 -0
  20. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__init__.py +0 -0
  21. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/__init__.cpython-36.pyc +0 -0
  22. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/pbesa.cpython-36.pyc +0 -0
  23. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/settings.cpython-36.pyc +0 -0
  24. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/urls.cpython-36.pyc +0 -0
  25. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/__pycache__/wsgi.cpython-36.pyc +0 -0
  26. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/asgi.py +0 -0
  27. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/pbesa.py +0 -0
  28. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/settings.py +0 -0
  29. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/urls.py +0 -0
  30. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/helloworld/wsgi.py +0 -0
  31. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/manage.py +0 -0
  32. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__init__.py +0 -0
  33. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/__init__.cpython-36.pyc +0 -0
  34. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/admin.cpython-36.pyc +0 -0
  35. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/apps.cpython-36.pyc +0 -0
  36. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/models.cpython-36.pyc +0 -0
  37. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/urls.cpython-36.pyc +0 -0
  38. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/__pycache__/views.cpython-36.pyc +0 -0
  39. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/admin.py +0 -0
  40. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/apps.py +0 -0
  41. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  42. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  43. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  44. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translatecontroller.py +0 -0
  45. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translatedelegate.py +0 -0
  46. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/controller/translateresponse.py +0 -0
  47. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  48. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  49. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/translatetask.py +0 -0
  50. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/mas/worker/workeragent.py +0 -0
  51. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/migrations/__init__.py +0 -0
  52. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/migrations/__pycache__/__init__.cpython-36.pyc +0 -0
  53. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/models.py +0 -0
  54. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/tests.py +0 -0
  55. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/urls.py +0 -0
  56. {pbesa-4.0.6 → pbesa-4.0.7}/examples/django/helloworld/translate/views.py +0 -0
  57. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/countercontroller.cpython-36.pyc +0 -0
  58. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/counterdelegate.cpython-36.pyc +0 -0
  59. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/counterresponse.cpython-36.pyc +0 -0
  60. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translatecontroller.cpython-36.pyc +0 -0
  61. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translatedelegate.cpython-36.pyc +0 -0
  62. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/__pycache__/translateresponse.cpython-36.pyc +0 -0
  63. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/countercontroller.py +0 -0
  64. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/counterdelegate.py +0 -0
  65. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/controller/counterresponse.py +0 -0
  66. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/counteragent.cpython-36.pyc +0 -0
  67. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/countertask.cpython-36.pyc +0 -0
  68. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/translatetask.cpython-36.pyc +0 -0
  69. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/__pycache__/workeragent.cpython-36.pyc +0 -0
  70. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/counteragent.py +0 -0
  71. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/mas/worker/countertask.py +0 -0
  72. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/remote_a.py +0 -0
  73. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/remote_b.py +0 -0
  74. {pbesa-4.0.6 → pbesa-4.0.7}/examples/remote/remote_c.py +0 -0
  75. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/__init__.py +0 -0
  76. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/__init__.py +0 -0
  77. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/adapter.py +0 -0
  78. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/agent.py +0 -0
  79. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/io/__init__.py +0 -0
  80. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/io/system_file.py +0 -0
  81. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/io/tcp_server.py +0 -0
  82. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/__init__.py +0 -0
  83. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-36.pyc +0 -0
  84. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-37.pyc +0 -0
  85. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/__pycache__/__init__.cpython-38.pyc +0 -0
  86. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/res/conf.json +0 -0
  87. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/kernel/world.py +0 -0
  88. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/__init__.py +0 -0
  89. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/adm_listener.py +0 -0
  90. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/adm_listener_handler.py +0 -0
  91. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/exceptions.py +0 -0
  92. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/remote_adm.py +0 -0
  93. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/remote/remote_adm_handler.py +0 -0
  94. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/__init__.py +0 -0
  95. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/collaborative_team.py +0 -0
  96. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/delegator_team.py +0 -0
  97. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/dispatcher_team.py +0 -0
  98. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/selected_dispatcher_team.py +0 -0
  99. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa/social/worker.py +0 -0
  100. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa.egg-info/SOURCES.txt +0 -0
  101. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa.egg-info/dependency_links.txt +0 -0
  102. {pbesa-4.0.6 → pbesa-4.0.7}/pbesa.egg-info/top_level.txt +0 -0
  103. {pbesa-4.0.6 → pbesa-4.0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.6
3
+ Version: 4.0.7
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo==4.6.3
@@ -13,6 +13,7 @@
13
13
  # Define resources
14
14
  # --------------------------------------------------------
15
15
 
16
+ import uuid
16
17
  import json
17
18
  import logging
18
19
  import traceback
@@ -20,13 +21,16 @@ from pydantic import BaseModel
20
21
  from typing import List, Optional
21
22
  from abc import ABC, abstractmethod
22
23
  from pbesa.models import AIFoundry, AzureInference, GPTService, ServiceProvider
23
- from pbesa.social.dialog import DialogState, imprimir_grafo, recorrer_interacciones, extraer_diccionario_nodos, ActionNode, DeclarativeNode#, TerminalNode
24
+ from pbesa.social.dialog import (
25
+ DialogState, imprimir_grafo, recorrer_interacciones, extraer_diccionario_nodos,
26
+ ActionNode, DeclarativeNode, GotoNode) #, TerminalNode
24
27
  from pbesa.social.prompts import CLASSIFICATION_PROMPT, DERIVE_PROMPT, RECOVERY_PROMPT
25
28
  # --------------------------------------------------------
26
29
  # Define DTOs
27
30
  # --------------------------------------------------------
28
31
 
29
32
  class InteraccionDTO(BaseModel):
33
+ id: str
30
34
  tipo: str
31
35
  texto: str
32
36
  actor: str
@@ -38,6 +42,7 @@ def interaccion_serializer(interaccion):
38
42
  if isinstance(interaccion, list):
39
43
  return [interaccion_serializer(i) for i in interaccion]
40
44
  return {
45
+ "id": interaccion["id"] if "id" in interaccion and interaccion["id"] else str(uuid.uuid4()),
41
46
  "tipo": interaccion["tipo"],
42
47
  "texto": interaccion["texto"],
43
48
  "actor": interaccion["actor"],
@@ -477,6 +482,10 @@ class Dialog(ABC):
477
482
  }
478
483
  # Define recovery message
479
484
  self.RECOVERY_MSG = "Lo lamento, puedes darme más detalles o reformular"
485
+ # Define vertices list
486
+ self.__vertices = []
487
+ # Define visited nodes
488
+ self.__visited_nodes = 0
480
489
 
481
490
  def setup_world(self):
482
491
  """ Set up model method """
@@ -642,9 +651,10 @@ class Dialog(ABC):
642
651
 
643
652
  def get_text(self, mensaje) -> str:
644
653
  if mensaje:
645
- mensaje_limpio = mensaje.replace("<|im_start|>user<|im_sep|>", "").replace("<|im_start|>system<|im_sep|>", "")
646
- mensaje_limpio = mensaje_limpio.replace("<|im_start|>", "").replace("<|im_sep|>", "").replace("<|im_end|>", "")
647
- mensaje_limpio = mensaje_limpio.replace("[Usuario]: ", "").replace("[Sistema]: ", "")
654
+ mensaje_limpio = mensaje.replace("<|im_start|>user<|im_sep|>", "").replace("<|im_start|>system<|im_sep|>", "") \
655
+ .replace("<|im_start|>", "").replace("<|im_sep|>", "").replace("<|im_end|>", "") \
656
+ .replace("[Usuario]: ", "").replace("[Sistema]: ", "") \
657
+ .replace("<|user|>", "").replace("<|system|>", "")
648
658
  return mensaje_limpio.strip()
649
659
  else:
650
660
  return ""
@@ -680,20 +690,25 @@ class Dialog(ABC):
680
690
  }
681
691
  logging.info(f"Recovery attemps: {self.__recovery["counter"]}")
682
692
  # Verifica si se ha alcanzado el límite de recuperación
683
- if self.__recovery['counter'] <= 3:
684
- self.notify("identificando la performativa...")
693
+ if self.__recovery['counter'] <= 3 and self.__visited_nodes < 5:
694
+ self.notify("identificando concepto...")
695
+ #--------------------------
685
696
  # Verifica que exista la performativa
686
697
  if not dialog_state in self.__dfa:
687
- self.notify("performativa no encontrada")
698
+ self.notify("concepto no encontrado")
688
699
  return self.recovery(query)
689
700
  # Performativa encontrada
690
701
  children = None
691
- self.notify("performativa encontrada")
702
+ self.notify("concepto encontrado")
703
+ #--------------------------
704
+ # Obtiene los hijos del nodo
692
705
  node = self.__dfa[dialog_state]
693
706
  if not isinstance(node, list):
694
707
  children = node.children
695
708
  else:
709
+ # Es una lista de nodos
696
710
  children = node
711
+ #--------------------------
697
712
  # Flujo de selección
698
713
  select_node = None
699
714
  self.notify("flujo de seleccion...")
@@ -724,20 +739,52 @@ class Dialog(ABC):
724
739
  logging.info(f"--> Una opción.")
725
740
  select_node = children[0]
726
741
  else:
727
- logging.info(f"???????????????????> text: {res} es terminal")
728
- # Nuevo nodo
742
+ logging.info("???> Es un nodo terminal o iniciador")
743
+ return self.recovery(query)
744
+ #--------------------------
745
+ # Verifica si es un nodo
746
+ # que ya fue recorrido
747
+ if select_node.performative in self.__vertices:
748
+ logging.info(f"-> nodo ya recorrido: {select_node.text}")
749
+ self.__visited_nodes += 1
750
+ else:
751
+ logging.info(f"-> nodo no recorrido: {select_node.text}")
752
+ self.__visited_nodes = 0
753
+ # Maraca el nodo como visitado
754
+ self.__vertices.append(select_node.performative)
755
+ #---------------------------
756
+ # Verifica si el nodo es un
757
+ # nodo de salto
758
+ if isinstance(select_node, GotoNode):
759
+ logging.info(f"-> node de salto: {select_node.text}")
760
+ performative = select_node.text.replace("Salta a:", "").strip()
761
+ select_node = self.__dfa[performative]
762
+ logging.info(f"-> Salto: {select_node.text}, performativa: {select_node.performative}")
763
+ #---------------------------
764
+ # Efectua transicion
729
765
  if select_node:
730
766
  res = select_node.text
731
767
  node = select_node.children[0]
732
- # Nodo seleccionado
733
768
  logging.info(f"Flujo normal: {res}")
734
769
  self.notify(res)
770
+ #---------------------------
771
+ # Verifica si el nuevo nodo
772
+ # es un nodo de salto
773
+ if isinstance(node, GotoNode):
774
+ logging.info(f"-> node de salto: {node.text}")
775
+ performative = node.text.replace("Salta a:", "").strip()
776
+ node = self.__dfa[performative]
777
+ logging.info(f"-> Salto: {node.text}, performativa: {node.performative}")
778
+ #---------------------------
779
+ # Actualiza la memoria de
780
+ # trabajo
735
781
  if team_source:
736
782
  self.__work_memory.append({"role": "user", "content": res})
737
783
  else:
738
784
  self.__work_memory.append({"role": "user", "content": query})
739
785
  self.__work_memory.append({"role": "user", "content": res})
740
- # Efectua inferencia
786
+ #---------------------------
787
+ # Efectua inferencia
741
788
  new_owner, new_dialog_state, res, team = self.do_transition(owner, node, query)
742
789
  res = self.get_text(res)
743
790
  return new_owner, new_dialog_state, res, team
File without changes
File without changes
File without changes
File without changes
@@ -37,7 +37,7 @@ class DialogState:
37
37
  class Node:
38
38
  def __init__(self, actor, performative, text=None, is_terminal=False):
39
39
  self.actor = actor
40
- self.performative = performative # Se asigna el ID del objeto (en str)
40
+ self.performative = performative
41
41
  self.text = text
42
42
  self.is_terminal = is_terminal
43
43
  self.children = []
@@ -57,6 +57,10 @@ class ResponseNode(Node):
57
57
  def __init__(self, actor, performative, text, is_terminal=False):
58
58
  super().__init__(actor, performative=performative, text=text, is_terminal=is_terminal)
59
59
 
60
+ class GotoNode(Node):
61
+ def __init__(self, actor, performative, text, is_terminal=False):
62
+ super().__init__(actor, performative=performative, text=text, is_terminal=is_terminal)
63
+
60
64
  #------------------------------------------
61
65
  # Define functions
62
66
  #------------------------------------------
@@ -125,7 +129,7 @@ def recorrer_interacciones(obj):
125
129
  # Si tiene la clave "tipo", creamos un nodo (según su valor) y procesamos sus hijos
126
130
  if "tipo" in obj:
127
131
  # Se usa el id del diccionario convertido a cadena para 'performative'
128
- current_id = str(id(obj))
132
+ current_id = obj["id"] if "id" in obj else str(id(obj))
129
133
  texto = obj.get("texto")
130
134
 
131
135
  # Procesamos los nodos hijos buscando en las claves "interacciones" y "Interacciones"
@@ -150,6 +154,8 @@ def recorrer_interacciones(obj):
150
154
  nuevo_nodo = ActionNode(actor=obj["actor"], performative=current_id, text=texto, action=tipo, team=obj["equipo"], tool=obj["herramienta"], is_terminal=is_terminal)
151
155
  elif tipo == "respuesta de equipo":
152
156
  nuevo_nodo = ResponseNode(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
157
+ elif tipo == "salta a":
158
+ nuevo_nodo = GotoNode(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
153
159
  else:
154
160
  nuevo_nodo = Node(actor=obj["actor"], performative=current_id, text=texto, is_terminal=is_terminal)
155
161
 
@@ -168,8 +174,10 @@ def recorrer_interacciones(obj):
168
174
  nodos.extend(resultado)
169
175
  else:
170
176
  nodos.append(resultado)
177
+ # Devolvemos la lista de nodos encontrados
171
178
  return nodos if nodos else None
172
179
  else:
180
+ # Si no es ni lista ni diccionario, devolvemos None
173
181
  return None
174
182
  except Exception as e:
175
183
  print(f"Error al recorrer interacciones: {e}")
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pbesa
3
- Version: 4.0.6
3
+ Version: 4.0.7
4
4
  License-File: LICENSE
5
5
  License-File: LICENSE.txt
6
6
  Requires-Dist: pymongo==4.6.3
File without changes
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name='pbesa',
7
- version='4.0.6',
7
+ version='4.0.7',
8
8
  packages=find_packages(),
9
9
  install_requires=[
10
10
  'pymongo==4.6.3',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes