Index: controlies/branches/web2py/debian/changelog
===================================================================
--- controlies/branches/web2py/debian/changelog	(revision 166)
+++ controlies/branches/web2py/debian/changelog	(revision 167)
@@ -1,3 +1,9 @@
+controlies (0.2-1) unstable; urgency=low
+
+  * Completando funcionalidades
+
+ -- José L. Redrejo Rodríguez <jredrejo@debian.org> Fri, 13 May 2011 14:37:17 +0200
+
 controlies (0.1-1) unstable; urgency=low
 
   * First Debian package
Index: controlies/branches/web2py/applications/controlies/models/menu.py
===================================================================
--- controlies/branches/web2py/applications/controlies/models/menu.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/models/menu.py	(revision 167)
@@ -31,10 +31,9 @@
      [
             ('Usuarios', False, URL( 'usuarios', 'index' )),
             ('Grupos', False,URL( 'grupos', 'index' )),
-            ('Servidores LTSP',False, URL( 'hosts', 'getLTSPServers' )),
+            ('Servidores LTSP',False, URL( 'hosts', 'ltspservers' )),
             ('Workstations', False,URL( 'hosts', 'workstations' )),
-            ('Clientes Ligeros', False,URL( 'hosts', 'thinclient' )),
-            ('Portátiles', False,URL( 'hosts', 'portatil' )),            
+            ('Clientes Ligeros', False,URL( 'hosts', 'thinclients' )),         
             ('Parámetros DHCP', False,URL( 'dhcpd', 'index' )),
 
             ]
@@ -52,6 +51,13 @@
         ('Alumnos', False, URL( 'gestion', 'rayuela_alumnos')),
 
         ]),
+        
+    ('Mantenimiento de LDAP', False, None,
+        [
+        ('Limpieza de usuarios inexistentes en grupos', False, URL( 'gestion', 'limpieza_usuarios')),
+        ('Detección de uid o gid duplicados', False, URL( 'gestion', 'duplicados')),
 
+        ]),        
+
     ]
    )]
Index: controlies/branches/web2py/applications/controlies/models/db.py
===================================================================
--- controlies/branches/web2py/applications/controlies/models/db.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/models/db.py	(revision 167)
@@ -91,3 +91,7 @@
 auth.settings.login_methods=[ldap_auth( server='localhost', base_dn='ou=People,dc=instituto,dc=extremadura,dc=es',secure=LdapConnection.ldap_secure,cert_path=LdapConnection.ldap_cert,mode='cn')]
 
 #auth.settings.login_onaccept=lambda form: session_ldap(form)
+def conecta():
+    l=LdapConnection.LdapConnection(session)
+    l.process()
+    return l
Index: controlies/branches/web2py/applications/controlies/controllers/grupos.py
===================================================================
--- controlies/branches/web2py/applications/controlies/controllers/grupos.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/controllers/grupos.py	(revision 167)
@@ -1,15 +1,13 @@
 # coding: utf8
 from applications.controlies.modules.Groups import Groups
-import applications.controlies.modules.Utils.LdapUtils as LdapUtils
-import applications.controlies.modules.LdapConnection as LdapConnection  
                 
 def index(): 
     return dict()
 
 @service.json
+@auth.requires_login()
 def list():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     g = Groups(l,"","","")
     a=request.vars
     response = g.list(a)
@@ -16,18 +14,18 @@
     l.close()
     return response  
     
-@service.json  
+@service.json 
 def getAllGroups():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    import applications.controlies.modules.Utils.LdapUtils as LdapUtils
+    l=conecta()
     response = LdapUtils.getAllGroups(l)
     l.close()
     return response
     
 @service.json
+@auth.requires_login()
 def modify():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     g = Groups(l,request.vars['type'], request.vars['name'], request.vars['users'])
     response = g.process(request.vars['action'])    
     l.close()
@@ -36,21 +34,18 @@
 
 @service.json  
 def getGroupData():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     g = Groups(l,"",request.vars['name'],"")
     response = g.getGroupData()
-
     l.close()
     return dict(response=response)
 
-@service.json      
+@service.json  
+@auth.requires_login()    
 def delete():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     g = Groups(l,"",request.vars['name'],"")
     response = g.delete()
-
     l.close()
     return dict(response=response)
     
Index: controlies/branches/web2py/applications/controlies/controllers/hosts.py
===================================================================
--- controlies/branches/web2py/applications/controlies/controllers/hosts.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/controllers/hosts.py	(revision 167)
@@ -1,35 +1,89 @@
 # coding: utf8
-
+from applications.controlies.modules.Hosts import Hosts
+    
 def index():
 #equivalente a list
     return dict(message="hello from hosts.py")
     
-    
+@service.json    
 def getThinclientGroups():
-    return dict()
+    l=conecta()
+    h = Hosts (l,"","","","","")
+    response = h.getThinclientGroups()
+    l.close()
+    return dict(response=response)
 
 
-def getInternalGroups():
-    return dict()
+@service.json
+def getHostData():
+    l=conecta()
+    h = Hosts(l,request.vars['cn'],"","",request.vars['group'],request.vars['type'])
+    response = h.getHostData()    
+    l.close()
+    return dict(response=response)
     
-def getLTSPServers():
-    return dict()
-    
+@service.json   
+@auth.requires_login()
+def list_ltspservers():
+    l=conecta()
+    h = Hosts (l,"","","","","")
+    response = h.getLTSPServers()
+    l.close()
+    return response    
+   
+   
+@service.json   
+@auth.requires_login()
+def list():
+    l=conecta()
+    h = Hosts (l,"","","","","")
+    a=request.vars
+    response = h.list(a)    
+    l.close()
+    return response    
 
-def getLTSPStatus():
-    return dict()
-    
-def getClassroomDetails():
-    return dict()
-    
+@service.json
+@auth.requires_login()
+def modify():
+    l=conecta()
+    ip=''
+    if request.vars['type']!='thinclient':ip=request.vars['ip']
+    h = Hosts(l,request.vars['name'],ip,request.vars['mac'],request.vars['group'],request.vars['type'])
+    response=h.process(request.vars['action']  )
+    l.close()
+    return dict(response=response)
+   
+@service.json
+@auth.requires_login()    
 def delete():
+    l=conecta()
+    h = Hosts(l,request.vars['cn'],"","",request.vars['group'],request.vars['type'])
+    response=h.process(request.vars['action']  )
+    l.close()
+    return dict(response=response)
+
+#necesaria estas funciones en el controlador para poder cargar las vistas correspondientes:    
+def ltspservers():
     return dict()
     
-def getHostData():
-    return dict()
+def workstations():
+    return dict()    
+
+def thinclients():
+    return dict()  
     
-def thinclient():
+def form_thinclient():
     return dict()
 
-def portatil():
+def form_ltspserver():
     return dict()
+
+def call():
+    """
+    exposes services. for example:
+    http://..../[app]/default/call/jsonrpc
+    decorate with @services.jsonrpc the functions to expose
+    supports xml, json, xmlrpc, jsonrpc, amfrpc, rss, csv
+    """
+    session.forget()
+    return service()
Index: controlies/branches/web2py/applications/controlies/controllers/gestion.py
===================================================================
--- controlies/branches/web2py/applications/controlies/controllers/gestion.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/controllers/gestion.py	(revision 167)
@@ -1,6 +1,35 @@
 # coding: utf8
+@service.json   
 @auth.requires_login()
 def servidores_aula():
+    return dict()
+    
+@service.json   
+@auth.requires_login()    
+def getClassroomDetails():
+    import xmlrpclib
+    from applications.controlies.modules.Users import Users
+    l=conecta()
+    objUser = Users(l,"","","","",request.vars['teacher'],"","","","")
+    teacherData = objUser.getUserData()
+
+    s = xmlrpclib.Server("http://" + request.vars['classroom'] + ":8900");
+
+    users = s.Users()
+
+    response = []
+    for u in users:
+        user = u.split("@")
+
+        objUser = Users(l,"","","","",user[0],"","","","")
+        photo = objUser.getUserPhoto()
+
+    #    response.append({ 'username': user[0], 'host': user[1], 'photo': photo })
+
+    #return json.dumps({ "teacher" : teacherData, "classroom" : request.args['classroom'][0], "students" : response })
+
+
+
     return dict(message="hello from gestion.py")
 
 
@@ -11,3 +40,21 @@
 @auth.requires_login()    
 def rayuela_profesores():
     return dict()
+
+@service.json
+def getLTSPServers():
+    return dict()
+
+@service.json
+def getLTSPStatus():
+    return dict()
+
+def call():
+    """
+    exposes services. for example:
+    http://..../[app]/default/call/jsonrpc
+    decorate with @services.jsonrpc the functions to expose
+    supports xml, json, xmlrpc, jsonrpc, amfrpc, rss, csv
+    """
+    session.forget()
+    return service()
Index: controlies/branches/web2py/applications/controlies/controllers/usuarios.py
===================================================================
--- controlies/branches/web2py/applications/controlies/controllers/usuarios.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/controllers/usuarios.py	(revision 167)
@@ -1,24 +1,22 @@
 # coding: utf8
 from applications.controlies.modules.Users import Users
-import applications.controlies.modules.LdapConnection as LdapConnection
-import applications.controlies.modules.Utils.LdapUtils as LdapUtils
 
 def index():    
     return dict()
 
 @service.json
+@auth.requires_login()
 def list():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     u = Users(l,"","","","","","","","","")
     response = u.list(request.vars)
     l.close()
     return response    
 
-@service.json    
+@service.json
+@auth.requires_login()    
 def searchUsername():
-    l=LdapConnection.LdapConnection(session)
-    l.process()    
+    l=conecta()
     u = Users(l,"",request.vars['name'],request.vars['surname'],"","","","","","")
     response = u.searchNewUsername() 
     l.close()                
@@ -26,8 +24,7 @@
     
 @service.json
 def getUserData():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     u = Users(l,"","","","",request.vars['username'],"","","","")
     response = u.getUserData()
     l.close()
