tag:blogger.com,1999:blog-17699934315853021412024-03-08T01:23:05.717-03:00quinqui bitacoritaBitácora de una programadora: Tips sobre programación, especialmente sobre PHP, Javascript y MySQL/TSQLquinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.comBlogger51125tag:blogger.com,1999:blog-1769993431585302141.post-41202052813753190192023-08-04T19:59:00.006-04:002023-08-05T22:40:51.758-04:00[linux] file_get_contents de PHP no puede acceder a otro servidor de la misma LAN<p>Acabo de escribir sobre nuestros devaneos neuronales para lograr <a href="https://quinqui-bitacorita.blogspot.com/2023/08/linux-error-404-al-usar-reglas-de.html" target="_blank">hacer funcionar los enlaces permanentes de Wordpress en un servidor remoto RedHat</a>. Y ahí mencioné que antes de dicho problema, habíamos tenido que luchar con otro igual de porfiado y jaquecoso.</p><p>La situación era esta: Tenía un script que solicitaba información a un servidor remoto. Valiéndome de <b>file_get_contents()</b>, en mi instalación de <i>localhost</i> lograba conectar con el servidor remoto, pues estábamos en la misma LAN, o red local. Pero, claro, mi servidor local es un Windows 10 con Xampp, que prácticamente no tiene inhibiciones ^^U Por lo que la comunicación era directa y sin tapujos.</p><p>Pero cuando subí mi sitio web al servidor de desarrollo, al que llamaré "Servidor A", la cosa ya no funcionó tan bonita.</p><p>Pues, aun estando en la misma LAN, el servidor remoto, que llamaré "Servidor B", no contestaba las solicitudes del nuevo chico del barrio, "Servidor A". </p><p>No profundizaré en todos los caminos que tomamos con mi compañero de pega para encontrar la solución, pues a estas alturas no me vale la pena y en verdad fue un tortuoso camino que prefiero olvidar, jajaja...</p><p>Por eso, les dejo el desenlace directo, sin preámbulos:</p><p>El culpable de todas nuestras penas y horas de funcionamiento cerebral al 1000% fue el señor don <b>SELinux</b>.</p><p>Si ya lo conocen, sabrán que se encarga de reforzar la seguridad de los servidores Linux. Y este fue el caso en este pequeño Servidor A, de desarrollo, montado en RedHat. </p><p>Don señor SELinux nos bloqueaba cada acción que necesitábamos hacer. No dejaba que Servidor A pudiera comunicarse con ningún otro servidor de la cuadra. Casi me recordó a las madrastras o tías malas de las telenovelas mexicanas de los años 80s... Pero lo bueno (y a diferencia de las villanas de las teleseries), fue que de a poco fuimos descubriendo sus mañas, y al final, entendimos que no era cosa de puertos, ni de librerías sin activar en PHP lo que producía la incomunicación... El señor SELinux sólo necesitaba que le dijéramos que Apache del señor Servidor A quería conversar con el señor Servidor B, que no fuera malito y lo dejara enviarle mensajitos, que a nadie hacía daño con esa pequeña comunicación... Y accedió :) Claro, que usando el comando:</p><p><span style="font-family: courier;">setsebool -P httpd_can_network_connect on</span></p><p><br /></p><p>Y esop. Otro día coloco las referencias, pues ahora estoy apurada, y sólo quería dejar el registro de este tip antes de que se me olvidara todo lo sucedido (ya saben, con el internet no sé lo que pasó hace 30 segundos...).</p><p>Gracias por leer y hasta pronto! </p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-271924077958774512023-08-04T19:34:00.013-04:002023-08-05T22:47:08.347-04:00[linux] Error 404 al usar reglas de .htaccess en Apache<p>Hola a tod@s.</p><p>Los últimos días estuvimos luchando con mi compañero de pega, intentando averiguar por qué los enlaces bonitos de Wordpress no funcionaban en el nuevo servidor RedHat que mi amigo levantó para el efecto.</p><p>Les cuento la historia desde el principio. </p><p>Hice una instalación de Wordpress 6.2.2 en mi servidor local (mi pc con Xampp) para poder desarrollar un <i>Theme</i> acorde al requerimiento que me habían dado de hacer una web con x características. Todo bien ahí.</p><p>Los problemas comenzaron cuando repliqué mi desarrollo en el servidor remoto. <a href="https://quinqui-bitacorita.blogspot.com/2023/08/linux-filegetcontents-de-php-no-puede.html" target="_blank">No hablaré del primer problema que tuvimos, porque no viene a cuento en el actual tema</a>. <strike>Tal vez otro día escriba sobre eso</strike>. Pero sí decir que nos tomó tiempo solucionarlo, y cuando por fin lo logramos, y veíamos todo color de rosa, apareció este otro desgraciado a matarnos la felicidad: los enlaces formateados que nos ofrece Wordpress no funcionaban en el servidor remoto.</p><p>El camino para darle explicación y solución daba comienzo:</p><h4 style="text-align: left;">Revisión de permisos de usuario a los archivos: </h4><p>Modifiqué los permisos y la propiedad de los archivos de la web a fin de que pudieran ser leídos y sobreescritos por el usuario propietario de los procesos del servidor, vale decir, por el usuario "apache". Pero no bastó: por más entregados que dejara a los pobres archivos, "apache" no podía tocarlos -_-.</p><h4 style="text-align: left;">Revisión de las directivas de seguridad de SELinux: </h4><p>Este señor es muy estricto, y ya nos había dado la lucha con el primer obstáculo que tuvimos al mudar el sitio web a este servidor remoto. Pensando que también tendría que ver con el embrollo, volví a investigar, y me encontré con que efectivamente existía un bloqueo de parte de él. Lo bueno es que era solucionable mediante la activación de los permisos de lectura/escritura de los archivos, vía los comandos:</p><p><span style="font-family: courier;">chcon -R -t httpd_sys_rw_content_t /var/www/html</span></p><p></p><p><span style="font-family: courier;">semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html(/.*)?"</span></p><p>El primer comando se supone que habilita recursivamente la lectura/escritura sobre los archivos de la carpeta de mi instalación de Wordpress. El segundo comando hace lo mismo, pero permanente.</p><p>Gracias a este comando, ahora Wordpress podía leer, escribir y hacer lo que quisiera con el <b>.htaccess</b> :D</p><p>Pensé que por fin todos mis problemas se habían solucionado, hasta que me encontré con que al navegar por el sitio web, seguía saliendo el "Error 404" al entrar a los <i>pretty links</i> de Wordpress ¬_¬...</p><h4 style="text-align: left;">Configuración de Directivas de Apache:</h4><p>Y ya cuando me estaba por dar por vencida, tocaba subir el último peldaño del esfuerzo: revisar la configuración de Apache. Respirando profundo, me puse a comparar línea por línea los archivos "conf" de mi localhost y del servidor remoto, comparándolos en lo que debiera ser idéntico. Pero no encontré diferencias...</p><p>Googleando, algunos decían que sus problemas se solucionaron al darle a la directiva de Apache "AllowOverride" el valor de "All": pero esto no me daba confianza alguna, y seguía buscando una alternativa segura.</p><p>Hasta que encontré a otro usuario de los foros que indicaba que, en vez de usar "All", él había usado "FileInfo" como valor de la directiva... Fue entonces que me di cuenta (¡por todos los cielos, cuánto nos nubla el cansancio, que no lo vi antes!) que en mi propio archivo "conf", el de mi <i>localhost</i>, la directiva siempre estuvo en "All", y no en "None" como lo estaba en el servidor remoto: por eso era que los enlaces bonitos funcionaban en mi <i>localhost</i> 🤦x1000</p><p>Pero no sólo esto: en los comentarios del mismo archivo "conf" se explicaba que esa directiva era usada precisamente para el caso de <b>.htaccess</b> , y yo no lo había leído antes! Me hubiera ahorrado otro par de horas de búsqueda si hubiese leído todo con atención, jajaja!</p><p>En fin, que cambié la directiva a "FileInfo", et voilà! Los enlaces bonitos de Wordpress comenzaron a funcionar! XDDDD</p><p><span style="font-family: courier;"><Directory "/var/www/html"></span></p><p><span style="font-family: courier;"><i> # Otras directivas...</i></span></p><p><span style="font-family: courier;"> AllowOverride FileInfo</span></p><p><span style="font-family: courier;"><i> # Más directivas...</i></span></p><p><span style="font-family: courier;"><//Directory></span></p><p><br /></p><p>Pues eso. Espero que les ayude en sus propios devaneos mentales cuando quieran habilitar los <i>pretty links</i> en sus sitios web en servidores Linux con SELinux activado. Gracias por leer y hasta pronto!</p><p><br /></p><p><b>Referencias</b>:</p><p></p><ul style="text-align: left;"><li>Apache HTTP Server Project. <a href="https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride" target="_blank">Directiva AllowOverride</a>. Funcionalidad Básica de Apache.</li><li>@Dwils (2015). Comentario en <a href="https://unix.stackexchange.com/a/50641" target="_blank">httpd can't write to folder/file because of SELinux</a>. StackOverflow.</li><li>@JB0x2D1 (2022). Respuesta en <a href="https://stackoverflow.com/questions/47307662/wordpress-post-page-get-404-but-homepage-works" target="_blank">Wordpress post page get 404 but Homepage works</a>. StackOverflow.</li><li>Kili, A. (2016). <a href="https://www.tecmint.com/check-apache-modules-enabled/" target="_blank">How to Check Which Apache Modules are Enabled/Loaded in Linux</a>. TecMint</li><li>Rainville, S. (2014). <a href="https://www.serverlab.ca/tutorials/linux/web-servers-linux/configuring-selinux-policies-for-apache-web-servers/" target="_blank">Configuring SELinux Policies for Apache Web Servers</a>. ServerLab.</li></ul><p></p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-60205663300847495962023-03-13T16:15:00.006-03:002023-03-13T16:20:52.948-03:00[google.maps] Restringir polígono dentro de otro<p>Hola a todos!!</p><p>En mi trabajo me toca desarrollar hartas cosas bonitas usando la <a href="https://developers.google.com/maps/documentation/javascript/reference?hl=es-419" target="_blank">API de Google Maps</a>.</p><p>La última cosa bonita que estoy haciendo es un Editor Gráfico web, que ocupa <span style="font-family: courier;">Polyline</span>s y <span style="font-family: courier;">Rectangle</span>s. En el siguiente registro les quiero dejar algunos tips sobre cómo lograr cierta característica que puede serles útil, aun si su desarrollo no apunta a lo mismo. Por lo mismo, este tip requiere de conocimientos previos de manejo de la API para comprenderlo.</p><p>Vamos al asunto.</p><p>El Editor que estoy realizando requiere de un área base, o como diríamos en términos gráficos, un <b>lienzo</b> donde trabajar. El <b>objetivo</b> es que el usuario sólo trabaje dentro de esta área, y no fuera de ella.</p><p>Para ello, me valgo de algunas configuraciones previas, que incluyen un par de variables globales, y algunos manejadores de eventos de Google Maps.</p><p>Una variable global me indica en qué "Modo" se encuentra el usuario: para este caso, los valores pueden ser "creando" o "en espera". Otra variable me indicará el "Tipo" de elemento que quiero agregar al Mapa, siendo los valores posibles "lienzo", "rectángulo" o "línea" (no literalmente éstos, claro).</p><p>Paralelamente, he agregado un <i>listener</i> para el "<span style="font-family: courier;">click</span>" del Mapa. La acción asociada es precisamente "Crear Lienzo", acción que sólo se ejecuta si el valor de la variable "Modo" es "creando" y de la variable "Tipo" es "lienzo". Lo que hago es capturar dos clicks en el mapa, de los cuales obtengo las dos coordenadas que servirán de vértices para crear mi <span style="font-family: courier;">Rectangle</span> "Lienzo". Una vez creado, la variable "Modo" pasa a "en espera", por lo que cualquier nuevo click sobre el Mapa no realizará acción alguna.</p><p>Este rectángulo Lienzo es editable, por lo que el usuario puede modificarlo o moverlo a voluntad. Una vez que el usuario le da <i>click</i> a un botón de "Guardar", bloqueo toda edición de este Lienzo, y ahora ya se puede comenzar a trabajar sobre él.</p><p>Previamente, al momento de crear el rectángulo Lienzo, había agregado sobre él un <i>listener</i> para el "<span style="font-family: courier;">click</span>". Este evento ejecuta casi la misma acción que el click sobre el Mapa: si el Modo es "creando", captura los clicks sobre el Lienzo, y dibuja otro <span style="font-family: courier;">Rectangle </span>o un <span style="font-family: courier;">Polyline</span>, según el valor de la variable "Tipo".</p><p>De este modo, si el usuario hace click sobre el Lienzo en Modo "creando" de uno de los dos Tipos antes mencionados ("rectángulo" o "línea"), podrá agregar uno de estos elementos dentro del Lienzo. Estos elementos son creados en modo editable, por lo que el usuario puede moverlos y modificar sus dimensiones o forma a voluntad.</p><p>Ahora bien, para <b>evitar</b> que estos elementos se salgan del Lienzo, lo primero es detectar los cambios en los elementos, tales como reposicionamiento o redimensionamiento.</p><p>En el caso de los <span style="font-family: courier;">Rectangle</span>, nos basta con manejar el evento "<span style="font-family: courier;">bounds_changed</span>": este evento se gatilla cuando las coordenadas Norte, Sur, Este u Oeste del rectángulo cambian, lo cual puede ocurrir tanto si redimensiomos el polígono como si lo movemos de posición.</p><p>En el caso de los <span style="font-family: courier;">Polyline</span>, nos toca manejar dos eventos: "<span style="font-family: courier;">drag</span>" y "<span style="font-family: courier;">mouseup</span>". <br />El evento "<span style="font-family: courier;">drag</span>" se gatilla al mover (arrastrar) el <span style="font-family: courier;">Polyline</span>. <br />El evento "<span style="font-family: courier;">mouseup</span>" se gatilla al soltar el elemento tras haberlo clickado en cualquiera de sus puntos vértice, o sea, se gatilla cuando modificamos la posición de sus vértices (este último evento fue el que más tiempo me tocó averiguar para poder manejarlo, pues no aparece en la documentación ni hay ejemplos de ello, hasta la fecha; lo obtuve de la experimentación en base a ejemplos de otros casos en Stack Overflow).</p><p>Tras haber agregado los <i>listeners</i> respectivos a cada elemento, toca asociarles la acción para "restringir" el movimiento.</p><p>Para ello, lo primero que hago es detectar los límites del rectángulo contenedor del elemento. Teniendo esta "caja", se puede determinar fácilmente con comparaciones simples si ella se encuentra dentro o fuera de la "caja" del Lienzo: el Norte del elemento debe ser inferior al Norte del Lienzo; el Sur del elemento debe ser superior al Sur del Lienzo; etc. </p><p>En el caso de los <span style="font-family: courier;">Rectangle</span>, usamos sus coordenadas tal cual, usando el método <span style="font-family: courier;"><a href="https://developers.google.com/maps/documentation/javascript/reference/polygon?hl=es-419#Rectangle.getBounds" target="_blank">getBounds()</a></span> de la API. </p><p>Pero en el caso de los <span style="font-family: courier;">Polyline</span>, no existe este método (en la V.3 de la API), por lo que debemos calcularlas. Afortunadamente, gracias a los usuarios de Stack Overflow, tenemos una <a href="https://stackoverflow.com/a/36489756/2956233" target="_blank">solución</a> dada por el usuario <a href="https://stackoverflow.com/users/393329/jamie-carl" target="_blank">Jamie Carl</a>: añadiendo esta orden una vez cargado nuestro Mapa, podremos acceder al método <span style="font-family: courier;">getBounds()</span> en todos los <span style="font-family: courier;">Polyline</span> que añadamos al Mapa.</p><p><span style="font-family: courier;"><i><span style="color: #38761d;">/*<br />@author Jamie Carl <br />@date 2016 <br />*/</span></i><br /></span><span style="font-family: courier;">google.maps.Polyline.</span><b style="font-family: courier;">prototype</b><span style="font-family: courier;">.getBounds = </span><b style="font-family: courier;">function</b><span style="font-family: courier;">() {<br /></span><span style="font-family: courier; white-space: pre;"> </span><b style="font-family: courier;">var </b><span style="font-family: courier;">bounds = </span><b style="font-family: courier;">new </b><span style="font-family: courier;">google.maps.LatLngBounds();</span><span style="font-family: courier; white-space: pre;"> </span><b style="font-family: courier;">this</b><span style="font-family: courier;">.getPath().</span><b style="font-family: courier;">forEach</b><span style="font-family: courier;">(</span><b style="font-family: courier;">function</b><span style="font-family: courier;">(item, index) {</span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">bounds.</span><b style="font-family: courier;">extend</b><span style="font-family: courier;">(</span><b style="font-family: courier;">new</b><span style="font-family: courier;"> google.maps.LatLng(item.lat(), item.lng()));<br /></span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">});<br /></span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;"><b>return </b>bounds;<br /></span><span style="font-family: courier;">};</span></p><p>Retomando el caso de la verificación de los <span style="font-family: courier;">Rectangle</span>, como dije antes, sólo debemos comparar que los puntos cardinales del elemento se encuentren dentro de los puntos cardinales del Lienzo. Si uno o más puntos se encuentran fuera, la idea es reposicionar por completo el elemento dentro del Lienzo. Esto se consigue sumando o restando a cada punto cardinal del elemento la diferencia entre los puntos cardinales paralelos del elemento y el Lienzo que se están desbordando. Haré un ejemplo con un gráfico cartesiando ultra simple:</p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSo0uqy92yIwM1iLeg16dfix9xxt_XIx9dYTWkvnA_lCLmgeDvSKb4O8ER3YAfj90m_aR-e-nTrqkrrU4Owa5TEnmyHb7yTVXname8YOHUv-hDfUdsGe7cVc_rGMNKMpyyEUlodcKoAsx-WILaw7i-m1c3BdkhjTS7Fk79VcDK4xHnhepoN8gAGQ/s1082/quinqui-bitacorita_grafico-cart-restringirMov-gmaps-api_230313_1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="1082" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSo0uqy92yIwM1iLeg16dfix9xxt_XIx9dYTWkvnA_lCLmgeDvSKb4O8ER3YAfj90m_aR-e-nTrqkrrU4Owa5TEnmyHb7yTVXname8YOHUv-hDfUdsGe7cVc_rGMNKMpyyEUlodcKoAsx-WILaw7i-m1c3BdkhjTS7Fk79VcDK4xHnhepoN8gAGQ/w400-h311/quinqui-bitacorita_grafico-cart-restringirMov-gmaps-api_230313_1.png" width="400" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><i>Gráfico de ejemplo: Elemento fuera del Lienzo</i></div><p>Tomando el gráfico de ejemplo:</p><p></p><ul style="text-align: left;"><li>La caja de nuestro Lienzo tiene los siguientes puntos cardinales o límites (<i>bounds</i>):</li><ul><li>Norte: 7</li><li>Sur: 2</li><li>Oeste: 3</li><li>Este: 10</li></ul><li>La caja del rectángulo "A" tiene los siguientes límites:</li><ul><li>Norte: 6</li><li>Sur: 4</li><li>Oeste: 2</li><li>Este: 5</li></ul><li>Y tiene las siguientes dimensiones:</li><ul><li>Alto (N - S): 2</li><li>Ancho (E - W): 3</li></ul><li>Al comparar sus límites con los del Lienzo, tenemos que:</li><ul><li>Hacia el Norte: 6 < 7 = Verdadero => Se encuentra dentro del Lienzo</li><li>Hacia el Sur: 4 > 2 = Verdadero => Se encuentra dentro del Lienzo</li><li>Hacia el Oeste: 2 > 3 = Falso => Se encuentra fuera del Lienzo</li><li>Hacia el Este: 5 < 10 = Verdadero => Se encuentra dentro del Lienzo</li><li><u>Conclusión</u>: Por el hecho de tener sólo un punto Fuera del Lienzo, decimos que el Rectangle "A" está fuera del Lienzo, por lo tanto, hay que reposicionarlo dentro.</li></ul><li>Para <b>reposicionarlo</b>, obtenemos los nuevos límites de "A":</li><ul><li>Hacemos el cálculo con el/los punto(s) cardinal(es) divergentes. En este caso, sólo ocurrió con el punto "Oeste". Esto significa que deberemos modificar tanto el límite Oeste como el Este, manteniendo intactos los límites Norte y Sur.</li><li>Nuevo Norte: 6 (sin cambio)</li><li>Nuevo Sur: 4 (sin cambio)</li><li>Nuevo Oeste: 2 (usamos el límite Oeste del Lienzo)</li><li>Nuevo Este: Oeste del Lienzo + Ancho de "A" = 3 + 3 = 6</li></ul></ul><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2HExbXfMKWhhSXIjbpoE7aOYNzHuQZjoQGV9DQfXewXvezAmk8JKZW1ILKMjNPj7WqvjlV6BpQNXsdsimgHYwAK1cJLHXa4Mpo6BycaFIxDtEF8DH4DBlF63UtTuk0BZyhwYDjOrvcpTfnz_YaaldkyfaArkRtBtsQ2oAH0BvbInQ6PO6Qip4Rg/s1082/quinqui-bitacorita_grafico-cart-restringirMov-gmaps-api_230313_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="1082" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2HExbXfMKWhhSXIjbpoE7aOYNzHuQZjoQGV9DQfXewXvezAmk8JKZW1ILKMjNPj7WqvjlV6BpQNXsdsimgHYwAK1cJLHXa4Mpo6BycaFIxDtEF8DH4DBlF63UtTuk0BZyhwYDjOrvcpTfnz_YaaldkyfaArkRtBtsQ2oAH0BvbInQ6PO6Qip4Rg/w400-h311/quinqui-bitacorita_grafico-cart-restringirMov-gmaps-api_230313_2.png" width="400" /></a></div><div style="text-align: center;"><i>Gráfico de ejemplo: Elemento reposicionado</i></div><div><br /></div><p></p><p></p><ul style="text-align: left;"><li>Cabe mencionar que, si al calcular los nuevos límites de "A", notamos que el elemento no cabe dentro del Lienzo, tocará modificar los límites del elemento para que coincidan con los límites del Lienzo (o sea, que ocupe todo el ancho o alto de éste, según sea el caso).</li><li>Teniendo los límites definitivos, los aplicamos al elemento usando el método <a href="https://developers.google.com/maps/documentation/javascript/reference/polygon?hl=es-419#Rectangle.setBounds" target="_blank"><span style="font-family: courier;">setBounds()</span></a>.</li></ul><div>Eso soluciona la verificación en cuanto a <span style="font-family: courier;">Rectangle</span>s.</div><div><br /></div><div>Pero nos queda aún por realizar la verificación a los <span style="font-family: courier;">Polyline</span>s.</div><div><br /></div><div>Gracias al método <span style="font-family: courier;">getBounds()</span> agregado manualmente al prototipo del <span style="font-family: courier;">Polyline</span>, podemos hacer la comparación para constatar si el elemento se encuentra dentro o fuera del Lienzo, pero no nos ayuda necesariamente a determinar la nueva posición del elemento. Pues, en este caso, la verificación se debe hacer en cuanto a los puntos vértice del Polyline, uno por uno.</div><div><br /></div><div>En este caso, lo que hacemos es obtener la lista de puntos del <span style="font-family: courier;">Polyline</span> mediante el método <span style="font-family: courier;"><a href="https://developers.google.com/maps/documentation/javascript/reference/polygon?hl=es-419#Polyline.getPath" target="_blank">getPath()</a></span>, para recorrerla, y realizar la misma comparación simple que hicimos previamente con los límites del <span style="font-family: courier;">Rectangle</span>, pero ahora con cada Punto de la línea.</div><div><br /></div><div>Importante es recordar que no podemos modificar las coordenadas de un Punto existente, <a href="https://developers.google.com/maps/documentation/javascript/reference/coordinates?hl=es-419#LatLng" target="_blank">tal cual lo dice la documentación</a>, por lo que es necesario recrear el <i>path</i> completo, a partir de nuevos puntos, que incluirán tanto a los puntos no modificados como a los modificados tras el reposicionamiento.</div><div><br /></div><div>La lógica de la comparación en este caso, por Punto, sería:</div><div style="text-align: left;"><ul style="text-align: left;"><li>Si tenemos las coordenadas del Punto:</li><ul><li>Latitud (posición en eje N-S)</li><li>Longitud (posición en eje W-E)</li></ul><li>Al compararlas con los límites del Lienzo, podremos determinar sus nuevas coordenadas usando la siguiente lógica:</li><ul><li>Latitud:</li><ul><li>Si Latitud > Norte del Lienzo => Latitud = Norte del Lienzo</li><li>Si Latitud < Norte del Lienzo y Latitud > Sur del Lienzo => Latitud sin cambios</li><li>Si Latitud < Sur del Lienzo => Latitud = Sur del Lienzo</li></ul><li>Longitud:</li><ul><li>Si Logintud > Este del Lienzo => Longitud = Este del Lienzo</li><li>Si Longitud < Este del Lienzo y Longitud > Oeste del Lienzo => Longitud sin cambios</li><li>Si Longitud < Oeste del Lienzo => Longitud = Oeste del Lienzo</li></ul></ul><li>Por cada Punto verificado, creamos un nuevo Punto para añadir a un nuevo <i>path</i>, el cual asignamos al <span style="font-family: courier;">Polyline</span> mediante el método <span style="font-family: courier;"><a href="https://developers.google.com/maps/documentation/javascript/reference/polygon?hl=es-419#Polyline.setPath" target="_blank">setPath()</a></span> tras salir del ciclo de verificaciones. </li></ul></div><div>Y ese sería el "tip" del día de hoy. Espero que les sirva ^_^</div><div>Hasta pronto!</div><div><br /></div><p></p><p><u>Referencias</u>:</p><p></p><ul style="text-align: left;"><li><a href="https://stackoverflow.com/questions/3284808/getting-the-bounds-of-a-polyline-in-google-maps-api-v3" target="_blank">Getting the bounds of a polyline in Google Maps API v3 - Stack Overflow</a></li><li><a href="https://developers.google.com/maps/documentation/javascript/reference/polygon?hl=es-419" target="_blank">Polygons | API de Maps JavaScript | Google Developers</a></li></ul><div><br /></div><p></p><p><br /></p><p><br /></p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-35037022603891043652022-11-07T17:06:00.006-03:002022-11-07T17:14:40.201-03:00[tip] Leer Código QR sin cámara, desde tu navegador web<p>Hola a todos.</p><p>Regularmente estamos encontrándonos con que, tras terminar de leer un anuncio o información, el remitente nos deja un código QR para que podamos expandir nuestro conocimiento respecto del tema recién leído.</p><p>La lectura de estos códigos se ha vuelto muy popular y accesible a todos los usuarios gracias a los dispositivos móviles. Si el mismo no cuenta con una cámara que tenga incorporado el lector, siempre podemos descargar e instalar una liviana aplicación que cumpla con esta función.</p><p>Todo bien hasta ahí.</p><p>Pero, ¿qué pasa si estoy en el computador, sentada frente a la pantalla que me muestra el código, y no me interesa tener que tomar el teléfono móvil, activarlo, abrir la aplicación de lectura de código, enfocar a la pantalla del computador, leer el código, copiar el texto obtenido, buscar la forma de traspasarlo a mi computador (yo generalmente lo envío a un contacto de confianza de Whatsapp, para luego leerlo desde Web Whatsapp -_-), para hacer algo que debiera estar incorporado en mi computador por defecto?</p><p>Pues bien, busqué alguna forma de hacerlo sin la necesidad de una cámara o dispositivo externo a mi computador, y aunque para Google Chrome encontré varias <b>extensiones</b> que dicen realizar la tarea con eficiencia, el hecho de que Chrome me advirtiera que estas extensiones iban a tener acceso a mis ventanas de navegador, donde podrían leer y modificar lo que yo tuviera en ellas, pues me hizo retroceder varios pasos atrás...</p><p>Entonces, recordé al <b>Buscador de Imágenes de Google</b>.</p><h3 style="text-align: left;">El Buscador de Imágenes de Google (BIG)</h3><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">Ocasionalmente uso este buscador cuando, teniendo una imagen, quiero averiguar dónde es que estaba alojada originalmente, o simplemente para hallar imágenes similares (vamos, cuando descargo la foto de un vestido hermoso, y años después no recuerdo de dónde la descargué, y gracias a este buscador logro encontrar el sitio web de origen). </span></div><p>Y de este mismo modo, el habiloso de Google nos vuelve a sorprender gratamente: al mostrarle la imagen del código QR, no sólo nos dice dónde lo podemos encontrar, sino que nos traduce su contenido \(^_^)/ </p><h3 style="text-align: left;">¿Como se hace?</h3><p>1. (Por si eres nuev@ usando BIG), ve a <a href="http://www.google.com" target="_blank">www.google.com</a>, y (1) haz click sobre el enlace "Imágenes" en la parte superior derecha de la ventana, o (2) ingresa directamente al Buscador en este link: <a href="https://www.google.cl/imghp" target="_blank">https://www.google.cl/imghp</a></p><p>2. Te aparecerá la pantalla de BIG:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgNZQ6dWyoF_01N679ntqnT0OY5fNGieYNtOfIg7iMSJhD-xaRuCr2bbl30HusoCiJsyf5AgDRAGGR02wC7RAcXmBDTp704oeYkfpyjvW2y9KLxVvBOTxYFnFre6V5QLzvavt_8vmy5akznysCDBoNvxy6noyhSvQDl3DqYhzgekAzTwcZ67zkZyw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="243" data-original-width="637" height="153" src="https://blogger.googleusercontent.com/img/a/AVvXsEgNZQ6dWyoF_01N679ntqnT0OY5fNGieYNtOfIg7iMSJhD-xaRuCr2bbl30HusoCiJsyf5AgDRAGGR02wC7RAcXmBDTp704oeYkfpyjvW2y9KLxVvBOTxYFnFre6V5QLzvavt_8vmy5akznysCDBoNvxy6noyhSvQDl3DqYhzgekAzTwcZ67zkZyw=w400-h153" width="400" /></a></div><br />3. Haz click sobre el ícono de la camarita, y se expandirá lo siguiente:<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEifJ0NfZupI0LtD9TY_klhWJqg39YvqAV6Zw1fi75zpudiK13h_wc6rF2tM1812FfR8fMViraRZ1JbRzz_X7rCnBzk2yg4KFwXYbi4T0xR0sYXWefQkc68xg_NKQzuqbO764IEZTVSUGRi2kJfbjSzHR_t-U2xnOld7w3rWoVAgIYrUQOzbYenUtA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="522" data-original-width="635" height="329" src="https://blogger.googleusercontent.com/img/a/AVvXsEifJ0NfZupI0LtD9TY_klhWJqg39YvqAV6Zw1fi75zpudiK13h_wc6rF2tM1812FfR8fMViraRZ1JbRzz_X7rCnBzk2yg4KFwXYbi4T0xR0sYXWefQkc68xg_NKQzuqbO764IEZTVSUGRi2kJfbjSzHR_t-U2xnOld7w3rWoVAgIYrUQOzbYenUtA=w400-h329" width="400" /></a></div><br />4. Si la imagen del QR está en tu computador, puedes subirla donde dice "sube un archivo". Pero si se trata de una imagen que está en la web, puedes pegar su enlace en la caja donde dice "Pegar vínculo de imagen".<p></p><p>5. En cualquiera de los casos, BIG analizará la imagen por ti, <i>et voilà</i>! Ya podrás saber qué dice tu código QR misterioso.</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>En este ejemplo, mi código QR trae el URL de esta, mi bitacorita, y así es cómo BIG te lo enseña:</li></ul><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgf4pjCIXw4Pj8UW3jjRei7poEm_DbZeYIlLdhMWy9zs0ugNnwhxyIZVuPeA0uGXZnEF0NZ2pzfD3enu2PZNjgf0qTwOvnj90t5igGfElbV1jpPsqzXG6CrZ0WtH2DbJdvvNv0zH5fqvhQubqITk4JNThsFFcLs3l9cfMPWLJWXdpzaFYm8A1TymQ" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgf4pjCIXw4Pj8UW3jjRei7poEm_DbZeYIlLdhMWy9zs0ugNnwhxyIZVuPeA0uGXZnEF0NZ2pzfD3enu2PZNjgf0qTwOvnj90t5igGfElbV1jpPsqzXG6CrZ0WtH2DbJdvvNv0zH5fqvhQubqITk4JNThsFFcLs3l9cfMPWLJWXdpzaFYm8A1TymQ" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjRiERC9DU2u1xoy1AGZQKah-qZGHSc-h-NaRlSZKxR8WV2dY-DTagj5vPsmjchYQG4hGTfyqreT2MhdLewO4yVqrwgXcx8_yP8xh2YB5tPs9i8JYXrrKhLDEyzEZmpShbune155MOKKsA8ABBUDc6lgCa-F06bVcrHmjk4ZhtEF5TbUtYlwc0XXA" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="528" data-original-width="1313" height="258" src="https://blogger.googleusercontent.com/img/a/AVvXsEjRiERC9DU2u1xoy1AGZQKah-qZGHSc-h-NaRlSZKxR8WV2dY-DTagj5vPsmjchYQG4hGTfyqreT2MhdLewO4yVqrwgXcx8_yP8xh2YB5tPs9i8JYXrrKhLDEyzEZmpShbune155MOKKsA8ABBUDc6lgCa-F06bVcrHmjk4ZhtEF5TbUtYlwc0XXA=w640-h258" width="640" /></a></div><br /></div><br /><ul style="text-align: left;"><li>En este segundo ejemplo, mi código QR contiene sólo un texto, y así es cómo BIG nos lo muestra:</li></ul><div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj2zPwNDKYLomhqjGqfvSKN-gnfwq4r0M3H2w6289188RS1OPgJS2YudejeJoH8DO0gH6wbbPSoP9peMAX0F0g5tGhCF1ekFiCAE9Try_ZuaH4o8i9MBmaxHofOBVFRJSY0_su2yfs5pqH3fzoGzKN41wG0ii3GFrIyw5O-b9c_2qCm3cOVGlQkgA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="534" data-original-width="1303" height="262" src="https://blogger.googleusercontent.com/img/a/AVvXsEj2zPwNDKYLomhqjGqfvSKN-gnfwq4r0M3H2w6289188RS1OPgJS2YudejeJoH8DO0gH6wbbPSoP9peMAX0F0g5tGhCF1ekFiCAE9Try_ZuaH4o8i9MBmaxHofOBVFRJSY0_su2yfs5pqH3fzoGzKN41wG0ii3GFrIyw5O-b9c_2qCm3cOVGlQkgA=w640-h262" width="640" /></a></div><br /><br /><br /><p></p><p>Gracias, san Google, nuevamente, por favor concedido (^_~)</p></div></div>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-37020625186515894172022-08-09T12:38:00.007-04:002022-08-09T12:40:30.210-04:00[php] No usar "die" en páginas web<p> Este es sólo un registro para aconsejar a los programadores de PHP que trabajan en entorno web, a evitar en lo posible el uso de <span style="font-family: courier;">die</span> en sus algoritmos.</p><p><br /></p><h3 style="text-align: left;">Definición de <span style="font-family: courier;">die</span></h3><p>Según la <a href="https://www.php.net/manual/es/function.die.php" rel="nofollow" target="_blank">documentación oficial</a>, <span style="font-family: courier;">die</span> es un constructor del lenguaje equivalente a <span style="font-family: courier;">exit</span>.</p><p>A su vez, <span style="font-family: courier;">exit</span> se define como una construcción del lenguaje que "Imprime un mensaje y termina el script actual" (<a href="https://www.php.net/manual/es/function.exit.php" rel="nofollow" target="_blank">PHP: exit - Manual</a>).</p><p>En resumen, se trata de una instrucción que ordena al procesador <b>interrumpir o detener la ejecución del programa de inmediato</b>. </p><p><br /></p><h3 style="text-align: left;">¿Por qué no recomiendo usar <span style="font-family: courier;">die</span> en desarrollo web?</h3><p>Muchos programadores usan esta instrucción en programas o scripts que son ejecutados en consola o como tareas programadas. En ese sentido, es totalmente pertinente su aplicación en scripts que no son parte de un sistema mayor, que trabajan independiente o que aunque sean parte de un sistema de tareas, su desempeño no afecta visualmente el resultado, pues son controlados por otros procesos.</p><p>En entorno web, sin embargo, el uso de esta instrucción debe ser concienzudamente planeado. La razón principal es que PHP es un lenguaje que se ejecuta linealmente, y si lo incluimos en una página web (que también se ejecuta linealmente), al interrumpir la ejecución de un proceso PHP dentro de una página web, estaremos también deteniendo la ejecución de esta última.</p><p>Esto no aplica si la ejecución de nuestros procesos PHP se ejecutan asíncronamente o contra eventos de la página web, pues esta última ya se ha cargado completamente al momento de ordenar la ejecución de las tareas PHP. Esto no quita, no obstante, el manejo de los errores y mensajes, de modo de informar al usuario siguiendo la gráfica y estética de la página web.</p><p>Me tomé el tiempo de escribir este consejo para mis colegas programadores, dado que cuando he revisado el código de páginas web PHP escrito por otros, me he encontrado con muchos <span style="font-family: courier;">die</span> por cada error o cada resultado vacío de consulta, cuando en entorno web, lo ideal sería guardar dichos resultados en variables de control (booleanos, u objetos manejadores de error, etc.), de modo que la ejecución de la página web en sí no se detenga, y en su lugar, consulte el estado de dichas variables de control, y en base a ellas, ejecute el siguiente proceso o muestre el mensaje pertinente, etc. La idea es que el usuario reciba una página web completa, con la información que le sirva, y no una página mutilada inentendible o poco amigable (como el típico mensaje en <i>Times New Roman</i> -o la fuente por defecto del navegador- en fondo blanco -o el color por defecto que otorgue el navegador-, indicando el error encontrado: esto resulta en algo brusco e incluso irrespetuoso para el usuario).</p><p>Eso sería, les dejo un saludo y hasta pronto! 😉</p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-78310407861605035532022-02-17T17:03:00.003-03:002022-02-17T17:15:37.730-03:00[phpMyAdmin] El almacenamiento de configuración phpMyAdmin no está completamente configurado...<p>Estaba trabajando en la página de Wordpress para mi cliente, en mi instalación local (<span style="font-family: courier;">localhost</span>) y cuando se me ocurre actualizar un par de plugins de WP, todo se cae. Wordpress me da unos avisos horribles de que el usuario de base de datos de WP no tiene el privilegio para alterar la BD... Me sugiere reparar las tablas. Y cuando voy a phpMyAdmin (pMA), el administrador de la BD, éste me sale con el mensaje:</p><blockquote><p>El almacenamiento de configuración phpMyAdmin no está completamente configurado, algunas funcionalidades extendidas fueron deshabilitadas. Averigüe por qué.</p></blockquote><p>Le doy click al link de "Averigüe por qué" y me muestra un nuevo mensaje, que me informa que la "Configuración de pma ... <span style="color: red;">no recibió el OK</span>".</p><p>El primer mensaje me apareció en la pantalla de inicio de phpMyAdmin. </p><p>Pero yo primero lo vi (no exactamente el mismo) en la pestaña de <b>Operaciones</b> de la BD de WP... y sucesivamente en la pestaña de <b>Operaciones</b> de todas las BD. En este caso, me ofrecía crear las tablas de la base de phpMyAdmin en la base en curso, mientras que en la página de inicio, me ofrecía crear la base de phpMyAdmin desde cero. </p><p>Como entré en mini-pánico, al principio le dí a Crear las Tablas en la BD en curso, y así vi aparecer en la BD de WP las tablas de phpMyAdmin (todas llevan el prefijo "<span style="font-family: courier;">pma__</span>"), momento tras el cual las borré todas de allí. Acto seguido busqué info por internet, y aunque no me dieron muchas luces, volví a pMA y entré a la BD de phpMyAdmin para crear sus tablas. Allí me encontré con que las tablas ya existían, pero estaban vacías (salvo una). Pensé que por ahí iba el error. Pero no.</p><p>Incluso le concedí todos los permisos al usuario de BD WP, para ver si con eso se resolvía al menos el problema por parte de WP, pero tampoco funcionó.</p><p>Volviendo a pMA, y tras leer algunas respuestas en internet, resolví revisar el archivo <span style="font-family: courier;">config.inc.php</span> de la instalación de pMA (en mi caso, ubicado en <span style="font-family: courier;">C:\xampp\phpMyAdmin\</span>). Pero todos los datos estaban correctamente ingresados.</p><p>Revisando la <b>documentación</b> sugerida por pMA, me topé con un par de líneas que me dieron ciertas luces. Si el usuario <span style="font-family: courier;">pma</span>, el definido en <span style="font-family: courier;">config.inc.php</span> para administrar la BD de phpMyAdmin, no existía en el servidor, tal vez por ahí podría encontrar la solución.</p><p>Entonces se me ocurrió revisar en pMA los Privilegios de la BD de phpMyAdmin. Y ahí me encontré con que <b>no estaba asociado el usuario <span style="font-family: courier;">pma</span></b>, definido en la configuración. Este usuario existía, pero a nivel servidor solamente. Entonces ingresé a<b> editar sus privilegios</b>, de modo de darle los correspondientes sobre la BD de phpMyAdmin. <i>Et voilà!</i></p><p><span style="font-family: courier;">GRANT SELECT, INSERT, UPDATE, DELETE ON `<pma_db>`.* TO 'pma'@'localhost';</span></p><p>(Yo reemplacé el <span style="font-family: courier;"><pma_db></span> por el nombre de la BD de phpMyAdmin en mi localhost). Cabe destacar como último punto importante, que tal vez sea necesario reiniciar tanto Apache como el servidor de BD para ver reflejados los cambios.</p><p>Eso, espero que les ayude si es que tienen el mismo problema, y así eviten tener que editar demasiadas cosas en su instalación de pMA, como sugieren en los sitios que leí.</p><p>Fuentes:<br /></p><ul style="text-align: left;"><li><a href="https://es.stackoverflow.com/questions/502555/el-almacenamiento-de-la-configuraci%C3%B3n-de-phpmyadmin-ha-sido-desactivado" target="_blank">El almacenamiento de la configuración de PhpMyAdmin ha sido desactivado</a> @ StackOverflow</li><li><a href="http://www.forosdelweb.com/f54/problema-con-phpmyadmin-no-recibio-ok-1087076/" target="_blank">Problema con phpMyAdmin no recibió el OK</a> @ Foros del Web</li></ul><p></p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-30430852321680663322021-12-30T16:02:00.002-03:002021-12-30T16:03:21.530-03:00[wordpress] Error establishing a database connection<p>Hola a todos.</p><p>Trabajando aún con Wordpress, a veces me suele ocurrir el error del título: </p><p></p><blockquote>Error establishing a database connection.</blockquote><p></p><p>Este mensaje nos aparece al acceder a cualquier parte de nuestro sitio de Wordpress, pues intenta conectarse a la base de datos (BD) y no lo consigue. Lamentablemente, no nos entrega más información detallada para poder saber la causa del fallo.</p><p>La causa típica es que las credenciales para acceder a la base de datos, que debimos haber ingresado en el archivo <span style="font-family: courier;">wp-config.php</span>, están incorrectas. Tal vez reemplazamos sin querer el archivo por otro antiguo, o pasamos a llevar una letra en el archivo actual. Si revisamos este archivo y lo corregimos usando los datos correctos de acceso a la BD, el problema estaría resuelto.</p><p>Otra causa, un poco más errática, es que aun teniendo las credenciales correctas, sea la base de datos el problema. En ese sentido, podríamos tener distintos escenarios, tales como:</p><p>- El servidor de base de datos está caído. En ese caso, nos bastaría con revisar su estado, y de tener acceso administrador, volver a levantarlo.</p><p>- La base de datos, el usuario y/o sus privilegios, han sido modificados sin saberlo nosotros. Para esto, será necesario que revisemos con énfasis estos tres aspectos, a fin de que todo esté correctamente operativo y los nombres respectivos coincidan con los de las credenciales en <span style="font-family: courier;">wp-config.php</span> .</p><p>- Error en la tabla de usuarios. Este es el error más rebuscado (y el causante de que terminara escribiendo esta entrada en mi bitacorita) pero que afortunadamente tiene solución. Por alguna misteriosa razón, la BD <span style="font-family: courier;">mysql</span> de mi servidor <span style="font-family: courier;">localhost</span> tiende cada cierto a arrojarme un error cuando ingreso por <i>phpMyAdmin</i>. El error es que no puedo administrar ni las cuentas de usuario ni sus privilegios. El mensaje dice a veces:</p><p></p><blockquote>Error 176 "Read page with wrong checksum" from storage engine Aria</blockquote><p></p><p>a lo que los masters de <a href="https://stackoverflow.com/questions/60864367/1030-got-error-176-read-page-with-wrong-checksum-from-storage-engine-aria" target="_blank">StackOverflow</a> nos sugieren reparar todas las tablas de la base de datos <span style="font-family: courier;">mysql</span>, lo cual efectivamente soluciona este fallo del servidor. No obstante, en cuanto a Wordpress, esto no soluciona el problema original. Y esto se debe a que, aunque ya podamos ver el usuario que creamos para acceder a la BD de Wordpress, ¡ha perdido todos los privilegios sobre ella! Entonces, la solución es simplemente volver a dárselos.</p><p>Et voilà. Eso sería.</p><p>Nos leemos en una próxima aventura programmística 😜</p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-91780480875715898932021-10-08T22:07:00.002-03:002021-10-26T18:53:45.945-03:00[javascript] Scroll vertical se vuelve loco al trabajar un menú fijo (fixed menu)<p>Estoy trabajando en el desarrollo de una página web, en la cual va incluido un menú en la parte superior, de esos amplios que están tan de moda en el diseño gráfico web hoy en día. La idea es que al bajar por la página, este menú permanezca fijo y visible en la parte superior de la página, pero con el detalle de que sea una versión reducida del menú original. O sea, disminuye el alto del menú y el tamaño de la fuente, a fin de no molestar demasiado con el resto del contenido visible en la ventana. </p><p><b>El problema:</b></p><p>Hasta ahí había logrado hacer toda la funcionalidad usando CSS y Javascript. De hecho iba perfecto, <i>exceeeeepto</i> en algunas ocasiones en las que, especialmente cuando la cantidad de contenido en la página no alcanzaba a traspasar mucho el alto de la ventana, y se generaba la barra de desplazamiento vertical, con la cual yo intentaba bajar con el scroll, el mismo se volvía loco y alternaba la apariencia del menú superior entre la amplia y la reducida, moviendo el scroll por sí mismo de arriba a abajo en un pinponeo visual super molesto. Como quien dice, parecía que la página se estancaba en este vaivén super rápido, y encima no permitía bajar, pues cada vez que bajaba, la página me devolvía a la parte superior de la misma.</p><p><b>La investigación:</b></p><p>Estuve depurando los datos por un rato en la consola de Chrome, y lo único que podía entender era que en algún punto, cuando el evento del scroll vertical superaba la posición que yo le daba para transformar el menú amplio por el reducido, efectivamente realizaba la reducción, pero de inmediato, por sí solo, volvía a moverse hacia arriba, a la posición 30px, por lo que volvía a mostrar el menú amplio, y eso lo repetía unas veinte veces hasta parar. Esos 30px que se repetían me hizo pensar que el problema tenía que ver con las medidas. Por eso entré a modificar mi función, mi algoritmo, incluso redondeé los valores, pero nada, no resultaba.</p><p>Investigué, y encontré mi pregunta en el sitio de StackOverflow (<a href="https://stackoverflow.com/questions/35300894/toggling-div-positionfixed-sometimes-causes-scrolling-bug/35325426" target="_blank">Toggling div position:fixed sometimes causes scrolling bug</a>). Si bien había varias respuestas, e incluso una de ellas dada por correcta, todo estaba en inglés, y reconozco que en viernes por la tarde mi cerebro está medio fundido como para traducir bien, jajaja, así que con suerte logré entender la respuesta correcta, y no me convenció su solución (hablaban de crear una DIV que sirviera de referencia para el evento scroll, una DIV que no cambiara de posición, pues siempre iba a estar antes que el menú, por lo que el evento no causaría estragos. Pero esa solución de poner otro DIV antes de los míos no me gustaba.). </p><p>Seguí leyendo las demás respuestas, pero ya en modo lectura rápida, y fue así que en una de ellas creí que entrever que hablaba sobre el "alto del documento". Y ahí me vino el "ting!" jajaja! Lo entendí: lo que estaba pasando era que el documento de mi página era modificado cada vez que yo alternaba entre el menú amplio y el reducido, y por eso el scroll se volvía loco. Ahora lo explico.</p><p>El documento de una página web tiene un alto. Esto suena tan obvio que ni siquiera había pensado que esto era así. O sea, siempre manejamos el ancho de nuestra página y de los elementos en ella, e incluso el alto de estos elementos, pero nunca nos preocupamos mucho del alto de la página en sí.</p><p>Pues bien, este alto existe, y en este caso, estaba medido en pixels. Pixels que se veían modificados cada vez que yo le cambiaba el alto a mi menú superior.</p><p><br /></p><p><span style="color: #38761d; font-family: courier;">/* CSS de mi menú amplio (por defecto, al ver la página en su parte superior): */<br /></span><span style="font-family: courier;">#<span style="color: #741b47;">menu</span><br /></span><span style="font-family: courier;">{<br /></span><span style="font-family: courier;"> <span style="color: #0b5394;">height</span>:102px;<br /></span><span style="font-family: courier;">}<br /><br /><span style="color: #38761d;">/* CSS de mi menú reducido (al desplazarnos hacia abajo en la página): */</span><br />#<span style="color: #741b47;">menu</span>.<span style="color: #990000;">reducido</span><br />{<br /> <span style="color: #0b5394;">position</span>:fixed;<br /> <span style="color: #0b5394;">top</span>:0;<br /> <span style="color: #0b5394;">height</span>:60px;<br />}</span></p><p> </p><p><b>La solución: </b></p><p>Agregar un <span style="font-family: courier;"><DIV></span> en el pie de página (generalmente llamado <i>footer</i>), que actuará como regulador del alto de la página. Para este elemento no necesitamos generar estilos (CSS), sólo necesitamos identificarlo.</p><p><span style="font-family: courier;"><span style="color: #38761d;"> <!-- Esto sería el pie de página o Footer --></span><br /> <<span style="color: #0b5394;">div</span> id="footer"><br /><span style="color: #38761d;"> <!-- Aca el contenido de nuestro footer --><br /></span> <b><<span style="color: #0b5394;">div</span> id="ajuste"></<span style="color: #0b5394;">div</span>></b><br /> </<span style="color: #0b5394;">div</span>><br /> </<span style="color: #0b5394;">body</span>><br /></<span style="color: #0b5394;">html</span>></span></p><p>Luego, en el mismo Javascript donde tenemos nuestra función que realiza la conversión entre el menú amplio y el reducido, agregamos el "ajuste" de alto:</p><p><span style="font-family: courier;"><span style="color: #741b47;">function</span> alternarMenu()<br />{<br /> <span style="color: #741b47;">var</span> menu = <span style="color: #0b5394;">document</span>.getElementById("menu");<br /></span><span style="font-family: courier;"> var ajuste = <span style="color: #0b5394;">document</span>.getElementById("ajuste");<br /></span><span style="font-family: courier;"> <span style="color: #741b47;">var</span> </span><span style="font-family: courier;">altoMinimo = 60;</span></p><p><span style="font-family: courier;"> <span style="color: #741b47;">if</span> (<span style="color: #0b5394;">window</span>.scrollY > altoMinimo)<br /> {<br /> menu.className = "reducido";<br /> <b>ajuste.style.height = "42px";<br /></b> }<br /> <span style="color: #741b47;">else</span> if (</span><span style="color: #0b5394; font-family: courier;">window</span><span style="font-family: courier;">.scrollY < altoMinimo</span><span style="font-family: courier;">)<br /></span><span style="font-family: courier;"> {<br /></span><span style="font-family: courier;"> menu.className = "";<br /></span><span style="font-family: courier;"> <b>ajuste.style.height = "0";<br /></b></span><span style="font-family: courier;"> }<br /></span><span style="font-family: courier;">}<br /></span><span style="font-family: courier;"><span style="color: #0b5394;">window</span>.addEventListener("scroll", alternarMenu);</span></p><p><br /></p><p>Este código, por supuesto, es una super mega simplificación del código real, pero es para que se entienda que en el mismo momento en que le ordenamos al menú cambiar su estilo (o clase), al mismo tiempo debemos alterar el alto del DIV de ajuste, de modo que nuestro alto de documento no varíe. Eso es lo más importante. De ese modo, "engañamos" al scroll, haciéndole creer que nada ha cambiado y que puede proceder como corresponde con nuestro menú cambiante ^_^</p><p>Y pues eso. Esa fue la solución que encontré, y que me puso muy contenta, jejeje. <br />Espero que les sirva también a ustedes.</p><p>Gracias por leer, saludos y que tengan buena programación! ^_^</p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-80335789746864954142021-06-10T23:56:00.001-04:002021-06-10T23:58:23.582-04:00[php+oracle] Función explode() retorna array con valores cero<p>Hola a todos!</p><p>Hoy les comparto un tip que acabo de aprender, tras horas de análisis de un extraño fallo que ocurría en mi programación al usar la función PHP <span style="font-family: courier;">explode()</span>.</p><p>El fallo que ocurría era que al ejecutarlo sobre un <i>string</i>, los valores retornados en el <i>array</i> resultante, eran todos igual a <b>cero</b>, en vez de ser los <i>substrings</i> esperados.</p><p>Ejemplo:</p><p><span style="font-family: courier;">$cadena = <span style="color: #cc0000;">"Hola, mundo"</span>;</span></p><p><span style="font-family: courier;">$array = <b>explode</b>(<span style="color: #cc0000;">","</span>, $cadena);</span></p><p>Al revisar el valor de <span style="font-family: courier;">$array</span>, me salía esto:</p><p><span style="font-family: courier;">Array(<br /> [0] => 0,<br /> [1] => 0<br />)</span></p><p>En vez de esto:</p><p><span style="font-family: courier;">Array(<br /> [0] => "Hola",<br /> [1] => " mundo"<br />)</span></p><p>Al principio, pensé que el separador, la coma, tal vez no era tal, y que era un caracter "similar" a la coma, y entonces debía usar ese caracter "similar" como separador. Por ello, reemplacé el uso de <span style="font-family: courier;">explode()</span> por <span style="font-family: courier;">preg_split()</span>, en la cual puedo usar expresiones regulares como separador. Pero no resultó, pues el caracter, la coma "similar", era exactamente la misma que la de mi separador inicial.</p><p>Entonces pensé que podría deberse al tipo de datos de la variable, que provenía de una base de datos.</p><p>En efecto, el campo de origen era de tipo <span style="font-family: courier;">CLOB</span>. Por eso, en PHP intenté "castear" la variable como <i>string</i> usando su función <span style="font-family: courier;">strval()</span>, pero no bastó. Entonces busqué directamente en Oracle la forma de hacer lo mismo, y así llegué a la función SQL <span style="font-family: courier;">TO_CHAR()</span>:</p><p><span style="font-family: courier;">SELECT TO_CHAR(campo) AS campo...</span></p><p>Y voilà! Mi variable ahora era un sencillo <i>string</i>, y <span style="font-family: courier;">explode()</span> por fin la reconoció como tal, retornándome los valores esperados.</p><p>Sé que es algo muy obvio, pero yo estuve horas devanándome los sesos para averiguar por qué <span style="font-family: courier;">explode()</span> me retornaba estos valores raros, jajaja. Espero que les sirva, y <b>tengan siempre en cuenta el tipo de dato</b> de las variables, especialmente si se cargan desde una base de datos!</p><p>Hasta pronto!</p><p><br /></p><div><br /></div>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-56422891566422829912021-02-03T19:00:00.001-03:002021-02-03T19:00:35.464-03:00[css] La útil función calc()<p>Hola a todos, después de mucho tiempo.</p><p>Este tip que compartiré hoy no es nada extraño para los expertos en CSS, pero para los que empiezan, siento que les será de mucha ayuda (al menos yo no lo conocí sino hasta casi una década después de programar en web...).</p><p>Se trata de la función <b><span style="font-family: courier;">calc()</span></b> para uso en CSS.</p><p>Esta función permite realizar operaciones aritméticas simples para obtener valores numéricos de forma dinámica en nuestra definición de estilos.</p><p>Esto es de muchísima utilidad cuando necesitas precisión al pixel de tu layout; o bien cuando necesitas obtener una posición que es relativa al contenedor, y no es siempre fija.</p><p>Te dejo algunos ejemplos en los que yo he utilizado esta maravillosa función, salvándome la vida:</p><p><b>EJEMPLO 1:</b></p><p><span style="font-family: courier;"><span style="color: #990000;">.miEstilo<br /></span></span><span style="font-family: courier;">{<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">width</span><span style="font-family: courier;">: </span><span style="color: #134f5c; font-family: courier;">calc(100% - 30px)</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">margin</span><span style="font-family: courier;">: </span><span style="color: #134f5c; font-family: courier;">5px 15px</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;">}</span></p><p>En este ejemplo, lo que hacemos es que el elemento html al que se asigne la clase "miEstilo", tendrá un ancho del 100% dentro de su Contenedor, pero además, a este 100% se le restarán 30 píxeles, que corresponden a la suma de los márgenes derecho e izquierdo, cada cual midiendo 15px, de acuerdo a la definición de la línea "margin". Si nosotros omitimos restar el margen al ancho, es probable que el elemento con clase "miEstilo" se desborde de su contenedor, y nuestro layout luzca desprolijo. (A propósito de tener en cuenta el margen en el ancho de nuestros elementos, te recomiendo también tener presente el <span style="font-family: courier;">padding</span> y el <span style="font-family: courier;">border</span>, que también se añaden al ancho final del elemento)<br /></p><div><br /></div><p><b>EJEMPLO 2:</b></p><p><span style="font-family: courier;"><span style="color: #990000;">.miEstilo<br /></span></span><span style="font-family: courier;">{<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">width</span><span style="font-family: courier;">:</span><span style="color: #134f5c; font-family: courier;">100%</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">height</span><span style="font-family: courier;">:</span><span style="color: #134f5c; font-family: courier;">24px</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">background-image</span><span style="font-family: courier;">:</span><span style="color: #134f5c; font-family: courier;">url("img/icono.png")</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">background-repeat</span><span style="font-family: courier;">:</span><span style="color: #134f5c; font-family: courier;">no-repeat</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;"> </span><span style="color: #2b00fe; font-family: courier;">background-position</span><span style="font-family: courier;">:</span><span style="color: #134f5c; font-family: courier;">calc(100% - 5px) center</span><span style="font-family: courier;">;<br /></span><span style="font-family: courier;">}</span></p><p>En este ejemplo, asignamos una imagen de fondo al elemento de clase "miEstilo", el cual tiene una forma ancha y baja, como una barra horizontal. Con la definición de estilo de la imagen de fondo lo que estamos ordenando es que ésta no se repita más que una vez, y sobretodo, que aparezca alineada a la derecha de nuestro elemento, centrada verticalmente. Como no queremos que quede exactamente pegada al borde derecho de nuestro elemento, le decimos que la posicione a 5px antes de llegar al final (su ancho máximo, 100%).</p><div><br /></div><p><b>Acotaciones Importantes:</b></p><p></p><ul style="text-align: left;"><li>Recuerda dejar el espacio necesario entre cada elemento dentro de la función, ya que al no dejarlo, el intérprete no realiza la operación deseada o bien la malinterpreta. Ejemplos:<br />✔ Correcto: <span style="font-family: courier;">calc(100% - 15px)</span><br />❌ Incorrectos: <span style="font-family: courier;">calc(100%-15px) ; calc(100% -15px)</span></li><li>Puedes anidar la función calc() tantas veces como te sea necesario, recordando respetar religiosamente los espacios entre operandos para que la operación se realice correctamente.</li><li>Como pudiste notar en los ejemplos, puedes usar la función mezclando el tipo de dato de los operandos: puedes restar/sumar/multiplicar/dividir porcentajes con píxeles, o cualquier otra medida numérica permitida en CSS, pertinente al caso, claro.</li><li>En general, puedes usar la función en lugar de cualquier atributo que requiera un valor numérico CSS.</li></ul><p></p><p><br /></p><p>Espero que el tip te sirva para perfeccionar tus definiciones de layout como lo hizo conmigo. Saludos y hasta pronto!</p><p><br /></p><p>Referencias:</p><p>- <a href="https://www.w3schools.com/cssref/func_calc.asp" target="_blank">Función calc() en la W3Schools.com</a><br /></p>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-53780878136729066832019-02-14T20:56:00.000-03:002019-02-14T21:05:14.204-03:00[php] htmlentities no funciona como se debeHola a todos! Ha pasado mucho de la última vez que escribí aquí, jijiji!<br />
<br />
Esta vez les traigo un nuevo tip. Se trata del uso de la función PHP <span style="font-family: "courier new" , "courier" , monospace;">htmlentities</span>.<br />
<br />
Como recordarán, esta función retorna una cadena de texto, con los caracteres especiales convertidos a su forma HTML, vale decir, convierte letras tildadas y otros signos a sus respectivos códigos HTML. Esto permite que el navegador interprete nuestra página HTML como corresponde, y no se quede pillada al encontrarse con extraños símbolos que no entiende.<br />
<br />
Ahora bien, desde cierta versión de PHP, la forma de usar esta función cambió un poco. Ya no bastaba con llamarla, sino que hay que indicarle ciertos parámetros para que funcione bien.<br />
<br />
Antes:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>$cadena</b> = <span style="color: #cc0000;">"Hola, ¡cómo estás?"</span>;<br /><b>$cadena_html</b> = <span style="color: blue;">htmlentities</span>(<b>$cadena</b>);<br /><span style="color: blue;">print </span><b>$cadena_html</b>;<br /><span style="color: #6aa84f;">// A nivel de código, obteníamos: Hola, &iexcl;c&oacute;mo est&aacute;s?</span></span></blockquote>
<br />
Ahora:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>$cadena</b> = <span style="color: #cc0000;">"Hola, ¡cómo estás?"</span>;<br /><b>$cadena_html</b> = <span style="color: blue;">htmlentities</span>(<b>$cadena</b>, ENT_COMPAT | ENT_HTML401, <span style="color: #cc0000;">"UTF-8"</span>);<br /><span style="color: blue;">print </span><b>$cadena</b></span><b style="font-family: "courier new", courier, monospace;">_html</b><br />
<span style="font-family: "courier new" , "courier" , monospace;">;<br /><span style="color: #6aa84f;">// A nivel de código, obtenemos de nuevo: Hola, </span></span><br />
<span style="color: #6aa84f; font-family: "courier new" , "courier" , monospace;">&iexcl;c&oacute;mo est&aacute;s?</span></blockquote>
<br />
En teoría, hasta ahí vamos bien.<br />
<br />
Pero resulta que con los nuevos parámetros, vienen nuevos detalles.<br />
<br />
Como habrán notado, ahora nos toca declarar el tipo de codificación de nuestro texto: en el ejemplo, he colocado la codificación "universal", la UTF-8, que es claro, la usada por los anglo parlantes (ya que ellos son los dueños del mundo, ehm! quiero decir, los que inventaron el lenguaje de programación XD).<br />
<br />
En ese sentido, si queremos programar páginas para hispano-lectores, debemos declarar nuestra codificación a ISO-8859-1, para que nos tome los caracteres especiales de nuestro idioma correctamente (vocales tildadas, letras ñ, inicios de signos de exclamación e interrogación, etc.).<br />
<br />
Ese es uno de los primeros detalles: Tener en cuenta el <b>tipo de codificación de nuestra página</b>, para que sea la misma que usamos al invocar la función htmlentities. (Recordar que la codificación de nuestra página se define en el <span style="font-family: "courier new" , "courier" , monospace;">header</span> de nuestro HTML, en la etiqueta <span style="font-family: "courier new" , "courier" , monospace;">meta</span> "Content-type", parámetro "charset".)<br />
<br />
Con dicha información, yo estuve bien todo el tiempo, hasta hace unos días, que comencé a programar nuevos sitios, pero la función fallaba al convertir los caracteres especiales.<br />
<br />
En el mismo ejemplo anterior, me pasaba lo siguiente:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>$cadena</b> = <span style="color: #cc0000;">"Hola, ¡cómo estás?"</span>;<br /><b>$cadena_html</b> = <span style="color: blue;">htmlentities</span>(<b>$cadena</b>, HTML_COMPAT | ENT_HTML401, <span style="color: #cc0000;">"ISO-8859-1"</span>);<br /><span style="color: blue;">print </span><b>$cadena</b></span><b style="font-family: "courier new", courier, monospace;">_html</b><span style="font-family: "courier new", courier, monospace;">;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #6aa84f;">// Tanto a nivel de código como en el navegador web, obtenía esto: Hola, ¡cómo estás?</span></span></blockquote>
<br />
Por más que cambiara la codificación de la página (en el meta del header) o en la función misma htmlentities, no había cambio.<br />
<br />
Hasta que, al investigar, encontré la respuesta en <b>uno</b> de los comentarios de la pregunta de Stack Overflow en inglés <a href="https://stackoverflow.com/questions/18266782/why-does-the-htmlentities-function-not-properly-work" target="_blank">Why does the htmlentities function not properly work?</a> : La respuesta estaba en el tipo de codificación, pero no ya de PHP o HTML, sino del <b>editor de texto</b> que estuviéramos usando! 😲<br />
<br />
En mi caso, había cambiado mi usual Crimson Editor por el Notepad++. Con el primero jamás tuve este problema: tal vez manejaba automáticamente el asunto de qué codificación usar. Pero en el último, estaba en UTF-8, y al cambiarla a ANSI, voilà! Asunto resuelto! XD<br />
<br />
Ese fue el segundo detalle. Espero que les sirva de ayuda, y demos las gracias a los chicos de Stack Overflow, porque siempre nos ayudan con sus conversaciones ^_~<br />
<br />
Hasta pronto!<br />
<br />
<br />
<br />
<div>
<br /></div>
<br />quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com1tag:blogger.com,1999:blog-1769993431585302141.post-31409077277079393872016-04-11T18:59:00.000-03:002016-04-11T18:59:08.396-03:00[genexus] JSConstructor User ControlHace un par de años, me tocó aprender a trabajar con un framework llamado <b>GeneXus</b>. Se trata de una "herramienta de desarrollo de software", tal como la describe la <a href="https://es.wikipedia.org/wiki/GeneXus" target="_blank">Wikipedia</a>, que permite agilizar la construcción de aplicaciones, pues el desarrollador tiene por única tarea diseñar y luego sólo declarar (lo que se conoce como programación de alto nivel): luego GeneXus se encarga de convertir dichas definiciones y declaraciones en código fuente, sobre la plataforma deseada (web, escritorio, móvil).<br />
<br />
Como humilde programadora rasa, esta herramienta me resultó (y sigue resultándome) algo engorrosa de aprender: para alguien que construye una casa colocando ladrillo a ladrillo, es difícil pasar a construirla usando muros ya prefabricados por otros. Es imposible no sentir una cierta desconfianza, pues acostumbrada a verificar cada ínfimo detalle de la programación, ahora le pasamos esa responsabilidad a un autómata. Según como lo veo yo, esta herramienta está hecha no sólo para agilizar la tarea de implementar una idea de software, sino para que los ingenieros que no programan, puedan hacerlo en el menor tiempo y menor cantidad de dificultad posibles. Un logro no falto de ambición y mérito.<br />
<br />
Cuando me tocó adentrarme en esta herramienta, vi todos los tutoriales oficiales, hice los ejercicios, y entendí lo que más pude. Luego, al comenzar a trabajar en aplicaciones reales (para el trabajo), pude ir entendiéndola aun mejor. Mas, al cabo de un par de meses, me topé con ciertas limitaciones, más que nada referidas a la parte gráfica y visual del software final. Por ello, me adentré entonces en lo que la <b>comunidad de desarrolladores</b> en GeneXus llaman <b>User Controls</b>: estos son pequeños módulos o widgets que permiten ampliar las facultades de la herramienta base.<br />
<br />
A la sazón, desarrollé dos User Controls, los cuales usé en las aplicaciones que construí usando GeneXus. Uno de ellos lo publiqué (compartí) en la plataforma social de GeneXus, el <a href="https://marketplace.genexus.com/" target="_blank"><b>Market Place</b></a>. El otro, a falta de tiempo y de finiquitar su documentación, nunca pude publicarlo (aunque lo subí al MP, pero sin poder publicarlo: la documentación es un requisito para ello, tras la revisión de los moderadores del sitio).<br />
<br />
Esta entrada de mi bitacorita es para compartir con ustedes el link hacia el User Control que pude publicar en el Market Place: <a href="https://marketplace.genexus.com/product.aspx?jsconstructor,es" target="_blank"><b>JSConstructor</b></a>. Éste permite crear elementos HTML desde GeneXus en tiempo de ejecución. Los elementos creados no tienen relación con los elementos GeneXus, lamentablemente, pero dejé abierta la interrogante a otros desarrolladores que puedan solucionarla. A la fecha, no sé en qué versión de GeneXus va la cosa, pero el JSConstructor fue desarrollado para la X Evolution 1.<br />
<br />
Pues esop. Para los desarrolladores de GeneXus, espero les sirva en sus aplicaciones mi pequeño aporte ^_^<br />
<br />
Saludos a todos!<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://2.bp.blogspot.com/-rxwRdfJMEAY/VwwdM4u1J8I/AAAAAAAAJ7Y/q7p4qsWR_Rw4kVG5amtIu9DLSRae6b0qw/s1600/banner_JSConstructor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-rxwRdfJMEAY/VwwdM4u1J8I/AAAAAAAAJ7Y/q7p4qsWR_Rw4kVG5amtIu9DLSRae6b0qw/s1600/banner_JSConstructor.jpg" /></a></div>
<br />
<span class="st">© 2014 Carolina Casanova García</span> <br />
- <a href="https://marketplace.genexus.com/product.aspx?jsconstructor,es" target="_blank">Descargar User Control JSConstructor</a><br />
- <a href="http://wiki.genexus.com/commwiki/servlet/wiki?24330,JSConstructor," target="_blank">Documentación JSConstructor</a><br />
quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-90973917403227124432015-09-29T18:59:00.005-03:002015-09-29T19:03:15.516-03:00[javascript] Averiguar si Objeto existe usando JQueryTengo un sistema donde al cargar la página, se ejecutan una serie de funciones e instrucciones dentro del evento <span style="font-family: "Courier New",Courier,monospace;">onLoad</span> de la misma. Ahora bien, detecté que un error JS se estaba gatillando en algunas páginas. Resulta que tengo una barra de herramientas (un DIV con botones), la cual tiene asociado cierto comportamiento JS. Esta barra se encuentra en ciertas páginas que la usarán, pero en las que no, precisamente es en donde el error se gatilla.<br />
<br />
Ya que estoy usando JQuery, tengo todas las funciones de <span style="font-family: "Courier New",Courier,monospace;">onLoad </span>condensadas en un solo archivo JS, por lo que era posible que esto ocurriera.<br />
<br />
Por supuesto podría crear un archivo JS por cada página del sistema, de modo que cada una tenga programado de forma personalizada lo que ocurre en el evento <span style="font-family: "Courier New",Courier,monospace;">onLoad </span>de la misma. Peeeeero, como esto me parece sumamente lento y engorroso, prefiero seguir con el archivo único que es compartido por todas las páginas.<br />
<br />
Pero, entonces, ¿cómo soluciono lo del error por objeto no definido (la barra que no existe)? <b>Lo lógico es preguntar si el objeto existe</b>, de modo que si no, pues pasar de largo, evitando los errores.<br />
<br />
Usando sintaxis Javascript clásica, habría aplicado:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="color: blue;"><b>if</b> </span>(<span style="color: blue;"><b>type </b>document</span>.<span style="color: magenta;">getElementById</span>(<span style="color: #990000;">"divCualquiera"</span>) != <span style="color: #990000;">"undefined"</span>)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> <span style="color: #38761d;">// realizar las tareas de divCualquiera </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<br />
Pero quise averiguar si <b>JQuery </b>no tenía ya implementada una forma más elegante de hacerlo.<br />
<br />
Y bien, pues <b>no, no la tiene</b>.<br />
<br />
Pero la alternativa que tiene, y que es usada por todos los programadores (de acuerdo a los mensajes en diversos sitios donde se consultó este mismo tópico) es:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="color: blue;"><b>if</b></span> ($(<span style="color: #990000;">"#divCualquiera"</span>).length)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> <span style="color: #38761d;">// realizar las tareas de divCualquiera</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<br />
Ahora bien, la propiedad "length" en JQuery retorna siempre un valor numérico (nos informa la cantidad de elementos contenidos por nuestro objeto). De ahí que se pueda consultar como si fuera un booleano (si cero, es falso; de lo contrario, verdadero).<br />
<br />
Debo decir que no me gusta para nada esta solución, ya que no es entendible para quien ve el código por primera vez. Yo esperaba encontrar algo como una función "exists()" o algo por el estilo, pero nada. (De hecho, alguien sugirió crearla por cuenta propia, pero fue increíble la cantidad de comentarios negativos que recibió: pues el fin último de todo programador es reducir el código escrito. Pero yo soy de la opinión que sería ideal mantener la legibilidad del mismo en la medida de lo posible, y una función que pregunta lo que uno realmente quiere, es lo ideal.)<br />
<br />
Esop. Hasta pronto con otro tip :)<br />
<br />
Referencias:<br />
- <a href="http://stackoverflow.com/questions/31044/is-there-an-exists-function-for-jquery" target="_blank">Is there an “exists” function for jQuery?</a> <br />
- <a href="https://api.jquery.com/length/" target="_blank">Jquery .length</a>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-6503873953102191132015-03-09T23:21:00.000-03:002015-03-09T23:21:03.682-03:00[Web] Error: No aparecen los tipos de documento al intentar Crear Nuevo en Google Drive desde FirefoxHolas!! Hace mil años que no me aparecía por acá, jejeje... Pero bueno, acá estoy :P<br />
<br />
Esta vez, es para compartir un nuevo Tip. En esta ocasión, comentarles la rápida solución para aquellos que disfrutan de <b>Google Drive</b>, que usan <b>Firefox</b>, pero que les ha surgido un curioso fallo al intentar Crear un nuevo documento en sus carpetas.<br />
<br />
El error que a mí me apareció fue que al <b>intentar crear un nuevo documento</b>, no me aparecían los <b>tipos de documento</b> para elegir. En su lugar, me decía "Conectar aplicaciones...", lo cual hice siguiendo los pasos en la misma web descritos. Pero en vista que ni reiniciando el navegador el error se corregía (vale decir, me seguía saliendo vacía la lista de tipos de documentos, aun cuando al abrir el panel de Conectar Aplicaciones, las apps que yo había "conectado", efectivamente aparecían "conectadas", y encima un error en fondo rojo sobre el Drive me decía unas veces "Surgieron algunos problemas al cargar tus aplicaciones" y otras "Error al conectar con el servidor" o algo parecido).<br />
<br />
El caso es que de pronto recordé que en algún momento, no sé si Firefox o mi PC, me mostró alguna pantalla de actualización de Google, y yo no lo tomé en cuenta. Entonces, pensé que de pronto se trataría de algún plugin que ahora era necesario tener activado para hacer que GD funcionara con Firefox. Y de hecho, por allí fue la solución.<br />
<br />
Pero no fue en los plugins, sino en los <b>Complementos de Firefox</b>, en donde coloqué en la Búsqueda de Complementos "Google Drive", y me salió algo como "GDrive Panel", asunto que instalé, que pidió reiniciar, y que finalmente, solucionó el problema.<br />
<br />
Y esop. Espero que les sirva a ustedes también, si tienen el problema. Y si lo solucionaron de otra forma más sencilla u ortodoxa, les agradeceré compartirlo con nosotros para aumentar nuestra sabiduría, ok? Gracias a todos por leer y aún más por comentar!! Hasta pronto!! :Dquinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-14337885880841292082013-11-28T13:49:00.000-03:002013-11-29T09:50:55.389-03:00[javascript] Función retorna descendiente de objeto DOM HTMLHolas a todos!<br />
<br />
Hoy les traigo una funcioncita Javascript que hice para apoyar ciertas tareas que estoy haciendo. Así como hace un tiempo les presenté la función <a href="http://quinqui-bitacorita.blogspot.com/2011/06/prog-funcion-javascript-para-obtener.html" rel="nofollow" target="_blank"><b>tatas()</b></a>, que les devolvía los ancestros de un objeto HTML, ahora les traigo la función inversa: la función <b>getDescendiente()</b> les devolverá los objetos hijos o descendientes del objeto HTML buscado.<br />
<br />
En su momento, dejé el código fuente de la función tatas() en una página en mi host personal. En esta ocasión, lo colocaré acá no más :) Espero que les sea de utilidad :D<br />
<br />
Recuerden que si van a reutilizar la función, respeten los créditos colocados en los comentarios! Gracias y hasta pronto!<br />
<br />
<span style="font-family: "Courier New",Courier,monospace; font-size: x-small;"><span style="color: #38761d;">/**<br />-----------------------------------------------------------------------------<br />@about Retorna objeto DOM (unico o coleccion) descendiente del DOM padre.<br /> Puede ser hijo, nieto, bisnieto: vendra dado por la Generacion.<br />@author Carolina Casanova Garcia, aka, quinqui <quinqui_unica at="" yahoo.com.ar=""><br />@date 25/11/2013<br />@param fDom object Requerido.<br />@param fGeneracion integer Requerido.<br />@return object<br />*/</quinqui_unica></span><br /><b>function</b> getDescendiente(fDom, fGeneracion)<br />{<br /> <b>var</b> fHijo = <span style="color: magenta;">false</span>;<br /> <b>if</b> (<b>typeof</b> fDom === <span style="color: #990000;">"undefined"</span> || fDom === <span style="color: magenta;">undefined</span> || fDom === <span style="color: magenta;">null</span>)<br /> {<br /> <span style="color: #38761d;">//alert("Error: Objeto No Existe");</span><br /> }<br /> <b>else</b><br /> {<br /> fGeneracion = (<b>typeof</b> fGeneracion == <span style="color: #990000;">"undefined"</span> ? <span style="color: magenta;">1</span>: fGeneracion);<br /> <b>var</b> fHijo = fDom;<br /> <b>var</b> fPadre;<br /> <b>var</b> f = <span style="color: magenta;">0</span>;<br /> <br /> <b>while</b> (f < fGeneracion)<br /> {<br /> fPadre = fHijo;<br /> fHijo = fPadre.<span style="color: #0b5394;">childNodes</span>;<br /> f++;<br /> }<br /> }<br /> <b>return</b> fHijo;<br />}</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-75672678258046901882013-08-07T19:10:00.000-04:002013-08-07T19:10:03.682-04:00[php] NuSOAP HTTP Error: socket read of headers timed outHolas a todos. Este es para comentar un problema que he tenido al trabajar un servicio web montado en PHP con la clase NuSOAP. El problema surgió cuando intenté llamar al servicio web desde el otro servidor, pero se caía a los exactos 30 segundos de ejecución, mostrando el mensaje que titula este registro: HTTP Error: socket read of headers timed out<br />
<br />
Sabía que el problema era el timeout, pero ¿el timeout de qué? En los servidores y páginas web hay timeouts por todos lados: el de la Conexión a internet o la red, el del Servidor (hardware), el del Servidor Web en sí (Apache, mi caso), el de PHP (mi caso)... Pero nunca se me habría ocurrido que las Aplicaciones o frameworks también pudieran tener :o<br />
<br />
Por eso, tras buscar por la red la solución a mi problema, la respuesta vino precisamente de alguien que señaló sencillamente que había que modificar el timeout de la clase NuSOAP. Y dicho y hecho, eso solucionó el problema.<br />
<br />
Si están usando en su servidor y/o cliente la clase NuSOAP, y desean alterar el timeout, deberán abrir el archivo <span style="font-family: "Courier New",Courier,monospace;">nusoap.php</span> y editar en donde se declare la variable <span style="font-family: "Courier New",Courier,monospace;">$response_timeout</span>, la cual siempre estará definida con un valor de <span style="font-family: "Courier New",Courier,monospace;">30</span> (segundos). Yo intenté modificarla sólo en la definición de las propiedades de la clase, pero no bastó, por lo que terminé modificándola en todas las partes donde fuera llamada o utilizada (habrán sido unas 10 ó más veces en el archivo, dentro y fuera de métodos).<br />
<br />
Espero que este tip les sirva, saludos a todos y gracias por leer!<br />
<br />
<i>Fuente de la respuesta:</i><br />
- <a href="http://www.forosdelweb.com/f18/problema-intentar-consumir-muchos-registros-consulta-web-services-942283/#post3983351" target="_blank">Foros del Web: Problema al intentar consumir muchos registros de una consulta en Web Services</a><br />
<br />quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-79489198865272265942013-06-20T15:26:00.001-04:002013-06-27T18:42:40.183-04:00[tip] Crea tu propio tema en Windows 7Habiendo instalado el Windows 7 en el PC de mi trabajo, me enteré de aquella bella característica de los temas con fondo de escritorio cambiante. Aunque en la ventana de personalización de pantalla no aparece una opción de "Crear Tema", pues me di a la tarea de averiguar si existía la forma de hacerlo. Tras bastante tiempo sin saber cómo se hacía, hoy encontré la respuesta en <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb773190%28v=vs.85%29.aspx" target="_blank">Theme File Format</a> y en la <a href="http://answers.microsoft.com/en-us/windows/forum/windows_7-desktop/where-are-themes-theme-pack-stored-in-windows-7/f62ca678-fb96-4958-9b78-7f70684a8755" target="_blank">Community</a>, ambos sitios de Microsoft.<br />
<br />
La respuesta no podía ser más sencilla, y por eso se las dejo comentada acá.<br />
<br />
Cuando seleccionamos un Tema en nuestra ventana de personalización, lo que hace Windows es buscar el archivo correspondiente a dicho tema. Ese archivo lleva por extensión "theme". De ese modo, tenemos el archivo "aero.theme" para el tema Aero; el archivo "nature.theme" para el tema Naturaleza; y así sucesivamente. Lo increíble y mejor de todo es que estos archivos "theme" no son sino simples archivos de texto, que guardan información en la clásica sintaxis de los archivos "ini"; o sea, parámetros y sus respectivos valores.<br />
<br />
Ahora bien, lo importante es poder primero averiguar dónde Windows almacena estos archivitos, para luego poder editar el nuestro.<br />
<br />
Los archivos de los temas que trae por defecto Windows los podemos encontrar en:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:\Windows\Resources\Themes</span> <br />
<br />
Los archivos de los temas guardados por nosotros los encontramos en:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:\Users\<tu usuario="">(Tu Usuario)\AppData\Local\Microsoft\Windows\Themes</tu></span><br />
<br />
Deben reemplazar donde yo puse <tu usuario=""> </tu><tu usuario=""><span style="font-family: "Courier New",Courier,monospace;">(Tu Usuario)</span> con el ID de usuario de ustedes. </tu><br />
<br />
Es en esta carpetita donde encontrarán los temas guardados por ustedes.<br />
<br />
¿Cómo se guarda un tema propio? Es tan sencillo como abrir la ventana de Personalizar (click derecho sobre el Escritorio), y darle a Guardar al tema actualmente en uso (que probablemente diga "Tema No Guardado"). Una vez que el tema está guardado, vamos a nuestra carpeta personal de temas y abrimos el archivo con un editor de texto cualquiera (un editor que permita abrir y guardar archivos de texto sin corromperlos, claro).<br />
<br />
Estando dentro del archivo, verán un sinfín de parámetros con sus respectivos valores. No modifiquen nada de eso, pues no interfiere con nuestro objetivo, los fondos cambiantes. Diríjanse directo al final del archivo, y, si esta categoría no existe ya, agréguenla (las categorías son aquellas encerradas en corchetes):<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">[Slideshow]<br />Interval=1800000<br />Shuffle=0<br />ImagesRootPath=D:\Mis imágenes\MiTema</span><br />
<br />
Ahora bien, cada parámetro debe ser completado como indica:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">Interval</span> : medido en milisegundos, indicará a Windows el tiempo que debe transcurrir entre cada cambio de imagen.<br />
<span style="font-family: "Courier New",Courier,monospace;">Shuffle </span>: admite valor 1 ó 0 (booleano), e indica si queremos que las imágenes se muestren aleatoriamente (1) o en el orden en el que están guardadas en la carpeta (0).<br />
<span style="font-family: "Courier New",Courier,monospace;">ImagesRootPath </span>: acá deberán señalar la ruta completa a la carpeta donde se encuentran las imágenes a ser mostradas en slide show.<br />
<br />
Y pues, claro, que deben primero haber creado esa carpeta (en mi ejemplo, "D:\Mis Imágenes\MiTema"), y haberla llenado con todas las imágenes que quieran formen parte de su slide show. Algo importante a recordar es que seleccionen para esto imágenes que tengan una resolución igual o superior a la de su pantalla, de modo que no se vean pixeladas a la hora de correr el slide. <br />
<br />
Una vez terminen de editar el archivito, guárdenlo, ciérrenlo, y entonces vuelvan a abrir la ventana de Personalizar. Marquen otro tema, para que Windows asuma otra configuración, y entonces vuelvan a marcar sobre el Tema guardado por ustedes. En la vista previa, si todo salió bien, debiera salirles igual que los otros temas, así como con muchas imágenes hacia atrás.<br />
<br />
Si quieren tener distintos temas, sería crear nuevos temas, abrir el archivo correspondiente e indicar la carpeta respectiva: imaginen tener 10 carpetas con imágenes de distintas temáticas dentro cada una, creando un tema para cada una, resulta muy genial, no? ^^<br />
<br />
Y eso es :)<br />
Espero que les sirva y así puedan disfrutar de un hermoso fondo de escritorio cambiante, y con sus imágenes favoritas.<br />
Saludos y gracias por leer! ^___^<br />
<br />
<b>Editado 27/06/2013</b><br />
No habían pasado unas horas de que lograra hacer esto, que uno de mis compañeros de trabajo me dice "pero si eso se hace por este lado, has reinventado la rueda", aludiendo a la efectiva existencia de la opción que yo buscaba, dentro del mismo panel de Personalizar -____- . Como ya se me pasó la rabia, lo comento acá xD. Pues eso, que estando en dicha ventana, en la parte inferior, hay que hacer click donde dice "Fondo de Escritorio". Al entrar en esta opción viene la parte donde poder seleccionar las imágenes a usar como slideshow. No lo he probado en sí, ya que simplemente entré cuando mi compañero me dijo, y allí estaban las imágenes de la carpeta que yo configuré en el archivo .theme . Lo único que me queda como descargo es decirle nuevamente a los de Microsoft, que si van a darnos la opción de hacer un slideshow, coloquen en el título de la opción "slideshow" (o su equivalente en español), y no "fondo de escritorio", que a todas luces a mí me daba la impresión de "un" fondo, "uno solo", se capta? Esop. Gracias por leer.quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-45998930651508739272013-06-11T16:50:00.002-04:002013-06-11T17:04:43.957-04:00[php] Averiguar si una cadena contiene código HTMLHolas a todos.<br />
<br />
Estaba buscando una manera rápida de averiguar si un texto era código HTML, y tras una breve indagación googleana, les presento la solución que encontré.<br />
<br />
Se usa la función nativa de PHP <a href="http://www.php.net/manual/es/function.strip-tags.php" target="_blank"><span style="font-family: "Courier New",Courier,monospace;">strip_tags()</span></a>, que lo que hace es limpiar una cadena de toda etiqueta HTML que encuentre, devolviéndonos dicha cadena "limpia". Ya que al usar esta función sobre una cadena que efectivamente tiene etiquetas dentro, nos retornará una cadena totalmente distinta, lo que hacemos es averiguar el resultado de comparar la cadena original con la procesada.<br />
<br />
<p style="font-family:'Courier New', Courier, Monospace">
<span style="color: #274e13;">/** <br />
---------------------------------------- <br />
@author Carolina Casanova García <br />
@date 11/06/2013 <br />
@return boolean <br />
*/ </span><br />
<b>function</b> is_html($fval) <br />
{ <br />
<span style="color: #274e13;">// si las cadenas son distintas, entonces se trata efectivamente <br />
// de una cadena con etiquetas HTML dentro </span><br />
<b>return</b> (strip_tags($fval) != $fval); <br />
} <br />
<span style="color: #274e13;">// acá un ejemplo de uso:</span><br />
$cadena = <span style="color: #660000;">'<u><b>¡Hola!</b></u>'</span>; <br />
<b>print</b> <span style="color: #660000;">"<p>La cadena original: "</span>.$cadena.<span style="color: #660000;">"</p>"</span><br />
<b>print</b> <span style="color: #660000;">"<p>Es HTML? ".</span>(is_html($cadena) ? <span style="color: #660000;">"Sí"</span>: <span style="color: #660000;">"Nup"</span>).<span style="color: #660000;">"</p>"</span>;
</p>
<br />
Espero que les haya servido ^^ Yo la usé sin recurrir a la función, sino directamente con la comparación para obtener el booleano, por ello puede que este código les dé errores, ya que no lo probé, pero me captan la idea, no? ^^<br />
<br />
Hasta pronto y gracias por leer!quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-55287763498741358192013-05-14T11:35:00.001-04:002013-05-17T12:15:27.754-04:00[tip] Videos se reproducen muy rápidoHolas a todos. Hoy les traigo un tip para aquellos que han tenido problemas con sus videos en su reproductor en Windows 7. En mi caso particular, la situación era esta:<br />
<br />
Tenía un pc con Windows XP, en donde Winamp era mi reproductor de audio-video de cabecera. La razón de usar Winamp principalmente radicaba en (para mí) su super útil opción de <b>acoplarse </b>a uno de los bordes de la ventana (como si fuera otra barra de herramientas más), y encima poder reproducir mis mini videos en formato FLV. Aquí entro en explicar que, como es el pc del trabajo, suelo descargar mis videos favoritos de internet en la más baja resolución, de modo de tener muchos, y de paso que se reproduzcan dentro de mi playlist como otro track más, sin interferir con mi escritorio de trabajo.<br />
<br />
El problema surgió cuando me cambiaron el pc, y con él, el sistema operativo. Ahora tengo Windows 7, y al instalar el Winamp, pues nada, que no había caso para poder reproducir los videitos en formato FLV. Sabía que era problema de Winamp porque al reproducir el mismo video en Windows Media no había problemas. No obstante, con más investigación caí en la cuenta que no eran los software el problema, sino los (dichosos) códecs. De hecho, bajé el clásico pack de K-Lite, esperando encontrar el decoder "ffdshow", que es el que solía asumir la lectura de todos mis videos. Como este pack aparentemente no funcionó, intenté instalando otros (FLVSplitter -no es pack, pero igual-, Windows 7 Codecs Pack). Pero ni eso funcionó, así que tuve que seguir indagando.<br />
<br />
Para resumir un poco, y sólo incluyendo los pasos más útiles y trascendentales de lo que hice para que esto funcionara, les comento:<br />
<br />
<b>¿Cómo hacer para que Winamp reproduzca los videos FLV?</b><br />
La respuesta más sencilla y repetida iba así:<br />
<ul>
<li>Entrar al menú de Preferencias (click derecho sobre la ventana de Winamp, o bien presionar CTRL+P), siguiendo la ruta "Preferencias » Plug-ins » Entrada". </li>
<li>En la lista de plugins instalados, hacer doble click sobre el decodificador "DirectShow".</li>
<li>En la ventanita que se abre, aparece una serie de extensiones de archivos de video; lo típico es "MPG;MPEG;M2V;AVI". Lo que hay que hacer es agregar la extensión FLV a la lista, de forma que quede algo como: "MPG;MPEG;M2V;AVI;FLV". </li>
</ul>
O sea, más sencillo dónde. A muchas personas les bastó con esto para que su problema de reproducción se solucionara. No fue mi caso.<br />
<br />
Al hacer esto, lo que logré fue que, efectivamente, Winamp reprodujera los videos FLV. El problema era que, si bien los mostraba correctamente, el audio se oía acelerado, y como el video no quería desentonar, se aceleraba también. O sea, era como ver todos los videos en cámara rápida, con voces de ratoncitos.<br />
<br />
Entendí que el problema era el Audio cuando, al entrar a ver la <b>información</b> del video (presionando ALT+3), me aparecían los códecs que estaban trabajando en la lectura del archivo:<br />
<ul>
<li>ffdshow Video Decoder</li>
<li>Microsoft DTV-DTD Audio Decoder</li>
</ul>
<br />
Ahora bien, al buscar la forma de configurar el códec de audio de Microsoft, no encontré prácticamente nada en internet. Mi ideal era poder leer el audio de los videos con el ffdshow, así como ocurría con el video. Por ello busqué en internet información acerca de cómo configurar este decoder de Windows 7, pero nada.<br />
<br />
<b>¿Cómo seleccionar manualmente el códec de Audio para nuestros videos?</b><br />
Lo único que terminé por entender, de todo lo que leí, era que este códec de Windows 7 era prioritario, y que la única forma de deshabilitarlo era eliminando el archivo DLL respectivo (lo que en la práctica, y siguiendo siempre el esquema de recuperabilidad, era renombrar el archivo, de modo que Windows no lo encontrara). El drama era que además de entrar a modificar un archivo de sistema, había que actualizar el registro, y ya con eso era mucho para mí, especialmente porque no es mi pc personal. Eso sin contar con que, según algunos testimonios, esto igual generaba problemas por otros lados.<br />
<br />
Seguí indagando, y al fin se me ocurrió buscar por "cómo deshabilitar" este bendito códec. Y alli por fin encontré lo que necesitaba: alguien que liberó un pequeño programa que hacía lo anterior por nosotros. Este programita se llama <b>Win7DSFilterTweaker</b> y lo pueden encontrar en <a href="http://www.codecguide.com/" target="_blank">Codec Guide</a>, específicamente <b><a href="http://www.codecguide.com/windows7_preferred_filter_tweaker.htm">acá</a></b>.<br />
<br />
Con este programita lo que se nos permite es, precisamente, deshabilitar los Microsoft DTV-DTD códecs. En mi caso particular, lo que hice fue deshabilitar el códec de Audio. Ahora, cuando abro la ventana de información del video que reproduzco, me aparece:<br />
<ul>
<li>ffdshow Video Decoder</li>
<li>ffdshow Audio Decoder</li>
</ul>
¡Ahora puedo ver y escuchar mis mini videos en Winamp como siempre! ^____^ *Felicidad*<br />
Pues eso. Espero que les ayude este tip, que yo estuve casi 3 semanas sufriendo de no poder ver mis videos kpoperos, jejeje :P<br />
<br />
Gracias por leer y hasta pronto!<br />
<br />
PD: <strike>El único detallito que me quedó en el tintero con haber logrado esto, es que, lamentablemente al apretar y cambiar tanta opción en las configuraciones de los códecs, algo hice que el audio ahora se escucha muy bajo, jajaja xD Pero es un mal menor al lado de no poder ver mis videos favoritos ^^ jejeje</strike> Editado (17/05/2013): Todavía no sé qué fue lo que hice mal antes, pero ahora ya encontré la "solución" al problema, y fue en el control de volumen de Windows, que ahora trae un control maestro y un control especial por cada aplicación abierta: sólo tuve que aumentar el volumen del control asociado a Winamp y listo :)<br />
PD2: Otra de las cosas que hice para poder encontrar la solución deseada, fue instalar otros reproductores. Así instalé el que conozco más, KMPlayer, pero como adolece de la acoplabilidad, tampoco solucionaba mi problema. Al respecto de esto mismo, en mi búsqueda hasta dejé preguntas en foros y sitios de consulta, pero como a muchos con la misma duda, siempre la sugerencia era cambiarse de reproductor, y esto lo encuentro tan mala respuesta como desubicada. Si uno va a un restaurant y pide "arroz con pollo", el mesero no va y le dice a uno "mejor coma puré con carne, que es más rico", sino que trae lo que uno pide. En fin, sólo un pequeño descargo para esos users soberbios de la red...<br />
<br />
<u>Referencias</u>:<br />
- <a href="http://forums.winamp.com/showthread.php?postid=2013385" target="_blank">How to play YouTube/Google Flash Videos (FLV) in Winamp</a><br />
- <a href="http://www.makeyoutubevideo.com/disablemicrosoftdtvdvdvideodecoder.html" target="_blank">How to Disable Microsoft Windows7 built-in Microsoft DTV-DVD Decoder </a><br />
- <a href="http://forums.bakabt.me/index.php?topic=25198.0" target="_blank">Microsoft DTV-DVD Audio decoder - help</a><br />
- <a href="http://www.codecguide.com/windows7_preferred_filter_tweaker.htm" target="_blank">Preferred Filter Tweaker for Windows 7 and 8</a><br />
Visité muchas páginas más, pero estas son las que valieron al final para lo conseguido. Muchas gracias a todos ellos! :Dquinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com4tag:blogger.com,1999:blog-1769993431585302141.post-55541029093006394742013-03-28T16:36:00.001-03:002013-04-08T09:44:17.168-03:00[tsql] Error: La instrucción INSERT EXEC no se puede anidarHolas a todos.<br />
<br />
Mientras programaba un procedimiento almacenado, intenté obtener los datos de otro procedimiento, como lo he venido haciendo desde que descubrí tamaña maravilla de la programación sql.<br />
<br />
Pero hoy me topé con este extraño error: <b>La instrucción INSERT EXEC no se puede anidar</b>.<br />
<br />
Tras investigar por algunos lados, di con la respuesta: no se puede almacenar en una tabla temporal de procedimiento almacenado, el resultado de otro procedimiento que también esté realizando una inserción de este tipo.<br />
<br />
Esto es algo como tener:<br />
<br />
<div style="font-family: 'Courier New', Courier;">
CREATE PROCEDURE miProcedimiento<br />
AS<br />
<br />
INSERT INTO #tablita EXEC otroProcedimiento;<br />
SELECT * FROM #tablita; <br />
<br />
END; <br />
<br />
CREATE PROCEDURE nuevoProcedimiento<br />
AS<br />
<br />
INSERT INTO #tabla1 EXEC miProcedimiento; <br />
<br />
END;
</div>
<br />
Esto significará que si ejecuto:<br />
<br />
<div style="font-family: 'Courier New', Courier;">
EXEC nuevoProcedimiento;
</div>
<br />
...SQL me arrojará el error antes mencionado.<br />
La solución al problema es no llamar a un procedimiento que esté llamando a otro ya en su interior. En algunos lados leí que transformaban el procedimiento intermedio (en el ejemplo, "miProcedimiento"), en una función que retorne un dato tipo TABLE. Pero esto no lo he probado, así que no sé si cambiaría las cosas.<br />
<br />
Bueno, esop. Saludos!<br />
<br />
Info:<br />
• <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlserveres/thread/ce6e3c1c-f6c6-44c4-8bee-e0c547a3adcc" target="_blank">Guardar el resultado de un procedimiento almacenado en una tabla</a> <br />
• <a href="http://www.sqlservercentral.com/Forums/Topic1122371-23-1.aspx" target="_blank">Problems with INSERT from stored procedure</a>quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com2tag:blogger.com,1999:blog-1769993431585302141.post-43143179432501770732013-03-13T13:17:00.001-03:002013-03-13T14:15:55.288-03:00[sql] Búsqueda por palabras en una fraseHolas de nuevo.<br />
<br />
Esta vez les he traído un tip especial para principiantes ultra novatos en desarrollo de consultas a bases de datos ^^. Se trata del método que uso para poder hacer consultas a una tabla, filtrando los resultados de acuerdo una frase de búsqueda. Usaré sentencias en TSQL y lenguaje PHP para hacer los ejemplos.<br />
<br />
Todos sabemos cómo hacer una consulta teniendo una palabra o frase exacta de búsqueda:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> tabla <br />
<b>WHERE</b> campo <b>LIKE</b> '%palabra o frase clave%';
</p>
Si queremos aplicar la palabra o frase de búsqueda en varias columnas, la sintaxis sería:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> tabla<br />
<b>WHERE</b> campo1 <b>LIKE</b> '%palabra o frase clave%' <br />
<b>OR</b> campo2 <b>LIKE</b> '%palabra o frase clave%';
</p>
...añadiendo todas las columnas deseadas a continuación, siempre separando con el OR. Si hubiesen más condiciones de filtro, sería encapsular todos los elementos separados por OR, dentro paréntesis redondo:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> tabla<br />
<b>WHERE</b> <br />
campoX = 'valor'<br />
<b>AND</b><br />
(campo1 <b>LIKE</b> '%palabra o frase clave%' <br />
<b>OR</b> campo2 <b>LIKE</b> '%palabra o frase clave%'); <br />
</p>
También podríamos realizar la búsqueda en varias columnas concatenadas, si así nos conviene:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> tabla<br />
<b>WHERE</b> campo1 + ' ' + campo2 <b>LIKE</b> '%palabra o frase clave%'; <br />
</p>
Ahora bien, todo esto va perfecto, pero... ¿qué pasa si queremos que la búsqueda usando la "frase clave" se realice buscando cada palabra de la frase, dentro del texto de la columna individual o las columnas concatenadas? Me explico con un ejemplo: la clásica búsqueda de personas mediante su nombre y apellidos.<br />
<br />
Tenemos la tabla <i><b>persona</b></i>, teniendo varias columnas, y entre ellas: <i>nombre1, nombre2, apellido1</i> y <i>apellido2</i>.<br />
Esta tabla contiene los siguientes registros:
<p style="font-family:'Courier New',Courier,monospace;">
------- - ------- - --------- - --------- <br />
nombre1 - nombre2 - apellido1 - apellido2<br />
------- - ------- - --------- - --------- <br />
Juan - Antonio - Pérez - Cortés<br />
María - Inés - González - Rojas<br />
Luis - Alberto - Rojas - Morales<br />
Karina - Pamela - Pérez - González<br />
Diego - Juan - Contreras - Pérez<br />
------- - ------- - --------- - ---------
</p>
Si en mi buscador yo quisiera buscar a "Juan Pérez", podría hacerlo de cualquiera de las siguientes maneras:<br />
<br />
<b>A) Buscador detallado.</b>
<br />
Colocar en el formulario de búsqueda una caja de texto para cada uno de los campos a consultar. O sea, una caja para hacer la búsqueda en la columna nombre1; otra, para la columna nombre2; y así etc.<br />
<br />
<div style="border: #888888 1px solid; padding:6px">
<b>Búsqueda</b><br />
Primer Nombre : <input type="text" /><br />
Segundo Nombre : <input type="text" /><br />
Primer Apellido : <input type="text" /><br />
Segundo Apellido : <input type="text" /><br />
<input type="button" value=" Buscar " />
</div>
<br />
Luego, cuando por programación recupere el valor de las cuatro cajas de texto, podría armar la consulta por programación así:<br />
<br />
En lenguaje PHP:
<p style="font-family:'Courier New',Courier,monospace;">
$consulta = "SELECT * FROM persona WHERE ";<br />
$consulta .= (!<b>empty</b>($_POST["nombre1"]) ? " nombre1 LIKE '%".$_POST["nombre1"]."%'": "");<br />
$consulta .= (!<b>empty</b>($_POST["nombre2"]) ? (!<b>empty</b>($_POST["nombre1"]) ? " AND ": "")." nombre2 LIKE '%".$_POST["nombre2"]."%'": "");
</p>
Y así continuar con los apellidos, etc...<br />
<br />
Ahora bien, ¿qué ocurre si el usuario no sabe si "Juan" es el primer o segundo nombre, y/o lo mismo con el apellido "Pérez"? Más aún, ¿qué ocurrirá si por extraña razón hay una persona a la que han bautizado "Pérez", o que uno de sus apellidos es "Juan"? Etc...<br />
<br />
En ese sentido, esta solución, aunque efectiva, resulta aparatosa y engorrosa, tanto para el usuario como el programador.<br />
<br />
<b>B) Buscador de Frase Exacta.</b>
<br />
Un formulario de búsqueda con una caja de texto única.<br />
<br />
<div style="border: #888888 1px solid; padding:6px">
<b>Ingrese Palabras :</b> <input type="text" /> <input type="button" value=" Buscar " />
</div>
Por programación, recibiremos el valor de la caja de texto y podríamos crear una gran consulta donde abarcar la mayor cantidad de alternativas de uso de la frase exacta de búsqueda:<br />
<br />
En lenguaje PHP:
<p style="font-family:'Courier New',Courier,monospace;">
$consulta = "SELECT * FROM persona WHERE ";<br />
$consulta .= " nombre1 LIKE '%".$_POST["frase"]."%'";<br />
$consulta .= " OR nombre2 LIKE '%".$_POST["frase"]."%'";<br />
$consulta .= " OR apellido1 LIKE '%".$_POST["frase"]."%'";<br />
$consulta .= " OR apellido2 LIKE '%".$_POST["frase"]."%'";
</p>
<br />
Incluso podemos aplicar la concatenación de columnas:
<p style="font-family:'Courier New',Courier,monospace;">
$consulta .= " OR nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 LIKE '%".$_POST["frase"]."%'";
</p>
El resultado, no obstante, no será el esperado, sea cual sea la condición usada. Si las analizamos una por una, tenemos que:<br />
<br />
"Juan Pérez" en Nombre1 => Falso<br />
"Juan Pérez" en Nombre2 => Falso<br />
"Juan Pérez" en Apellido1 => Falso<br />
"Juan Pérez" en Apellido2 => Falso<br />
"Juan Pérez" en Nombre1 + Nombre2 + Apellido1 + Apellido2 => Falso<br />
<br />
Para obtener los resultados esperados, sería necesario programar desarme de la frase y generar todas las combinaciones de columnas x palabras de búsqueda posibles. Por eso, es mejor pasar directo a la opción C).<br />
<br />
<b>C) Buscador de frase, por palabra (ordenado)</b><br />
Teniendo el mismo formulario de búsqueda que en B), sólo tenemos que cambiar la consulta SQL armada por programación, de modo que la búsqueda sea realizada en todas las columnas, pero tomando todas las palabras de la frase por separado, aunque respetando el orden en el que fueron escritas.<br />
<br />
En lenguaje PHP:
<p style="font-family:'Courier New',Courier,monospace;">
$consulta = "SELECT * FROM persona WHERE ";<br />
$consulta .= " nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 LIKE '%".<b>str_replace</b>(" ", "%", $_POST["frase"])."%'";
</p>
En SQL, la consulta generada tendría la siguiente apariencia:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> persona <br />
<b>WHERE</b> nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 <b>LIKE </b>'%Juan%Perez%';
</p>
Ya que hemos colocado esos comodines entre las palabras de la frase, SQL buscará dentro de la concatenación de columnas, todos los registros que contengan las palabras "Juan" y "Perez" en su interior. El resultado de esta consulta, nos retornará 2 registros:
<p style="font-family:'Courier New',Courier,monospace;">
------- - ------- - --------- - --------- <br />
nombre1 - nombre2 - apellido1 - apellido2<br />
------- - ------- - --------- - --------- <br />
Juan - Antonio - Pérez - Cortés<br />
Diego - Juan - Contreras - Pérez<br />
------- - ------- - --------- - ---------<br />
</p>
...ya que "Juan" fue encontrado en el nombre1 del primer registro y en el nombre2 del quinto registro; y "Perez" fue encontrado en el apellido1 del primer registro y en el apellido2 del quinto registro.<br />
<br />
Finalmente, si analizamos esta consulta SQL armada por programación, podremos notar que incluso podríamos haber prescindido de dicha programación: aprovechando las funcionalidades del lenguaje de SQL, podemos armar la misma consulta de la forma:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> persona <br />
<b>WHERE</b> nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 <b>LIKE </b>'%' + <b>REPLACE</b>('Juan Perez', ' ', '%') + '%';
</p>
<br />
Y si trabajamos netamente en SQL, usando variables TSQL, también podría quedar:
<p style="font-family:'Courier New',Courier,monospace;">
<b>DECLARE</b> @frase <b>VARCHAR</b>(255); <br />
<b>SET</b> @frase = 'Juan Perez';<br />
<b>SELECT</b> * <br />
<b>FROM</b> persona <br />
<b>WHERE</b> nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 <b>LIKE</b> '%' + <b>REPLACE</b>(@frase, ' ', '%') + '%';
</p>
<br />
¡Esto nos ayudará mucho si trabajamos las búsquedas dentro de procedimientos y/o funciones almacenadas!<br />
<br />
<b>Observación:</b><br/>
Es importante recalcar que la forma de separar la frase, explicada con anterioridad, asume que queremos buscar las palabras en el <b>mismo orden</b> en que fueron escritas las palabras de la frase la primera vez.<br/>
<br/>
Si por alguna razón quisiéramos que <b>no tomara en cuenta el orden</b>, y que buscara indistintamente por todas las palabras, tendríamos que separar previamente por programación cada palabra de la frase y repetir la condición de búsqueda por cada palabra encontrada.<br/>
<br/>
Esto lo podemos hacer por programación:<br/>
<br/>
En lenguaje PHP:
<p style="font-family:'Courier New',Courier,monospace;">
$consulta = "SELECT * FROM persona WHERE ";<br />
$palabras = <b>explode</b>(" ", $_POST["frase"]);<br />
$c = 0;<br />
<b>foreach</b> ($palabras as $palabra)<br />
{<br />
$c++;<br />
$consulta .= " nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 LIKE '%".$palabra."%' ";<br />
$consulta .= (count($palabras) == $c ? "": " OR ");<br />
}
</p>
Lo que daría por resultado:
<p style="font-family:'Courier New',Courier,monospace;">
<b>SELECT</b> * <br />
<b>FROM</b> persona <br />
<b>WHERE</b> <br/>
nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 <b>LIKE</b> '%Juan%'<br />
<b>OR</b> nombre1 + ' ' + nombre2 + ' ' + apellido1 + ' ' + apellido2 <b>LIKE</b> '%Perez%';
</p>
Para hacerlo por SQL, podrían valerse de la forma que explico en mi tip <a href="http://quinqui-bitacorita.blogspot.com/2010/03/prog-pasar-array-parametro-de.html" target="_blank">Pasar array a parámetro de procedimiento almacenado</a>, aunque sólo es efectivo cuando las columnas contienen un solo valor (una palabra sola o una frase que sea no-separable, como nombres compuestos, etc.).<br/>
<br/>
Si existe una forma correcta de hacerlo en SQL, sería bueno leerlo en los comentarios ^_^ Al menos por ahora no conozco una función tipo split o explode en SQL.<br/>
<br />
Y eso sería. Resultó largo de explicar, pero espero que les sirva de alguito ^^.<br />
Saludos y gracias por leer!quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-66404345695419672772013-03-11T14:52:00.003-03:002013-03-13T12:09:28.867-03:00[linux] Cambio de hora en servidor CentOS (Chile)No soy una experta en Linux, pero me ha tocado trabajar periódicamente sobre este sistema operativo, especialmente en modo consola, ya que la mitad de los sitios web de mis trabajo se encuentran alojados en esta plataforma.<br />
<br />
Uno de los problemas con lo que me he topado (y seguro muchos de ustedes también), es el tema del Cambio de Hora Chileno, que en los últimos años ha venido variando como loco, por lo que hemos tenido que realizar el ajuste de hora prácticamente de forma manual en clientes y servidores.<br />
<br />
Hoy, al llegar al trabajo, precisamente me topé con la sorpresa de que uno de los servidores tenía la hora cambiada. Claro: la configuración del servidor tenía puesto cambio de hora el Sábado 9 de Marzo (y el siguiente cambio en Octubre), ya que esa es la regla de cambio de hora que Chile tuvo por muchos años, por lo que me tuve que poner a la tarea de corregir el fallo.<br />
<br />
En años pasados había tenido que solucionar lo mismo, por lo que busqué entre mis favoritos y reencontré este muy buen tutorial la respecto: <a href="http://www.chw.net/foro/gnu-linux-y-otros-sistemas-operativos-f18/879526-guia-modificar-tzdata-cambio-no-cambio-de-hora-chile.html" target="_blank">Guía: Modificar tzdata, cambio/no cambio de hora Chile</a>.<br />
<br />
Ahora bien, el tutorial es del 2011, pero aplica bien para todos los años. Yo me puse a hacer todos los pasos, pero en el camino descubrí que, ya que había hecho el tutorial en años anteriores, me pude saltar varios pasos.<br />
<br />
Por ejemplo, no tenía que editar el archivo de las reglas (Rules), ya que al bajar la última versión actualizada del sitio <a href="http://www.iana.org/time-zones" target="_blank">IAIA - Time Zone Database</a>, era sólo cosa de descargar el archivo:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># wget http://www.iana.org/time-zones/repository/releases/tzdata2013b.tar.gz</span><br />
<br />
...descomprimirlo:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># tar zxvf tzdata2013b.tar.gz</span><br />
<br />
...y actualizar el archivo local con el contenido en el zip:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># zic southamerica</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># zic backward</span><br />
<br />
<br />
Al ejecutar de nuevo la instrucción que nos muestra las reglas para este año:<br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"># zdump -v /etc/localtime | grep 2013</span><br />
<br />
...las reglas se habrán actualizado correctamente de forma automática:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">/etc/localtime Sun Apr 28 02:59:59 2013 UTC = Sat Apr 27 23:59:59 2013 CLST isdst=1 gmtoff=-10800<br />/etc/localtime Sun Apr 28 03:00:00 2013 UTC = Sat Apr 27 23:00:00 2013 CLT isdst=0 gmtoff=-14400<br />/etc/localtime Sun Sep 8 03:59:59 2013 UTC = Sat Sep 7 23:59:59 2013 CLT isdst=0 gmtoff=-14400<br />/etc/localtime Sun Sep 8 04:00:00 2013 UTC = Sun Sep 8 01:00:00 2013 CLST isdst=1 gmtoff=-10800</span><br />
<br />
Y para asegurarse de que la fecha actual se encuentre correcta, pueden ejecutar <span style="font-family: "Courier New",Courier,monospace;">date</span>:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># date<br />Mon Mar 11 09:40:20 CLST 2013</span><br />
<br />
Si les tocara el caso de que aun habiendo hecho esto, las reglas y la fecha no se han actualizado, deberán pisar manualmente la configuración de localtime con la actualizada de Chile/Continental:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># cp /usr/share/zoneinfo/Chile/Continental /etc/localtime </span><br />
<br />
Si ejecutan de nuevo el <span style="font-family: "Courier New",Courier,monospace;">zdump</span>, les debieran aparecer las reglas actualizadas; lo mismo si ejecutan el <span style="font-family: "Courier New",Courier,monospace;">date</span>.<br />
<br />
Dentro del tutorial antes mencionado, algunos usuarios aludían al sencillo uso de:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># yum update tzdata</span><br />
<br />
El problema de usar esta actualización ultra simple es que dependemos de los servidores de repositorios que tengamos configurados en nuestro servidor Linux. Esto quiere decir que si en la lista de repositorios que tengamos configurada no está el que contiene la última versión del tzdata, de nada nos servirá tratar de usar el yum update. Esto también quiere decir que si contamos con la URL del repositorio indicado, podemos agregarlo a nuestra lista y así poder usar el yum update a gusto.<br />
<br />
Finalmente, y no necesariamente referido a Linux, en mi caso particular tengo un servidor <b>Mysql</b> instalado en la misma máquina, y al hacer un:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">SELECT NOW();</span><br />
<br />
...tras haber realizado la corrección de la hora en Linux, Mysql me seguía mostrando la hora "incorrecta".<br />
<br />
Para solucionar eso, deberán reiniciar el server Mysql:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"># service mysqld restart</span><br />
<br />
Esto último deben hacerlo tomando todas las precauciones pertinentes a vuestro caso particular.<br />
<br />
Y eso sería el tip. No olviden leer la guía del link de CHW.<br />
Saludos y gracias por leer!quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-12082657779745066162013-01-07T18:40:00.001-03:002013-01-07T18:42:06.995-03:00[js] Autoajustar posición de capas con JavascriptHolas a todos. Hoy he querido compartir con ustedes una función Javascript que he logrado crear con el fin de realizar la tarea de ajustar la posición de un grupo de capas, de modo que queden todas pegadas, con un valor de margen determinado entre ellas.<br />
<br />
Esta característica la quería aplicar en mis sitios web desde hacía tiempo, y lo había intentado aplicando la propiedad <span style="font-family: "Courier New",Courier,monospace;">float:left</span> al CSS de las capas, pero no era suficiente. Si bien en los primeros elementos se veía bastante bien la cosa, luego, cuando debían bajar, pues venía el desorden. En otro intento por acercarme al efecto deseado sin usar programación extra, le asigné a cada capa el mismo alto, de modo que al menos se vieran ordenadas hacia abajo. Pero esto no me convencía, y me di a la tarea de ver la manera de hacerlo con Javascript.<br />
<br />
Y he aquí el resultado :D<br />
<br />
Antes:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-MuzaOQyYaP0/UOs_80AobeI/AAAAAAAABZ4/KljefA51KXY/s1600/qbit_qAjustar-antes.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-MuzaOQyYaP0/UOs_80AobeI/AAAAAAAABZ4/KljefA51KXY/s320/qbit_qAjustar-antes.gif" width="261" /></a></div>
Después:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-EjA2q5vhdNU/UOs_-7iZ9fI/AAAAAAAABaA/h8oJVQ9Zokc/s1600/qbit_qAjustar-despues.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-EjA2q5vhdNU/UOs_-7iZ9fI/AAAAAAAABaA/h8oJVQ9Zokc/s320/qbit_qAjustar-despues.gif" width="307" /></a></div>
<br />
<br />
Pueden ver el código fuente para lograr este efecto en los siguientes enlaces: pero antes, <b>por favor, ¡no borren los créditos!</b> No espero que me mencionen en sus páginas como la autora de la función (si lo hacen, muchas gracias de antemano), pero al menos respeten mi trabajo manteniendo mis comentarios y créditos dentro del archivo Javascript! Gracias y ojalá les sirva!<br />
<br />
<br />
<b>Página de ejemplo:</b> <a href="http://www.quinqui.cl/ext/qAjustar.html" target="_blank">qAjustar.html</a><br />
<b>URL del archivo Javascript:</b> <a href="http://www.quinqui.cl/ext/qAjustar.js" target="_blank">qAjustar.js</a><br />
<br />
Saludos!<br />
<br />
PD: A la fecha, he aplicado esta funcionalidad en mi página <a href="http://www.quinqui.cl/baul/" target="_blank">El Baúl</a>, por si la quieren ver en ejecución ^^.quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-85722710226274785892013-01-05T02:12:00.001-03:002013-01-05T02:12:30.966-03:00Fin de la bitacorita como la conocíaHolas a todos. Como lo dijera en mi último registro, he decidido realizar un cambio en mi bitacorita. Esto no incluye el cierre de la misma, sino un cambio de temática.<br />
<br />
Inicialmente la bitacorita nació para servir de registro de las actualizaciones de mis sitios web; luego mudó a un blog típico, donde hablaba sobre mis cosas cotidianas; y finalmente llegó a ser lo que es ahora: un compendio de todo lo que quisiera escribir: desde notificaciones sobre mis sitios web; reflexiones personales; comentarios de libros y películas; hasta consejos y tips de programación y otros.<br />
<br />
Y es en esta última área donde he decidido dejar acotada la bitacorita. Ya no será "mi" bitacorita, sino la <b>bitácora de una programadora</b>, en ayuda de otros programadores y/o usuarios del ámbito.<br />
<br />
Todo el material "personal" se irá a mi Baúl, el cual acabo de inaugurar y en el cual me siento realmente cómoda escribiendo. Como todo "baúl", puedo "echar" dentro todo lo que se me ocurra, siempre en el ámbito de "gustos y preferencias".<br />
<br />
El único tema que me queda volando es lo referente a las actualizaciones y noticias sobre mis sitios, pero para eso me valdré de <a href="https://www.twitter.com/quinquiunica" target="_blank">Twitter</a>, y Google+, por ahora. Todavía tengo pendiente la construcción de mi sitio web de <i>Portafolio Artístico</i>, y las actualizaciones del mismo las pondré ahí mismo (ahora lo que dibujo lo subo a <a href="http://quinqui.deviantart.com/" target="_blank">deviantart</a>... al menos, cuando solía dibujar -_-).<br />
<br />
En fin, pues eso. La quinqui bitacorita da el paso a la senda de la programación, que es a fin de cuentas, el motivo del grueso de las visitas al blog. Les doy las gracias por leer y haber seguido la bitacorita hasta ahora. Por eso, si les interesan los temas de programación, continúen visitándola; pero si quieren seguirme en otras temáticas, visiten mi <a href="http://www.quinqui.cl/baul" target="_blank"><b>Baúl</b></a>.<br />
<br />
Gracias y saludos!!quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0tag:blogger.com,1999:blog-1769993431585302141.post-12282218835855521662013-01-03T01:42:00.001-03:002013-01-03T01:42:26.282-03:00El BaúlHolas a todos. Montando mi nuevo sitio "<a href="http://www.quinqui.cl/baul/" target="_blank">El Baúl</a>", di en la cuenta de que en él no sólo quiero hablar sobre mis gustos y preferencias, sino sobre todo lo que se me ocurra. En ese sentido, es altamente probable que este sitio, mi bitacorita, dé un paso atrás y se retire definitivamente. Esta bitacorita nació con el fin de informar las actualizaciones de mis sitios web, pero terminó transformándose en un blog común y corriente, con pocas visitas y menos comentarios. En mi Baúl ya no espero recibir comentarios, sólo quiero expresarme, y por eso también me desligaré de Blogger. Gracias a la herramienta de comentarios de Disqus creo que podré salvar gratamente este tema del feedback básico del sitio. Si la bitacorita ha de seguir en línea sólo será por los temas de programación, que son a fin de cuentas, los más requeridos y visitados (útiles). Tal vez le haga un cambio completo de look, y deje de ser bitacorita en general, y pase a ser sitio de tips de programación tan sólo.<br />
Bueno, eso. Nos leemos espero que pronto. Saludos y gracias por leer!quinquihttp://www.blogger.com/profile/16255550952953648936noreply@blogger.com0