Sie sind auf Seite 1von 47

FACULTAD DE INGENIERIA DE SISTEMAS E.A.

P INGENIERIA DE SISTEMAS E INFORMATICA

TAREA N-2 DE SISTEMAS OPERATIVOS

CURSO TEMA PROFESORA

: : :

SISTEMAS OPERATIVOS ADMINISTRADOR DE TAREAS MARIA ELENA RUIZ RIVERA

ALUMNOS

MONDRAGON PANTIGOSO, MARCO GIMENEZ ALATA, RICARDO

CIUDAD UNIVERSITARIA, NOVIEMBRE DEL 2011

Tabla de contenido
Tabla de contenido..............................................................................................2 1. Objetivo...........................................................................................................3 2. Explicacin del programa (Qu es lo que hace?)...........................................3 3. Cdigo........................................................................................................... 18 4. Conclusiones.................................................................................................46

1. Objetivo
Implementar un administrador de tareas bajo el S.O. Windows XP que nos permita visualizar los procesos que hayan sido llevados a memoria principal, siendo capaces de observar a manera de lista y de forma grfica los nombres, tamaos y el PID de estos procesos en tiempo real. Por otro lado, la asignacin de memoria de trato de forma continua y su representacin en memoria (direcciones fsicas) se hizo mediante registros (base, lmite) y el tamao que ocupa (el proceso) en memoria (desplazamiento). Para desarrollar la aplicacin se utiliz el lenguaje Java y el IDE Netbeans 6.5. Los temas abarcados son: POO (clases), hilos, Java swing y Java 2d.

2. Explicacin del programa (Qu es lo que hace?)


Primero, en nuestra interfaz nos vamos a la pestaa de procesos, en ella podemos visualizar la lista de procesos que se estn cargadas en memoria todo ello gracias al comando tasklist del cmd (ms-dos). De donde obtuvimos el nombre del proceso, su PID, nombre de usuario (sesin), nmero de sesin y el uso de memoria que utiliza el proceso en memoria real. Su implementacin se llev a cabo mediante un hilo llamado Clase Hilo el cual monitorea constantemente por los cambios en el nmero de proceso y actualiza la lista y sus campos. El cual a su vez llama al mtodo procesar que se encarga de separar cada lnea de comando leda por el tasklist.()