@@ -36,25 +33,25 @@
 
 @service.json      
 def getAllUsers():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    import applications.controlies.modules.Utils.LdapUtils as LdapUtils
+    l=conecta()
     response = LdapUtils.getAllUsers(l)
     l.close()
     return response
 
-@service.json       
+@service.json
+@auth.requires_login()       
 def delete():
-    l=LdapConnection.LdapConnection(session)
-    l.process()
+    l=conecta()
     u = Users(l,"","","","",request.vars['user'],"","","","")
     response = u.delete()  
     l.close()                          
     return dict(response=response)
 
-@service.json    
+@service.json
+@auth.requires_login()    
 def modify_user():
-    l=LdapConnection.LdapConnection(session)
-    l.process()    
+    l=conecta() 
     departments=[]
     classrooms=[]                
     if 'multiselect_departments' in request.vars: departments = request.vars['multiselect_departments']
Index: controlies/branches/web2py/applications/controlies/static/js/utils.js
===================================================================
--- controlies/branches/web2py/applications/controlies/static/js/utils.js	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/static/js/utils.js	(revision 167)
@@ -0,0 +1,111 @@
+/* #########################################################################
+# Project:     ControlIES
+# Module:     	utils.js
+# Purpose:     Util functions
+# Language:    javascript
+# Copyright:   2009-2010 - Manuel Mora Gordillo <manuito @nospam@ gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# 
+############################################################################## */
+
+function selectAll(){
+	$("#tabsClassroom").tabs("select","tabsClassroom-1");
+	$("#selectable li").addClass("ui-selected");
+}
+
+function selectNone(){
+	$("#tabsClassroom").tabs("select","tabsClassroom-1");
+	$("#selectable li").removeClass("ui-selected");
+}
+
+function computersSelected(){
+	var selected = Array();
+	var j=0;
+	
+	$("#selectable li").each(function(i, item){
+		if($("#"+item.id).hasClass('ui-selected')==true){
+			selected[j] = $("#"+item.id + ":eq(0) > #pcName").html();
+			j++;
+		}
+	});
+	return selected;
+}
+
+function sendOrderSelected(url,args,action){
+
+	var selected = computersSelected(url);
+
+	if(selected.length==0){
+		modalAlert("Para realizar la acci&oacute;n debe seleccionar al menos un equipo");
+		return;
+	}
+
+	var classroom = {
+		"pclist" : selected,
+		"args" : args
+	}
+
+	var dataString = $.JSON.encode(classroom)
+	connection(url,dataString,action);
+}
+
+function sendOrder(url,args,action){
+
+	var classroom = {
+		"args" : args
+	}
+
+	var dataString = $.JSON.encode(classroom);
+	connection(url,dataString,action);
+}
+
+
+function modalAlert(message){
+
+	$("#dialogAlertMessage").html(message);
+
+	$("#dialogAlert")
+		.dialog({
+			modal: true,
+			width: 350,
+			resizable: false,
+			hide: "explode",
+			buttons: {
+				Ok: function() { $( this ).dialog( "close" ); }
+			}
+		})
+		.dialog('open'); 
+
+	return true;
+}
+
+function modalConfirm(message, funct){
+
+	$("#dialogAlertMessage").html(message);
+
+	$("#dialogAlert")
+		.dialog({
+			modal: true,
+			width: 350,
+			resizable: false,
+			buttons: {
+				"Si": function() { eval(funct); },
+				"No": function() { $( this ).dialog( "close" ); }
+			}
+		})
+		.dialog('open'); 
+
+	return true;
+}
Index: controlies/branches/web2py/applications/controlies/modules/Hosts.py
===================================================================
--- controlies/branches/web2py/applications/controlies/modules/Hosts.py	(revision 166)
+++ controlies/branches/web2py/applications/controlies/modules/Hosts.py	(revision 167)
@@ -6,10 +6,10 @@
 # Language:    Python 2.5
 # Date:        7-Feb-2011.
 # Ver:        7-Feb-2011.
-# Author:	Manuel Mora Gordillo
-#			Francisco Mendez Palma
+# Author:   Manuel Mora Gordillo
+#           Francisco Mendez Palma
 # Copyright:    2011 - Manuel Mora Gordillo <manuito @no-spam@ gmail.com>
-#				2011 - Francisco Mendez Palma <fmendezpalma @no-spam@ gmail.com>
+#               2011 - Francisco Mendez Palma <fmendezpalma @no-spam@ gmail.com>
 #
 # ControlIES is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -33,383 +33,386 @@
 class Hosts(object):
 
     def __init__(self):
-		pass
-	
+        pass
+    
     def __init__(self,ldap,name,ip,mac,group,type):
-		self.ldap = ldap
-		self.name = name
-		self.ip = ip
-		self.mac = mac
-		self.group = group 
-		self.type = type
-	
+        self.ldap = ldap
+        self.name = name
+        self.ip = ip
+        self.mac = mac
+        self.group = group 
+        self.type = type
+    
     def getName (self):
-		return self.mac	
-				
+        return self.mac 
+                
     def validation(self,action):
 
-		if action == "add":
-			if self.type == "none":
-				return "type"
-		
-		if self.name == "":
-			return "name"
-			
-		if self.type <> 'thinclient':
-			if self.ip == "":
-				return "ip"
+        if action == "add":
+            if self.type == "none":
+                return "type"
+        
+        if self.name == "":
+            return "name"
+            
+        if self.type <> 'thinclient':
+            if self.ip == "":
+                return "ip"
 
-		if self.mac == "":
-			return "mac"
-			
-		if self.type =="thinclient":
-			if self.group == "":
-				return "group"
+        if self.mac == "":
+            return "mac"
+            
+        if self.type =="thinclient":
+            if self.group == "":
+                return "group"
 
-		if self.type == "":
-			return "type"
-		
-		if action == "add":
-			if self.existsHostname():
-				return "hostAlreadyExists"
-		
-			# thinclients no requieren ip, la cogen dinamicamente en el aula
-			if self.type <> "thinclient":
-				if self.existsIP():
-					return "ipAlreadyExists"
-			#controlar overflow en nodos		
-			if self.groupOverflow(300):
-				return "groupOverflow"
+        if self.type == "":
+            return "type"
+        
+        if action == "add":
+            if self.existsHostname():
+                return "hostAlreadyExists"
+        
+            # thinclients no requieren ip, la cogen dinamicamente en el aula
+            if self.type <> "thinclient":
+                if self.existsIP():
+                    return "ipAlreadyExists"
+            #controlar overflow en nodos        
+            if self.groupOverflow(300):
+                return "groupOverflow"
 
-			if self.existsMAC():
-				return "macAlreadyExists"
+            if self.existsMAC():
+                return "macAlreadyExists"
 
-		elif action == "modify":		
-			if self.groupOverflow(300):
-				return "groupOverflow"
+        elif action == "modify":        
+            if self.groupOverflow(300):
+                return "groupOverflow"
 
-			if self.existsMAC():
-				return "macAlreadyExists"	
+            if self.existsMAC():
+                return "macAlreadyExists"   
 
-		return "OK"		
-		
+        return "OK"     
+        
     def process(self,action):
-		if action == "add":
-			val = self.validation(action)
-			
-			if val != "OK":
-				return val
-			else:
-				response = self.add()
-				return response
+        if action == "add":
+            val = self.validation(action)
+            
+            if val != "OK":
+                return val
+            else:
+                response = self.add()
+                return response
 
-		if action == "modify":
-			val = self.validation(action)
-			
-			if val != "OK":
-				return val
-			else:
-				response = self.modify()
-				return response
-				
-		if action == "delete":
-			response = self.delete()
-			return response
-		
-		if action == "list":
-			response = self.list();
-			return response	
-			
+        if action == "modify":
+            val = self.validation(action)
+            
+            if val != "OK":
+                return val
+            else:
+                response = self.modify()
+                return response
+                
+        if action == "delete":
+            response = self.delete()
+            return response
+        
+        if action == "list":
+            response = self.list();
+            return response 
+            
     def list(self,args):
-		
-		#from Plugins.LdapConnection import LdapConnection
+        
+        #from Plugins.LdapConnection import LdapConnection
 
-		#l = LdapConnection("172.23.36.5",'cn=admin,ou=People,dc=instituto,dc=extremadura,dc=es',"Sta1987teleco")
-		#l.connect()
-		
-		# grid parameters
-		limit = int(args['rows'][0])
-		page = int(args['page'][0])
-		start = limit * page - limit
-		finish = start + limit;				
+        #l = LdapConnection("172.23.36.5",'cn=admin,ou=People,dc=instituto,dc=extremadura,dc=es',"Sta1987teleco")
+        #l.connect()
+        
+        # grid parameters
+        limit = int(args['rows'])
+        page = int(args['page'])
+        start = limit * page - limit
+        finish = start + limit;             
 
-		# sort by field
-		sortBy = args['sidx'][0]
-		#if sortBy == "uid":
-			#sortBy = "id"
+        # sort by field
+        sortBy = args['sidx']
+        #if sortBy == "uid":
+            #sortBy = "id"
 
