From 64a8b41881f38d48a15569cd6123003b85fabbed Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 9 Feb 2025 11:09:21 +0100 Subject: [PATCH] Funcionando con la edicion de los esquemas --- __pycache__/config_manager.cpython-310.pyc | Bin 9367 -> 12295 bytes backend/script_groups/esquema.json | 16 +- .../example_group/description.json | 6 + .../script_groups/example_group/schema.json | 4 + config_manager.py | 207 +++++++++++++--- data/data.json | 6 +- data/esquema.json | 26 +- data/log.txt | 4 +- data/schema.json | 4 + templates/index.html | 227 +++++++++++------- 10 files changed, 351 insertions(+), 149 deletions(-) create mode 100644 backend/script_groups/example_group/description.json create mode 100644 backend/script_groups/example_group/schema.json create mode 100644 data/schema.json diff --git a/__pycache__/config_manager.cpython-310.pyc b/__pycache__/config_manager.cpython-310.pyc index 6da376a52de5aa3ee92d4f9f5f71ac0f3b2b8fb4..88e9b57ee3a577d9acf659dc5b944a5488f815ad 100644 GIT binary patch literal 12295 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 a`jj~Th9dZz;4E@NDENEe2MQmz(#;H@scF#;G zjT{+hr69BmbkANSc-UlLR?$A}vgY!{!#?c3^R^o83rI*jA)Xcq3Bv!Mv11chk!U`j z`S0id|MQ>Oy!yw5SS=b2De#y3_%F*}9K9QRoBo>I{p)g5A5lt_C0O!~b|uPYS--8b z0eB2MWb1aUM1gOx6dSywUy1);{tz1meqS)qmKf=3_gK@VHIt>;0gz6hbW=L~o;VAX zOm>hR0iB>jVsMURyD5d8Wu+Vvq*^e**;05PjEZTLqT&sF|otLYwrExUFrw}GlgxI|XMLO_x$KD|` z^Ux@WSUTS`>uKCBFrGzq3t&g}?V%|?i_jCDxMlvYFO5V$LR^iCW^f`kgUh*n;;r|C zkB|gL_EnG-+``<7Q>*f{Fv6Kj_n|EIk!A8=XU#LXN+QG&FiKBDEl*=>tM$%iQIGc_ z$S`{&Y=o;h0vrt<6&?q}-Be115k~KruChg5RaWRWIjh_zP#bkUE7l@2WKO)SrJ9&% z2XnEkG?eH1Hi)aNkS!`v1wE}nwn3NE2DwXb&_zExkk7p>czW4kW$wqH081A2=-e@n zFrI?9c9~)2g-%tMWqy-s<`B`b7GZ9r0)woNzG>LhS<;7sgs^fqS@I0kU;Z&2q* zS-GSvDqWcd1t}Hu)i%dys4Q@sz7gA4(%it7+0eGhC50-?)SxYHt3(<&t~mLdgedrb z8J&`jOU%uGQiA+wJanK@o+_qfI=Zoj0-L5iEt=LsL-#yiFIgDF*U(AaS$EUN;U{JF^5LpC= z%93x~`MuH#O}s|J*v#$8Fa9+7njyR5sK`wXpTODR>0rNH_ktImK7VoH{6c=dd#&(i zLBI<5zOjG#q*$Lin*IUb{FlJ~o6`E{)GL%67iVW43(M~G50&`C%oAiud@|!?@G9d3 z;U@r=>KU~)x4!1`<4C(txY^tQCd7;2Xu4VB*Ozcio);fv4>#dLDHmNYU{_x#bGVh{ z;M4JvariYi>|RXJ|_N*E&%&syozRWzib58p5*!wcFt0+v>t<^A0fvtP7}YjBSIviw_Vy=UDa zO<9!?sB%n5-imZDqwX!_U--C5Id?o2QqptVo84`kS9ZJT>%&`O=(RL{e_7FVsmxjKf$?wuA&_-ioGdCHQRj;GFtKz-f MSl@o9;?vy3x10%bi2wiq diff --git a/backend/script_groups/esquema.json b/backend/script_groups/esquema.json index 16cbb07..54d842d 100644 --- a/backend/script_groups/esquema.json +++ b/backend/script_groups/esquema.json @@ -1,20 +1,20 @@ { + "type": "object", "properties": { "batch_size": { - "description": "N\u00c3\u00bamero de elementos a procesar por lote", + "type": "number", "title": "Tama\u00c3\u00b1o de Lote", - "type": "number" + "description": "N\u00c3\u00bamero de elementos a procesar por lote" }, "input_dir": { - "description": "Ruta al directorio de archivos de entrada", + "type": "string", "title": "Directorio de Entrada", - "type": "string" + "description": "Ruta al directorio de archivos de entrada" }, "output_dir": { - "description": "Ruta al directorio para archivos generados", + "type": "string", "title": "Directorio de Salida", - "type": "string" + "description": "Ruta al directorio para archivos generados" } - }, - "type": "object" + } } \ No newline at end of file diff --git a/backend/script_groups/example_group/description.json b/backend/script_groups/example_group/description.json new file mode 100644 index 0000000..0e0f8c1 --- /dev/null +++ b/backend/script_groups/example_group/description.json @@ -0,0 +1,6 @@ +{ + "name": "Grupo de Ejemplo", + "description": "Scripts de demostración que muestran las funcionalidades básicas del sistema", + "version": "1.0", + "author": "Admin" +} diff --git a/backend/script_groups/example_group/schema.json b/backend/script_groups/example_group/schema.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/backend/script_groups/example_group/schema.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/config_manager.py b/config_manager.py index 542ad50..8a943de 100644 --- a/config_manager.py +++ b/config_manager.py @@ -66,13 +66,36 @@ class ConfigurationManager: return {"status": "success", "path": path} - def get_script_groups(self) -> List[str]: - """Returns list of available script groups.""" - return [ - d - for d in os.listdir(self.script_groups_path) - if os.path.isdir(os.path.join(self.script_groups_path, d)) - ] + def get_script_groups(self) -> List[Dict[str, Any]]: + """Returns list of available script groups with their descriptions.""" + groups = [] + for d in os.listdir(self.script_groups_path): + group_path = os.path.join(self.script_groups_path, d) + if os.path.isdir(group_path): + description = self._get_group_description(group_path) + groups.append( + { + "id": d, + "name": description.get("name", d), + "description": description.get( + "description", "Sin descripción" + ), + "version": description.get("version", "1.0"), + "author": description.get("author", "Unknown"), + } + ) + return groups + + def _get_group_description(self, group_path: str) -> Dict[str, Any]: + """Get description for a script group.""" + description_file = os.path.join(group_path, "description.json") + try: + if os.path.exists(description_file): + with open(description_file, "r", encoding="utf-8") as f: + return json.load(f) + except Exception as e: + print(f"Error reading group description: {e}") + return {} def get_config(self, level: str, group: str = None) -> Dict[str, Any]: """Get configuration for specified level.""" @@ -93,27 +116,159 @@ class ConfigurationManager: def get_schema(self, level: str, group: str = None) -> Dict[str, Any]: """Get schema for specified level.""" - # Clean level parameter (remove -form suffix if present) - level = level.split("-")[0] - try: + # Clean level parameter + level = str(level).split("-")[0] + + # Determine schema path based on level if level == "1": path = os.path.join(self.data_path, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.data_path, "schema.json") elif level == "2": - path = os.path.join(self.script_groups_path, "esquema.json") + path = os.path.join(self.script_groups_path, group, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.script_groups_path, group, "schema.json") elif level == "3": if not group: - return {} # Return empty schema if no group is specified + return {"type": "object", "properties": {}} path = os.path.join(self.script_groups_path, group, "esquema.json") + # Try esquema.json first, then schema.json if not found + if not os.path.exists(path): + path = os.path.join(self.script_groups_path, group, "schema.json") else: - return {} # Return empty schema for invalid levels + return {"type": "object", "properties": {}} - with open(path, "r") as f: - return json.load(f) - except FileNotFoundError: - return {} # Return empty schema if file doesn't exist - except json.JSONDecodeError: - return {} # Return empty schema if file is invalid JSON + # Read existing schema from whichever file exists + if os.path.exists(path): + with open(path, "r", encoding="utf-8") as f: + schema = json.load(f) + return ( + schema + if isinstance(schema, dict) + else {"type": "object", "properties": {}} + ) + + # Create default schema if no file exists + default_schema = {"type": "object", "properties": {}} + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "w", encoding="utf-8") as f: + json.dump(default_schema, f, indent=2) + return default_schema + + except Exception as e: + print(f"Error loading schema: {str(e)}") + return {"type": "object", "properties": {}} + + def update_schema( + self, level: str, data: Dict[str, Any], group: str = None + ) -> Dict[str, str]: + """Update schema for specified level and clean corresponding config.""" + try: + # Determinar rutas de schema y config + if level == "1": + schema_path = os.path.join(self.data_path, "esquema.json") + config_path = os.path.join(self.data_path, "data.json") + elif level == "2": + schema_path = os.path.join( + self.script_groups_path, group, "esquema.json" + ) + config_path = os.path.join(self.script_groups_path, group, "data.json") + elif level == "3": + if not group: + return { + "status": "error", + "message": "Group is required for level 3", + } + schema_path = os.path.join( + self.script_groups_path, group, "esquema.json" + ) + config_path = ( + os.path.join(self.working_directory, "data.json") + if self.working_directory + else None + ) + else: + return {"status": "error", "message": "Invalid level"} + + # Ensure directory exists + os.makedirs(os.path.dirname(schema_path), exist_ok=True) + + # Validate schema structure + if ( + not isinstance(data, dict) + or "type" not in data + or "properties" not in data + ): + data = { + "type": "object", + "properties": data if isinstance(data, dict) else {}, + } + + # Write schema + with open(schema_path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + # Clean corresponding config file + self._clean_config_for_schema(config_path, data) + + return {"status": "success"} + + except Exception as e: + print(f"Error updating schema: {str(e)}") + return {"status": "error", "message": str(e)} + + def _clean_config_for_schema( + self, config_path: str, schema: Dict[str, Any] + ) -> None: + """Clean configuration file to match schema structure.""" + if not config_path or not os.path.exists(config_path): + return + + try: + # Cargar configuración actual + with open(config_path, "r", encoding="utf-8") as f: + config = json.load(f) + + # Limpiar configuración recursivamente + cleaned_config = self._clean_object_against_schema(config, schema) + + # Guardar configuración limpia + with open(config_path, "w", encoding="utf-8") as f: + json.dump(cleaned_config, f, indent=2, ensure_ascii=False) + + except Exception as e: + print(f"Error cleaning config: {str(e)}") + + def _clean_object_against_schema( + self, data: Dict[str, Any], schema: Dict[str, Any] + ) -> Dict[str, Any]: + """Recursively clean object to match schema structure.""" + if not isinstance(data, dict) or not isinstance(schema, dict): + return {} + + result = {} + schema_props = schema.get("properties", {}) + + for key, value in data.items(): + # Solo mantener campos que existen en el schema + if key in schema_props: + prop_schema = schema_props[key] + + # Si es un objeto anidado, limpiar recursivamente + if prop_schema.get("type") == "object": + result[key] = self._clean_object_against_schema(value, prop_schema) + # Si es un enum, verificar que el valor sea válido + elif "enum" in prop_schema: + if value in prop_schema["enum"]: + result[key] = value + # Para otros tipos, mantener el valor + else: + result[key] = value + + return result def update_config( self, level: str, data: Dict[str, Any], group: str = None @@ -132,20 +287,6 @@ class ConfigurationManager: with open(path, "w") as f: json.dump(data, f, indent=2) - def update_schema( - self, level: str, data: Dict[str, Any], group: str = None - ) -> None: - """Update schema for specified level.""" - if level == "1": - path = os.path.join(self.data_path, "esquema.json") - elif level == "2": - path = os.path.join(self.script_groups_path, "esquema.json") - elif level == "3": - path = os.path.join(self.script_groups_path, group, "esquema.json") - - with open(path, "w") as f: - json.dump(data, f, indent=2) - def list_scripts(self, group: str) -> List[Dict[str, str]]: """List all scripts in a group with their descriptions.""" try: diff --git a/data/data.json b/data/data.json index e599297..245a1ab 100644 --- a/data/data.json +++ b/data/data.json @@ -1,6 +1,4 @@ { "api_key": "your-api-key-here", - "model": "gpt-3.5-turbo", - "max_tokens": 1000, - "temperature": 0.7 -} + "model": "gpt-3.5-turbo" +} \ No newline at end of file diff --git a/data/esquema.json b/data/esquema.json index 88b52aa..5d04917 100644 --- a/data/esquema.json +++ b/data/esquema.json @@ -1,32 +1,20 @@ { + "type": "object", "properties": { "api_key": { - "description": "Tu clave de API para servicios externos", + "type": "string", "title": "API Key", - "type": "string" - }, - "max_tokens": { - "description": "N\u00c3\u00bamero m\u00c3\u00a1ximo de tokens por respuesta", - "title": "Tokens M\u00c3\u00a1ximos", - "type": "number" + "description": "Tu clave de API para servicios externos" }, "model": { + "type": "string", + "title": "Modelo LLM", "description": "Modelo de lenguaje a utilizar", "enum": [ "gpt-3.5-turbo", "gpt-4", "claude-v1" - ], - "title": "Modelo LLM", - "type": "string" - }, - "temperature": { - "description": "Creatividad de las respuestas (0-1)", - "maximum": 1, - "minimum": 0, - "title": "Temperatura", - "type": "number" + ] } - }, - "type": "object" + } } \ No newline at end of file diff --git a/data/log.txt b/data/log.txt index cac062f..7119ef2 100644 --- a/data/log.txt +++ b/data/log.txt @@ -5,9 +5,7 @@ Iniciando ejecución de x1.py... Configuraciones cargadas: Nivel 1: { "api_key": "your-api-key-here", - "model": "gpt-3.5-turbo", - "max_tokens": 1000, - "temperature": 0.7 + "model": "gpt-3.5-turbo" } Nivel 2: { "input_dir": "D:/Datos/Entrada", diff --git a/data/schema.json b/data/schema.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/data/schema.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 81639c4..d8dd941 100644 --- a/templates/index.html +++ b/templates/index.html @@ -92,7 +92,7 @@ // Form rendering functionality async function renderForm(containerId, data) { - console.log(`Rendering form for ${containerId}`); // Debug line + console.log(`Rendering form for ${containerId} with data:`, data); // Debug line const container = document.getElementById(containerId); const level = containerId.replace('level', '').split('-')[0]; @@ -101,13 +101,14 @@ const schema = await schemaResponse.json(); console.log(`Schema for level ${level}:`, schema); // Debug line - if (Object.keys(schema).length === 0) { + if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) { container.innerHTML = '

No hay esquema definido para este nivel.

'; - } else { - const formHtml = generateFormFields(schema, data, '', level); - console.log(`Generated HTML for ${containerId}:`, formHtml.substring(0, 100) + '...'); // Debug line - container.innerHTML = formHtml; + return; } + + const formHtml = generateFormFields(schema, data || {}, '', level); + console.log(`Generated HTML for ${containerId}:`, formHtml.substring(0, 100) + '...'); // Debug line + container.innerHTML = formHtml; } catch (error) { console.error(`Error rendering form ${containerId}:`, error); container.innerHTML = '

Error cargando el esquema.

'; @@ -115,10 +116,18 @@ } function generateFormFields(schema, data, prefix, level) { + console.log('Generating fields with data:', { schema, data, prefix, level }); // Debug line let html = ''; + + if (!schema.properties) { + console.warn('Schema has no properties'); + return html; + } + for (const [key, def] of Object.entries(schema.properties)) { const fullKey = prefix ? `${prefix}.${key}` : key; const value = getValue(data, fullKey); + console.log(`Field ${fullKey}:`, { definition: def, value: value }); // Debug line html += `
`; @@ -139,6 +148,15 @@ return html; } + function getValue(data, path) { + console.log('Getting value for path:', { path, data }); // Debug line + if (!data || !path) return undefined; + + const value = path.split('.').reduce((obj, key) => obj?.[key], data); + console.log('Found value:', value); // Debug line + return value; + } + function generateInputField(def, key, value, level) { const baseClasses = "w-full p-2 border rounded bg-green-50"; // Agregado bg-green-50 para fondo verde claro @@ -177,33 +195,45 @@ try { console.log('Loading schema for level:', level); // Debug line const response = await fetch(`/api/schema/${level}?group=${currentGroup}`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } const schema = await response.json(); console.log('Loaded schema:', schema); // Debug line // Show schema editor modal const modal = document.getElementById('schema-editor'); + if (!modal) { + throw new Error('Schema editor modal not found'); + } modal.classList.remove('hidden'); - // Inicializar JSON editor - const jsonEditor = document.getElementById('json-editor'); - jsonEditor.value = JSON.stringify(schema, null, 2); + // Inicializar el esquema si está vacío + const finalSchema = Object.keys(schema).length === 0 ? + { type: 'object', properties: {} } : schema; - // Inicializar visual editor + // Inicializar editores + const jsonEditor = document.getElementById('json-editor'); const visualEditor = document.getElementById('visual-editor'); + const schemaLevel = document.getElementById('schema-level'); + + if (!jsonEditor || !visualEditor || !schemaLevel) { + throw new Error('Required editor elements not found'); + } + + jsonEditor.value = JSON.stringify(finalSchema, null, 2); visualEditor.innerHTML = '
' + ''; + schemaLevel.value = level; - // Renderizar campos existentes - renderVisualEditor(schema); - - // Guardar nivel actual - document.getElementById('schema-level').value = level; + // Renderizar editor visual + renderVisualEditor(finalSchema); // Activar pestaña visual por defecto switchEditorMode('visual'); } catch (error) { console.error('Error loading schema:', error); - alert('Error cargando el esquema'); + alert('Error cargando el esquema: ' + error.message); } } @@ -218,11 +248,27 @@ jsonEditor.classList.add('hidden'); visualTab.classList.add('border-blue-500'); jsonTab.classList.remove('border-blue-500'); + + // Actualizar el editor visual desde JSON + try { + const schema = JSON.parse(jsonEditor.value); + renderVisualEditor(schema); + } catch (e) { + console.error('Error parsing JSON:', e); + } } else { visualEditor.classList.add('hidden'); jsonEditor.classList.remove('hidden'); visualTab.classList.remove('border-blue-500'); jsonTab.classList.add('border-blue-500'); + + // Actualizar el JSON desde el editor visual + try { + const schema = updateVisualSchema(); + jsonEditor.value = JSON.stringify(schema, null, 2); + } catch (e) { + console.error('Error updating JSON:', e); + } } } @@ -333,91 +379,85 @@ // Funciones de actualización del esquema visual function updateVisualSchema() { - const fields = document.getElementById('schema-fields').children; - const schema = { - type: 'object', - properties: {} - }; - - Array.from(fields).forEach(field => { - const inputs = field.getElementsByTagName('input'); - const select = field.getElementsByTagName('select')[0]; - const key = inputs[0].value; - - schema.properties[key] = { - type: select.value === 'enum' ? 'string' : select.value, - title: inputs[1].value, - description: inputs[2].value + try { + const fields = document.getElementById('schema-fields').children; + const schema = { + type: 'object', + properties: {} }; - if (select.value === 'enum') { - const textarea = field.getElementsByTagName('textarea')[0]; - schema.properties[key].enum = textarea.value.split('\n').filter(v => v.trim()); - } - }); + Array.from(fields).forEach(field => { + const inputs = field.getElementsByTagName('input'); + const select = field.getElementsByTagName('select')[0]; + const key = inputs[0].value; + + schema.properties[key] = { + type: select.value === 'enum' ? 'string' : select.value, + title: inputs[1].value, + description: inputs[2].value + }; - document.getElementById('schema-content').value = JSON.stringify(schema, null, 2); - return schema; + if (select.value === 'enum') { + const textarea = field.getElementsByTagName('textarea')[0]; + if (textarea) { + schema.properties[key].enum = textarea.value.split('\n').filter(v => v.trim()); + } + } + }); + + // Actualizar el JSON editor directamente + const jsonEditor = document.getElementById('json-editor'); + if (jsonEditor) { + jsonEditor.value = JSON.stringify(schema, null, 2); + } + + return schema; + } catch (error) { + console.error('Error updating schema:', error); + return null; + } } async function saveSchema() { try { const level = document.getElementById('schema-level').value; - const schema = updateVisualSchema(); + let schema; - await fetch(`/api/schema/${level}?group=${currentGroup}`, { + // Obtener el esquema según el modo activo + const visualEditor = document.getElementById('visual-editor'); + const jsonEditor = document.getElementById('json-editor'); + + if (!visualEditor.classList.contains('hidden')) { + schema = updateVisualSchema(); + } else { + schema = JSON.parse(jsonEditor.value); + } + + console.log('Saving schema:', schema); // Debug line + + const response = await fetch(`/api/schema/${level}?group=${currentGroup}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(schema) }); - const response = await fetch(`/api/config/${level}?group=${currentGroup}`); - const data = await response.json(); - renderForm(`level${level}-form`, data); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + // Recargar el formulario + const configResponse = await fetch(`/api/config/${level}?group=${currentGroup}`); + const data = await configResponse.json(); + await renderForm(`level${level}-form`, data); + + // Cerrar modal document.getElementById('schema-editor').classList.add('hidden'); } catch (e) { + console.error('Error saving schema:', e); alert('Error guardando esquema: ' + e.message); } } - function getValue(data, path) { - return path.split('.').reduce((obj, key) => obj?.[key], data); - } - - // Actualizar configuración cuando cambia un campo - async function updateConfig(level, key, value) { - const group = currentGroup; - // Obtener configuración actual - const response = await fetch(`/api/config/${level}?group=${group}`); - const config = await response.json(); - - // Actualizar el valor usando la ruta del campo - setNestedValue(config, key, value); - - // Guardar configuración actualizada - await fetch(`/api/config/${level}?group=${group}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(config) - }); - } - - // Función auxiliar para establecer valor en objeto anidado - function setNestedValue(obj, path, value) { - const keys = path.split('.'); - let current = obj; - - for (let i = 0; i < keys.length - 1; i++) { - if (!(keys[i] in current)) { - current[keys[i]] = {}; - } - current = current[keys[i]]; - } - - current[keys[keys.length - 1]] = value; - } - async function setWorkingDirectory() { if (!currentGroup) { alert('Por favor, seleccione un grupo de scripts primero'); @@ -537,6 +577,17 @@ } currentGroup = selectElement.value; // Siempre establecer currentGroup con el valor actual del select console.log('Current group initialized as:', currentGroup); // Debug line + updateGroupDescription(); // Actualizar descripción inicial + + // Configurar el evento de cambio de grupo + selectElement.addEventListener('change', async (e) => { + currentGroup = e.target.value; + localStorage.setItem('selectedGroup', e.target.value); + console.log('Group changed to:', currentGroup); // Debug line + updateGroupDescription(); // Actualizar descripción al cambiar + await initWorkingDirectory(); + await loadConfigs(); + }); // Luego cargar el directorio de trabajo await initWorkingDirectory(); @@ -582,6 +633,13 @@ logArea.innerHTML += lines; logArea.scrollTop = logArea.scrollHeight; } + + function updateGroupDescription() { + const select = document.getElementById('script-group'); + const option = select.options[select.selectedIndex]; + const description = option.getAttribute('data-description'); + document.getElementById('group-description').textContent = description; + } @@ -606,11 +664,16 @@

Grupo de Scripts

- {% for group in script_groups %} - + {% endfor %} +

+
+ + +