Hola
Dejo el enlace de un pequeño resumen sobre SCRUM que recopilé hace unos meses. El contenido es:
Historia de Scrum
Marco técnico de Scrum
Roles
Scrum Team
Product Owner
Scrum Master
Development Team
Artefactos
Temas y epics
Historias de usuario
Product Backlog
Sprint Backlog
Incremento
Gráfico de producto (Burn up)
Gráfico de avance (Burn down)
Scrum Task Board
Estimación Planning poker
Eventos
Sprint
Reunión de planificación del sprint
Scrum diario
Revisión del sprint
Retrospectiva del sprint
Refinamiento
El enlace al documento es:
https://mega.nz/#!tcpBSIjI!oG_p7E_pzvthMs3niWL3cObvhd7eTdET2Y7SKAHzbNs
Un saludo
Páginas
sábado, 23 de septiembre de 2017
Problemas en Ubuntu al copiar ficheros desde disco duro a discos externos NTFS vía USB
Hola
En las últimas versiones de Ubuntu 16.04, 16.10 y 17.04 siempre he tenido problemas para copiar ficheros grandes (desde varios cientos de MB en adelante) desde el disco duro a unidades NTFS externas vía USB.
Al copiar estos ficheros la velocidad de copiado se va degradando poco a poco, llegando a bajar a velocidades de unos pocos cientos de bytes/sec. Si dejas el proceso de copia lanzado horas y horas
finalmente la copia se efectúa correctamente y el sistema se recupera, pero mientras se ejecuta el proceso de copiado el rendimiento general del sistema se degrada, llegando incluso a dejar de responder el ratón y el teclado, con lo que he llegado a tirar del cable USB o incluso a reiniciar el PC, cosa que no he tenido que hacer en Linux nunca.
Después de mucho googlear he dado con una solución PARCIAL que me permite una velocidad de copiado normal, PERO QUE SOLO FUNCIONA MEDIANTE LINEA DE COMANDOS lanzando cosas como:
cp /path-origen/mi-fichero-grande /media/egdepedro/usbdisk
EL TEMA NO FUNCIONA SI COPIAMOS DESDE GNOME USANDO POR EJEMPLO NAUTILUS, POR ESE LADO HAY QUE SEGUIR INVESTIGANDO......
El problema viene por la extrema lentitud de los accesos USB, pero hay claramente algún bug que lleva ya años apareciendo y que no he notado en versiones anteriores de Ubuntu.
La solución es ajustar ciertos parámetros del kernel vía '/proc/sys/vm' y hacer luego esos ajustes permanentes en todos los arranques. Los pasos son:
1) Creamos el fichero de configuración del servicio /etc/systemd/system/rc.local.service con el siguiente comando:
sudo gedit /etc/systemd/system/rc.local.service
2) Copiamos en el fichero de configuración del servicio el siguiente contenido:
[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
3) Creamos el script /etc/rc.local con el siguiente comando:
sudo gedit /etc/rc.local
4) Copiamos en el script el siguiente contenido:
#!/bin/sh
echo 'tupasswordroot' | sudo -S su
echo $((16*1024*1024)) > /proc/sys/vm/dirty_background_bytes
echo $((48*1024*1024)) > /proc/sys/vm/dirty_bytes
5) Cambiamos los permisos al script para que sea ejecutable
sudo chmod 755 /etc/rc.local
6) Por último activamos el servicio y lo iniciamos con los comandos:
sudo systemctl enable rc.local.service
sudo systemctl start rc.local.service
7) Podemos verificar que el servicio está bien generado con el comando:
sudo systemctl status rc.local.service
Que debería devolver algo de tipo:
systemctl status rc.local.service
rc.local.service - /etc/rc.local Compatibility
Loaded: loaded (/etc/systemd/system/rc.local.service; enabled; vendor preset: enabled)
Active: active (exited) since Sat 2017-09-23 01:15:22 CEST; 1min 2s ago
14) Reiniciamos el PC y ya podemos copiar a la unidad USB ficheros grandes de forma ágil y sin afectar al rendimiento del sistema. OJO COPIANDO SIEMPRE DESDE LINEA DE COMANDOS.
Eso sería todo.
Nota. Para restaurar los valores de los parámetros del kernel 'dirty_background_bytes' y 'dirty_bytes' deberíamos hacer lo siguiente:
sudo systemctl stop rc.local.service
sudo systemctl disable rc.local.service
sudo rm /etc/systemd/system/rc.local.service
sudo rm /etc/rc.local
cd /proc/sys/vm
sudo su
echo 0 > /proc/sys/vm/dirty_background_bytes
echo 0 > /proc/sys/vm/dirty_bytes
Y tras reiniciar el PC todo volvería a estar como al comienzo.
Referencias:
https://lwn.net/Articles/572911/
https://unix.stackexchange.com/questions/107703/why-is-my-pc-freezing-while-im-copying-a-file-to-a-pendrive
https://www.netroby.com/view/3895
En las últimas versiones de Ubuntu 16.04, 16.10 y 17.04 siempre he tenido problemas para copiar ficheros grandes (desde varios cientos de MB en adelante) desde el disco duro a unidades NTFS externas vía USB.
Al copiar estos ficheros la velocidad de copiado se va degradando poco a poco, llegando a bajar a velocidades de unos pocos cientos de bytes/sec. Si dejas el proceso de copia lanzado horas y horas
finalmente la copia se efectúa correctamente y el sistema se recupera, pero mientras se ejecuta el proceso de copiado el rendimiento general del sistema se degrada, llegando incluso a dejar de responder el ratón y el teclado, con lo que he llegado a tirar del cable USB o incluso a reiniciar el PC, cosa que no he tenido que hacer en Linux nunca.
Después de mucho googlear he dado con una solución PARCIAL que me permite una velocidad de copiado normal, PERO QUE SOLO FUNCIONA MEDIANTE LINEA DE COMANDOS lanzando cosas como:
cp /path-origen/mi-fichero-grande /media/egdepedro/usbdisk
EL TEMA NO FUNCIONA SI COPIAMOS DESDE GNOME USANDO POR EJEMPLO NAUTILUS, POR ESE LADO HAY QUE SEGUIR INVESTIGANDO......
El problema viene por la extrema lentitud de los accesos USB, pero hay claramente algún bug que lleva ya años apareciendo y que no he notado en versiones anteriores de Ubuntu.
La solución es ajustar ciertos parámetros del kernel vía '/proc/sys/vm' y hacer luego esos ajustes permanentes en todos los arranques. Los pasos son:
1) Creamos el fichero de configuración del servicio /etc/systemd/system/rc.local.service con el siguiente comando:
sudo gedit /etc/systemd/system/rc.local.service
2) Copiamos en el fichero de configuración del servicio el siguiente contenido:
[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
3) Creamos el script /etc/rc.local con el siguiente comando:
sudo gedit /etc/rc.local
4) Copiamos en el script el siguiente contenido:
#!/bin/sh
echo 'tupasswordroot' | sudo -S su
echo $((16*1024*1024)) > /proc/sys/vm/dirty_background_bytes
echo $((48*1024*1024)) > /proc/sys/vm/dirty_bytes
5) Cambiamos los permisos al script para que sea ejecutable
sudo chmod 755 /etc/rc.local
6) Por último activamos el servicio y lo iniciamos con los comandos:
sudo systemctl enable rc.local.service
sudo systemctl start rc.local.service
7) Podemos verificar que el servicio está bien generado con el comando:
sudo systemctl status rc.local.service
Que debería devolver algo de tipo:
systemctl status rc.local.service
rc.local.service - /etc/rc.local Compatibility
Loaded: loaded (/etc/systemd/system/rc.local.service; enabled; vendor preset: enabled)
Active: active (exited) since Sat 2017-09-23 01:15:22 CEST; 1min 2s ago
14) Reiniciamos el PC y ya podemos copiar a la unidad USB ficheros grandes de forma ágil y sin afectar al rendimiento del sistema. OJO COPIANDO SIEMPRE DESDE LINEA DE COMANDOS.
Eso sería todo.
Nota. Para restaurar los valores de los parámetros del kernel 'dirty_background_bytes' y 'dirty_bytes' deberíamos hacer lo siguiente:
sudo systemctl stop rc.local.service
sudo systemctl disable rc.local.service
sudo rm /etc/systemd/system/rc.local.service
sudo rm /etc/rc.local
cd /proc/sys/vm
sudo su
echo 0 > /proc/sys/vm/dirty_background_bytes
echo 0 > /proc/sys/vm/dirty_bytes
Y tras reiniciar el PC todo volvería a estar como al comienzo.
Referencias:
https://lwn.net/Articles/572911/
https://unix.stackexchange.com/questions/107703/why-is-my-pc-freezing-while-im-copying-a-file-to-a-pendrive
https://www.netroby.com/view/3895
Usando ffmpeg para recortar un trozo de video
Para recortar N segundos, por ejemplo 20 segundos a partir del minuto 10, de una pelicula con ffmpeg necesitamos debemos lanzar el comando siguiente:
ffmpeg -i pelicula.avi -vcodec copy -acodec copy -ss 00:10:00.000 -t 00:10:20.0000 trozo.avi
Aclaraciones:
-ss 00:10:00.000 --> Especifica que el corte comience en el instante 10:00.000
-t 00:10:20.000 --> Especifica que el corte termine en el instante 10:20.000
Un saludo
ffmpeg -i pelicula.avi -vcodec copy -acodec copy -ss 00:10:00.000 -t 00:10:20.0000 trozo.avi
Aclaraciones:
-ss 00:10:00.000 --> Especifica que el corte comience en el instante 10:00.000
-t 00:10:20.000 --> Especifica que el corte termine en el instante 10:20.000
Un saludo
martes, 19 de septiembre de 2017
¿Cómo cerrar una sesión de telnet en bash?
Hola
Cuando haces telnet contra cierta máquina, por ejemplo un server de smtp, con un comando como:
telnet smtp.ejemplo.org 25
Obtenemos (si tenemos autorización para llegar a la máquina por ese puerto) una respuesta como:
Trying xxx.xxx.xxx.Xxx...
Connected to smtp.ejemplo.org.
Escape character is '^]'.
220 smtp.ejemplo.org ESMTP
La cuestión es, ¿cual es la combinación de teclas necesaria '^]' para cerrar la conexión?
Pues bien, la combinación de teclas es Ctrl + Alt_Gr + ]
Un saludo
Cuando haces telnet contra cierta máquina, por ejemplo un server de smtp, con un comando como:
telnet smtp.ejemplo.org 25
Obtenemos (si tenemos autorización para llegar a la máquina por ese puerto) una respuesta como:
Trying xxx.xxx.xxx.Xxx...
Connected to smtp.ejemplo.org.
Escape character is '^]'.
220 smtp.ejemplo.org ESMTP
La cuestión es, ¿cual es la combinación de teclas necesaria '^]' para cerrar la conexión?
Pues bien, la combinación de teclas es Ctrl + Alt_Gr + ]
Un saludo
jueves, 11 de mayo de 2017
Experimentos con gráficos en Javascript
Hola
En esta entrada voy a subir un pequeño juego de rebotes montado en JavaScript puro. El experimento se centra en el manejo de las opciones gráficas de un canvas y en el manejo de los intervalos de repetición en Javascript
El código HTML5 sería:
<!-- Definimos el documento como HTML 5 -->
<!DOCTYPE html>
<!-- Definimos el idioma de la página -->
<html lang="es">
<head>
<!-- Definimos el juego de caracteres de la página -->
<meta charset="UTF-8">
<!-- Definimos el autor de la página -->
<meta name="author" content="Eduardo García">
<!-- Describimos el contenido de la página -->
<meta name="description" content="Rebotes">
<!-- Describimos algunos términos clave de la página -->
<meta name="keywords" content="HTML5,CSS,JavaScript">
<!-- Un pequeño fichero de estilos -->
<link rel="stylesheet" type="text/css" href="./css/ejercicio33.css">
</head>
<body>
<!-- Aquí el contenido de la página -->
<h1>Experimentos con gráficos</h1>
<canvas id="canvas" width="640" height="480"></canvas>
<form>
<input type="button" id="inic" value="Iniciar partida" onclick="iniciar();"/>
<input type="button" id="fin" value="Finalizar partida" onclick="detener();"/>
</form>
<!-- Definimos nuestras dependencias de scripts externos -->
<script type="text/javascript" src="./js/rebotes.js" defer></script>
</body>
</html>
La hoja de estilos sería:
canvas {
background: #eee;
}
El código Javascript sería:
/**
* Constantes
*/
var radioBola = 10; //Radio de la bola
var paletaAltura = 2; //Altura de la paleta de juego
var paletaAnchura = 75; //Anchura de la paleta de juego
var velocBarra = 3; //Velocidad de movimiento de la paleta
var velocX = 1; //Velocidad inicial de movimiento de la bola en el eje X
var velocY = -1; //Velocidad inicial de movimiento de la bola en el eje Y
var deltaVel = 1.2; //Porcentaje de aumento de velocidad de la bola en cada raquetazo
var deltaAnchura = 1.1; //Porcentaje de aumento de la anchura de la barra en cada raquetazo
/**
* Variables globales
*/
var canvas; //Area de dibujo
var ctx; //Objeto para dibujar en el canvas
var bolaX; //Coordenada X de la bola
var bolaY; //Coordenada Y de la bola (ojo Y crece hacia abajo de la pantalla)
var paletaX; //Coordenada del borde izquierdo de la paleta
var flechaDerecha; //Flag que indica si la flecha derecha se está pulsando
var flechaIzquierda; //Flag que indica si la flecha izquierda se está pulsando
var ctrlIntervRepet; //Variable para controlar la repeticion
/**
* Lanzador del juego
*/
function iniciar() {
//Definimos el área de dibujo en 2D
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
//Inicialmente centramos la bola
bolaX = canvas.width/2;
bolaY = canvas.height/2;
//Inicialmente centramos la barra
paletaX = (canvas.width-paletaAnchura)/2;
//Inicialmente marcamos que no hay ninguna tecla pulsada
flechaDerecha = false;
flechaIzquierda = false;
//Fijamos el intervalo de repintado de la mesa en 10ms
ctrlIntervRepet = setInterval(dibujar, 10);
//Definimos listener para las acciones pulsar tecla y soltar tecla
document.addEventListener("keydown", pulsaTecla, false);
document.addEventListener("keyup", sueltaTecla, false);
//Reajustamos los botones
document.getElementById("inic").disabled = true;
document.getElementById("fin").disabled = false;
}
/**
* Detiene la partida
*/
function detener(){
//Paramos la repeticion
clearInterval(ctrlIntervRepet);
//Reajustamos los botones
document.getElementById("inic").disabled = false;
document.getElementById("fin").disabled = true;
//Restauramos anchura de la paleta
paletaAnchura = 75;
//Restauramos la velocidad de la bola
velocX = 1;
velocY = -1;
}
/**
* Controlamos qué tecla se pulsa
*/
function pulsaTecla(e) {
//Si se pulsa la flecha derecha (39) o la flecha izquierda (37)
if(e.keyCode == 39) {
flechaDerecha = true;
} else if(e.keyCode == 37) {
flechaIzquierda = true;
}
}
/**
* Controlamos qué tecla se suelta
*/
function sueltaTecla(e) {
//Si se pulsa la flecha derecha (39) o la flecha izquierda (37)
if(e.keyCode == 39) {
flechaDerecha = false;
}
else if(e.keyCode == 37) {
flechaIzquierda = false;
}
}
/**
* Dibuja el talero, la bola y la barra
*/
function dibujar() {
//Limpiamos el restángulo
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Dibujamos la bola
ctx.beginPath();
ctx.arc(bolaX, bolaY, radioBola, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
//Dibujamos la barra
ctx.beginPath();
ctx.rect(paletaX, canvas.height-paletaAltura, paletaAnchura, paletaAltura);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
//Hay rebote arriba
if(bolaY + velocY < radioBola) {
velocY = -velocY;
}
//Hay rebote abajo
if(bolaY + velocY > canvas.height-radioBola) {
//Vemos si hay barra bajo la bola
if(bolaX<paletaX || bolaX>paletaX+paletaAnchura) {
//Paramos la partida
detener();
//Preguntamos si quiere jugar de nuevo
if(confirm("¿Quieres jugar de nuevo?")){
//Iniciamos la partida
iniciar();
}
} else {
//Tenemos rebote en la barra
velocY = -velocY;
//Incrementamos la velocidad un deltaVel
velocX = velocX*deltaVel;
velocY = velocY*deltaVel;
//Hacemos crecer la barra en un deltaAnchura
paletaAnchura = paletaAnchura*deltaAnchura;
}
}
//Hay rebote izquierda o derecho
if(bolaX + velocX > canvas.width-radioBola || bolaX + velocX < radioBola) {
velocX = -velocX;
}
//Movemos la bola
bolaX += velocX;
bolaY += velocY;
//Movemos la barra sin salirnos del borde
if(flechaDerecha) {
if (paletaX+paletaAnchura+velocBarra<canvas.width){
paletaX += velocBarra;
}
} else if(flechaIzquierda) {
if (paletaX-velocBarra>0){
paletaX -= velocBarra;
}
}
}
Un saludo
En esta entrada voy a subir un pequeño juego de rebotes montado en JavaScript puro. El experimento se centra en el manejo de las opciones gráficas de un canvas y en el manejo de los intervalos de repetición en Javascript
El código HTML5 sería:
<!-- Definimos el documento como HTML 5 -->
<!DOCTYPE html>
<!-- Definimos el idioma de la página -->
<html lang="es">
<head>
<!-- Definimos el juego de caracteres de la página -->
<meta charset="UTF-8">
<!-- Definimos el autor de la página -->
<meta name="author" content="Eduardo García">
<!-- Describimos el contenido de la página -->
<meta name="description" content="Rebotes">
<!-- Describimos algunos términos clave de la página -->
<meta name="keywords" content="HTML5,CSS,JavaScript">
<!-- Un pequeño fichero de estilos -->
<link rel="stylesheet" type="text/css" href="./css/ejercicio33.css">
</head>
<body>
<!-- Aquí el contenido de la página -->
<h1>Experimentos con gráficos</h1>
<canvas id="canvas" width="640" height="480"></canvas>
<form>
<input type="button" id="inic" value="Iniciar partida" onclick="iniciar();"/>
<input type="button" id="fin" value="Finalizar partida" onclick="detener();"/>
</form>
<!-- Definimos nuestras dependencias de scripts externos -->
<script type="text/javascript" src="./js/rebotes.js" defer></script>
</body>
</html>
La hoja de estilos sería:
canvas {
background: #eee;
}
El código Javascript sería:
/**
* Constantes
*/
var radioBola = 10; //Radio de la bola
var paletaAltura = 2; //Altura de la paleta de juego
var paletaAnchura = 75; //Anchura de la paleta de juego
var velocBarra = 3; //Velocidad de movimiento de la paleta
var velocX = 1; //Velocidad inicial de movimiento de la bola en el eje X
var velocY = -1; //Velocidad inicial de movimiento de la bola en el eje Y
var deltaVel = 1.2; //Porcentaje de aumento de velocidad de la bola en cada raquetazo
var deltaAnchura = 1.1; //Porcentaje de aumento de la anchura de la barra en cada raquetazo
/**
* Variables globales
*/
var canvas; //Area de dibujo
var ctx; //Objeto para dibujar en el canvas
var bolaX; //Coordenada X de la bola
var bolaY; //Coordenada Y de la bola (ojo Y crece hacia abajo de la pantalla)
var paletaX; //Coordenada del borde izquierdo de la paleta
var flechaDerecha; //Flag que indica si la flecha derecha se está pulsando
var flechaIzquierda; //Flag que indica si la flecha izquierda se está pulsando
var ctrlIntervRepet; //Variable para controlar la repeticion
/**
* Lanzador del juego
*/
function iniciar() {
//Definimos el área de dibujo en 2D
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
//Inicialmente centramos la bola
bolaX = canvas.width/2;
bolaY = canvas.height/2;
//Inicialmente centramos la barra
paletaX = (canvas.width-paletaAnchura)/2;
//Inicialmente marcamos que no hay ninguna tecla pulsada
flechaDerecha = false;
flechaIzquierda = false;
//Fijamos el intervalo de repintado de la mesa en 10ms
ctrlIntervRepet = setInterval(dibujar, 10);
//Definimos listener para las acciones pulsar tecla y soltar tecla
document.addEventListener("keydown", pulsaTecla, false);
document.addEventListener("keyup", sueltaTecla, false);
//Reajustamos los botones
document.getElementById("inic").disabled = true;
document.getElementById("fin").disabled = false;
}
/**
* Detiene la partida
*/
function detener(){
//Paramos la repeticion
clearInterval(ctrlIntervRepet);
//Reajustamos los botones
document.getElementById("inic").disabled = false;
document.getElementById("fin").disabled = true;
//Restauramos anchura de la paleta
paletaAnchura = 75;
//Restauramos la velocidad de la bola
velocX = 1;
velocY = -1;
}
/**
* Controlamos qué tecla se pulsa
*/
function pulsaTecla(e) {
//Si se pulsa la flecha derecha (39) o la flecha izquierda (37)
if(e.keyCode == 39) {
flechaDerecha = true;
} else if(e.keyCode == 37) {
flechaIzquierda = true;
}
}
/**
* Controlamos qué tecla se suelta
*/
function sueltaTecla(e) {
//Si se pulsa la flecha derecha (39) o la flecha izquierda (37)
if(e.keyCode == 39) {
flechaDerecha = false;
}
else if(e.keyCode == 37) {
flechaIzquierda = false;
}
}
/**
* Dibuja el talero, la bola y la barra
*/
function dibujar() {
//Limpiamos el restángulo
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Dibujamos la bola
ctx.beginPath();
ctx.arc(bolaX, bolaY, radioBola, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
//Dibujamos la barra
ctx.beginPath();
ctx.rect(paletaX, canvas.height-paletaAltura, paletaAnchura, paletaAltura);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
//Hay rebote arriba
if(bolaY + velocY < radioBola) {
velocY = -velocY;
}
//Hay rebote abajo
if(bolaY + velocY > canvas.height-radioBola) {
//Vemos si hay barra bajo la bola
if(bolaX<paletaX || bolaX>paletaX+paletaAnchura) {
//Paramos la partida
detener();
//Preguntamos si quiere jugar de nuevo
if(confirm("¿Quieres jugar de nuevo?")){
//Iniciamos la partida
iniciar();
}
} else {
//Tenemos rebote en la barra
velocY = -velocY;
//Incrementamos la velocidad un deltaVel
velocX = velocX*deltaVel;
velocY = velocY*deltaVel;
//Hacemos crecer la barra en un deltaAnchura
paletaAnchura = paletaAnchura*deltaAnchura;
}
}
//Hay rebote izquierda o derecho
if(bolaX + velocX > canvas.width-radioBola || bolaX + velocX < radioBola) {
velocX = -velocX;
}
//Movemos la bola
bolaX += velocX;
bolaY += velocY;
//Movemos la barra sin salirnos del borde
if(flechaDerecha) {
if (paletaX+paletaAnchura+velocBarra<canvas.width){
paletaX += velocBarra;
}
} else if(flechaIzquierda) {
if (paletaX-velocBarra>0){
paletaX -= velocBarra;
}
}
}
Un saludo
Peticiones AJAX (GET, POST, PUT y DELETE) usando jQuery
Hola
En esta entrada vamos a ver cómo invocar métodos GET, POST, PUT y DELETE mediante jQuery.
Utilizaremos el API REST ofertado en la URL https://reqres.in/api
Montaremos una página HTML como la siguiente:
<!-- Definimos el documento como HTML 5 -->
<!DOCTYPE html>
<!-- Definimos el idioma de la página -->
<html lang="es">
<head>
<!-- Definimos el juego de caracteres de la página -->
<meta charset="UTF-8">
<!-- Definimos el autor de la página -->
<meta name="author" content="Eduardo García">
<!-- Describimos el titulo de la página -->
<title>AJAX y jQuery</title>
<!-- Describimos algunos términos clave de la página -->
<meta name="keywords" content="HTML5,CSS,JavaScript,jQuery">
</head>
<body>
<!-- Aquí el contenido de la página -->
<h1>AJAX&JQUERY I. Ejemplos de llamadas GET, POST, PUT y DELETE a un servicio REST.</h1>
<!-- Aquí meteremos los usuarios -->
<div id="usuarios"></div>
<!-- Definimos nuestras dependencia con jQuery -->
<script type="text/javascript" src="js/jquery-3.2.1.js"></script>
<!-- Definimos nuestros propios ficheros Javascript -->
<script type="text/javascript" src="js/ejemplo.js"></script>
</body>
</html>
El contenido de nuestro fichero javascript con jQuery 'ejemplo.js' sería:
/**
* En este ejemplo usaremos un servicio REST gratuíto que está
* disponible en Internet y que ofrece métodos GET, POST, PUT
* y DELETE para operar con 'usuarios'
*/
var urlListaUsuarios = "https://reqres.in/api/users?page=1";
var urlGetUsuario = "https://reqres.in/api/users/";
var urlAltaUsuario = "https://reqres.in/api/users";
var urlBajaUsuario = "https://reqres.in/api/users/";
var urlModificaUsuario = "https://reqres.in/api/users/";
$(document).ready(getListaUsuarios);
//$(document).ready(getUsuario(2));
//$(document).ready(altaUsuario);
//$(document).ready(bajaUsuario(2));
//$(document).ready(modificaUsuario(2));
/**
* Obtenemos por GET la primera página de una lista de usuarios
*/
function getListaUsuarios(){
$.getJSON(urlListaUsuarios)
.done(function(respuesta, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Recuperados los siguientes usuarios:</h3>");
$.each(respuesta.data, function(i,result){
$("#usuarios").append("<div>Id: "+ result.id +
" Nombre: " + result.first_name +
" Apellido: " + result.last_name +
" Foto: <img src="+result.avatar+"></img></div>");
});
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Obtenemos por GET los datos del usuario con el id recibido
*/
function getUsuario(idUsuario){
$.getJSON(urlGetUsuario+idUsuario)
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Recuperado el siguiente usuario:</h3>");
$("#usuarios").append("<div>Id: "+ result.data.id +
" Nombre: " + result.data.first_name +
" Apellido: " + result.data.last_name +
" Foto: <img src="+result.data.avatar+"></img></div>");
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Damos de alta a un nuevo usuario
*/
function altaUsuario(){
$.ajax({
type: "POST",
dataType: "json",
url: urlAltaUsuario,
data: {"name": "eduardo", "job": "developer"}
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Creado el siguiente usuario:</h3>");
$("#usuarios").append("<div>Id: "+ result.id +
" Nombre: " + result.name +
" Puesto: " + result.job +
" Fecha alta: " + result.createdAt );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Damos de baja al usuario con el id recibido
*/
function bajaUsuario(idUsuario){
$.ajax({
type: "DELETE",
dataType: "json",
url: urlBajaUsuario+idUsuario
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Borrado correctamente el usuario: "+idUsuario+"</h3>");
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Modificamos los datos del usuario recibido por parametro
*/
function modificaUsuario(idUsuario){
$.ajax({
type: "PUT",
dataType: "json",
url: urlModificaUsuario+idUsuario,
data: {"name": "EduardoX", "job": "DeveloperX"}
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Modifiacdo correctamente el usuario: "+idUsuario+"</h3>");
$("#usuarios").append("<div>Nombre: " + result.name +
" Puesto: " + result.job +
" Fecha modificacion: " + result.updatedAt );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
En esta entrada vamos a ver cómo invocar métodos GET, POST, PUT y DELETE mediante jQuery.
Utilizaremos el API REST ofertado en la URL https://reqres.in/api
Montaremos una página HTML como la siguiente:
<!-- Definimos el documento como HTML 5 -->
<!DOCTYPE html>
<!-- Definimos el idioma de la página -->
<html lang="es">
<head>
<!-- Definimos el juego de caracteres de la página -->
<meta charset="UTF-8">
<!-- Definimos el autor de la página -->
<meta name="author" content="Eduardo García">
<!-- Describimos el titulo de la página -->
<title>AJAX y jQuery</title>
<!-- Describimos algunos términos clave de la página -->
<meta name="keywords" content="HTML5,CSS,JavaScript,jQuery">
</head>
<body>
<!-- Aquí el contenido de la página -->
<h1>AJAX&JQUERY I. Ejemplos de llamadas GET, POST, PUT y DELETE a un servicio REST.</h1>
<!-- Aquí meteremos los usuarios -->
<div id="usuarios"></div>
<!-- Definimos nuestras dependencia con jQuery -->
<script type="text/javascript" src="js/jquery-3.2.1.js"></script>
<!-- Definimos nuestros propios ficheros Javascript -->
<script type="text/javascript" src="js/ejemplo.js"></script>
</body>
</html>
El contenido de nuestro fichero javascript con jQuery 'ejemplo.js' sería:
/**
* En este ejemplo usaremos un servicio REST gratuíto que está
* disponible en Internet y que ofrece métodos GET, POST, PUT
* y DELETE para operar con 'usuarios'
*/
var urlListaUsuarios = "https://reqres.in/api/users?page=1";
var urlGetUsuario = "https://reqres.in/api/users/";
var urlAltaUsuario = "https://reqres.in/api/users";
var urlBajaUsuario = "https://reqres.in/api/users/";
var urlModificaUsuario = "https://reqres.in/api/users/";
$(document).ready(getListaUsuarios);
//$(document).ready(getUsuario(2));
//$(document).ready(altaUsuario);
//$(document).ready(bajaUsuario(2));
//$(document).ready(modificaUsuario(2));
/**
* Obtenemos por GET la primera página de una lista de usuarios
*/
function getListaUsuarios(){
$.getJSON(urlListaUsuarios)
.done(function(respuesta, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Recuperados los siguientes usuarios:</h3>");
$.each(respuesta.data, function(i,result){
$("#usuarios").append("<div>Id: "+ result.id +
" Nombre: " + result.first_name +
" Apellido: " + result.last_name +
" Foto: <img src="+result.avatar+"></img></div>");
});
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Obtenemos por GET los datos del usuario con el id recibido
*/
function getUsuario(idUsuario){
$.getJSON(urlGetUsuario+idUsuario)
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Recuperado el siguiente usuario:</h3>");
$("#usuarios").append("<div>Id: "+ result.data.id +
" Nombre: " + result.data.first_name +
" Apellido: " + result.data.last_name +
" Foto: <img src="+result.data.avatar+"></img></div>");
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Damos de alta a un nuevo usuario
*/
function altaUsuario(){
$.ajax({
type: "POST",
dataType: "json",
url: urlAltaUsuario,
data: {"name": "eduardo", "job": "developer"}
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Creado el siguiente usuario:</h3>");
$("#usuarios").append("<div>Id: "+ result.id +
" Nombre: " + result.name +
" Puesto: " + result.job +
" Fecha alta: " + result.createdAt );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Damos de baja al usuario con el id recibido
*/
function bajaUsuario(idUsuario){
$.ajax({
type: "DELETE",
dataType: "json",
url: urlBajaUsuario+idUsuario
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Borrado correctamente el usuario: "+idUsuario+"</h3>");
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
/**
* Modificamos los datos del usuario recibido por parametro
*/
function modificaUsuario(idUsuario){
$.ajax({
type: "PUT",
dataType: "json",
url: urlModificaUsuario+idUsuario,
data: {"name": "EduardoX", "job": "DeveloperX"}
})
.done(function(result, textStatus, jqXHR ) {
$("#usuarios").append("<h3>Modifiacdo correctamente el usuario: "+idUsuario+"</h3>");
$("#usuarios").append("<div>Nombre: " + result.name +
" Puesto: " + result.job +
" Fecha modificacion: " + result.updatedAt );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
$("#usuarios").append("Error llamando al servicio: " + textStatus);
});
}
viernes, 17 de febrero de 2017
Descargar vídeos de Youtube con Ubuntu desde la terminal
Hola
Tras probar sin éxito varias extensiones de Firefox y Chrome que permitiesen descargar vídeos desde YouTube he googleado un poco encontrando una herramienta de línea de comando muy buena y fácil de manejar llamada 'youtube-dl'.
Para instalarla teclearemos:
$ sudo apt-get install youtube-dl
Su utilización es muy simple, basta con movernos a la carpeta donde deseemos que se almacene el vídeo, por ejemplo el escritorio:
$ cd $HOME/Escritorio
Luego lanzamos la herramienta mediante el comando:
$ youtube-dl URL_VIDEO_YOUTUBE
Por ejemplo:
$ youtube-dl https://www.youtube.com/watch?v=PlLHc60egiQ
Con lo que se descargará el vídeo deseado
Un saludo
Tras probar sin éxito varias extensiones de Firefox y Chrome que permitiesen descargar vídeos desde YouTube he googleado un poco encontrando una herramienta de línea de comando muy buena y fácil de manejar llamada 'youtube-dl'.
Para instalarla teclearemos:
$ sudo apt-get install youtube-dl
Su utilización es muy simple, basta con movernos a la carpeta donde deseemos que se almacene el vídeo, por ejemplo el escritorio:
$ cd $HOME/Escritorio
Luego lanzamos la herramienta mediante el comando:
$ youtube-dl URL_VIDEO_YOUTUBE
Por ejemplo:
$ youtube-dl https://www.youtube.com/watch?v=PlLHc60egiQ
Con lo que se descargará el vídeo deseado
Un saludo
Eliminar Malware Extensions de Google Chrome en Ubuntu
Hola
Tras instalar una cierta extensión (video-download-helper) de Google Chrome, que se anunciaba como extensión para la descarga de videos de Youtube, me he dado cuenta de que dicha extensión no solo no descargaba vídeos sino que además levantaba ventanas de publicidad y cerraba Chrome cada vez que intentaba acceder a la configuración de extensiones para desinstalarla.
En fin, no se cómo Google ofrece este tipo de extensiones en su área de descargas (https://chrome.google.com/webstore/detail/video-download-helper/mngdadkapbemiekajhhalpakdpleogfn?hl=es), muchos usuarios pueden llegar a desinstalar el navegador definitivamente, porque las extensiones no desaparecen al reinstalar Chrome.
Para desinstalar la extensión a mano debemos acceder a la carpeta:
$HOME/.config/google-chrome/Default/Extensions
Donde encontraremos varios directorios con nombres como:
mlomiejdfkolichcflejclcbmpeaniij
nmmhkkegccagdldgiimedpiccmgmieda
pkedcjkdefgpdelpbcmbmeomcjbeemfm
He optado por borrar todos los directorios, dado que no he tenido ganas de entretenerme en averiguar cual era el directorio asociado a la extensión malware en cuestión:
$ rm -R *
Tras lo cual he reiniciado Chrome y he podido acceder a la zona de configuración de extensiones con normalidad, limpiando los 'residuos' de las extensiones anteriormente existentes y reinstalando mis extensiones favoritas.
Un saludo
Tras instalar una cierta extensión (video-download-helper) de Google Chrome, que se anunciaba como extensión para la descarga de videos de Youtube, me he dado cuenta de que dicha extensión no solo no descargaba vídeos sino que además levantaba ventanas de publicidad y cerraba Chrome cada vez que intentaba acceder a la configuración de extensiones para desinstalarla.
En fin, no se cómo Google ofrece este tipo de extensiones en su área de descargas (https://chrome.google.com/webstore/detail/video-download-helper/mngdadkapbemiekajhhalpakdpleogfn?hl=es), muchos usuarios pueden llegar a desinstalar el navegador definitivamente, porque las extensiones no desaparecen al reinstalar Chrome.
Para desinstalar la extensión a mano debemos acceder a la carpeta:
$HOME/.config/google-chrome/Default/Extensions
Donde encontraremos varios directorios con nombres como:
mlomiejdfkolichcflejclcbmpeaniij
nmmhkkegccagdldgiimedpiccmgmieda
pkedcjkdefgpdelpbcmbmeomcjbeemfm
He optado por borrar todos los directorios, dado que no he tenido ganas de entretenerme en averiguar cual era el directorio asociado a la extensión malware en cuestión:
$ rm -R *
Tras lo cual he reiniciado Chrome y he podido acceder a la zona de configuración de extensiones con normalidad, limpiando los 'residuos' de las extensiones anteriormente existentes y reinstalando mis extensiones favoritas.
Un saludo
miércoles, 18 de enero de 2017
Miniservidor con Node.js y oracledb
Hola
En esta entrada vamos a montar un miniservidor html con Node.js que conecte a cierta tabla de Oracle mediante oracledb. Los pasos para instalar todo son:
1) Instalamos node.js y su gestor de paquetes npm
sudo apt-get install nodejs
sudo apt-get install npm
2) Verificamos que está bien instalado con:
nodejs --version --> v4.2.6
npm --version --> 3.5.2
3) Instalamos algunas de las librerías javascript que vamos a necesitar en nuestro servidor 'miserver.js':
npm install http
npm install httpdispatcher
4) Descargamos el 'Oracle Instant Client' de Oracle (http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html) siguiendo las instrucciones de (https://github.com/oracle/node-oracledb). Necesitaremos los packages 'basic' y 'SDK' si la BBDD está en remoto (es lo habitual). Por lo que hemos bajado las versiones de RedHat/linux:
oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
5) Para Ubuntu no hay instalador, así que transformamos el instalador rpm (RedHat) con:
sudo alien -i oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
sudo alien -i oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
Nota Ubuntu. Tambien hemos necesitado instalar la libreria libaio, no se para qué hace falta
sudo apt-get install libaio1
6) Seguidamente instalamos la librería javascript oracledb con:
npm install oracledb
Nota Ubuntu. Para poder lanzar sin problemas la instalacion de oracledb (saltaba un error en 'node-gyp rebuild' descrito en (https://github.com/npm/npm/issues/11335)) he tenido que crear un softlink 'node' dado que se petaba por tener instalado nodejs (el package de ubuntu) en vez del paquete node 'oficial'. Para crear el softlink lanzamos:
sudo ln -s /usr/bin/nodejs /usr/local/bin/node
8) Creamos nuestro servidor web por el puerto 8888 en javascrip, para ello creamos un fichero llamado 'miserver.js' con el siguiente codigo:
//Importamos las librerias necesarias
var http = require('http');
var HttpDispatcher = require('httpdispatcher');
var oracledb = require('oracledb');
//Inicializamos el enrutador
var enrutador = new HttpDispatcher();
//Definimos la función que manejara las peticiones
function handleRequest(request, response){
console.log("Peticion:");
console.log(request.url);
enrutador.dispatch(request, response);
}
//Creamos el servidor y lo ponemos a escuchar en el puerto 8888
var server = http.createServer(handleRequest);
server.listen(8888, function(){
console.log("Arrancado y escuchando en el puerto 8888");
});
//Creamos la función que devuelve la pagina /
enrutador.onGet("/", function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("<?xml version='1.0' encoding='UTF-8'?>");
res.write("<!DOCTYPE html>");
res.write("<html lang='es' xmlns='http://www.w3.org/1999/xhtml'>");
res.write("<head>");
res.write(" <meta http-equiv='Content-type' content='text/html; charset=UTF-8'/>");
res.write(" <meta name='language' content='es'/>");
res.write("</head>");
res.write("<body>");
res.write("<h3> Primer miniportal con Node.js</h3>");
res.write(" <ul>");
res.write(" <li><a href='/listaprovincias'>Lista de provincias</a></li>");
res.write(" </ul>");
res.write("</body>");
res.end();
});
//Creamos la función que devuelve la pagina /listaprovincias
enrutador.onGet("/listaprovincias", function(req, res) {
oracledb.getConnection(
{
user : "user",
password : "pwd",
connectString : "127.0.0.1:1535/prueba"
},
function(err, connection) {
if (err) {
console.error(err);
return;
}
connection.execute("SELECT CPRO, DPRO FROM PROVINCIAS ORDER BY DPRO",
function(err, result) {
if (err) {
console.error(err.message);
connection.close();
return;
}
console.log("Encontradas "+result.rows.length+" provincias");
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("<?xml version='1.0' encoding='UTF-8'?>");
res.write("<!DOCTYPE html>");
res.write("<html lang='es' xmlns='http://www.w3.org/1999/xhtml'>");
res.write("<head>");
res.write(" <meta http-equiv='Content-type' content='text/html; charset=UTF-8'/>");
res.write(" <meta name='language' content='es'/>");
res.write("</head>");
res.write("<body>");
res.write("<h3> Listado de provincias </h3>");
res.write("<table>");
res.write("<tr>");
res.write("<th>CPRO</th>");
res.write("<th>DPRO</th>");
res.write("</tr>");
for (reg in result.rows){
res.write("<tr>");
res.write("<th>"+result.rows[reg][0]+"</th>");
res.write("<th>"+result.rows[reg][1]+"</th>");
res.write("</tr>");
console.log(result.rows[reg][0] + "---" + result.rows[reg][1]);
}
res.write("</table>");
res.write("<a href='/'>Volver</a>");
res.write("</body>");
res.end();
});
});
});
9) Levantamos el servidor con:
node miserver.js
10) Desde el navegador lanzamos la siguiente URL: http://localhost:8888/
Eso es todo
En esta entrada vamos a montar un miniservidor html con Node.js que conecte a cierta tabla de Oracle mediante oracledb. Los pasos para instalar todo son:
1) Instalamos node.js y su gestor de paquetes npm
sudo apt-get install nodejs
sudo apt-get install npm
2) Verificamos que está bien instalado con:
nodejs --version --> v4.2.6
npm --version --> 3.5.2
3) Instalamos algunas de las librerías javascript que vamos a necesitar en nuestro servidor 'miserver.js':
npm install http
npm install httpdispatcher
4) Descargamos el 'Oracle Instant Client' de Oracle (http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html) siguiendo las instrucciones de (https://github.com/oracle/node-oracledb). Necesitaremos los packages 'basic' y 'SDK' si la BBDD está en remoto (es lo habitual). Por lo que hemos bajado las versiones de RedHat/linux:
oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
5) Para Ubuntu no hay instalador, así que transformamos el instalador rpm (RedHat) con:
sudo alien -i oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
sudo alien -i oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
Nota Ubuntu. Tambien hemos necesitado instalar la libreria libaio, no se para qué hace falta
sudo apt-get install libaio1
6) Seguidamente instalamos la librería javascript oracledb con:
npm install oracledb
Nota Ubuntu. Para poder lanzar sin problemas la instalacion de oracledb (saltaba un error en 'node-gyp rebuild' descrito en (https://github.com/npm/npm/issues/11335)) he tenido que crear un softlink 'node' dado que se petaba por tener instalado nodejs (el package de ubuntu) en vez del paquete node 'oficial'. Para crear el softlink lanzamos:
sudo ln -s /usr/bin/nodejs /usr/local/bin/node
8) Creamos nuestro servidor web por el puerto 8888 en javascrip, para ello creamos un fichero llamado 'miserver.js' con el siguiente codigo:
//Importamos las librerias necesarias
var http = require('http');
var HttpDispatcher = require('httpdispatcher');
var oracledb = require('oracledb');
//Inicializamos el enrutador
var enrutador = new HttpDispatcher();
//Definimos la función que manejara las peticiones
function handleRequest(request, response){
console.log("Peticion:");
console.log(request.url);
enrutador.dispatch(request, response);
}
//Creamos el servidor y lo ponemos a escuchar en el puerto 8888
var server = http.createServer(handleRequest);
server.listen(8888, function(){
console.log("Arrancado y escuchando en el puerto 8888");
});
//Creamos la función que devuelve la pagina /
enrutador.onGet("/", function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("<?xml version='1.0' encoding='UTF-8'?>");
res.write("<!DOCTYPE html>");
res.write("<html lang='es' xmlns='http://www.w3.org/1999/xhtml'>");
res.write("<head>");
res.write(" <meta http-equiv='Content-type' content='text/html; charset=UTF-8'/>");
res.write(" <meta name='language' content='es'/>");
res.write("</head>");
res.write("<body>");
res.write("<h3> Primer miniportal con Node.js</h3>");
res.write(" <ul>");
res.write(" <li><a href='/listaprovincias'>Lista de provincias</a></li>");
res.write(" </ul>");
res.write("</body>");
res.end();
});
//Creamos la función que devuelve la pagina /listaprovincias
enrutador.onGet("/listaprovincias", function(req, res) {
oracledb.getConnection(
{
user : "user",
password : "pwd",
connectString : "127.0.0.1:1535/prueba"
},
function(err, connection) {
if (err) {
console.error(err);
return;
}
connection.execute("SELECT CPRO, DPRO FROM PROVINCIAS ORDER BY DPRO",
function(err, result) {
if (err) {
console.error(err.message);
connection.close();
return;
}
console.log("Encontradas "+result.rows.length+" provincias");
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("<?xml version='1.0' encoding='UTF-8'?>");
res.write("<!DOCTYPE html>");
res.write("<html lang='es' xmlns='http://www.w3.org/1999/xhtml'>");
res.write("<head>");
res.write(" <meta http-equiv='Content-type' content='text/html; charset=UTF-8'/>");
res.write(" <meta name='language' content='es'/>");
res.write("</head>");
res.write("<body>");
res.write("<h3> Listado de provincias </h3>");
res.write("<table>");
res.write("<tr>");
res.write("<th>CPRO</th>");
res.write("<th>DPRO</th>");
res.write("</tr>");
for (reg in result.rows){
res.write("<tr>");
res.write("<th>"+result.rows[reg][0]+"</th>");
res.write("<th>"+result.rows[reg][1]+"</th>");
res.write("</tr>");
console.log(result.rows[reg][0] + "---" + result.rows[reg][1]);
}
res.write("</table>");
res.write("<a href='/'>Volver</a>");
res.write("</body>");
res.end();
});
});
});
9) Levantamos el servidor con:
node miserver.js
10) Desde el navegador lanzamos la siguiente URL: http://localhost:8888/
Eso es todo
Suscribirse a:
Entradas (Atom)