-		# reverse Sort
-		reverseSort = False
-		if args['sord'][0] == "asc":
-			reverseSort = True
-		
-		#Distinguimos entre hosts ltsp, workstations y portatiles
-		type = args['type'][0]
-		
-						
-		if type == "ltsp":
-			# Obtengo todos los elementos del nodo hosts
-			#search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
-			#filter = self.buildFilter(args)		
-			search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])		
-			
-			# triplets que contiene los nombres de los ltsp-servers
-			hostnames = self.getLTSPServers()
-							
-			# Ahora tengo que quedarme con los elementos de search que estan en hostnames: los que son ltsp
-			resultado=list()
-			for element in search:
-				if element[0][1]["cn"][0] in hostnames:
-					resultado.append(element)
-			
-			search = resultado 
+        # reverse Sort
+        reverseSort = False
+        if args['sord'] == "asc":
+            reverseSort = True
+        
+        #Distinguimos entre hosts ltsp, workstations y portatiles
+        type = args['type']
+        
+                        
+        if type == "ltsp":
+            # Obtengo todos los elementos del nodo hosts
+            #search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
+            #filter = self.buildFilter(args)        
+            search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])     
+            
+            # triplets que contiene los nombres de los ltsp-servers
+            hostnames = self.getLTSPServers()
+                            
+            # Ahora tengo que quedarme con los elementos de search que estan en hostnames: los que son ltsp
+            resultado=list()
+            for element in search:
+                if element[0][1]["cn"][0] in hostnames:
+                    resultado.append(element)
+            
+            search = resultado 
 
-			rows = []
-			for i in search:
-				row = {
-					"id":i[0][1]["cn"][0], 
-					"cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
-					"cn":i[0][1]["cn"][0],
-					"ipHostNumber":i[0][1]["ipHostNumber"][0],
-					"macAddress":i[0][1]["macAddress"][0]
-				}
-				#row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
-				rows.append(row)
-				
-			if len(rows) > 0:
-				totalPages = ceil( len(rows) / int(limit) )
-			else:
-				totalPages = 0
-			if page > totalPages:
-				page = totalPages
+            rows = []
+            for i in search:
+                row = {
+                    "id":i[0][1]["cn"][0], 
+                    "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
+                    "cn":i[0][1]["cn"][0],
+                    "ipHostNumber":i[0][1]["ipHostNumber"][0],
+                    "macAddress":i[0][1]["macAddress"][0]
+                }
+                #row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
+                rows.append(row)
+                
+            if len(rows) > 0:
+                totalPages = ceil( len(rows) / int(limit) )
+            else:
+                totalPages = 0
+            if page > totalPages:
+                page = totalPages
 
-			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
-			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish]  }		
-				
-		elif type == "thinclient":
-			search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn","dhcpHWAddress"])
-			filter="(|(dhcpOption=*subnet*)(dhcpOption=*log*))"
-			
-			rows = []
-			
-			# esto hay que cambiarlo: tenemos 4 groups en thinclientes
-			for i in search[6:len(search)]:
-					nodeinfo=i[0][0].replace ("cn=","").split(",")
-					row = {
-						"id":i[0][1]["cn"][0], 
-						"cell":[i[0][1]["cn"][0], i[0][1]["dhcpHWAddress"][0].replace("ethernet ",""), nodeinfo[1]],
-						"cn":i[0][1]["cn"][0],
-						"dhcpHWAddress":i[0][1]["dhcpHWAddress"][0],
-						"groupName":i[0][1]["dhcpHWAddress"][0]
-					}						
-					rows.append(row)
-			if len(rows) > 0:
-				totalPages = ceil( len(rows) / int(limit) )
-			else:
-				totalPages = 0
-			if page > totalPages:
-				page = totalPages
-				
-			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
-			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }					
-		
-		elif type == "workstation":
-			# Obtengo todos los elementos del nodo hosts
-			#search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
-			search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])					
-			# triplets que contiene los nombres de las workstations
-			#triplets = l.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
-			triplets = self.ldap.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
-			triplets = triplets [0][0][1]["nisNetgroupTriple"]
-			hostnames=list()
-			
-			# obtengo lista de nombres de los hosts workstation
-			for node in triplets:
-				name = node.replace(",-,-)","").replace("(","")
-				hostnames.append(name)
-				
-			# Ahora tengo que quedarme con los elementos de search que estan en hostnames
-			resultado=list()
-			for element in search:
-				if element[0][1]["cn"][0] in hostnames:
-					resultado.append(element)
-			
-			search = resultado 
+            result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
+            return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish]  }       
+                
+        elif type == "thinclient":
+            search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn","dhcpHWAddress"])
+            filter="(|(dhcpOption=*subnet*)(dhcpOption=*log*))"
+            
+            rows = []
+            
+            # esto hay que cambiarlo: tenemos 4 groups en thinclientes
+            for i in search[6:len(search)]:
+                    nodeinfo=i[0][0].replace ("cn=","").split(",")
+                    row = {
+                        "id":i[0][1]["cn"][0], 
+                        "cell":[i[0][1]["cn"][0], i[0][1]["dhcpHWAddress"][0].replace("ethernet ",""), nodeinfo[1]],
+                        "cn":i[0][1]["cn"][0],
+                        "dhcpHWAddress":i[0][1]["dhcpHWAddress"][0],
+                        "groupName":i[0][1]["dhcpHWAddress"][0]
+                    }                       
+                    rows.append(row)
+            if len(rows) > 0:
+                totalPages = ceil( len(rows) / int(limit) )
+            else:
+                totalPages = 0
+            if page > totalPages:
+                page = totalPages
+                
+            result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
+            return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }                    
+        
+        elif type == "workstation":
+            # Obtengo todos los elementos del nodo hosts
+            #search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
+            search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])                 
+            # triplets que contiene los nombres de las workstations
+            #triplets = l.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
+            triplets = self.ldap.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
+            triplets = triplets [0][0][1]["nisNetgroupTriple"]
+            hostnames=list()
+            
+            # obtengo lista de nombres de los hosts workstation
+            for node in triplets:
+                name = node.replace(",-,-)","").replace("(","")
+                hostnames.append(name)
+                
+            # Ahora tengo que quedarme con los elementos de search que estan en hostnames
+            resultado=list()
+            for element in search:
+                if element[0][1]["cn"][0] in hostnames:
+                    resultado.append(element)
+            
+            search = resultado 
 
-			rows = []
-			for i in search:
-				row = {
-					"id":i[0][1]["cn"][0], 
-					"cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
-					"cn":i[0][1]["cn"][0],
-					"ipHostNumber":i[0][1]["ipHostNumber"][0],
-					"macAddress":i[0][1]["macAddress"][0]
-				}						
-				#row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
-				rows.append(row)
+            rows = []
+            for i in search:
+                row = {
+                    "id":i[0][1]["cn"][0], 
+                    "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
+                    "cn":i[0][1]["cn"][0],
+                    "ipHostNumber":i[0][1]["ipHostNumber"][0],
+                    "macAddress":i[0][1]["macAddress"][0]
+                }                       
+                #row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
+                rows.append(row)
 
-			if len(rows) > 0:
-				totalPages = ceil( len(rows) / int(limit) )
-			else:
-				totalPages = 0
-			if page > totalPages:
-				page = totalPages					
+            if len(rows) > 0:
+                totalPages = ceil( len(rows) / int(limit) )
+            else:
+                totalPages = 0
+            if page > totalPages:
+                page = totalPages                   
 
-			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
-			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }		
+            result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
+            return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }        
 
     def add(self):
-		if self.type=="thinclient":
-			attr = [
-			('objectclass', ['top','dhcpHost']),
-			('cn', [self.name] ),
-			('dhcpStatements', ['filename "/var/lib/tftpboot/ltsp/i386/pxelinux.0"'] ),	
-			('dhcpHWAddress', ['ethernet ' + self.mac] )
-			]
-			
-			self.ldap.add("cn="+self.name +",cn="+self.group+",cn=THINCLIENTS,cn=DHCP Config", attr)
-						
-		return "OK"
-		
+        if self.type=="thinclient":
+            attr = [
+            ('objectclass', ['top','dhcpHost']),
+            ('cn', [self.name] ),
+            ('dhcpStatements', ['filename "/var/lib/tftpboot/ltsp/i386/pxelinux.0"'] ), 
+            ('dhcpHWAddress', ['ethernet ' + self.mac] )
+            ]
+            
+            self.ldap.add("cn="+self.name +",cn="+self.group+",cn=THINCLIENTS,cn=DHCP Config", attr)
+                        
+        return "OK"
+        
     def modify(self):
-		attr = [
-		(ldap.MOD_REPLACE, 'cn', [self.name] ),
-		(ldap.MOD_REPLACE, 'dhcpHWAddress', ["ethernet "+ self.mac])
-		]
-			
-		self.ldap.modify("cn="+self.name+",cn="+self.group +",cn=THINCLIENTS,cn=DHCP Config", attr)
+        attr = [
+        (ldap.MOD_REPLACE, 'cn', [self.name] ),
+        (ldap.MOD_REPLACE, 'dhcpHWAddress', ["ethernet "+ self.mac])
+        ]
+            
+        self.ldap.modify("cn="+self.name+",cn="+self.group +",cn=THINCLIENTS,cn=DHCP Config", attr)
 
-		return "OK"
+        return "OK"
 
     def delete(self):
-		if self.type=="thinclient":
-			self.ldap.delete('cn='+ self.name +',cn=' +self.group +',cn=THINCLIENTS,cn=DHCP Config')
+        if self.type=="thinclient":
+            self.ldap.delete('cn='+ self.name +',cn=' +self.group +',cn=THINCLIENTS,cn=DHCP Config')
 
-		return "OK"		
+        return "OK"     
 
     def wakeup(self):
-		from Plugins import NetworkUtils
-		NetworkUtils.startup(self.mac)
-		
+        from Plugins import NetworkUtils
+        NetworkUtils.startup(self.mac)
+        
     def groupOverflow(self,overflow):
-		if self.type == 'thinclient':
-			search = self.ldap.search("cn=" + self.group +",cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn"])
-			if len(search)-2 >= overflow:
-				return True
-				
-		return False
-			
+        if self.type == 'thinclient':
+            search = self.ldap.search("cn=" + self.group +",cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn"])
+            if len(search)-2 >= overflow:
+                return True
+                
+        return False
+            
     def existsHostname(self):