(Fig.1) Ejemplo: se separa la lnea 1 hasta la lnea n(# procesos en memoria) todos sus campo. A manera de ejemplo la lnea se separara as (System Idle Process PID-Nombre nmero de sesin- uso de memoria) y estos

campos son almacenados en el Jtable tabla_procesos de la Fig.2. Asimismo, este mtodo procesar tambin nos sirve para llenar el JTable tabla_aplicaciones de la pestaa Aplicaciones (Fig.3).

(Fig. 2)

(Fig. 3) Cabe resaltar que la pestaa de Aplicaciones se actualiza del mismo mtodo procesar, el cual es lee el proceso. Ejemplo: netbeans.exe y nosotros detectamos esta cadena si esto sucede entonces procedemos a llenar con estos datos la tabla_aplicaciones. Por lo que este Jtable est sujeto a las aplicaciones para los procesos que nosotros hayamos definido, esto es, solo se mostraran las aplicaciones para los cuales exista su equivalente (ver Fig. 4).

(Fig.4) Segundo, la pestaa memoria nos muestra la memoria RAM total, memoria RAM libre y la memoria usada mediante un hilo llamado hmemoria de la clase Hilo_memoria que mediante la librera hyperic-sigar-1.6.4, especficamente el jar de sigar.jar que contiene la clase Sigar y esta a su vez contiene la clase Mem cuyos mtodos: getTotal(),getFree(),getUsed() nos permiten saber que cantidad de memoria se est utilizando(ver Fig.5) . Long memTotal=memoria.getTotal(); Long memLibre=memoria.getFree(); Long memUsada=memoria.getUsed(); (Fig. 5) En la misma ventana disponemos de los botones iniciar grfica y detener grfica de los cuales iniciar grfica dibuja en el Jpanel grfica( mediante La clase Graphics de la librera Java2d) utilizndolo como superficie de dibujo a este panel. Lo que hacemos es dibujar rectngulos con el mtodo fillRect(int x, int y, int width, int height) cuyos puntos x,y es el vrtice superior izquierdo del rectngulo y width viene a ser el ancho y height el alto todos ellos en pixeles (tipo entero). Donde cada entero representa un pixel donde cada punto se ubica de acuerdo a la figura 6(ver los ejes). La figura es similar al del panel.

(Fig. 6) Partiendo del mtodo procesar que vimos anteriormente hacemos lo siguiente: la primera vez que se inicie el mtodo procesar se crear una lista de registros con los datos( nombre, registro base, desplazamiento y registro lmite) de los procesos. Luego de creada esta lista de Nodos llamada lista_registro de la clase Lista_Reg est nos servir para realizar la grfica resumen de todos los procesos (que se encuentren en la lista) guardando una proporcin con su tamao en pxeles. Como dijimos esta lista solo se crear la primera vez(utilizando el mtodo agregarNodo() de la lista por cada proceso) mediante un uso del booleano primeraVez para las veces siguientes si es que se detecta una modificacin en la lectura de procesos (actualizacin lista agregaron o finalizaron procesos) y se buscar en la misma lista ya creada lnea por lnea cada proceso ledo por el comando cmd tasklist y si el nombre del proceso no se encuentra en la lista_registro se agrega un nuevo nodo con los datos mencionados anteriormente en el primer espacio en donde quepa el proceso(ver lnea 474 de la clase Admin.java del mtodo procesar).

(Fig. 7) Una vez explicado esto veamos la grfica resumen de la Fig.8 generada (click en iniciar grfica). Por otro lado el botn detener grfica lo que hace es resetear los valores del Jpane con el mtodo (grafica.updateUI()).

(Fig. 8)

Tercero, la pestaa Usuario nos muestra la cuenta de usuario usada para entrar a Windows con el mtodo del Frame Principal (InformacionUsuario()) el cual a su vez hace uso del mtodo System.getProperty("user.name"). Cuarto, la pestaa de registros contiene un Jtable llamado tabla_registros el cual se llena cuando presionamos el botn de ver en consola los registros. Este JTable toma los datos de la lista_registros(el cual contiene todos los campos que aparecen aqu, ver los atributos de la clase Nodo) que es la que se actualiza a cada momento por se encuentra en el mtodo procesar del Hilo(ver Fig.11). Para visualizar el grfico de la parte inferior del uso de la memoria, solo debemos de ingresar el mouse al rea del JScrollPane(jScrollPane5) en cuyo interior se encuentra un JPane(grafica2). Esta rea se pintar automticamente cada vez que lo ingresemos el cursor del mouse OJO(ver Fig.9).

(Fig. 9) En la figura 10 podemos visualizar el rea libre de la RAM y esta se clcula de la misma manera que se calcul en el mtodo informacinMemoria() del hilo hmemoria (con la librera del Sigar.jar). Por otro lado, se sum recorriendo la lista_registros los desplazamientos y a la cantidad de memoriaTotal se le resto esta suma dndonos la memoriaLibre y ese espacio se puede ver en la fig. 10. Cabe mencionar que estos desplazamientos son tan diversos en tamao que

para fines didcticos y para poder visualizar mejor los tamaos de los rectngulos se hizo uso de intervalos si el proceso es menor a 25 000Kb es de tamao pequeo (ancho de 150 pxeles), si esta entre 25 000Kby 50 000Kb es de tamao intermedio (ancho de 300 pxeles) y si es mayor a 50 000Kb entonces es de tamao grande (ancho de 450 pxeles). (Ver mtodo sumaDesplazamiento2() de la clase Lista_Reg).

(Fig. 10)

(Fig. 11)

(Fig.12)

Quinto, probaremos al mismo tiempo si se actualiza la grfica cuando se finalice un proceso y cuando se agregue uno nuevo este busque el primer espacio vaco que se adece a su tamao y que cuando se libere un proceso y este se encuentre al lado de otro vaco (seguidos) se condensen los espacios vacos en uno solo. Vallamos paso a paso con las siguientes imgenes explicando este ejemplo del paso cinco.

(Fig. 13) En la fig. 13 se aprecia el proceso notepad.exe y este se va a finalizar(click en archivo y de ah en finalizar tarea, se va a abrir una ventana como en la en la fig 14.) A continuacin escribir su nombre sin el .exe (del proceso). Y click el matar proceso. Luego entrar el cursor en la zona de la grfica para que se repinte el rea (fig. 15)

(Fig. 14)

(Fig. 15) Para probar la condensacin veremos una secuencia rpida de imgenes (Fig 16-20). Con el notepad ya abierto y despus de ejecutada la aplicacin se tiene lo de la fig.16.

(Fig. 16)

(Fig.17) Luego de haber finalizado el notepad(Fig.17) se puede visualizar en la grfica esta actualizacin al haber entrado el cursor en el rea, pero no olvidar que para que actualice la tabla del JTable debemos hacer click en el botn en ver en consola los registros. NO OLVIDAR. Nosotros si hicimos click en este botn por eso es que sale actualizada la tabla, pero ambas el JTable y el Jpane se actualizan con los datos de la lista_registros (Nodos).

Probamos a abrir un programa que es el buscaminas winmine.exe y como vemos en la fig.18 este se aloja en el primer espacio que se adece a su tamao el cual como se aprecia es el espacio libre que quedo vaco tras haberse liberado el notepad. En esta figura (#18) si se le dio click al botn ver en consolado los registros es por eso que la tabla si aparece como actualizada.

(Fig. 18) Si matamos al winmine(buscaminas) haciendo click en el men Archivo>Finalizar Tarea y escribimos winmine y click en matar proceso vamos a tener lo que vemos fig.19. Slo que en la fig. 19 no le dimos click al botn no alarmase (este cambio ms rpido de lo que pudimos dar click en el botn ver en consola registros para actualizar la tabla). Y la condensacin se realiza con un hilo (hcondensar) que monitorea constantemente y cada ocho segundos est viendo si existen espacios contiguos y los condensa pasando de la figura 19 a la 20.

(Fig. 19)

(Fig. 20)

3. Cdigo ************************CLASE Lista_Reg********************


package newpackage; import javax.swing.JTable; /** * * @author APOYO - UIC */ /*Registro lmite = tamao mximo del programa y los datos * Registro base =posicin de inicio del programa en memoria*/ public class Lista_Reg { Nodo inicio;

Nodo fin; int total; public Lista_Reg(){ total=0; inicio=null; fin=null; } public void agregarNodo(String nom,int rb, int d, int rl){ total++; Nodo nodo=new Nodo(total, nom,rb,d,rl); if(inicio==null){ // si lista vacia crea el primer elemento, sino aade un nodo inicio=nodo; }else{ //ya existe al menos un nodo fin.setSig(nodo); } fin=nodo; } //para la consola public void recorrerLista(){ int i=1; Nodo p=new Nodo(); p=inicio; while(p!=null){ System.out.println("Proceso " +i); System.out.println("Nombre: "+p.getNombre()); System.out.println("R_base: "+p.getR_base()); System.out.println("Desplazamiento: "+p.getDesplazamiento()); System.out.println("R_limite: "+p.getR_limite()); p=p.getSig(); i++; } } //para el jTable public void recorreLLenar(JTable tabla,int maxFilas){ int i=0; Nodo p=new Nodo(); p=inicio; int num=1; while(p!=null&&i<maxFilas){ tabla.setValueAt(""+p.getNombre(), i, 0); tabla.setValueAt(""+p.getR_base(), i, 1); tabla.setValueAt(""+p.getDesplazamiento(), i, 2); tabla.setValueAt(""+p.getR_limite(), i, 3); tabla.setValueAt(""+num, i, 5); if(p.getNombre().equals("vacio")){ tabla.setValueAt(false, i, 4); }else{ tabla.setValueAt(true, i, 4); }

p=p.getSig(); i++; num++; } if(i>=maxFilas){ System.out.println("Se alcanzo lmite maximo de filas"); } } public boolean buscar(String nombre){ boolean encontro=false; Nodo p=new Nodo(); p=inicio; while(p!=null){ if(p.getNombre().equals(nombre)){ encontro=true; } p=p.getSig(); } return encontro; } public int sumaDesplazamiento(){ int suma=0; Nodo p=new Nodo(); p=inicio; while(p!=null){ if(!p.getNombre().equals("vacio")){ suma=suma+p.getDesplazamiento(); } p=p.getSig(); } return suma; } public int sumaDesplazamiento2(){ int suma=0; Nodo p=new Nodo(); p=inicio; while(p!=null){ int desp=450; if(p.getDesplazamiento()<25000){ desp=150; }else{ if(25000<p.getDesplazamiento()&&p.getDesplazamiento()<50000){ desp=300; } //cuando es de 350 es xq es >50000 } suma=suma+desp; p=p.getSig(); } return suma;

} public void llenarBlanco(String cadena){ Nodo p=new Nodo(); p=inicio; while(p!=null){ if(p.getNombre().equals(cadena+".exe")|| p.getNombre().equals(cadena.toUpperCase()+".EXE")){ p.setNombre("vacio"); } p=p.getSig(); } }

***************************************************************** **************************CLASE NODO ********************


/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package newpackage; /** * * @author APOYO - UIC */ public class Nodo { private String nombre; private int r_base; private int desplazamiento; private int r_limite; private int numero; private Nodo sig; int R; int G; int B; public Nodo(){ } public Nodo(int n,String nom,int rb, int d, int rl){ numero=n; R=(int) (Math.random() * 254 + 1); //1-254 G=(int) (Math.random() * 254 + 1); B=(int) (Math.random() * 254 + 1); nombre=nom; r_base=rb; desplazamiento=d; r_limite=rl; sig=null; }

/** * @return the nombre */ public String getNombre() { return nombre; } /** * @param nombre the nombre to set */ public void setNombre(String nombre) { this.nombre = nombre; } /** * @return the r_base */ public int getR_base() { return r_base; } /** * @param r_base the r_base to set */ public void setR_base(int r_base) { this.r_base = r_base; } /** * @return the desplazamiento */ public int getDesplazamiento() { return desplazamiento; } /** * @param desplazamiento the desplazamiento to set */ public void setDesplazamiento(int desplazamiento) { this.desplazamiento = desplazamiento; } /** * @return the r_limite */ public int getR_limite() { return r_limite; } /** * @param r_limite the r_limite to set */ public void setR_limite(int r_limite) { this.r_limite = r_limite; }

/** * @return the sig */ public Nodo getSig() { return sig; } /** * @param sig the sig to set */ public void setSig(Nodo sig) { this.sig = sig; } /** * @return the numero */ public int getNumero() { return numero; } /** * @param numero the numero to set */ public void setNumero(int numero) { this.numero = numero; } }

***************************************************************** **********************CLASE ADMIN*************************


/* * To change this template, choose Tools | Templates * and open the template in the editor. */ /* * NewJFrame.java * * Created on 22/04/2011, 03:26:03 PM */ package newpackage; import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.io.BufferedReader; import java.io.File; import java.io.IOException;

import java.io.InputStream; import java.io.InputStreamReader; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableModel; import org.hyperic.sigar.Mem; import org.hyperic.sigar.Sigar; import org.hyperic.sigar.SigarException; /** * * @author User */ public class Admin extends javax.swing.JFrame { String noAgregar=" "; boolean pararGrafica=true; Hilo_memoria hmemoria=new Hilo_memoria(); Hilo_condensar hcondensar=new Hilo_condensar(); Sigar plugin= new Sigar(); int retVal=0;//valor del FileChooser int numP=0,numA=0; String nom_P = "", pid_P = "",nom_User ="" ,num_Sesion = "",mem = ""; String sesion_usuario; int conta=0; int procesos = 0; WindowsLookAndFeel win = new WindowsLookAndFeel(); ImageIcon im=new ImageIcon(getClass().getResource("/Iconos/duke-small.png")); private FechaHora fh=new FechaHora(); boolean primeraVez=true; DefaultTableModel dt=new DefaultTableModel(); Fecha fe = new Fecha(); HORA hor=new HORA(); Lista_Reg lista_registros=new Lista_Reg(); private String fileName; private JFileChooser FileC=new JFileChooser(); /** Creates new form NewJFrame */ public Admin() throws UnsupportedLookAndFeelException { UIManager.setLookAndFeel(win); initComponents();

FrameMatar.setVisible(false); setIconImage(im.getImage()); FrameMatar.setIconImage(im.getImage()); //SPlash window=new LW(this); //asignamos hora y fecha lblFecha.setText(fe.getFecha()); lblHora.setText(hor.getHora()); FileC.setVisible(false); //LLenado Tabla Procesos y Aplicaciones procesar(); // Informacion de memoria //hgrafica.start(); // InformacionMemoria(); //Inciar el hilo de memoria hmemoria.start(); //Informacion de Usuario InformacionUsuario(); //****************TAMAO DE LA GRAFICA JPANE DENTRO DEL JSCROLLPANE********* grafica2.setMinimumSize(new Dimension(4540, 400)); grafica2.setPreferredSize(new Dimension(4540, 400)); //jScrollPane5.setMinimumSize(new Dimension(18040, 400)); //jScrollPane5.setPreferredSize(new Dimension(18040, 400)); // grafica2.setMinimumSize(new Dimension((Integer.parseInt(dim)/10000)+50, 400)); //grafica2.setPreferredSize(new Dimension((Integer.parseInt(dim)/10000)+50, 400)); //******************* lblnum.setText("Aplicaciones :"); lblnum2.setText(numA+""); new Hilo().start(); hcondensar.start(); } public void InformacionUsuario(){ String a=System.getProperty("user.name"); tabla_usuario.setValueAt(a,0 ,0); tabla_usuario.setValueAt("0",0 ,1); tabla_usuario.setValueAt("Activo",0 ,2); tabla_usuario.setValueAt(sesion_usuario,0 ,3); } public void InformacionMemoria() throws SigarException{ Mem memoria=plugin.getMem(); Long memTotal=memoria.getTotal(); Long memLibre=memoria.getFree();

Long memUsada=memoria.getUsed(); lbltotal.setText(memTotal/1024+" Kb"); lbllib.setText(memLibre/1024+" Kb"); lbluso.setText(memUsada/1024+" KB"); } public class Hilo_memoria extends Thread{ @Override public void run(){ while(true){ try { //Modifica las etiquetas de memoria fsica. InformacionMemoria(); Hilo_memoria.sleep(1000); } catch (InterruptedException ex) { Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex); } catch (SigarException ex) { Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex); } } } } public void condensar(){ Nodo p=lista_registros.inicio; Nodo sig=p.getSig(); while(p!=null){ if(sig!=null){ if(p.getNombre().equals("vacio")&&sig.getNombre().equals("vacio")){ int sumaDesp=0; sumaDesp=p.getDesplazamiento()+sig.getDesplazamiento(); p.setDesplazamiento(sumaDesp); p.setR_limite(p.getR_base()+sumaDesp-1); p.setSig(sig.getSig()); } } if(p.getSig()==null){ lista_registros.fin=p; } p=p.getSig(); //pedir el siguiente solo si p es diferente de nulo if(p!=null){ sig=p.getSig(); } } } public class Hilo_condensar extends Thread{ @Override public void run(){ while(true){ try{ condensar(); Hilo_condensar.sleep(8000);

} catch (InterruptedException ex) { Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex); } } } } public class Hilo_grfica extends Thread{ int red=0; int green=0; int blue=0; int base_X=40; int base_Y=40; Nodo p=new Nodo(); @Override public void run(){ while(pararGrafica){ //dibujar en el canvas(jpane) de grfica de memoria //***************************************************** //CANVAS //****************modificado para la grafica2 Graphics m=grafica2.getGraphics(); m.setColor(Color.BLACK); m.fillRect(base_X,base_Y,700 ,200 ); //************************************************* /*Pintaremos de la lista de registros *x cada registro un rectangulo. */ p=lista_registros.inicio; int anchoCanvas=650; //en realidad es 700 pero 50 es libre while(p!=null){ //*************GENERA NUEVO COLOR********** red=(int) (Math.random() * 255 + 1); //1-255 green=(int) (Math.random() * 255 + 1); blue=(int) (Math.random() * 255 + 1); Color pintura=new Color(red,green,blue); m.setColor(pintura); //***************************************** int ancho=(int) (lista_registros.sumaDesplazamiento()*p.getDesplazamiento()/anchoCanvas); int baseEnX=(int) (lista_registros.sumaDesplazamiento()*p.getR_base()/anchoCanvas); m.fillRect(base_X+baseEnX,base_Y, ancho,200 ); p=p.getSig(); } try { Hilo_grfica.sleep(1000); //****************************************************** } catch (InterruptedException ex) {

Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex); } //****************************************************** } } } public class Hilo extends Thread{ public Hilo(){ } @Override /* ste hilo lo que hace es llamar al mtodo procesar * constantemente para que actualice los campos de la pestaa * procesos de la interfaz, es decir, si se ha agregado algn * proceso(cont>procesos) a eliminado(cont<procesos) alguno llama. * Dnde cont almacena la cantidad de procesos(actuales) cada vez * que se llama constamente al hilo y procesos es valor anterior a cont * el cual almacena el # procesos anteriores ledos. */ public void run(){ try { while(conta<5000){ // este while y el for son para delimitar for(int i=0;i<10;i++){ //el tiempo que se va a ejecutar el hilo. conta++; int cont = leerProcesos(); //Cuantos procesos existen, se han creado if(cont > procesos || cont < procesos){ procesos = 0; procesar(); } //Hilo.sleep(2000); Hilo.sleep(10); //dormir el hilo 1000 equivale 1 segundo. } } } catch (InterruptedException ex) { ex.printStackTrace(); } } } public int leerProcesos(){ //Cuantos procesos existen se han creado int num_pro = 0; try{ Process pro=Runtime.getRuntime().exec ("cmd /c tasklist"); InputStream is = pro.getInputStream(); BufferedReader br = new BufferedReader (new InputStreamReader (is)); br.readLine(); br.readLine(); br.readLine(); while (br.readLine() != null){ num_pro++;

} } catch (Exception e){ e.printStackTrace(); } return num_pro; } public int separaNumero(String cadena){ int numero=0; String subcadena=""; for(int i=0;i<cadena.length();i++){ if(cadena.charAt(i)!=',' &&cadena.charAt(i)!='K'&&cadena.charAt(i)!=' '&&cadena.charAt(i)!='.'){ subcadena=subcadena+cadena.charAt(i); }else{ if(cadena.charAt(i)=='K' || cadena.charAt(i)==' '){ i=cadena.length(); //terminar } } } return numero=Integer.valueOf(subcadena); } public void procesar(){ //*********REGISTROS BASE.LIMITE.DESPLAZAMIENTO*********** int r_base=0; int r_limite=0; int desplazamiento=0; //******************************************************** numA=0; numP=0; try{ Process pro=Runtime.getRuntime().exec ("cmd /c tasklist"); InputStream is = pro.getInputStream(); BufferedReader br = new BufferedReader (new InputStreamReader(is)); br.readLine(); //es una linea vaca br.readLine(); // son los ttulos de los campos br.readLine(); // son los caracteres '====' del tasklist String aux = br.readLine(); //llego a la lnea 1 donde se encuet ordenar(aux); //separ una linea todos sus campos int i = 0; int y =0; while (aux != null){ numP=numP+1; procesos++; //llenado Tabla if(nom_P.equalsIgnoreCase("firefox.exe")) {tabla_aplicaciones.setValueAt("Mozilla Firefox",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++;

} if(nom_P.equalsIgnoreCase("ATVR1.exe")) {tabla_aplicaciones.setValueAt("Analog TVR",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("t2ev.exe")) {tabla_aplicaciones.setValueAt("Tarifador Telefnico",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("netbeans.exe")) {tabla_aplicaciones.setValueAt("Netbeans",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("winword.exe")) {tabla_aplicaciones.setValueAt("Microsoft Word",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("WINWORD.EXE")) {tabla_aplicaciones.setValueAt("Microsoft Word",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("powerpnt.exe")) {tabla_aplicaciones.setValueAt("PowerPoint",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("powerpnt.xe")) {tabla_aplicaciones.setValueAt("PowerPoint",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("excel.exe")) {tabla_aplicaciones.setValueAt("Microsoft Excel",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("EXCEL.EXE")) {tabla_aplicaciones.setValueAt("Microsoft Excel",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("notepad.exe")) {tabla_aplicaciones.setValueAt("Block de Notas",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("calc.exe")) {tabla_aplicaciones.setValueAt("Calculadora",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } if(nom_P.equalsIgnoreCase("mspaint.exe"))

{tabla_aplicaciones.setValueAt("Paint",y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; } //***********TABLA DE PROCESOS*************************** tabla_procesos.setValueAt(nom_P,i,0); tabla_procesos.setValueAt(pid_P,i,1); tabla_procesos.setValueAt(nom_User,i,2); tabla_procesos.setValueAt(num_Sesion,i,3); tabla_procesos.setValueAt(mem,i,4); // Generamos la lista de nodos que nos servira para //la grafica de la memoria RAM if(primeraVez){ desplazamiento=separaNumero(mem); if(lista_registros.inicio==null){//1ero elemento r_base=0; r_limite=desplazamiento-1; }else{ r_base=lista_registros.fin.getR_limite()+1; r_limite=r_base+desplazamiento-1; } lista_registros.agregarNodo(nom_P, r_base,desplazamiento ,r_limite ); //para la primera vez de agregar Nodo //r_base=r_base+desplazamiento; //r_limite= }else{ //borrar o agregar del vector //borrar es poner a String "null" el nombre del proceso //agregar es poner al final de la lista //&&!nom_P.equals(noAgregar+".exe") boolean soloUna=true; if(!lista_registros.buscar(nom_P) ){ //no lo encontro, lo agrega System.out.println("nom_P ENTRO"); //lista_registros.agregarNodo(nom_P, r_base,desplazamiento ,r_limite ); //ahora asignar al primer hueco libre introducirle el proceso //ACA AGREGAR EL CODIGO PARA QUE ACTUALICE EL TAMANO //DEL ULTIMO REGISTRO //debe buscar su hueco donde meterse primero int numero=lista_registros.total; lista_registros.total++; Nodo ant=new Nodo(); Nodo p=new Nodo(); p=lista_registros.inicio; ant=p; boolean salir=true; int tamVacio; desplazamiento=separaNumero(mem); while(p!=null&&salir){

//2 casos if(p.getNombre().equals("vacio")&&desplazamiento<p.getDesplazamiento ()){ //1er caso tamVacio=p.getDesplazamiento(); //modificar sus valores desplazamiento=separaNumero(mem); r_base=ant.getR_limite()+1; r_limite=r_base+desplazamiento-1; Nodo nodo=new Nodo(numero,nom_P,r_base,desplazamiento ,r_limite ); ant.setSig(nodo); nodo.setSig(p); //ya esta enlazado lso ndoos p.setR_base(r_limite+1); p.setDesplazamiento(tamVacio-desplazamiento); salir=false; //1ero nodo }else{ //2 do caso son ='s if(p.getNombre().equals("vacio")&&desplazamiento==p.getDesplazami ento()){ soloUna=false; p.setNombre(nom_P); } } ant=p; p=p.getSig(); }//end while

}//fin if } i++; //Verifica si son aplicaciones o procesos if(num_Sesion.equalsIgnoreCase("1")){ sesion_usuario=nom_User; tabla_aplicaciones.setValueAt(nom_P,y,0); tabla_aplicaciones.setValueAt("Activo",y,1); y++; numA=numA+1; } aux = br.readLine(); if(aux != null) { ordenar(aux);} }//end of while

//aki //******************************************* if(primeraVez){ //agregar un nodo ms a la lista que es lo libre //recien creada por primera vez int base,desp,lim; base=lista_registros.fin.getR_limite()+1; Mem memoria=plugin.getMem(); Long memTotal=memoria.getTotal(); desp=memTotal.intValue()-lista_registros.sumaDesplazamiento(); lim=base+desp-1; lista_registros.agregarNodo("vacio", base, desp, lim); System.out.println("Memoria libre agregada al final_lista"); primeraVez=false; } //******************************************* primeraVez=false; } catch (Exception e){ e.printStackTrace(); } } void ordenar(String formato){ int i = 0; char car1,car2; String auxiliar = null; while( true ){ car1= formato.charAt(i); car2 = formato.charAt(i+1); auxiliar = String.valueOf(car1); if(auxiliar.equals(" ") == true){ auxiliar = String.valueOf(car2); if(auxiliar.equals(" ") == true) break; } i++; } nom_P = formato.substring(0,i); //devuelve el nombre del proceso while(auxiliar.equals(" ") == true){ car1 = formato.charAt(++i); auxiliar = String.valueOf(car1); } int j = i; while(auxiliar.equals(" ") == false){ car1 = formato.charAt(j++); auxiliar = String.valueOf(car1); } pid_P = formato.substring(i,j); i = j; car1 = formato.charAt(i);

auxiliar = String.valueOf(car1); while(auxiliar.equals(" ") == false){ car1 = formato.charAt(j++); auxiliar = String.valueOf(car1); } nom_User = formato.substring(i,j-1); while(auxiliar.equals(" ") == true){ car1 = formato.charAt(j++); auxiliar = String.valueOf(car1); } i = --j; while(auxiliar.equals(" ") == false){ car1 = formato.charAt(j++); auxiliar = String.valueOf(car1); } num_Sesion = formato.substring(i,j-1); while(auxiliar.equals(" ") == true){ car1 = formato.charAt(j++); auxiliar = String.valueOf(car1); } mem = formato.substring(j-1,formato.length()); }

private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) { System.exit(0); // TODO add your handling code here: } private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: FrameMatar.setVisible(true); txtMatar.setText(""); FrameMatar.setLocation(600,300); FrameMatar.setSize(470,150); } private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: FrameMatar.setVisible(true); txtMatar.setText(""); FrameMatar.setLocation(600,300); FrameMatar.setSize(470,150); } private void jTabbedPane1MouseClicked(java.awt.event.MouseEvent evt) { // TODO add your handling code here:

if(jTabbedPane1.getSelectedIndex()==0){ lblnum.setText("Aplicaciones :"); lblnum2.setText(numA+""); }else{ if(jTabbedPane1.getSelectedIndex()==0){ lblnum.setText("Procesos :"); lblnum2.setText(numP+""); }else { lblnum.setText("Procesos :"); lblnum2.setText(numP+""); } } } private void MenuNuevo(java.awt.event.ActionEvent evt) { crearProceso(); } public void crearProceso(){ FileC = new JFileChooser(); retVal = FileC.showOpenDialog(this); if (retVal == FileC.APPROVE_OPTION) { fileName = FileC.getSelectedFile().getPath(); System.out.println(fileName); File file = new File(fileName); String[] cmd = new String[4]; cmd[0] = "cmd"; cmd[1] = "/C"; cmd[2] = "start"; cmd[3] = fileName; // path del archivo que deseamos abrir Runtime rt = Runtime.getRuntime(); try { rt.exec(cmd); } catch (IOException ex) { ex.printStackTrace(); } numA++; numP++; } }/* private void MenuAyuda(java.awt.event.ActionEvent evt) { }

*/ private void MenuActualizar(java.awt.event.ActionEvent evt) { // TODO add your handling code here: procesar(); if(jTabbedPane1.getSelectedIndex()==0){ lblnum.setText("Aplicaciones :"); lblnum2.setText(numA+""); }else{ if(jTabbedPane1.getSelectedIndex()==0){ lblnum.setText("Procesos :"); lblnum2.setText(numP+""); }else { lblnum.setText("Procesos :"); lblnum2.setText(numP+""); } } } private void btnNuevo(java.awt.event.ActionEvent evt) { // TODO add your handling code here: crearProceso(); procesar(); } private void MenuCerrarS(java.awt.event.ActionEvent evt) { // TODO add your handling code here: int opcion=JOptionPane.showConfirmDialog(this, " Esta Seguro que desea Cerrar la Sesin? " , " Cerrar Sesin ", JOptionPane.YES_NO_OPTION); switch(opcion){ case JOptionPane.YES_OPTION:{ try { Runtime.getRuntime().exec("shutdown -l"); catch (Exception e) { e.printStackTrace();} } case JOptionPane.NO_OPTION: { JOptionPane.showMessageDialog(this, " Usted permanece en la sesin " , " Cerrar Sesin ", JOptionPane.INFORMATION_MESSAGE + JOptionPane.OK_OPTION); break; } } } private void MenuApagar(java.awt.event.ActionEvent evt) { // TODO add your handling code here: int opcion=JOptionPane.showConfirmDialog(this, " Esta Seguro que desea Apagar la PC? " , " Apagar ", JOptionPane.YES_NO_OPTION);

switch(opcion){ case JOptionPane.YES_OPTION:{ try { Runtime.getRuntime().exec("shutdown -s -t 3600"); catch (Exception e) { e.printStackTrace();} } case JOptionPane.NO_OPTION: { JOptionPane.showMessageDialog(this, " Siga Trabajando " , "Apagar", JOptionPane.INFORMATION_MESSAGE + JOptionPane.OK_OPTION); break; } } } private void MenuReiniciar(java.awt.event.ActionEvent evt) { // TODO add your handling code here: int opcion=JOptionPane.showConfirmDialog(this, " Esta Seguro que desea Reiniciar la PC? " , " Reiniciar ", JOptionPane.YES_NO_OPTION); switch(opcion){ case JOptionPane.YES_OPTION:{ try { Runtime.getRuntime().exec("shutdown -r -t 3600"); { e.printStackTrace();} } case JOptionPane.NO_OPTION: { JOptionPane.showMessageDialog(this, " Siga Trabajando " , " Reiniciar ", JOptionPane.INFORMATION_MESSAGE + JOptionPane.OK_OPTION); break; } } } private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: FrameMatar.setVisible(false); tabla_aplicaciones.setValueAt("",0,0); tabla_aplicaciones.setValueAt("",0,1); tabla_aplicaciones.setValueAt("",1,0); tabla_aplicaciones.setValueAt("",1,1); tabla_aplicaciones.setValueAt("",2,0); tabla_aplicaciones.setValueAt("",2,1); tabla_aplicaciones.setValueAt("",3,0); tabla_aplicaciones.setValueAt("",3,1); tabla_aplicaciones.setValueAt("",4,0);

} catch (Exception e)

tabla_aplicaciones.setValueAt("",4,1); tabla_aplicaciones.setValueAt("",5,0); tabla_aplicaciones.setValueAt("",5,1); tabla_aplicaciones.setValueAt("",6,0); tabla_aplicaciones.setValueAt("",6,1); tabla_aplicaciones.setValueAt("",7,0); tabla_aplicaciones.setValueAt("",7,1); String osName = System.getProperty("os.name"); String system = " "; system="tskill " + txtMatar.getText().trim(); noAgregar=txtMatar.getText().trim(); Process hijo; try { hijo = Runtime.getRuntime().exec(system); //Matan al proceso hijo.waitFor(); if ( hijo.exitValue()==0){ System.out.println( txtMatar.getText() + " Killed" ); /* //Lo mato eontces tambien borra de lista regsitros String nombre=txtMatar.getText().trim()+".exe"; lista_registros.buscar(nombre); //borra si se encuentra en la lista reg //pone null su nombre * */ System.out.println("mATO AL PROCESO"); lista_registros.llenarBlanco(txtMatar.getText().trim()); }else{ System.out.println( "Cannot kill " + txtMatar.getText() + ". Exit code: " + hijo.exitValue() ); } } catch (IOException e) { System.out.println("Incapaz de matar soffice."); } catch (InterruptedException e) { System.out.println("Incapaz de matar soffice."); } procesar(); } private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: FrameMatar.setVisible(false); } private void jMenuItem12ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: FrameMatar.setVisible(true); txtMatar.setText(""); FrameMatar.setLocation(600,300); FrameMatar.setSize(470,150);

} private void lblnum2AncestorAdded(javax.swing.event.AncestorEvent evt) { // TODO add your handling code here: } private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: } private void jMenu5ActionPerformed(java.awt.event.ActionEvent evt) { // JOptionPane.showMessageDialog(this,"Administrador de Tareas "); // TODO add your handling code here: } private void MenuAyudaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: File f=new File("taskmgr.chm"); String[] cmd = new String[4]; cmd[0] = "cmd"; cmd[1] = "/C"; cmd[2] = "start"; cmd[3] = f.getPath(); // path del archivo que deseamos abrir Runtime rt = Runtime.getRuntime(); try { rt.exec(cmd); } catch (IOException ex) { ex.printStackTrace(); } } private void jMenuItem17ActionPerformed(java.awt.event.ActionEvent evt) { //JOptionPane.showMessageDialog(this,"Administrador de Tareas "); // TODO add your handling code here: // TODO add your handling code here: } private void graficaMouseEntered(java.awt.event.MouseEvent evt) { // TODO add your handling code here: } private void graficaMouseExited(java.awt.event.MouseEvent evt) { // TODO add your handling code here: } private void jButton6ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: //Crear el hilo de la grfica

//Hilo_grfica hgrafica=new Hilo_grfica(); //Iniciar hilo de la grfica de la RAM // hgrafica.start(); // pararGrafica=true; // int base_X=40; int base_Y=40; Nodo p=new Nodo();

//dibujar en el canvas(jpane) de grfica de memoria //***************************************************** //CANVAS Graphics h=grafica.getGraphics(); h.setColor(Color.BLACK); h.fillRect(base_X,base_Y,700 ,200 ); /*Pintaremos de la lista de registros *x cada registro un rectangulo. */ //h.setColor(Color.blue); //h.fillRect(40,40,100, 200); p=lista_registros.inicio; int anchoCanvas=650; //en realidad es 700 pero 50 es libre while(p!=null){ //*************GENERA NUEVO COLOR********** Color pintura=new Color(p.R,p.G,p.B); if(p.getNombre().equals("vacio")){ h.setColor(Color.BLACK); }else{ h.setColor(pintura); } //***************************************** int ancho=(int)Math.floor(p.getDesplazamiento()*anchoCanvas/lista_registros.sumaDesplazam iento()); int baseEnX=(int)Math.floor(p.getR_base()*anchoCanvas/lista_registros.sumaDesplazamiento ()); h.fillRect(base_X+baseEnX,base_Y, ancho,200 ); p=p.getSig(); }

} private void jButton7ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: //detener el hilo //pararGrafica=false; grafica.updateUI(); } private void jButton8ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: //********************************************************* seCreoNuevoProceso(); // de ser asi agregarlo a la lista //************************************************************ //***********RECORRIDO DE LA LISTA EN CONSOLA******************** lista_registros.recorrerLista(); //***************************************************************** //******************LIMPIEZA DEL JTABLE TABLA DE REGISTROS******* int maxFila=77; //numero maximo de filas de la tabla registros int maxColumna=5; //numero maximo de columnas System.out.println("Realizando limpieza de tabla_registros..."); for(int i=0;i<maxFila;i++){ for(int j=0;j<maxColumna;j++){ if(j!=4){ tabla_registros.setValueAt("", i,j ); }else{ //columna j=4, de estado //llenar con false todo ya que // existe=true y no existe=false tabla_registros.setValueAt(false, i,j ); } } } //************************************************************ //************************************************************ System.out.println("LLenado de la tabla_registros..."); lista_registros.recorreLLenar(tabla_registros,maxFila); //************************************************************ } private void jScrollPane5MouseClicked(java.awt.event.MouseEvent evt) { // TODO add your handling code here:

} private void grafica2MouseDragged(java.awt.event.MouseEvent evt) { // TODO add your handling code here: } private void grafica2MouseWheelMoved(java.awt.event.MouseWheelEvent evt) { // TODO add your handling code here: } private void grafica2MouseEntered(java.awt.event.MouseEvent evt) { // TODO add your handling code here: //fin de dibujar el grafico2 //*********************Comienza la diversin**************** int base_X=20; int base_Y=20; Nodo p=new Nodo();

//dibujar en el canvas(jpane) de grfica de memoria //***************************************************** //CANVAS Graphics m=grafica2.getGraphics(); //m.setColor(Color.BLACK); //m.fillRect(base_X,base_Y,16000,200 ); /*Pintaremos de la lista de registros *x cada registro un rectangulo. */ //h.setColor(Color.blue); //h.fillRect(40,40,100, 200); p=lista_registros.inicio; //int anchoCanvas=Integer.parseInt(total); int anchoCanvas=4000; int baseEnX=(int)Math.floor(p.getR_base()*anchoCanvas/lista_registros.sumaDesplazamiento ()); baseEnX=0; int num=1; while(p!=null){ //*************GENERA NUEVO COLOR********** Color pintura=new Color(p.R,p.G,p.B); if(p.getNombre().equals("vacio")){

m.setColor(Color.BLACK); }else{ m.setColor(pintura); } //***************************************** //int ancho=(int)Math.floor(p.getDesplazamiento()*anchoCanvas/lista_registros.sumaDesplazam iento()); //int baseEnX=(int)Math.floor(p.getR_base()*anchoCanvas/lista_registros.sumaDesplazamiento ()); int ancho=450; if(p.getDesplazamiento()<25000){ ancho=150; }else{ if(25000<p.getDesplazamiento()&&p.getDesplazamiento()<50000){ ancho=300; } //cuando es de 350 es xq es >50000 } ancho=(int)Math.floor(ancho*anchoCanvas/lista_registros.sumaDesplazami ento2()); m.fillRect(base_X+baseEnX,base_Y, ancho,200 ); m.setColor(Color.BLACK); String nombre=p.getNombre(); String tamao=""+p.getDesplazamiento()+"Kb"; int x=(int)Math.floor(base_X+baseEnX+ancho/8); int y=base_Y+100; //ok if(p.getNombre().equals("vacio")){ m.setColor(Color.white); }else{ m.setColor(Color.BLACK); } m.drawString(nombre, x,y); m.drawString(tamao, x+nombre.length()/2, y+20); m.drawString(""+num, x+nombre.length()/2, y+40); num++; baseEnX+=ancho; p=p.getSig(); m.setColor(Color.BLACK); } //********************************************************** } private void jButton9ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: //PROCEREMOS A BUSCAR LOS ESPACIOS VACIOS CONTIGUOS Y A UNIRLOS EN //UN SOLO REGISTRO Nodo p=new Nodo();

Nodo ant=new Nodo(); p.setSig(lista_registros.inicio); int sumaDesp=0; int espaciosVacios=0; int base=0; int lim=0; /*while(p!=null){ if(p.getSig().getNombre().equals("vacio")&&!p.getNombre().equals("vacio")){ ant=p; sumaDesp=0; espaciosVacios=0; }else{ if(p.getNombre().equals("vacio")){ espaciosVacios++; sumaDesp=sumaDesp+p.getDesplazamiento(); }else{ //CONDENSAR. if(espaciosVacios>1){ //de 2 a mas hiuecos vacios contiguos base=ant.getR_limite()+1; lim=base+sumaDesp-1; Nodo n=new Nodo(lista_registros.total,"vacio",base,sumaDesp,lim); lista_registros.total++; n.setSig(p); ant.setSig(n); } } } p=p.getSig(); }*/ while(p!=null){ if(p.getSig().getNombre().equals("vacio")){ sumaDesp=0; espaciosVacios=0; ant=p.getSig(); p=p.getSig(); while(p.getNombre().equals("vacio")){ espaciosVacios++; sumaDesp=sumaDesp+p.getDesplazamiento(); p=p.getSig(); } //p es el ultimo despues del vacio } p=p.getSig(); if(espaciosVacios>1){ //de 2 a mas hiuecos vacios contiguos base=ant.getR_limite()+1; lim=base+sumaDesp-1; Nodo n=new Nodo(lista_registros.total,"vacio",base,sumaDesp,lim); lista_registros.total++; n.setSig(p); ant.setSig(n); }

} } public String devolversinKb(String tamao){ String cadena=""; for(int i=0;i<tamao.length();i++){ if(Character.isWhitespace(tamao.charAt(i))){ return cadena; }else{ if(tamao.charAt(i)!=',' &&tamao.charAt(i)!='.'){ cadena=cadena+tamao.charAt(i); } } } return cadena; } public void seCreoNuevoProceso(){ //Buscar en tabla_procesos si cada elemento se encuentra en //la lista de Registros for(int i=0;i<leerProcesos();i++){ String cadena=tabla_procesos.getValueAt(i, 0).toString().trim(); if(!lista_registros.buscar(cadena)){ //NO encontro //agregar a lista de registros el proceso int base=lista_registros.fin.getR_limite()+1; int desplazamiento=Integer.valueOf(devolversinKb(tabla_procesos.getValueAt(i, 4).toString().trim())); int limite=base+desplazamiento-1; lista_registros.agregarNodo(cadena, base, desplazamiento,limite ); } } } /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { try { new Admin().setVisible(true); } catch (UnsupportedLookAndFeelException ex) { Logger.getLogger(Admin.class.getName()).log(Level.SEVERE, null, ex); } } }); }

*****************************************************************

4. Conclusiones
Se logr cumplir con los objetivos pedidos para este trabajo del administrado de tareas los cuales eran ver los procesos en una lista, visualizar la cantidad de memoria RAM total, usada y libre, ver la lista de los registros para cada proceso en una tabla, y poder visualizar de manera grfica como es que est siendo asigna la memoria RAM. Tan slo nos falt mejorar la rapidez de actualizacin (ingreso y borrado de datos) del Jtable tabla_registros. En conclusin, se logr lo propuesto y se aprendi que a medida que los sistemas operativos son ms modernos estos consumen ms memoria RAM (recursos) y por lo mismo cargan ms procesos en memoria como es el caso del Windows 7 en comparacin con el Windows XP. Tambin hubo que trabajar con virtualizacin del S.O. Windows XP ya que ambos integrantes contaban con Windows 7 en sus Pcs. Y al hacerlo descubrimos que el cmd/tasklist de estos SO virtualizados nos regresan los tamaos de los procesos con puntos. Ejemplos: 9.845Kb. Y los SO. Windows XP instalados como sistemas Operativos Host (principales como en el laboratorio) devolvan el tamao de los procesos con comas. Ej: 9,675Kb. Tan solo hubo que hacer unos pequeos cambios en el cdigo para poder superar esta barrera. Tambin se tuvo dificultad para pintar la grfica en el Jpane tuvo que ponerse un JScrollPane y dentro el JPane para poder grficar la memoria RAM ya que sino la grfica nos sala entrecortada y no se poda ver en su tamao completo.

Das könnte Ihnen auch gefallen