|
12
|
Informática / Software / ¿Programa que ponga un gif delante de un programa, sin tener ventana?
|
en: 14 Junio 2025, 06:23 am
|
Como si fuera el puntero del mouse, pero una imagen significativamente más grande y posiblemente con animación, o sea, no creo que pueda ponerse de puntero.
Imaginen que esté andando un videojuego y le meto un gif de lo que quiera. Sé que lo puedo hacer de otros modos, pero tendría que ponerle música y hacer algunas cosas, esto sería cargar el juego, abrir el programa, la imagen, y ya está.
|
|
|
13
|
Programación / Programación General / Simplificar código de juego de cartas, veneno agregado.
|
en: 13 Junio 2025, 08:43 am
|
Creo que algunas cosas se repiten, quizá se pueda crear una función HumanoMayLose y otra IAMayLose. HumanoHP = 20; HumanoPsn = 0; IAHP = 20; IAPsn = 0; Cartas = ["MarioDK", "DK", "DKJr", "Popeye", "Brutus", "Stanley", "Milk"]; // Lo anterior se usa para causar sus efectos, // esto es cómo se muestran sus nombres: ShowerDeCartas = ["Mario de Donkey Kong", "Donkey Kong", "Donkey Kong Junior", "Popeye", "Brutus", "Stanley", "Milk"]; // Frame 1: La IA recibe una carta, el humano también. // F2: Un objeto repite TurnoDeHumano hasta que se presione A. // F3: Pequeña pausa. // F4: Turno de la IA. // F5: Nada, sólo para mostrar victoria o derrota. NroDeCartaDeIA = random(Cartas.length); Mensaje = "Es tu turno"; function HumanoObtieneCarta () { NroDeCartaDeHumano = random(Cartas.length); Mensaje = Mensaje+"\nHas obtenido a "+ShowerDeCartas[NroDeCartaDeHumano]; } HumanoObtieneCarta(); // En F2: function TurnoDeHumano () { // Si se presiona A: if (Key.isDown(65)) { // trace("A presionada"); // Usa la carta (dando su estadística AT y objetivo a la función): // Esto para resumir: CartaUsada = Cartas[NroDeCartaDeHumano]; eval(CartaUsada)(eval(CartaUsada+"AT"), "IA"); } } function FinDelTurnoDeHumano () { if (HumanoPsn > 0) { HumanoHP = HumanoHP-HumanoPsn; Mensaje = Mensaje+"\n¡El veneno te dañó!"; if (HumanoHP > 0) { Mensaje = Mensaje+"\n\nEs el turno del rival"; // Pequeña pausa, luego turno de IA: play(); } else { Mensaje = Mensaje+"\n¡Perdiste!"; gotoAndStop (5); } } else { Mensaje = Mensaje+"\n\nEs el turno del rival"; // Pequeña pausa, luego turno de IA: play(); } } function FinDelTurnoDeIA () { if (IAPsn > 0) { IAHP = IAHP-IAPsn; Mensaje = Mensaje+"\n¡Rival dañado por veneno!"; if (IAHP > 0) { // Turno de Humano: Mensaje = Mensaje+"\n\nEs tu turno"; HumanoObtieneCarta(); gotoAndStop (2); } else { Mensaje = Mensaje+"\n¡Ganaste!"; gotoAndStop (5); } } else { // Turno de Humano: Mensaje = Mensaje+"\n\nEs tu turno"; HumanoObtieneCarta(); gotoAndStop (2); } } // Estadísticas: MilkAt = 0; StanleyAt = 0; DKJrAt = 1; MarioDKAT = 2; PopeyeAt = 2; BrutusAt = 3; DKAT = 4; // Efectos: function TipicoFinDelTurnoDeHumano (ataque) { IAHP = IAHP-ataque; if (IAHP > 0) { FinDelTurnoDeHumano(); } else { Mensaje = Mensaje+"\n¡Ganaste!"; gotoAndStop (5); } } function TipicoFinDelTurnoDeIA (ataque) { HumanoHP = HumanoHP-ataque; if (HumanoHP > 0) { FinDelTurnoDeIA(); } else { Mensaje = Mensaje+"\n¡Perdiste!"; gotoAndStop (5); } } function MarioDK (ataque, objetivo) { if (objetivo == "IA") { Mensaje = "¡Tu rival ha sido enjaulado!"; TipicoFinDelTurnoDeHumano(ataque); } else { Mensaje = Mensaje+"\n¡DKMario rival te enjauló!"; TipicoFinDelTurnoDeIA(ataque); } } function DK (ataque, objetivo) { if (objetivo == "IA") { Mensaje = "¡Rival dañado!"; TipicoFinDelTurnoDeHumano(ataque); } else { Mensaje = Mensaje+"\n¡DK rival te dañó!"; TipicoFinDelTurnoDeIA(ataque); } } function DKJr (ataque, objetivo) { if (objetivo == "IA") { if (IAHP > ataque) { HumanoHP = HumanoHP+ataque; IAHP = IAHP-ataque; Mensaje = "¡Rival dañado y conseguiste "+ataque+"HP!"; FinDelTurnoDeHumano(); } else { HumanoHP = HumanoHP+IAHP; Mensaje = "¡Rival dañado y conseguiste "+IAHP+"HP!"; IAHP = IAHP-ataque; Mensaje = Mensaje+"\n¡Ganaste!"; gotoAndStop (5); } } else if (HumanoHP > ataque) { IAHP = IAHP+ataque; HumanoHP = HumanoHP-ataque; Mensaje = Mensaje+"\n¡DKJr rival te dañó y dió "+ataque+"HP al rival!"; FinDelTurnoDeIA(); } else { IAHP = IAHP+HumanoHP; Mensaje = Mensaje+"\n¡DKJr rival te dañó y dió "+HumanoHP+"HP al rival!"; HumanoHP = HumanoHP-ataque; Mensaje = Mensaje+"\n¡Perdiste!"; gotoAndStop (5); } } function Popeye (ataque, objetivo) { if (objetivo == "IA") { Mensaje = "¡Rival dañado y conseguiste 1HP!"; HumanoHP++; TipicoFinDelTurnoDeHumano(ataque); } else { Mensaje = Mensaje+"\n¡Popeye rival te dañó y dió 1HP al rival!"; IAHP++; TipicoFinDelTurnoDeIA(ataque); } } function Brutus (ataque, objetivo) { if (objetivo == "IA") { Mensaje = "¡Rival dañado y perdiste 1HP!"; IAHP = IAHP-ataque; HumanoHP--; if (IAHP > 0) { if (HumanoHP > 0) { FinDelTurnoDeHumano(); } else { Mensaje = Mensaje+"\n¡Perdiste!"; gotoAndStop (5); } } else if (HumanoHP > 0) { Mensaje = Mensaje+"\n¡Ganaste!"; gotoAndStop (5); } else { Mensaje = Mensaje+"\n¡Empate!"; gotoAndStop (5); } } else { Mensaje = Mensaje+"\n¡Brutus rival te dañó y el rival perdió 1HP!"; HumanoHP = HumanoHP-ataque; IAHP--; if (HumanoHP > 0) { if (IAHP > 0) { FinDelTurnoDeIA(); } else { Mensaje = Mensaje+"\n¡Ganaste!"; gotoAndStop (5); } } else if (IAHP > 0) { Mensaje = Mensaje+"\n¡Perdiste!"; gotoAndStop (5); } else { Mensaje = Mensaje+"\n¡Empate!"; gotoAndStop (5); } } } function Milk (ataque, objetivo) { // ERROR: Esto funciona bien pero está mal, // ya que el objetivo está marcando al rival, // pero esta carta se aplica al usuario. if (objetivo == "IA") { HumanoHP++; Mensaje = "¡Conseguiste 1 HP!"; FinDelTurnoDeHumano(); } else { Mensaje = Mensaje+"\n¡Milk rival dió 1HP al rival!"; IAHP++; FinDelTurnoDeIA(); } } function Stanley (ataque, objetivo) { Resumen = objetivo+"Psn"; set(Resumen, eval(Resumen)+1); if (objetivo == "IA") { Mensaje = "¡Rival envenenado!"; FinDelTurnoDeHumano(); } else { Mensaje = Mensaje+"\n¡Stanley te envenenó!"; FinDelTurnoDeIA(); } }
Milk: Te da 1HP. DK: Daña al rival. Popeye: Daña al rival y te da 1HP. Brutus: Daña al rival y te daña 1. DKJr: Daña al rival y te da HP según cuánto dañe (como por ahora su daño es 1, siempre da 1 y no hay necesidad de tanto código, pero eso es por ahora, el código en teoría está bien para cuando cambie). Stanley: Envenena al rival. MarioDK: Daña al rival y enjaula (pero aún no se aplica).
|
|
|
14
|
Foros Generales / Foro Libre / Volvió el ovni de todos los días en mismo lugar y hora.
|
en: 4 Junio 2025, 20:13 pm
|
De 1:30 a 2 al sur de Montevideo Uruguay, probablemente encima del mar ¿quizá más allá de la superficie del planeta? No lo sé. Hace tiempo, creo que 2 meses, fui a sitios cercanos al mar creyendo que simplemente estaba por ahí, y resultó que estaba más allá, más al sur. Antes lo que vi era un luz que se encendía desde el oeste, yendo hacia el este, se apagaba, y luego de un timpo, quizá 1 o 2 minutos, se repetía. Como esto: https://www.youtube.com/watch?v=yj-gPg9xR1wTambién se veía una luz muy chica y poco brillante moverse de un lado a otro (este y oeste), es lo que veo ahora, es casi imperceptible... Ahora tengo con qué grabarla pero la calidad es tan mala que no se ve, además mi interés es hablar con ellos (si es que son), y no creo que quieran ser filmados. Intentaré ir más cerca del mar a esa hora, pero me resulta complicado... Digo esto por si alguien tiene acceso a visión satelital o algo así y quiere mostrarlo. O si alguien es de este país y tiene algo mejor con qué verlo/grabarlo. Aviso que a esas horas a veces pasa un avión por ahí o al menos en mi línea de visión, y en ese momento las luces no se ven. En cuanto al título, no es que esté todos los días, pero hace 2 meses creo estuvo todos los días durante 2 o 3 semanas... Y fue a principio de mes como ahora.
|
|
|
15
|
Seguridad Informática / Seguridad / ¿Cómo protegerse?
|
en: 29 Mayo 2025, 11:55 am
|
Por privado alguien me comentó que tiene interés en el tema de las estafas, le dije que podía abrir un tema sobre cómo protegerse de eso, pero no lo hizo. Y suele haber gente que dice haber sido estafada; algunos cuentan su experiencia para que no le pase a otro, otros más bien tienen interés en encontrar al malechor. Más recientemente otro me comentó que le interesa el doxeo, que hacerlo por trolear (¿?) o para protegerse, no me queda claro. Parece que son sombreros negro, pero viendo esto que les puede interesar a todos, aunque pueda ser falso: https://www.youtube.com/watch?v=HtvVOrEgQqwpensé en compartirlo y de paso preguntar cómo protegerse, de todo lo malo que pueda ocurrir por usar Internet y esas cosas. Por mi parte diría: - Usar antivirus que bloquee malware. No sé si todos bloquean todo gratis. - Usar un bloqueador de anuncios. Ya que las páginas más peligrosas (o más o menos) suelen tener montones de links invisibles, por ejemplo cliqueas la barra de mover la pantalla y se te abre una pestaña o ventana a no se sabe qué página, de nombre rarísimo, o a veces incluso a una descarga que no tiene sentido que aparezca. - No publicar información personal. En cierto modo es inevitable, pero no es lo mismo decir en qué ciudad vives, que mostrar una foto en que se pueda saber dónde está tu casa exactamente. Además tengo entendido que los hackers pueden obtener información del reflejo de ciertos objetos. Del vidrio de una ventana, de un vaso, o algo así. Así es como doxearon a cierta persona, según he leído una vez. - No dar dinero ni información/fotos que puedan usar para extorsionarte.  - En caso de extorsión... Bueno, si me están apuntando con un revolver, difícil que piense "No haré caso, porque me podría disparar igual o luego me podría pedir otra cosa y otra, etc", uno tiene la esperanza de que si le haces caso te deje sano, y quizá más de uno aquí ha sobrevivido a una situación así, yo incluído (aunque habría que ver si el arma era real, si estaba cargada, etc), pero en el caso de una extorsión es claro que el malechor querrá quitarte más, o siempre podría tener una copia de lo que quieres ocultar, así que lo recomendable parece ir a la police y posiblemente seguirle el juego hasta atraparlo, aunque aquello que te averguence salga a la luz. - Si una persona dice querer ayudarte pero que para eso necesita verte en persona... Podrá haber algún caso en que sí, pero parece mentira. A mí alguien me decía que para enseñarme Programación teníamos que reunirnos en un sitio xP ¿Uds qué agregarían?
|
|
|
17
|
Foros Generales / Foro Libre / ¿Qué opinan de que las RRSS avisen si una cuenta fue reportada como robada?
|
en: 22 Mayo 2025, 11:38 am
|
Hemos visto a más de uno diciendo que le robaron una cuenta de un sitio, y que la ayuda técnica de ahí no les soluciona el problema.
Si la cuenta realmente fue robada, se podría usar con malos fines, y creerán que quien lo hace es la víctima del robo.
Si la víctima y muchas personas tienen la opción de reportar que la cuenta fue robada y eso aparece a los visitantes o quienes interactúan con la persona, eso podría evitar problemas ¿no? "Advertencia: Esta cuenta ha sido reportada como robada, sea cuidadoso al interactuar con su usuario".
Pero entiendo que podría haber reportes falsos, pero podrían tener un nivel de credibilidad según quien los haga. "Advertencia: Los siguientes usuarios han reportado que esta cuenta fue robada: Usuario, nivel, motivo, fecha. Cancelación: Motivo, fecha. Usuario, nivel, motivo, fecha. etc" Lista inicialmente ordenada por nivel, ordenable de otros modos. La cancelación se refiere a si el usuario canceló el reporte, como asumiendo que fue una confusión o la víctima recuperó su cuenta.
La persona podría hacer maldades y luego decir que su cuenta fue robada, pero eso ya es posible.
¿Entonces, esta idea tiene algo malo o es buena idea? ¿qué RRSS la usan?
|
|
|
18
|
Foros Generales / Dudas Generales / Lograr que YT no me recomiende cosas o lo haga en un costado.
|
en: 16 Mayo 2025, 11:49 am
|
No sé qué pasó, las recomendaciones de otros videos me aparecían en un costado o no me aparecían, o muy pequeñas, entonces luego de ver un video podía rápido ir hacia abajo y leer los comentarios. Si quería ver recomendaciones, ponía el final del video y aparecían en el mismo video.
Ahora me aparecen abajo del video y cada una es tan grande como el mismo video así que ir a los comentarios es tedioso.
Tiene algo que ver con el zoom aumentado en Chrome, pero antes no tenía problema.
Aparentemente depende del video al que entre... Si entro a ciertos videos, caben 4 recomendados en la pantalla, pero entrando a otros sólo 1. No me refiero a las recomendaciones cuando termina el video, esas están bien, yo digo las que ma aparecen abajo.
Con el zoom al 100%, aparecen en el costado. Yo le pongo 125% porque sino no veo bien las letras, pero los videos me aparecen abajo, enormes. Antes no pasaba.
|
|
|
19
|
Foros Generales / Foro Libre / ¿En tu país hay convenciones relacionadas con programación? ¿cómo te fue?
|
en: 12 Mayo 2025, 10:21 am
|
Soy de Uruguay. Hace años fui a una. Gratis. Llevé un cd con algo que estaba haciendo. El profesor dijo que no lo pudo ver porque no tenìa una PC con Windows. Era de robótica en realidad. Había robots chiquitos levantando maderitas e intentando colocarlas en un sitio, fallaban en general. Peleas de sumos o algo así, tenían que hacerse caer. Siempre empezaban girando hacia un lado. Le pregunté a uno de los creadores si no podía cambiarse eso, dijo que no. Luego un profesor, escuché, les sugirió que los robots deberían girar para distintos lados. Un tipo hizo un autito a control remoto creo, usando una carcasa de mouse. Me interesó pero... ¿qué podía hacer? ¿pedirle un curso gratis? Mostraron parte de un partido de fútbol usando IA, pero eran unas pelotas (jugadores) quietas con unas lineas, como si fuera la trayectoria de la pelota, supongo que hacerla avanzar pasándosela a otros jugadores aliados intentando que no pase cerca de los rivales. Quizá las pelotitas se movían, la cosa es que duró muy poco y me intersó pero no me pareció que quisieran explicar cómo lo hicieron. En definitiva me pareció como "Miren lo que hicimos, aplaudan y cuando se aburran váyanse", algo para sabiondos nada más, o para ignorantes que quieran mirar, yo pensaba que sería bueno formar un grupo de aprendizaje, pero no parecía posible, estaban los sabiondos o ricos con sus robotitos y estábamos los demás mirando como ignorantes, varios parecían padres, ocupados. Ayer para evitar ser multado tuve que ir a un colegio a votar, vi en él un cartel de olimpiadas de robótica y programación de videojuegos, sólo para alumnos, pero pensé que sería interesante ir a mirar, pero en la página esta https://ceibal.edu.uy/plataformas-y-programas/olimpiada/no vi cuando ni dónde es. Quizá ya se hizo, quizá no es un evento para público, no sé... Se me ocurrió hacer este tema, a ver qué cuentan uds.
|
|
|
20
|
Programación / Programación General / Haciendo juego muy sencillo de cartas, dudas.
|
en: 2 Mayo 2025, 00:30 am
|
Por ahora es que un jugador y la máquina... Tienen puntos de vida (HP). Obtienen 1 carta al azar cada uno. No hay mazo con cartas ordenadas de X modo, simplemente cartas posibles. Es el turno del humano, debe usar su carta. La carta puede tener opciones. La carta hace su efecto según cómo se especificó. Si la IA aún tiene HP, el humano toma otra carta y es el turno de la IA, que deberá seguir el mismo proceso que el humano. Sino, se muestra un mensaje de victoria. Cartas = ["MarioDK", "DK"]; // Lo anterior se usa para hacer sus efectos, esto es cómo se muestran sus nombres: ShowerDeCartas = ["Mario de Donkey Kong", "Donkey Kong"]; HumanoHP = 10; IAHP = 10; // Frame 1: Se dan cartas, el mensaje no tiene saltos de línea. // F2: Un objeto repite TurnoDeHumano hasta que se presione A. NroDeCartaDeHumano = random(Cartas.length); Mensaje = "Tu carta ahora es "+ShowerDeCartas[NroDeCartaDeHumano]; NroDeCartaDeIA = random(Cartas.length); function TurnoDeHumano () { // Si se presiona A: if (Key.isDown(65)) { // Usa la carta (dando su estadística AT a la función): eval(Cartas[NroDeCartaDeHumano])(eval(Cartas[NroDeCartaDeHumano]+"AT")); } } function HumanoObtieneCarta () { NroDeCartaDeHumano = random(Cartas.length); Mensaje = Mensaje+"\n\nTu carta ahora es "+ShowerDeCartas[NroDeCartaDeHumano]; } function FinDelTurnoDeHumano () { HumanoObtieneCarta(); // Turno de la IA: } function Victoria () { Mensaje = Mensaje+"\n\n¡Ganaste!"; gotoAndStop (4); } // Estadísticas: MarioDKAT = 1; DKAT = 2; // Efectos: function MarioDK (ataque) { Mensaje = "¡Tu rival ha sido enjaulado!"; IAHP = IAHP-ataque; if (IAHP > 0) { FinDelTurnoDeHumano(); } else { Victoria(); } } function DK (ataque) { Mensaje = "¡Rival dañado!"; IAHP = IAHP-ataque; if (IAHP > 0) { FinDelTurnoDeHumano(); } else { Victoria(); } }
Quisiera que me digan cómo lo mejorarían (no en cuanto a gráficos, sonido, etc, sino el código, eficiencia y claridad) y cómo puedo hacer que los efectos de las cartas se apliquen al humano o a la IA según quién las juegue. Así como están siempre afectan a la IA. La forma que se me ocurre es pasar un parámetro extra a las funciones, por ejemplo target, y luego meter un if para que afecten a uno u otro, pero pregunto si hay algo mejor. Esto se repite: IAHP = IAHP-ataque; if (IAHP > 0) { FinDelTurnoDeHumano(); } else { Victoria(); }
Es que antes ponía 1ero el daño, luego el mensaje (que varía según la carta) y luego esos ifs, pero tengo pensado que algunas cartas hagan daño a quien las usa o den una carta extra y deba descartarse una, así que ese código dudo que pueda servir repetirlo. Bueno, en general supongo que sí. Respuesta de Deepseek: # Análisis y Mejoras para el Juego de Cartas
## Mejoras de Código y Estructura
1. **Eliminar duplicación de código**: El patrón de reducir HP y verificar victoria se repite. Podrías crear una función común: ```actionscript function aplicarAtaque(target, ataque, mensajeEfecto) { target.HP -= ataque; Mensaje = mensajeEfecto; if (target.HP > 0) { FinDelTurnoDeHumano(); } else { Victoria(); } } ```
2. **Sistema de objetivos más flexible**: En lugar de hardcodear el objetivo, puedes pasar el objetivo como parámetro:
```actionscript function MarioDK(ataque, objetivo) { aplicarAtaque(objetivo, ataque, "¡Tu rival ha sido enjaulado!"); }
// Llamada: eval(Cartas[NroDeCartaDeHumano])(eval(Cartas[NroDeCartaDeHumano]+"AT"), IA); ```
3. **Estructura de datos más organizada**: En lugar de tener arrays separados para nombres y estadísticas, podrías usar objetos:
```actionscript Cartas = [ {nombre: "Mario de Donkey Kong", ataque: 1, efecto: MarioDK}, {nombre: "Donkey Kong", ataque: 2, efecto: DK} ]; ```
4. **Sistema de turnos más robusto**: Implementar un sistema de gestión de turnos que alterna entre jugadores.
## Implementación Mejorada
Aquí tienes una versión mejorada que aborda estos puntos:
```actionscript // Configuración inicial Cartas = [ {nombre: "Mario de Donkey Kong", ataque: 1, efecto: function(objetivo) { aplicarAtaque(objetivo, this.ataque, "¡Tu rival ha sido enjaulado!"); }}, {nombre: "Donkey Kong", ataque: 2, efecto: function(objetivo) { aplicarAtaque(objetivo, this.ataque, "¡Rival dañado!"); }} ];
Jugador = {HP: 10, nombre: "Humano"}; IA = {HP: 10, nombre: "IA"}; turnoActual = Jugador; Mensaje = "";
// Frame 1: Repartir cartas iniciales repartirCartas();
// Frame 2: Lógica del juego function repartirCartas() { NroDeCartaDeHumano = random(Cartas.length); NroDeCartaDeIA = random(Cartas.length); Mensaje = "Tu carta ahora es " + Cartas[NroDeCartaDeHumano].nombre; }
function TurnoDeHumano() { if (Key.isDown(65)) { // Si se presiona A var carta = Cartas[NroDeCartaDeHumano]; carta.efecto(IA); // Siempre ataca a la IA en este caso } }
function aplicarAtaque(objetivo, ataque, mensajeEfecto) { objetivo.HP -= ataque; Mensaje = mensajeEfecto; if (objetivo.HP <= 0) { Victoria(); } else if (turnoActual == Jugador) { FinDelTurnoDeHumano(); } else { // Turno de la IA turnoIA(); } }
function FinDelTurnoDeHumano() { turnoActual = IA; repartirCartas(); // La IA juega inmediatamente después turnoIA(); }
function turnoIA() { var carta = Cartas[NroDeCartaDeIA]; carta.efecto(Jugador); // La IA siempre ataca al jugador // Volver al turno del jugador turnoActual = Jugador; repartirCartas(); }
function Victoria() { var ganador = (IA.HP <= 0) ? Jugador : IA; Mensaje = "¡" + ganador.nombre + " ha ganado!"; gotoAndStop(4); } ```
## Ventajas de esta implementación:
1. **Flexibilidad en objetivos**: Las funciones de efecto ahora reciben explícitamente su objetivo. 2. **Estructura más clara**: Los datos de las cartas están encapsulados en objetos. 3. **Sistema de turnos**: Más fácil de extender para más jugadores o mecánicas complejas. 4. **Menos duplicación**: La lógica común está centralizada en `aplicarAtaque`.
## Para futuras expansiones:
1. **Efectos complejos**: Puedes añadir propiedades adicionales a las cartas (como "dañoAutomatico", "curar", etc.) 2. **Selección de objetivo**: Modificar la UI para permitir elegir objetivo cuando sea relevante. 3. **Múltiples jugadores**: El sistema de turnos ya está preparado para escalar.
Esta estructura hace que sea más fácil añadir nuevos tipos de cartas con efectos variados sin tener que modificar mucho la lógica principal del juego. Mucha cosa, lo pensaré.
|
|
|
|
|
|
|