-		
-		if self.type == 'thinclient':
-			result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn="+self.name,["cn"])
-		else:
-			result = self.ldap.search("ou=hosts","cn="+self.name,["cn"])
-		
-		if len(result) > 0:
-			return True
-		
-		return False
-		
+        
+        if self.type == 'thinclient':
+            result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn="+self.name,["cn"])
+        else:
+            result = self.ldap.search("ou=hosts","cn="+self.name,["cn"])
+        
+        if len(result) > 0:
+            return True
+        
+        return False
+        
     def existsMAC(self):
-		# Compruebo con las macs de la rama hosts
-		if self.type == 'thinclient':
-			result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","dhcpHWAddress=*",["dhcpHWAddress"])
-			for i in range (0, len(result) - 1):
-				if result [i][0][1]['dhcpHWAddress'][0].replace ("ethernet ", "") == self.mac:
-					return True
-		else:
-			result = self.ldap.search("ou=hosts","macAddress="+self.mac,["macAddress"])
+        # Compruebo con las macs de la rama hosts
+        if self.type == 'thinclient':
+            result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","dhcpHWAddress=*",["dhcpHWAddress"])
+            for i in range (0, len(result) - 1):
+                if result [i][0][1]['dhcpHWAddress'][0].replace ("ethernet ", "") == self.mac:
+                    return True
+        else:
+            result = self.ldap.search("ou=hosts","macAddress="+self.mac,["macAddress"])
 
-			if len(result) > 0:
-				return True
-		
-		return False
-		
+            if len(result) > 0:
+                return True
+        
+        return False
+        
     def existsIP (self):
-		# Cojo las ips de la rama hosts -> arpa -> in-addr
-		result = self.ldap.search ("dc=23,dc=172,dc=in-addr,dc=arpa,ou=hosts", "dc=*",["associatedDomain"])
-		
-		myIP = self.ip.split (".")
+        # Cojo las ips de la rama hosts -> arpa -> in-addr
+        result = self.ldap.search ("dc=23,dc=172,dc=in-addr,dc=arpa,ou=hosts", "dc=*",["associatedDomain"])
+        
+        myIP = self.ip.split (".")
 
-		for i in range (0, len (result) -1):
-			reverseIP = result [i][0][1]['associatedDomain'][0].replace (".in-addr.arpa","").split(".")
-			reverseIP.reverse() 
-			if myIP == reverseIP:
-				return True
-		
-		return False
-		
+        for i in range (0, len (result) -1):
+            reverseIP = result [i][0][1]['associatedDomain'][0].replace (".in-addr.arpa","").split(".")
+            reverseIP.reverse() 
+            if myIP == reverseIP:
+                return True
+        
+        return False
+        
     def getThinclientGroups (self):
 
-		groups = []
-		search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=group*",["cn"])
-		
-		for g in search:
-			groups.append (g[0][1]["cn"][0])
-			
-		return { "groups":groups }
-		
+        groups = []
+        search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=group*",["cn"])
+        
+        for g in search:
+            groups.append (g[0][1]["cn"][0])
+            
+        return { "groups":groups }
+        
     def getInternalGroups (self):
-		
-		groups = []
-		search = self.ldap.search("cn=INTERNAL,cn=DHCP Config","cn=group*",["cn"])
-		
-		for g in search:
-			groups.append (g[0][1]["cn"][0])
-			
-		return { "groups":groups }		
-		
-    def getHostData(self):
-		#self.getUserGroups()
-		if self.type == "thinclient":
-			result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn="+self.name,["cn","dhcpHWAddress"])
-		
-			dataHost = {
-				"cn":result[0][0][1]["cn"][0],
-				"mac":result[0][0][1]["dhcpHWAddress"][0].replace("ethernet ",""),
-				"group":self.group 
-			}
-		 
-		return dataHost		
-		
-		
+        
+        groups = []
+        search = self.ldap.search("cn=INTERNAL,cn=DHCP Config","cn=group*",["cn"])
+        
+        for g in search:
+            groups.append (g[0][1]["cn"][0])
+            
+        return { "groups":groups }      
+        
+    def getHostData(self):       
+        result1 = self.ldap.search("cn=DHCP Config","cn="+self.name,["cn","dhcpHWAddress"])
+        result2 = self.ldap.search(" ou=hosts","dc="+self.name,["aRecord"])   
+        dataHost = {
+            "cn":self.name,
+            "group":self.group,
+            "mac":"",
+            "ip":""
+        }
+        if len(result1)==1:
+            dataHost["mac"]=result1[0][0][1]["dhcpHWAddress"][0].replace("ethernet ","")
+        if len(result2)==1:
+            dataHost["ip"]=result2[0][0][1]["aRecord"][0]
+         
+        return dataHost     
+        
+        
     def getLTSPServers (self):
-		triplets = self.ldap.search("ou=Netgroup","cn=ltsp-server-hosts",["nisNetgroupTriple"])
-		triplets = triplets [0][0][1]["nisNetgroupTriple"]
-		hostnames=list()
-			
-		for node in triplets:
-			name = node.replace(",-,-)","").replace("(","")
-			hostnames.append(name)
-		hostnames.sort()
-		return hostnames
+        triplets = self.ldap.search("ou=Netgroup","cn=ltsp-server-hosts",["nisNetgroupTriple"])
+        triplets = triplets [0][0][1]["nisNetgroupTriple"]
+        hostnames=list()
+            
+        for node in triplets:
+            name = node.replace(",-,-)","").replace("(","")
+            hostnames.append(name)
+        hostnames.sort()
+        return hostnames
 
 
     def getLTSPStatus (self):
-		from Utils.avahiClient import avahiClient
-		import threading
-		
-		a = avahiClient()  
-		a.start() 
-		time.sleep(1000) 	
-		a.cancel()		
-		names = a.getList()
-		print names
-		
-		"""a = avahiClient()
-		time.sleep(1000) 		
-		names = a.getList()
-		print names
-		a.kill()"""
-		return names
+        from Utils.avahiClient import avahiClient
+        import threading
+        
+        a = avahiClient()  
+        a.start() 
+        time.sleep(1000)    
+        a.cancel()      
+        names = a.getList()
+        print names
+        
+        """a = avahiClient()
+        time.sleep(1000)        
+        names = a.getList()
+        print names
+        a.kill()"""
+        return names
 
-#	def wakeup(self):
-#		from twisted.internet.task import LoopingCall
-#		from twisted.internet import defer
-#		from Plugins import NetworkUtils
-#		NetworkUtils.startup(self.mac)
-		
+#   def wakeup(self):
+#       from twisted.internet.task import LoopingCall
+#       from twisted.internet import defer
+#       from Plugins import NetworkUtils
+#       NetworkUtils.startup(self.mac)
+        
 
 # Encender el equipo
 #def wakeup(self):
