#encoding:utf-8 from django.http import * from django.template.response import * from django.contrib.auth import * from django.contrib.auth.decorators import * from seguimiento_oficios.models import * from django.shortcuts import * from django.contrib.auth.models import User from seguimiento_oficios.forms import * from datetime import datetime from django.contrib import messages from django.db.models import Q # Create your views here. def login_ (request): return TemplateResponse(request,'index.html') def logout_user(request): response = logout(request) return HttpResponseRedirect('/login') def validar(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) mensaje = '' if user is not None: if user.is_active: login(request, user ) # return HttpResponse ( dependencia.objects.filter(usuarios__in=[user.id]).count() ) return HttpResponseRedirect( '/principal' ) else: mensaje = mensaje + 'cuenta desactivada' else: mensaje = mensaje + 'Usuario no valido, verifique sus credenciales' return TemplateResponse(request, 'index.html', {'msj': mensaje}) @login_required def perfil(request, user_id): return TemplateResponse(request, 'perfil.html' ) @login_required def personaView (request): # return HttpResponse ('asdf') formulario = PersonaForm() if request.method=='POST': formulario = PersonaForm( request.POST ) if formulario.is_valid(): try: formulario.save() msj='la persona se guardo correctamente' messages.success(request, msj) except Exception, e: msj = e.message.replace('llave duplicada viola restricción de unicidad', '') msj = msj.replace('«seguimiento_oficios_personas_nombre_apellidopaterno_apellid_key»', '') msj = msj.replace('DETAIL: ', '') messages.error(request, msj) # return TemplateResponse(request, 'persona.html', { 'formulario':formulario }) return HttpResponseRedirect( '/persona/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'persona.html', { 'formulario':formulario }) @login_required def puestoView (request): formulario = PuestoForm() if request.method=='POST': formulario = PuestoForm( request.POST ) if formulario.is_valid(): try: formulario.save() msj='el puesto "%s" se guardo correctamente' % request.POST['nombre'] messages.success(request, msj) except Exception, e: msj = e.message.replace('llave duplicada viola restricción de unicidad', '') msj = msj.replace('«seguimiento_oficios_puestos_nombre_key»', '') msj = msj.replace('DETAIL: ', '') messages.error(request, msj) return HttpResponseRedirect( '/persona/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'puesto.html', { 'formulario':formulario }) @login_required def tituloView (request): formulario = TituloForm() if request.method=='POST': formulario = TituloForm( request.POST ) if formulario.is_valid(): try: formulario.save() msj='el titulo "%s" se guardo correctamente' % request.POST['nombre'] messages.success(request, msj) except Exception, e: msj = e.message.replace('llave duplicada viola restricción de unicidad', '') msj = msj.replace('«seguimiento_oficios_puestos_nombre_key»', '') msj = msj.replace('DETAIL: ', '') messages.error(request, msj) return HttpResponseRedirect( '/titulo/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'titulo.html', { 'formulario':formulario }) @login_required def direccionView (request): formulario = DireccionForm() if request.method=='POST': formulario = DireccionForm( request.POST ) if formulario.is_valid(): try: formulario.save() msj='la direccion "%s" se guardo correctamente' % request.POST['nombre'] messages.success(request, msj) except Exception, e: msj = e.message.replace('llave duplicada viola restricción de unicidad', '') msj = msj.replace('«seguimiento_oficios_direccion_nombre_clave_key»', '') msj = msj.replace('DETAIL: ', '') messages.error(request, msj) return HttpResponseRedirect( '/direccion/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'direccion.html', { 'formulario':formulario }) @login_required def dependenciaView (request): formulario = DependenciaForm() if request.method=='POST': formulario = DependenciaForm( request.POST ) if formulario.is_valid(): formulario.save() msj='la dependencia "%s" se guardo correctamente' % request.POST['nombre'] messages.success(request, msj) return HttpResponseRedirect( '/persona/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'dependencia.html', { 'formulario':formulario }) @login_required def empresaView (request): formulario = EmpresaForm() if request.method=='POST': formulario = EmpresaForm( request.POST ) if formulario.is_valid(): try: formulario.save() msj='el empresa "%s" se guardo correctamente' % request.POST['nombre'] messages.success(request, msj) except Exception, e: msj = e.message.replace('llave duplicada viola restricción de unicidad', '') msj = msj.replace('«seguimiento_oficios_puestos_nombre_key»', '') msj = msj.replace('DETAIL: ', '') messages.error(request, msj) return HttpResponseRedirect( '/persona/add' ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) return TemplateResponse(request, 'empresa.html', { 'formulario':formulario }) def estatus_en_tramite(): return Estatus.objects.get(clave='T').id def estatus_archivo(tipo_documento): if tipo_documento == 1: return Estatus.objects.get(clave='AO').id elif tipo_documento == 2: return Estatus.objects.get(clave='A').id def tipo_documento_recibido(): # 2 Oficio recibido return TipoDocumento.objects.get(nombre = 'Oficio recibido').id def tipo_documento_elaborado(): # 1 Oficio elaborado return TipoDocumento.objects.get(nombre = 'Oficio elaborado').id @login_required def principalView(request): p = Perfil.objects.get(usuario_id = request.user.id) recibidos = None enviados = None inner_qs = Estatus.objects.values_list('id').filter( tipo_documento = tipo_documento_recibido ) recibidos = recepcion_oficio.objects.all().filter(estatus_id__in=inner_qs, dependencia = p.dependencia) rA = recibidos.filter(estatus__clave__in = ['A']) rE = recibidos.filter(estatus__clave__in = ['E']) rT = recibidos.filter(estatus__clave__in = ['T']) rN = recibidos.filter(estatus__clave__in = ['N']) rO = recibidos.filter(estatus__clave__in = ['O']) # rR = recibidos.filter(estatus__clave__in = ['R']) rA.percent = 0 rE.percent = 0 rT.percent = 0 rN.percent = 0 rO.percent = 0 # rR.percent = 0 if recibidos.count() != 0: rA.percent = str(rA.count() * 100 / recibidos.count()) rE.percent = str(rE.count() * 100 / recibidos.count()) rT.percent = str(rT.count() * 100 / recibidos.count()) rN.percent = str(rN.count() * 100 / recibidos.count()) rO.percent = str(rO.count() * 100 / recibidos.count()) # rR.percent = str(rR.count() * 100 / recibidos.count()) inner_qs = Estatus.objects.values_list('id').filter( tipo_documento = tipo_documento_elaborado ) enviados = elaboracion_oficio.objects.filter(estatus_id__in=inner_qs, dependencia = p.dependencia) rAO = enviados.filter(estatus__clave__in = ['AO']) rCO = enviados.filter(estatus__clave__in = ['CO']) # rED = enviados.filter(estatus__clave__in = ['ED']) rOO = enviados.filter(estatus__clave__in = ['OO']) # rRF = enviados.filter(estatus__clave__in = ['RF']) rSC = enviados.filter(estatus__clave__in = ['SC']) rSI = enviados.filter(estatus__clave__in = ['SI']) rSS = enviados.filter(estatus__clave__in = ['SS']) rCO.percent = 0 # rED.percent = 0 rOO.percent = 0 # rRF.percent = 0 rSC.percent = 0 rSI.percent = 0 rSS.percent = 0 rAO.percent = 0 if enviados.count() != 0: rCO.percent = str(rCO.count() * 100 / enviados.count() ) # rED.percent = str(rED.count() * 100 / enviados.count() ) rOO.percent = str(rOO.count() * 100 / enviados.count() ) # rRF.percent = str(rRF.count() * 100 / enviados.count() ) rSC.percent = str(rSC.count() * 100 / enviados.count() ) rSI.percent = str(rSI.count() * 100 / enviados.count() ) rSS.percent = str(rSS.count() * 100 / enviados.count() ) rAO.percent = str(rAO.count() * 100 / enviados.count() ) inicio = 'active' return TemplateResponse(request, 'principal.html', { 'inicio':inicio, 'p':p, 'recibidos':recibidos, 'enviados':enviados, 'rA':rA, 'rE':rE, 'rT':rT, 'rN':rN, 'rO':rO, # 'rR':rR, 'rCO':rCO, # 'rED':rED, 'rOO':rOO, # 'rRF':rRF, 'rSC':rSC, 'rSI':rSI, 'rSS':rSS, 'rAO':rAO }) # from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from pure_pagination import Paginator, EmptyPage, PageNotAnInteger @login_required def control_recibidosView (request, estatus_id = 0): p = Perfil.objects.get(usuario_id = request.user.id) if estatus_id != 0: oficios = recepcion_oficio.objects.all().filter( dependencia = p.dependencia, estatus = estatus_id ) else: oficios = recepcion_oficio.objects.all().filter( dependencia = p.dependencia).exclude( estatus = estatus_archivo(2) ) bscr = request.GET.get('bscr') if request.GET.get('bscr') else '' if bscr != '': oficios = oficios.filter( Q(folio_interno__icontains = bscr) | Q(no_oficio__icontains = bscr) | Q(firma__icontains = bscr) | Q(asunto__icontains = bscr) | Q(dependencia_envia__icontains = bscr) | Q(estatus__nombre__icontains = bscr) ) rpp = int(request.GET.get('rpp')) if request.GET.get('rpp') else 10 paginator = Paginator(oficios, rpp) page = request.GET.get('page') if request.GET.get('page') else 1 try: contacts = paginator.page(page) except PageNotAnInteger: # If page is not an integer, deliver first page. contacts = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. contacts = paginator.page(paginator.num_pages) estatus = Estatus.objects.filter(tipo_documento = tipo_documento_recibido) control_recibidos = 'active' return TemplateResponse(request, 'control_recibidos.html', { # 'oficios':oficios, 'control_recibidos':control_recibidos, 'estatus':estatus, 'p':p, 'contacts': contacts, 'rpp':rpp, 'bscr':bscr, 'page':page }) @login_required def control_elaboradosView (request, estatus_id = 0): p = Perfil.objects.get(usuario_id = request.user.id) if estatus_id != '0': oficios = elaboracion_oficio.objects.all().filter(dependencia = p.dependencia, estatus = estatus_id ) else: oficios = elaboracion_oficio.objects.all().filter(dependencia = p.dependencia).exclude(estatus = estatus_archivo(1)) bscr = request.GET.get('bscr') if request.GET.get('bscr') else '' if bscr != '': oficios = oficios.filter( Q(no_oficio__icontains = bscr) | Q(dependencia_envia__icontains = bscr) | Q(destinatario__icontains = bscr) | Q(asunto__icontains = bscr) | Q(observaciones__icontains = bscr) | Q(estatus__nombre__icontains = bscr) ) rpp = int(request.GET.get('rpp')) if request.GET.get('rpp') else 10 paginator = Paginator(oficios, rpp) page = request.GET.get('page') if request.GET.get('page') else 1 try: contacts = paginator.page(page) except PageNotAnInteger: # If page is not an integer, deliver first page. contacts = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. contacts = paginator.page(paginator.num_pages) estatus = Estatus.objects.filter(tipo_documento = tipo_documento_elaborado) control_elaborados = 'active' return TemplateResponse(request, 'control_elaborados.html', { 'contacts':contacts, 'rpp':rpp, 'bscr':bscr, 'control_elaborados':control_elaborados, 'estatus':estatus, 'p':p }) @login_required def oficio_recepcionView (request, oficio_id): p = Perfil.objects.get(usuario_id = request.user.id) dependencia_enviaAC = recepcion_oficio.objects.filter(dependencia = p.dependencia).values('dependencia_envia').distinct('dependencia_envia').order_by('dependencia_envia') dependenciasAC = Dependencia.objects.values('nombre').distinct('nombre').order_by('nombre') firmaAC = recepcion_oficio.objects.filter(dependencia = p.dependencia).values('firma').distinct('firma').order_by('firma') asuntoAC = recepcion_oficio.objects.filter(dependencia = p.dependencia).values('asunto').distinct('asunto').order_by('asunto') tmp_oficio = None if request.method == 'POST': if oficio_id == "0": # messages.info( request, oficio_id == "0" ) i = recepcion_oficio(captura = request.user, estatus = Estatus.objects.get( clave = 'T' ), dependencia = p.dependencia ) formulario = recepcion_oficioForm( request.POST, instance = i ) else: # messages.info( request, oficio_id ) i = recepcion_oficio(id = oficio_id, captura = request.user, estatus = recepcion_oficio.objects.get(pk = oficio_id).estatus, dependencia = p.dependencia ) formulario = recepcion_oficioForm( request.POST, instance = i ) # return HttpResponse ( str(formulario)) if formulario.is_valid(): try: # return HttpResponse( str(formulario) ) formulario.save() msj = 'el oficio "%s" se ha guardado correctamente' % request.POST.get('no_oficio').upper() messages.success(request, msj) except Exception, e: msj = e.message # msj = msj.replace('el valor null para la columna «captura_id» viola la restricción not null','') # msj = msj.replace('DETAIL: ','') messages.error(request, msj) if 'guardar' in request.POST: return HttpResponseRedirect('/control/recibidos') elif 'guardar_y_agregar_otro' in request.POST: return HttpResponseRedirect('/recepcion/0') elif 'guardar_y_continuar_editando' in request.POST: if oficio_id == '0': o = recepcion_oficio.objects.filter(dependencia = p.dependencia).latest('id').id else: o = oficio_id # messages.info( request, o ) return HttpResponseRedirect( '/recepcion/%s' % o ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) else: try: ultimo_oficio_dependencia = recepcion_oficio.objects.filter(dependencia = p.dependencia).latest('folio_interno').folio_interno ultimo_oficio_dependencia = ultimo_oficio_dependencia + 1 except recepcion_oficio.DoesNotExist: ultimo_oficio_dependencia = 1 formulario = recepcion_oficioForm() formulario.initial = {'folio_interno':ultimo_oficio_dependencia} # formulario.initial = {'estatus':Estatus.objects.get(clave='T').id} if oficio_id != "0": formulario = recepcion_oficioForm(instance = recepcion_oficio.objects.get(pk = oficio_id )) if formulario.instance.no_oficio_respuesta_contestacion: tmp_oficio = elaboracion_oficio.objects.get(pk=formulario.instance.no_oficio_respuesta_contestacion.id) control_recibidos = 'active' return TemplateResponse(request, 'recepcion.html', { 'perfil':p, 'formulario':formulario, 'control_recibidos':control_recibidos, 'dependencia_enviaAC':dependencia_enviaAC, 'dependenciasAC':dependenciasAC, 'firmaAC':firmaAC, 'asuntoAC':asuntoAC, 'oficio_id':oficio_id, 'elaboracion_oficio': tmp_oficio, 'oficios_elaborados': elaboracion_oficio.objects.all(), }) @login_required def oficio_turnarView (request, oficio_id, asignacion_id = 0): p = Perfil.objects.get(usuario_id = request.user.id) direccion_recibeAC = asignacion_oficio.objects.all().values('direccion_recibe').distinct('direccion_recibe').order_by('direccion_recibe') recibeAC = asignacion_oficio.objects.all().values('recibe').distinct('recibe').order_by('recibe') asignaciones = asignacion_oficio.objects.all().filter(folio_interno_id = oficio_id) # return HttpResponse ( recibeAC.count() ) # formulario = asignacion_oficioForm() if request.method == 'POST': i = asignacion_oficio(asigna = request.user, activo= True ) if asignacion_id != 0: i = asignacion_oficio(id=asignacion_id, asigna = request.user, activo= True ) formulario = asignacion_oficioForm( request.POST, instance = i ) if formulario.is_valid(): try: formulario.save() a = asignacion_oficio.objects.latest('id').id msj = 'la asignacion "%s" se ha guardado correctamente' % a messages.success(request, msj) o = recepcion_oficio.objects.get(pk = oficio_id) e = Estatus.objects.get(tipo_documento = 2, clave = 'E') o.estatus = e o.save() except Exception, e: msj = e.message # msj = msj.replace('el valor null para la columna «captura_id» viola la restricción not null','') # msj = msj.replace('DETAIL: ','') messages.error(request, msj) if 'guardar' in request.POST: return HttpResponseRedirect('/control/recibidos') elif 'guardar_y_agregar_otro' in request.POST: return HttpResponseRedirect('/turnar/%s' % (oficio_id) ) elif 'guardar_y_continuar_editando' in request.POST: if oficio_id == '0': o = asignacion_oficio.objects.latest('id').id else: o = oficio_id # messages.info( request, o ) return HttpResponseRedirect( '/turnar/%s/%s' % (o, asignacion_id) ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) else: formulario = asignacion_oficioForm() if oficio_id != '0': formulario.initial={'folio_interno':oficio_id, 'asigna':request.user } if asignacion_id != 0: formulario = asignacion_oficioForm(instance=asignacion_oficio.objects.get(pk = asignacion_id)) turnar = 'active' return TemplateResponse(request, 'turnar.html', { 'p':p, 'formulario':formulario, 'turnar':turnar, 'direccion_recibeAC':direccion_recibeAC, 'recibeAC':recibeAC, 'asignaciones':asignaciones, # 'asuntoAC':asuntoAC 'request':request }) def oficio_recepcion_detalleView(request, oficio_id): p = Perfil.objects.get(usuario_id = request.user.id) oficio = recepcion_oficio.objects.get(pk= oficio_id) asignaciones = asignacion_oficio.objects.filter(folio_interno_id = oficio_id) return TemplateResponse(request, 'recepcion_detalle.html', {'oficio':oficio, 'asignaciones':asignaciones, 'p':p}) def oficio_reportesView (request): contenido = 'Reportes' return HttpResponse (contenido) def oficio_borrarView (request, oficio_id): contenido = 'Borrar' return HttpResponse (contenido) def oficio_envioView(request, oficio_id): p = Perfil.objects.get(usuario_id = request.user.id) dependenciasAC = Dependencia.objects.values('nombre').distinct('nombre').order_by('nombre') dependencia_enviaAC = elaboracion_oficio.objects.values('dependencia_envia').distinct('dependencia_envia').order_by('dependencia_envia') firmaAC = recepcion_oficio.objects.filter(dependencia = p.dependencia).values('firma').distinct('firma').order_by('firma') asuntoAC = recepcion_oficio.objects.filter(dependencia = p.dependencia).values('asunto').distinct('asunto').order_by('asunto') tmp_oficio = None if request.method == 'POST': i = elaboracion_oficio(usuario = request.user, activo= True, fecha_captura = datetime.now(), dependencia = p.dependencia) if oficio_id != '0': i = elaboracion_oficio(id=oficio_id, usuario = request.user, activo= True, fecha_captura = datetime.now(), dependencia = p.dependencia ) formulario = elaboracion_oficioForm( request.POST, instance = i ) if formulario.is_valid(): try: formulario.save() a = elaboracion_oficio.objects.filter(dependencia = p.dependencia).latest('id').no_oficio # Actualizamos el oficio al que estamos respondiendo if 'no_oficio_respuesta' in request.POST: if request.POST['no_oficio_respuesta'] != 0: # recuperamos el oficio al que estamos respondiendo o = recepcion_oficio.objects.get(id = request.POST['no_oficio_respuesta']) o.no_oficio_respuesta = a o.save() msj = 'El oficio "%s" se ha guardado correctamente' % a messages.success(request, msj) except Exception, e: msj = e.message # msj = msj.replace('el valor null para la columna «captura_id» viola la restricción not null','') # msj = msj.replace('DETAIL: ','') messages.error(request, msj) if 'guardar' in request.POST: return HttpResponseRedirect('/control/elaborados/0') elif 'guardar_y_agregar_otro' in request.POST: return HttpResponseRedirect('/envio/0') elif 'guardar_y_continuar_editando' in request.POST: if oficio_id == '0': o = elaboracion_oficio.objects.filter(dependencia = p.dependencia).latest('id').id else: o = oficio_id # messages.info( request, o ) return HttpResponseRedirect( '/envio/%s' % (o) ) else: msj='Por favor, corrija el siguiente error.' messages.error(request, msj) else: formulario = elaboracion_oficioForm() if oficio_id == '0': formulario.initial={'folio_interno':oficio_id, 'asigna':request.user } else: formulario = elaboracion_oficioForm(instance=elaboracion_oficio.objects.get(pk = oficio_id)) if formulario.instance.no_oficio_respuesta: tmp_oficio = recepcion_oficio.objects.get(pk=formulario.instance.no_oficio_respuesta.id) control_elaborados = 'active' return TemplateResponse(request, 'envio.html', { 'p':p, 'formulario':formulario, 'control_elaborados':control_elaborados, 'dependencia_enviaAC':dependencia_enviaAC, 'dependenciasAC':dependenciasAC, # 'direccion_recibeAC':direccion_recibeAC, # 'recibeAC':recibeAC, # 'asignaciones':asignaciones, # # 'asuntoAC':asuntoAC 'request':request, 'elaboracion_oficio': tmp_oficio, 'oficios_recibidos': recepcion_oficio.objects.all(), }) def elaborados_detalleView( request, oficio_id ): p = Perfil.objects.get(usuario_id = request.user.id) oficio = elaboracion_oficio.objects.get(pk= oficio_id) return TemplateResponse(request, 'elaborados_detalle.html', {'oficio':oficio, 'p':p}) from django.core.exceptions import PermissionDenied from django.contrib.auth.models import User from django.http import Http404 @login_required def usuario(request): if not (request.user.has_perm('auth.change_user') or request.user.has_perm('auth.add_user')): raise PermissionDenied usuarios = User.objects.all().exclude(username='dgtic') context = { 'control_usuarios' : 'active', 'usuarios' : usuarios, } return render (request, 'control_usuarios.html', context) @permission_required('auth.change_user', raise_exception=True) def usuario_edit(request, usuario_id): u = User.objects.get(pk=usuario_id) if u == User.objects.get(username='dgtic'): raise Http404 if request.method == 'POST': form = UsuarioForm(request.POST, instance=u) if form.is_valid(): form.save() messages.success(request, ('El Usuario %s ha sido actualizada correctamente') % form.instance) return redirect(usuario) # return HttpResponseRedirect(reverse('usuario')) else: messages.error(request, 'Por favor corrija el siguiente error:') else: form = UsuarioForm(instance=u) context = { 'control_usuarios' : 'active', 'form' : form, } return render(request, 'usuario_edit.html', context) @login_required def buscar(request): p = Perfil.objects.get(usuario_id=request.user.id) estatus = Estatus.objects.all() tipo_documento_recibido = TipoDocumento.objects.filter(nombre='Oficio recibido') estatus_recibidos = estatus.filter(tipo_documento=tipo_documento_recibido) tipo_documento_elaborado = TipoDocumento.objects.filter(nombre='Oficio elaborado') estatus_enviados = estatus.filter(tipo_documento=tipo_documento_elaborado) context = { 'bscr': '', 'inicio': 'active', 'estatus_recibidos': estatus_recibidos, 'estatus_enviados': estatus_enviados } bscr = '' if 'bscr' in request.GET: if request.GET['bscr'] == '': messages.error(request, 'Debe especificar un parámetro de búsqueda'); return render(request, 'busqueda.html', context) bscr = request.GET['bscr'] context['bscr'] = bscr context['recibidos'] = recepcion_oficio.objects.filter(dependencia=p.dependencia).filter( Q(folio_interno__icontains = bscr) | Q(no_oficio__icontains = bscr) | Q(firma__icontains = bscr) | Q(asunto__icontains = bscr) | Q(dependencia_envia__icontains = bscr) | Q(estatus__nombre__icontains = bscr) ) context['enviados'] = elaboracion_oficio.objects.filter(dependencia=p.dependencia).filter( Q(no_oficio__icontains = bscr) | Q(dependencia_envia__icontains = bscr) | Q(destinatario__icontains = bscr) | Q(asunto__icontains = bscr) | Q(observaciones__icontains = bscr) | Q(estatus__nombre__icontains = bscr) ) # return HttpResponse(bscr) return render(request, 'busqueda.html', context)