Index: controlies/branches/web2py/applications/controlies/views/layout_form_hosts.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/layout_form_hosts.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/layout_form_hosts.html	(revision 167)
@@ -0,0 +1,89 @@
+<script language="javascript">
+
+    $(function() {
+        $("#name").focus();
+        $("#saveButton").button({ icons: { primary: "ui-icon-disk"}});
+          
+        $("#cancelButton")
+            .button({ icons: { primary: "ui-icon-close"}})
+            .click( function(){ $('#dialog-form').dialog('close'); });            
+    });
+
+    function restartStyle(){
+        $("#form_data p span").css("color","black");
+        $('#message').html("");
+    }
+
+
+    function send(){
+
+        restartStyle();
+
+{{block controlador}}               
+        jQuery.post('call/json/modify', jQuery("#form_data").serialize(), function(result) {
+{{end}}        
+            //var result = $.parseJSON(data);
+            switch(result.response){
+                case "OK":{
+                    jQuery('#message').html("Operación realizada correctamente").css("color","green").effect("highlight", {"color":"yellow"}, 1000);
+                    setTimeout("$('#dialog-form').dialog('close')",1000);
+                    jQuery("#list").trigger("reloadGrid");
+                    break;
+                }
+                case "fail":{
+                    jQuery('#message').html("Se produjo un error").effect("highlight", {"color":"yellow"}, 1000);
+                    break;
+                }
+                case "hostAlreadyExists":{
+                    jQuery('#nameTag').css("color","red");
+                    jQuery('#name').effect("highlight", {"color":"yellow"}, 1000).focus();
+                    jQuery('#message').html("Ya existe ese nombre de host").effect("slide");                 
+                    break;
+                }
+                case "macAlreadyExists":{
+                    jQuery('#macTag').css("color","red");
+                    jQuery('#mac').effect("highlight", {"color":"yellow"}, 1000).focus();
+                    jQuery('#message').html("Ya existe un host con esa MAC").effect("slide");                    
+                    break;
+                }
+                case "ipAlreadyExists":{
+                    jQuery('#ipTag').css("color","red");
+                    jQuery('#ip').effect("highlight", {"color":"yellow"}, 1000).focus();
+                    jQuery('#message').html("Ya existe un host con esa IP").effect("slide");                 
+                    break;
+                }                
+                case "groupOverflow":{
+                    jQuery('#groupTag').css("color","red");
+                    jQuery('#group').effect("highlight", {"color":"yellow"}, 1000).focus();
+                    jQuery('#message').html("El grupo escogido esta completo").effect("slide");                  
+                    break;  
+                }    
+                default:{
+                    jQuery('#'+result.response+"Tag").css("color","red");
+                    jQuery('#'+result.response).effect("highlight", {"color":"yellow"}, 1000).focus();
+                    jQuery('#message').html("Hay campos vacíos o incorrectos").effect("slide");
+                    break;
+                }
+            }
+        });
+
+        return false;
+    }
+    
+</script>
+
+
+<form id="form_data" onSubmit="return send();">
+    <input type="hidden" id="action" name="action"/>
+{{block form_table}}    
+   <input type="hidden" id="type" name="type" value="ltsp"/>
+    <p><span id="nameTag">Nombre del equipo:</span><br><input type="text" id="name" name="name" onChange="searchUsername();"/></p>
+    <p><span id="ipTag">Ip</span><br><input type="text" id="ip" name="ip"/></p> 
+    <p><span id="macTag">MAC</span><br><input type="text" id="mac" name="mac"/></p>
+
+{{end}}
+
+    <div id="message" style="text-align:center; font-weight:bold; color:red; padding:3px; "></div>
+    <div style="text-align:center;"><button id="saveButton" type="submit" style="width:100px;">Guardar</button>&nbsp;&nbsp;<button type="button" id="cancelButton" style="width:100px;">Cancelar</button></div>
+    <p style="padding-top:10px; text-align:center; font-size:10px;" id="messageForm"></p>       
+</form>
Index: controlies/branches/web2py/applications/controlies/views/layout_hosts.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/layout_hosts.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/layout_hosts.html	(revision 167)
@@ -0,0 +1,251 @@
+{{extend 'layout.html'}}
+        <div id="tabla_clientes" class="centerGrid">
+        <table width="100%">
+        <tr>
+            <td style="width:2%"></td>
+            <td><table id="list" width="100%"></table></td>
+            <td style="width:2%"></td>
+        </tr>
+        </table>
+        <div id="pager" style=""></div> 
+        <div id="filter" style="margin-left:30%;display:none">Search Invoices</div>
+        </div>
+
+        <div id="dialog-form"></div>
+
+        <div id="dialog-confirm" title="¿Borrar el registro seleccionado?" style="display:none;">
+            <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Este elemento quedará permanentemente eliminado. ¿Está seguro?</p>
+        </div>
+
+        <div id="dialog-alert" title="Atención" style="display:none;">
+            <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Para operar sobre un registro debe seleccionarlo previamente.</p>
+        </div>
+
+
+
+
+
+<script type="text/javascript">  
+    jQuery(function() {
+        jQuery("#dialog-confirm").dialog({ autoOpen: false });
+        jQuery("#dialog-alert").dialog({ autoOpen: false });
+    });
+
+    function print_grid(){  
+        jQuery("#list").jqGrid({
+            url:"{{=URL(c='hosts',f='call',args=['json','list'])}}",
+            data: "{}",
+            datatype: 'json',
+            mtype: 'GET',           
+            
+{{block camposgrid}}                               
+            colNames:['Nombre','IP','mac'],
+            colModel:[ 
+                {name:'cn',index:'cn', width:80, align:"center"},
+                {name:'ipHostNumber',index:'ipHostNumber', width:60, align:"center"},
+                {name:'macAddress',index:'macAddress', width:60, align:"center"}
+            ], 
+
+            postData:{type:'ltsp'}, 
+            caption:"Servidores de Aula (LTSP)",
+{{end}} 
+            rowNum:25,
+            height:335,
+            width: 800,
+            rowList:[25,50,75], 
+            pager: '#pager', 
+            sortname: 'cn', 
+            autowidth: false,
+            viewrecords: true, 
+            sortorder: "desc"
+            
+        }); 
+                      
+        jQuery("#list").jqGrid('navGrid','#pager',{add:false,edit:false,del:false,search:false,refresh:false});
+        
+        jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                caption: "Insertar",
+                buttonicon :'ui-icon-plus',
+                onClickButton : function (){ 
+                    addRecord();
+                } 
+        }); 
+        jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                caption: "Modificar", 
+                buttonicon :'ui-icon-pencil',
+                onClickButton : function (){ 
+                    modifyRecord();
+            } 
+        }); 
+        jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                caption: "Borrar", 
+                buttonicon :'ui-icon-trash',
+                onClickButton : function (){ 
+                    deleteRecord();
+            } 
+        });        
+          
+          jQuery("#list").jqGrid('filterToolbar'); 
+
+    }
+
+    function rowSelected(){
+            var id = jQuery("#list").jqGrid('getGridParam','selrow'); 
+        
+            if( id == null ){
+                jQuery( "#dialog-alert" ).dialog({
+                    resizable: false,
+                    height:150,
+                    width:290,
+                    modal: true,
+                    buttons: { "Aceptar": function() { $( this ).dialog( "close" ); }}
+                }).dialog('open');
+                return false;
+            }
+            return id;
+    }        
+                
+                
+    function getCell (column) {
+        var rowid = jQuery("#list").jqGrid('getGridParam', 'selrow');
+        
+        if( rowid == null ){
+            jQuery( "#dialog-alert" ).dialog({
+                resizable: false,
+                height:150,
+                width:290,
+                modal: true,
+                buttons: { "Aceptar": function() { $( this ).dialog( "close" ); }}
+            }).dialog('open');
+            return false;
+        }
+        
+        var Cell = jQuery("#list").jqGrid('getCell', rowid, column);
+        
+        
+        return Cell;
+    }
+            
+    function getThinClientGroups(selected) {
+        jQuery.post('call/json/getThinclientGroups', function(result) {
+
+                var selectGrupos = document.getElementById("group");                
+    
+                for (i=0;i<result.response.groups.length;i++) {
+                    var optn = document.createElement("option");
+                    optn.text = result.response.groups[i];
+                    optn.value = result.response.groups[i];
+                    if (selected==optn.text) 
+                        optn.selected = true;
+                    selectGrupos.options.add (optn);
+                }
+        });
+    }                
+
+
+            function modifyRecord(){
+                var hid;
+                var group; 
+                jQuery("#messageLoading").show();
+                
+                var hid = rowSelected();
+                var group = getCell("groupName"); 
+                if(hid==false)
+                    return false;
+
+                jQuery("#dialog-form").html("").css("display","none");
+{{block edit_form}}                      
+                jQuery("#dialog-form").load("form_ltspserver.html", function() {
+                   
+
+{{end}}                     
+                    jQuery("#form_data #action").val("modify");
+                    jQuery("#form_data #name").attr("readonly","true");
+                    jQuery("#form_data #name").css("background-color","#DDD");
+                    jQuery("#form_data #group").attr("readonly","true");
+                    jQuery("#form_data #group").css("background-color","#DDD");
+{{block edit2_form}}                       
+                    jQuery.post('call/json/getHostData',{ cn: hid,group:group,type:'ltsp' }, function(result) {
+                        jQuery("#form_data #name").val(result.response['cn']);
+                        jQuery("#form_data #ip").val(result.response['ip']);                        
+                        jQuery("#form_data #mac").val(result.response['mac']);                           
+{{end}}                        
+                        x = (jQuery(window).width()-300)/2;
+                        y = (jQuery(window).height()-500)/2;
+                        
+                        jQuery("#messageLoading").hide();
+                        
+                        jQuery("#dialog-form").dialog({
+                            resizable: false,
+                            modal: true,
+                            width: 300,
+{{block edit3_form}}                                                          
+                            title: "Modificar Servidor de aula"
+{{end}}
+                        }).dialog('option', 'position', [x, y]);                        
+                    });               
+                });
+            }
+
+
+
+    function addRecord(){
+    
+        jQuery("#dialog-form").html("");
+{{block edit_form}}        
+        jQuery("#dialog-form").load("form_ltspserver.html", function() {
+{{end}}        
+            jQuery("#form_data #action").val("add");
+            jQuery("#form_data #messageForm").html("Todos los campos son obligatorios");                 
+        });
+    
+        x = (jQuery(window).width()-250)/2;
+        y = (jQuery(window).height()-400)/2;
+    
+        jQuery("#dialog-form").dialog({
+            resizable: false,
+            position: top,
+            modal: true,                       
+{{block add_host}}            
+            title: "Añadir Servidor de Aula (ltsp)"  
+{{end}}
+        }).dialog('option', 'position', [x, y]);
+    } 
+
+
+    
+function deleteRecord(){
+    
+        var cn = rowSelected();
+        var grupo = getCell("groupName");
+
+        if(cn==false)
+            return false;    
+    
+    
+        jQuery( "#dialog-confirm" ).dialog({
+            resizable: false,
+            height:160,
+            width:350,
+            modal: true,
+            buttons: {
+                "Borrar": function() {
+{{block delete_host}}                
+                    jQuery.post("call/json/delete",{cn:cn,action:'delete',group:grupo,type:'ltsp'}, function(data){
+{{end}}                    
+                        jQuery("#dialog-confirm").dialog( "close" );
+                        jQuery("#list").trigger("reloadGrid");
+                    });
+                },
+                "Cancelar": function() {
+                    $(this).dialog( "close" );
+                }
+            }
+        }).dialog('open');
+}    
+
+</script>
+
+<script type="text/javascript">
+  jQuery(document).ready(function(){  print_grid();}); 
+</script>
Index: controlies/branches/web2py/applications/controlies/views/hosts/form_ltspserver.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/form_ltspserver.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/form_ltspserver.html	(revision 167)
@@ -0,0 +1 @@
+{{extend 'layout_form_hosts.html'}}
Index: controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html	(revision 167)
@@ -0,0 +1 @@
+{{extend 'layout_hosts.html'}}
Index: controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html.mio
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html.mio	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/ltspservers.html.mio	(revision 167)
@@ -0,0 +1,22 @@
+{{extend 'layout.html'}}
+        <div id="tabla_clientes" class="centerGrid">
+        <table width="100%">
+        <tr>
+            <td style="width:2%"></td>
+            <td><table id="list" width="100%"></table></td>
+            <td style="width:2%"></td>
+        </tr>
+        </table>
+        <div id="pager" style=""></div> 
+        <div id="filter" style="margin-left:30%;display:none">Search Invoices</div>
+        </div>
+
+        <div id="dialog-form"></div>
+
+        <div id="dialog-confirm" title="¿Borrar el registro seleccionado?" style="display:none;">
+            <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Este elemento quedará permanentemente eliminado. ¿Está seguro?</p>
+        </div>
+
+        <div id="dialog-alert" title="Atención" style="display:none;">
+            <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Para operar sobre un registro debe seleccionarlo previamente.</p>
+        </div>
Index: controlies/branches/web2py/applications/controlies/views/hosts/form_thinclient.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/form_thinclient.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/form_thinclient.html	(revision 167)
@@ -0,0 +1,13 @@
+{{extend 'layout_form_hosts.html'}}
+{{block form_table}}    
+    <input type="hidden" id="type" name="type" value="thinclient"/>
+    
+    <p><span id="groupTag">Grupo</span><br>
+        <select id="group" name="group">
+            <option value="none">Seleccione...</option>
+        </select>
+    </p>    
+        
+    <p><span id="nameTag">Nombre del equipo:</span><br><input type="text" id="name" name="name" onChange="searchUsername();"/></p>
+    <p><span id="macTag">MAC</span><br><input type="text" id="mac" name="mac"/></p>
+{{end}}
Index: controlies/branches/web2py/applications/controlies/views/hosts/thinclients.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/thinclients.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/thinclients.html	(revision 167)
@@ -0,0 +1,36 @@
+{{extend 'layout_hosts.html'}}
+
+{{block camposgrid}}
+
+            colNames:['Nombre','MAC','Grupo'],
+            colModel:[ 
+                {name:'cn',index:'cn', width:80, align:"center"},
+                {name:'macAddress',index:'dhcpHWAddress', width:60, align:"center"},
+                {name:'groupName',index:'groupName', width:60, align:"center"}
+            ], 
+
+
+            postData:{type:'thinclient'}, 
+            caption:"Clientes ligeros",
+{{end}}
+{{block edit_form}}        
+        jQuery("#dialog-form").load("form_thinclient.html", function() {
+              getThinClientGroups(group);
+{{end}}   
+{{block edit2_form}}                       
+                    jQuery.post('call/json/getHostData',{ cn: hid,group:group,type:'thinclient' }, function(result) {
+                        jQuery("#form_data #name").val(result.response['cn']);
+                        jQuery("#form_data #mac").val(result.response['mac']);                    
+{{end}}
+
+{{block edit3_form}}                                                          
+                            title: "Modificar Cliente ligero"
+{{end}}
+
+{{block add_host}}
+            title: "Añadir cliente ligero"
+{{end}}
+
+{{block delete_host}}
+            jQuery.post("call/json/delete",{cn:cn,action:'delete',group:grupo,type:'thinclient'}, function(data){
+{{end}}
Index: controlies/branches/web2py/applications/controlies/views/hosts/workstations.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/hosts/workstations.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/hosts/workstations.html	(revision 167)
@@ -0,0 +1,23 @@
+{{extend 'layout_hosts.html'}}
+
+{{block camposgrid}}
+            colNames:['Nombre','IP','mac'],
+            colModel:[ 
+                {name:'cn',index:'cn', width:80, align:"center"},
+                {name:'ipHostNumber',index:'ipHostNumber', width:60, align:"center"},
+                {name:'macAddress',index:'macAddress', width:60, align:"center"}
+            ], 
+
+            postData:{type:'workstation'}, 
+            caption:"Workstations",
+{{end}}
+{{block edit3_form}}                                                          
+                            title: "Modificar Workstation"
+{{end}}
+
+{{block add_host}}
+            title: "Añadir Workstation"
+{{end}}
+{{block delete_host}}
+            jQuery.post("call/json/delete",{cn:cn,action:'delete',group:grupo,type:'workstation'}, function(data){
+{{end}}
Index: controlies/branches/web2py/applications/controlies/views/gestion/servidores_aula.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/gestion/servidores_aula.html	(nonexistent)
+++ controlies/branches/web2py/applications/controlies/views/gestion/servidores_aula.html	(revision 167)
@@ -0,0 +1,190 @@
+<style>
+    #selectable .ui-selecting { background: #FECA40; }
+    #selectable .ui-selected { background: #F39814; color: white; }
+    #selectable { list-style-type: none; margin: 0; padding: 0; }
+    #selectable li { margin: 3px 3px 3px 0; padding: 1px; float: left; width: 80px; height: 95px; font-size: 1px; text-align: center; cursor:pointer; }
+
+    #selectableStudents .ui-selecting { background: #FECA40; }
+    #selectableStudents .ui-selected { background: #F39814; color: white; }
+    #selectableStudents { list-style-type: none; margin: 0; padding: 0; }
+    #selectableStudents li { margin: 3px 3px 3px 0; padding: 1px; float: left; width: 80px; height: 95px; font-size: 1px; text-align: center; cursor:pointer; } 
+</style>
+
+{{response.files.append(URL('static','js/jdgrid/css/ui.jqgrid.css'))}}
+
+{{extend 'layout.html'}}
+
+<script>
+    $(function() {
+        $("#tabsActions").tabs().css("font-size","13px");
+        $("#tabsServers").tabs().css("font-size","13px");
+        
+        $( "#selectAll" )
+            .css("font-size","11px")
+            .button({ icons: { primary: "ui-icon-circle-plus"}})
+            .click(function(){ selectAll() });
+
+        $( "#selectNone" )
+            .css("font-size","11px")
+            .button({ icons: { primary: "ui-icon-circle-minus"}})
+            .click(function(){ selectNone() });
+
+        $( "#turnOn" )
+            .css("font-size","11px")        
+            .button({ icons: { primary: "ui-icon-power"}})
+            .click(function(){ alert("En desarrollo");/*sendOrderSelected("wakeup","","cambiaconfig");*/ });
+
+        $( "#turnOff" )
+            .css("font-size","11px")        
+            .button({ icons: { primary: "ui-icon-circle-close"}})
+            .click(function(){ alert("En desarrollo");/*sendOrderSelected("sleep","","cambiaconfig");*/ });     
+
+        $( "#classroomDetails" )
+            .css("font-size","11px")        
+            .button({ icons: { primary: "ui-icon-circle-close"}})
+            .click(function(){ getClassroomDetails(); });       
+        
+        $( "#selectable" ).selectable();        
+
+        getLTSPServers();
+    });
+    
+    function getLTSPServers(){
+        jQuery.post('call/json/getLTSPServers', function(result) {
+            
+            $.each(result.response, function(i, l){
+                $('#selectable').append('<li class="ui-state-default" id="selectable-'+l+'"><div id="pcName" style="font-size:11px;">'+l+'</div><img class="thumb-image" src="img/turnOff.png"/><div id="userName" style="font-size:11px;"></div></li>');               
+            });
+            
+            getLTSPStatus();
+        });
+    }
+    
+    function getLTSPStatus(){
+
+        jQuery.post('call/json/getLTSPStatus', function(result) {        
+
+            $('#selectable li .thumb-image').attr('src','img/turnOff.png');
+            $('#selectable li #userName').html('');
+            
+            $.each(result.computers, function(i, l){                
+                $('#selectable #selectable-'+l+' .thumb-image').attr('src','img/turnOn.png');           
+            });
+
+            $.each(result.teachers, function(i, l){
+                var teacher = l.split(".");
+                var computer = teacher[0].split("@");
+                $('#selectable #selectable-'+computer[1]+' #userName').html(computer[0]);
+                $('#selectable #selectable-'+computer[1]+' .thumb-image').attr('src','img/nobody.png');
+            });
+
+            //getLTSPClients();
+            
+            setTimeout("getLTSPStatus()",10000);            
+        });
+    }
+
+
+    function getClassroomDetails(){
+        var selected = computersSelected();
+        
+        if(selected.length==0 || selected.length>1){
+            modalAlert("Únicamente hay que seleccionar un equipo");
+            return false;
+        }else{
+
+            if( $("#selectable-"+selected[0]+" #userName").html()=="" ){
+                modalAlert("No hay datos que mostrar");
+                return false;               
+            }
+
+            $("#messageLoading").show();
+
+            //$("#dialog-details").html("").css("display","none");;
+
+            $("#dialog-details").load("classroomServers/details.html", function() {
+             jQuery.post('call/json/getClassroomDetails',{classroom:selected[0],teacher:$("#selectable-"+selected[0]+" #userName")} function(result) {   
+
+                    $("#teacherName").html(result.teacher.name);
+
+                    $.each(result.teacher.groups.departments, function(i, l){
+                        $("#teacherDepartments").append(l+" ");
+                    });
+                    
+                    if(result.students.length>0){
+                        $.each(result.students, function(i, l){
+                            
+                            src = "img/nobody.png";
+                            if(l.photo.photo!="")
+                                src = "data:image/png;base64,"+l.photo.photo;
+                            
+                            $('#selectableStudents').append('<li class="ui-state-default" id="selectableStudents-'+l.username+'"><div id="pcName" style="font-size:11px;">'+l.host+'</div><img class="thumb-image" src="'+src+'" style="width:64px; height:64px;"/><div id="userName" style="font-size:11px;">'+l.username+'</div></li>');
+                        });
+                    }else{
+                        $("#dialog-details #selectableStudents").html("No hay alumnos detectados").css("text-align","center").css("font-weight","bold");
+                    }
+
+                    x = ($(window).width()-500)/2;
+                    y = ($(window).height()-500)/2;
+
+                    $("#messageLoading").hide();
+
+                    $("#dialog-details").dialog({
+                        resizable: false,
+                        position: top,
+                        modal: true,
+                        width: 500,
+                        title: "Detalles del aula: "+result.classroom
+                    }).dialog('option', 'position', [x, y]);
+                });
+            });
+        }
+    }
+
+</script>
+
+<table width="100" cellspacing="12">
+<tr>
+    <td style="vertical-align:top;">
+        <div id="tabsActions">
+            <ul>
+                <li><a href="#tabs-1"><span id="actions">Acciones</span></a></li>
+            </ul>
+            <div id="tabs-1" style="padding:3px;">
+                <table width="100%">
+                    <tr>
+                        <td style="text-align:center;"><button id="selectAll" style="width:123px;">Selecc. Todo</button></td>
+                        <td style="text-align:center;"><button id="selectNone" style="width:123px;">Selecc. Ninguno</button></td>                       
+                    </tr>
+                    <tr>
+                        <td style="text-align:center;"><button id="turnOn" style="width:123px;">Encender</button></td>
+                        <td style="text-align:center;"><button id="turnOff" style="width:123px;">Apagar</button></td>
+                    </tr>
+                    <tr>
+                        <td style="text-align:center;"><button id="classroomDetails" style="width:123px;">Mostrar Aula</button></td>
+                        <td style="text-align:center;"></td>
+                    </tr>                   
+                </table>
+            </div>
+        </div>
+    </td>
+    <td>
+        <div id="tabsServers">
+            <ul>
+                <li><a href="#tabs-1"><span id="actions">Servidores</span></a></li>
+            </ul>
+            <div id="tabs-1" style="padding:3px;">  
+                <table>
+                    <tr>
+                        <td id="tableSelectable">
+                            <ol id="selectable" style="width:870px;"></ol>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+        </div>              
+    </td>
+</tr>
+</table>
+
+<div id="dialog-details"></div>
Index: controlies/branches/web2py/applications/controlies/views/usuarios/index.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/usuarios/index.html	(revision 166)
+++ controlies/branches/web2py/applications/controlies/views/usuarios/index.html	(revision 167)
@@ -5,16 +5,10 @@
 {{#response.files.append(URL('static','css/helper.css'))}}
 {{#response.files.append(URL('static','css/dropdown.css'))}}
 {{#response.files.append(URL('static','css/default.advanced.css'))}}
-{{response.files.append(URL('static','js/jdgrid/css/ui.jqgrid.css'))}}
-{{response.files.append(URL('static','js/jquery/jquery.dropdown.js'))}}
-{{response.files.append(URL('static','js/jdgrid/grid.locale-sp.js'))}} 
-{{response.files.append(URL('static','js/jdgrid/jquery.jqGrid.min.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.common.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.formedit.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.custom.js'))}}
 
 
 
+
  
 {{extend 'layout.html'}}
 
@@ -48,219 +42,219 @@
 
 
 <script type="text/javascript">  
-
-jQuery(function() {
-    jQuery("#dialog-confirm").dialog({ autoOpen: false });
-    jQuery("#dialog-alert").dialog({ autoOpen: false });
-});
-
-            
-function print_grid(){  
-      jQuery("#list").jqGrid({
-            url:"{{=URL(c='usuarios',f='call',args=['json','list'])}}",
-            data: "{}",
-            datatype: 'json',
-            mtype: 'GET',
-            contentType: "application/json; charset=utf-8",
-            complete: function(jsondata, stat) {
-                if (stat == "success") {
-                    var thegrid = jQuery("#list")[0];
-                    thegrid.addJSONData(JSON.parse(jsondata.responseText).d);
-                }
-            },
-            
-            colNames:['Tipo Usuario','Nombre','Usuario','ID usuario','ID Grupo','Identificación'],
-            colModel:[ 
-                {name:'type',index:'type', width:60, align:"center",  stype:'select', editoptions:{value:":Todo;Profesor:Profesores;Alumno:Alumnos"}},                  
-                {name:'cn',index:'cn', width:140, align:"left"},
-                {name:'uid',index:'uid', width:90, align:"center"},
-                {name:'uidNumber',index:'uidNumber', width:70, align:"center"},
-                {name:'gidNumber',index:'gidNumber', width:70, align:"center"},
-                {name:'employeeNumber',index:'employeeNumber', width:80, align:"center"}
-            ], 
-            rowNum:25,
-            height:335,
-            width: 900,
-            rowList:[25,50,75],  
-            pager: '#pager', 
-            sortname: 'cn', 
-            autowidth: false,
-            viewrecords: true, 
-            sortorder: "desc", 
-            caption:"Usuarios"    
     
-      }); 
-      jQuery("#list").jqGrid('navGrid','#pager',{add:false,edit:false,del:false,search:false,refresh:false});
+    jQuery(function() {
+        jQuery("#dialog-confirm").dialog({ autoOpen: false });
+        jQuery("#dialog-alert").dialog({ autoOpen: false });
+    });
     
-        jQuery("#list").jqGrid('navButtonAdd','#pager',{
-                caption: "Insertar",
-                buttonicon :'ui-icon-plus',
-                onClickButton : function (){ 
-                    addRecord();
+                
+    function print_grid(){  
+          jQuery("#list").jqGrid({
+                url:"{{=URL(c='usuarios',f='call',args=['json','list'])}}",
+                data: "{}",
+                datatype: 'json',
+                mtype: 'GET',
+                contentType: "application/json; charset=utf-8",
+                complete: function(jsondata, stat) {
+                    if (stat == "success") {
+                        var thegrid = jQuery("#list")[0];
+                        thegrid.addJSONData(JSON.parse(jsondata.responseText).d);
+                    }
+                },
+                
+                colNames:['Tipo Usuario','Nombre','Usuario','ID usuario','ID Grupo','Identificación'],
+                colModel:[ 
+                    {name:'type',index:'type', width:60, align:"center",  stype:'select', editoptions:{value:":Todo;Profesor:Profesores;Alumno:Alumnos"}},                  
+                    {name:'cn',index:'cn', width:140, align:"left"},
+                    {name:'uid',index:'uid', width:90, align:"center"},
+                    {name:'uidNumber',index:'uidNumber', width:70, align:"center"},
+                    {name:'gidNumber',index:'gidNumber', width:70, align:"center"},
+                    {name:'employeeNumber',index:'employeeNumber', width:80, align:"center"}
+                ], 
+                rowNum:25,
+                height:335,
+                width: 900,
+                rowList:[25,50,75],  
+                pager: '#pager', 
+                sortname: 'cn', 
+                autowidth: false,
+                viewrecords: true, 
+                sortorder: "desc", 
+                caption:"Usuarios"    
+        
+          }); 
+          jQuery("#list").jqGrid('navGrid','#pager',{add:false,edit:false,del:false,search:false,refresh:false});
+        
+            jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                    caption: "Insertar",
+                    buttonicon :'ui-icon-plus',
+                    onClickButton : function (){ 
+                        addRecord();
+                    } 
+            }); 
+            jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                    caption: "Modificar", 
+                    buttonicon :'ui-icon-pencil',
+                    onClickButton : function (){ 
+                        modifyRecord();
                 } 
-        }); 
-        jQuery("#list").jqGrid('navButtonAdd','#pager',{
-                caption: "Modificar", 
-                buttonicon :'ui-icon-pencil',
-                onClickButton : function (){ 
-                    modifyRecord();
-            } 
-        }); 
-        jQuery("#list").jqGrid('navButtonAdd','#pager',{
-                caption: "Borrar", 
-                buttonicon :'ui-icon-trash',
-                onClickButton : function (){ 
-                    deleteRecord();
-            } 
-        }); 
+            }); 
+            jQuery("#list").jqGrid('navButtonAdd','#pager',{
+                    caption: "Borrar", 
+                    buttonicon :'ui-icon-trash',
+                    onClickButton : function (){ 
+                        deleteRecord();
+                } 
+            }); 
+        
+          
+          jQuery("#list").jqGrid('filterToolbar'); 
+       
+    }
     
-      
-      jQuery("#list").jqGrid('filterToolbar'); 
-   
-}
-
-
-function rowSelected(){
-        var uid = jQuery("#list").jqGrid('getGridParam','selrow'); 
     
-        if( uid == null ){
-            jQuery( "#dialog-alert" ).dialog({
-                resizable: false,
-                height:150,
-                width:290,
-                modal: true,
-                buttons: { "Aceptar": function() { $( this ).dialog( "close" ); }}
-            }).dialog('open');
-            return false;
-        }
-        return uid;
-}           
-
-function addRecord(){
-
-        jQuery("#messageLoading").show();
+    function rowSelected(){
+            var uid = jQuery("#list").jqGrid('getGridParam','selrow'); 
+        
+            if( uid == null ){
+                jQuery( "#dialog-alert" ).dialog({
+                    resizable: false,
+                    height:150,
+                    width:290,
+                    modal: true,
+                    buttons: { "Aceptar": function() { $( this ).dialog( "close" ); }}
+                }).dialog('open');
+                return false;
+            }
+            return uid;
+    }           
     
-        jQuery("#dialog-form").html("").css("display","none");;
-        jQuery("#dialog-form").load("form.html", function() {
-            getAllGroups();
-            jQuery("#form_data #action").val("add");
-            jQuery("#form_data #messageForm").html("Todos los campos son obligatorios");                                     
+    function addRecord(){
     
-            x = (jQuery(window).width()-300)/2;
-            y = (jQuery(window).height()-500)/2;
+            jQuery("#messageLoading").show();
+        
+            jQuery("#dialog-form").html("").css("display","none");;
+            jQuery("#dialog-form").load("form.html", function() {
+                getAllGroups();
+                jQuery("#form_data #action").val("add");
+                jQuery("#form_data #messageForm").html("Todos los campos son obligatorios");                                     
+        
+                x = (jQuery(window).width()-300)/2;
+                y = (jQuery(window).height()-500)/2;
+        
+                jQuery("#messageLoading").hide();
+        
+                jQuery("#dialog-form").dialog({
+                    resizable: false,
+                    position: top,
+                    modal: true,
+                    width: 300,                     
+                    title: "Añadir Usuario"
+                }).dialog('option', 'position', [x, y]);
+            });
+    }
     
-            jQuery("#messageLoading").hide();
+    function modifyRecord(){
+                    var uid;
     
-            jQuery("#dialog-form").dialog({
-                resizable: false,
-                position: top,
-                modal: true,
-                width: 300,                     
-                title: "Añadir Usuario"
-            }).dialog('option', 'position', [x, y]);
-        });
-}
-
-function modifyRecord(){
-                var uid;
-
-                jQuery("#messageLoading").show();
-                
-                var uid = rowSelected();
-                if(uid==false)
-                    return false;
-
-                jQuery("#dialog-form").html("").css("display","none");
-                jQuery("#dialog-form").load("form.html", function() {
+                    jQuery("#messageLoading").show();
                     
-                    getAllGroups();
-                    
-                    jQuery("#form_data #action").val("modify");
-                    jQuery("#form_data #user").attr("readonly","true");
-                    jQuery("#form_data #user").css("background-color","#DDD");
-                    jQuery("#form_data #messageForm").html("Si deja la contraseña en blanco no se modificará<br>El resto de campos son obligatorios");
-                    
-                    jQuery.post('call/json/getUserData',{ username: uid }, function(result) {
-                        //var result = jQuery.parseJSON(data);
-
-                        if(result.response['type']=="teacher")
-                            var textType = "Profesor";
-                        else
-                            var textType = "Alumno";
-                            
-                        var dep = Array(result.response['groups']['departments']);
-
-                        jQuery("#form_data #type").replaceWith(textType+"<input type='hidden' id='type' name='type' value='"+result.response['type']+"'/>");
-                        jQuery("#form_data #name").val(result.response['name']);
-                        jQuery("#form_data #nif").val(result.response['nif']);       
-                        jQuery("#form_data #user").val(result.response['user']);
-                        jQuery("#form_data #surname").val(result.response['surname']);
-                        if (result.response['photo']!='')
-                            jQuery("#form_data #photo").attr("src","data:image/png;base64,"+result.response['photo']);                       
-
-                        $.each(result.response['groups']['departments'], function(i, l){
-                            jQuery('#form_data input:checkbox[value='+l+']').attr('checked', true);                          
-                        });
-
-                        $.each(result.response['groups']['classrooms'], function(i, l){
-                            jQuery('#form_data input:checkbox[value='+l+']').attr('checked', true);                          
-                        });                     
-
-                        x = (jQuery(window).width()-300)/2;
-                        y = (jQuery(window).height()-500)/2;
+                    var uid = rowSelected();
+                    if(uid==false)
+                        return false;
+    
+                    jQuery("#dialog-form").html("").css("display","none");
+                    jQuery("#dialog-form").load("form.html", function() {
                         
-                        jQuery("#messageLoading").hide();
+                        getAllGroups();
                         
-                        jQuery("#dialog-form").dialog({
-                            resizable: false,
-                            modal: true,
-                            width: 300,
-                            title: "Modificar Usuario"
-                        }).dialog('option', 'position', [x, y]);                        
-                    });               
-                });
-}
-
-function deleteRecord(){
+                        jQuery("#form_data #action").val("modify");
+                        jQuery("#form_data #user").attr("readonly","true");
+                        jQuery("#form_data #user").css("background-color","#DDD");
+                        jQuery("#form_data #messageForm").html("Si deja la contraseña en blanco no se modificará<br>El resto de campos son obligatorios");
+                        
+                        jQuery.post('call/json/getUserData',{ username: uid }, function(result) {
+                            //var result = jQuery.parseJSON(data);
     
-        var uid = rowSelected();
-        if(uid==false)
-            return false;
+                            if(result.response['type']=="teacher")
+                                var textType = "Profesor";
+                            else
+                                var textType = "Alumno";
+                                
+                            var dep = Array(result.response['groups']['departments']);
     
-        jQuery( "#dialog-confirm" ).dialog({
-            resizable: false,
-            height:160,
-            width:350,
-            modal: true,
-            buttons: {
-                "Borrar": function() {
-                    jQuery.post("call/json/delete","user="+uid, function(data){
-                        jQuery("#dialog-confirm").dialog( "close" );
-                        jQuery("#list").trigger("reloadGrid");
+                            jQuery("#form_data #type").replaceWith(textType+"<input type='hidden' id='type' name='type' value='"+result.response['type']+"'/>");
+                            jQuery("#form_data #name").val(result.response['name']);
+                            jQuery("#form_data #nif").val(result.response['nif']);       
+                            jQuery("#form_data #user").val(result.response['user']);
+                            jQuery("#form_data #surname").val(result.response['surname']);
+                            if (result.response['photo']!='')
+                                jQuery("#form_data #photo").attr("src","data:image/png;base64,"+result.response['photo']);                       
+    
+                            $.each(result.response['groups']['departments'], function(i, l){
+                                jQuery('#form_data input:checkbox[value='+l+']').attr('checked', true);                          
+                            });
+    
+                            $.each(result.response['groups']['classrooms'], function(i, l){
+                                jQuery('#form_data input:checkbox[value='+l+']').attr('checked', true);                          
+                            });                     
+    
+                            x = (jQuery(window).width()-300)/2;
+                            y = (jQuery(window).height()-500)/2;
+                            
+                            jQuery("#messageLoading").hide();
+                            
+                            jQuery("#dialog-form").dialog({
+                                resizable: false,
+                                modal: true,
+                                width: 300,
+                                title: "Modificar Usuario"
+                            }).dialog('option', 'position', [x, y]);                        
+                        });               
                     });
-                },
-                "Cancelar": function() {
-                    $(this).dialog( "close" );
+    }
+    
+    function deleteRecord(){
+        
+            var uid = rowSelected();
+            if(uid==false)
+                return false;
+        
+            jQuery( "#dialog-confirm" ).dialog({
+                resizable: false,
+                height:160,
+                width:350,
+                modal: true,
+                buttons: {
+                    "Borrar": function() {
+                        jQuery.post("call/json/delete","user="+uid, function(data){
+                            jQuery("#dialog-confirm").dialog( "close" );
+                            jQuery("#list").trigger("reloadGrid");
+                        });
+                    },
+                    "Cancelar": function() {
+                        $(this).dialog( "close" );
+                    }
                 }
-            }
-        }).dialog('open');
-}
-
-function getAllGroups(){
-        $.post("{{=URL(c='grupos',f='call',args=['json','getAllGroups'])}}",   function(groups) {
-            //var groups = $.parseJSON(data);                 
-            
-            $.each( groups.departments, function(i, l){
-                jQuery("#form_data #departments").append("<option value='"+l+"'>"+l+"</option>");
-             });
-            $.each( groups.classrooms, function(i, l){
-                jQuery("#form_data #classrooms").append("<option value='"+l+"'>"+l+"</option>");
-             });                         
-            jQuery("#form_data #departments").multiselect(); 
-            jQuery("#form_data #classrooms").multiselect();                       
-        });             
-}
-
+            }).dialog('open');
+    }
+    
+    function getAllGroups(){
+            $.post("{{=URL(c='grupos',f='call',args=['json','getAllGroups'])}}",   function(groups) {
+                //var groups = $.parseJSON(data);                 
+                
+                $.each( groups.departments, function(i, l){
+                    jQuery("#form_data #departments").append("<option value='"+l+"'>"+l+"</option>");
+                 });
+                $.each( groups.classrooms, function(i, l){
+                    jQuery("#form_data #classrooms").append("<option value='"+l+"'>"+l+"</option>");
+                 });                         
+                jQuery("#form_data #departments").multiselect(); 
+                jQuery("#form_data #classrooms").multiselect();                       
+            });             
+    }
+    
 </script>
 
 
Index: controlies/branches/web2py/applications/controlies/views/grupos/form.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/grupos/form.html	(revision 166)
+++ controlies/branches/web2py/applications/controlies/views/grupos/form.html	(revision 167)
@@ -19,7 +19,6 @@
         restartStyle();
 
         jQuery.post('call/json/modify', jQuery("#form_data").serialize(), function(result) {
-            //var result = $.parseJSON(data);
             switch(result.response){
                 case "OK":{
                     jQuery('#message').html("Operación realizada correctamente").css("color","green").effect("highlight", {"color":"yellow"}, 1000);
Index: controlies/branches/web2py/applications/controlies/views/grupos/index.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/grupos/index.html	(revision 166)
+++ controlies/branches/web2py/applications/controlies/views/grupos/index.html	(revision 167)
@@ -10,18 +10,6 @@
 {{response.files.append(URL('static','js/autocomplete/TextboxList.Autocomplete.js'))}}
 {{response.files.append(URL('static','js/autocomplete/TextboxList.Autocomplete.Binary.js'))}}
 
-         
-
-{{response.files.append(URL('static','js/jdgrid/css/ui.jqgrid.css'))}}
-{{response.files.append(URL('static','js/jquery/jquery.dropdown.js'))}}
-{{response.files.append(URL('static','js/jdgrid/grid.locale-sp.js'))}} 
-{{response.files.append(URL('static','js/jdgrid/jquery.jqGrid.min.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.common.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.formedit.js'))}}
-{{response.files.append(URL('static','js/jdgrid/src/grid.custom.js'))}}
-
-
-
  
 {{extend 'layout.html'}}
 
Index: controlies/branches/web2py/applications/controlies/views/layout.html
===================================================================
--- controlies/branches/web2py/applications/controlies/views/layout.html	(revision 166)
+++ controlies/branches/web2py/applications/controlies/views/layout.html	(revision 167)
@@ -37,6 +37,14 @@
     <!-- All JavaScript at the bottom, except for Modernizr which enables HTML5 elements & feature detects -->
     <script src="{{=URL('static','js/modernizr-1.7.min.js')}}"></script>
     
+{{response.files.append(URL('static','js/jdgrid/css/ui.jqgrid.css'))}}
+{{response.files.append(URL('static','js/jquery/jquery.dropdown.js'))}}
+{{response.files.append(URL('static','js/jdgrid/grid.locale-sp.js'))}} 
+{{response.files.append(URL('static','js/jdgrid/jquery.jqGrid.min.js'))}}
+{{response.files.append(URL('static','js/jdgrid/src/grid.common.js'))}}
+{{response.files.append(URL('static','js/jdgrid/src/grid.formedit.js'))}}
+{{response.files.append(URL('static','js/jdgrid/src/grid.custom.js'))}}
+    
     {{#------  require CSS and JS files for this page (read info in base.css) ------}}
     {{response.files.append(URL('static','css/base.css'))}}
     {{response.files.append(URL('static','css/superfish.css'))}}
