Commit fbb5af39 authored by bhmeyer's avatar bhmeyer

Merge branch 'development' into 'master'

deploy

See merge request !105
parents a0c9ad57 b6711131
Pipeline #21160 passed with stage
in 2 minutes and 20 seconds
from django.core.management.base import BaseCommand
from submission.models import Submission
from degree.models import Degree
from submission.analysis.main import analyze
class Command(BaseCommand):
help = ' Reexecute last analyze of all degree'
def handle(self, *args, **options):
degrees = Degree.objects.all()
submissions = Submission.objects.all()
to_analyze = []
# for each degree, get last submission with sucessful and re execute
for degree in degrees:
# get all submissions of degree
submissions = Submission.objects.filter(degree=degree, analysis_status=Submission.STATUS_FINISHED)
# check if degree has submissions
if len(submissions) > 0:
# Put each submission on queue and set it to executing status
for submission in submissions.order_by('timestamp'):
submission.set_executing()
to_analyze.append(submission)
# Execute each analyze in chronological order
for submission in to_analyze:
analyze(submission)
from django.core.management.base import BaseCommand
from submission.models import Submission
from degree.models import Degree
from submission.analysis.main import analyze
class Command(BaseCommand):
help = ' Reexecute last analyze of all degree'
def handle(self, *args, **options):
degrees = Degree.objects.all()
submissions = Submission.objects.all()
to_analyze = []
# for each degree, get last submission with sucessful and re execute
for degree in degrees:
# get all submissions of degree
submissions = Submission.objects.filter(degree=degree, analysis_status=Submission.STATUS_FINISHED)
# check if degree has submissions
if len(submissions) > 0:
# sort reverse submission by timestamp and the most recent submission
submission = submissions.order_by('timestamp').reverse()[0]
submission.set_executing()
to_analyze.append(submission)
# Execute each analyze in chronological order
for submission in to_analyze:
analyze(submission)
\ No newline at end of file
.fa{
color:#132940;
}
.popover{
max-width:30%;
}
html {
height: 100%;
......@@ -47,6 +39,48 @@ h1#title {
.alert {
border-radius: 0;
color: 000;
}
.alert a:link {
color:black;
}
.card-body-icon {
position: absolute;
z-index: 0;
top: -1.25rem;
right: -1rem;
opacity: 0.4;
font-size: 5rem;
-webkit-transform: rotate(15deg);
transform: rotate(15deg);
}
.bg-upload{
background-color: rgb(44, 62, 80);
}
.bg-mananger{
background-color: rgb(52, 152, 219);
}
.bg-upload:hover{
background-color: rgba(44, 62, 80, 0.9);
}
.bg-mananger:hover{
background-color: rgba(52, 152, 219, 0.9);
}
.button-adega a{
text-decoration: none;
}
.alert a:visited {
color:blue;
}
#messages {
......@@ -253,6 +287,23 @@ span.data {
.grade .name {
display: block; }
.materia_selected {
outline-style:solid;
outline-color:rgb(138, 64, 207);
outline-width:1px;
}
.materia_prerequisite {
outline-style:solid;
outline-color:#FFD700;
outline-width:1px;
}
.materia_posrequisite {
outline-style:solid;
outline-color:#6B8E23;
outline-width:1px;
}
/* ============================================== MATERIA */
.materia {
background-color: #FFF;
......@@ -359,4 +410,3 @@ span.data {
font-weight: bold;
font-size: 1.2em;
margin: 10px; }
......@@ -9884,4 +9884,4 @@ a.text-dark:hover, a.text-dark:focus {
border-color: #dee2e6;
}
}
/*# sourceMappingURL=bootstrap.css.map */
\ No newline at end of file
/*# sourceMappingURL=bootstrap.css.map */
......@@ -5,19 +5,68 @@
{% block content%}
<h2>Dashboard</h2>
<div class="alert alert-warning" role="alert">
Os links a seguir exibirão os resumos (gráficos e taxas) dos <b>últimos relatórios
<div style="background-color:#fff; color:#000; text-align:justify;">
<!-- Os links a seguir exibirão os resumos (gráficos e taxas) dos <b>últimos relatórios
submetidos e processados</b> referentes aos cursos registrados no sistema. Caso não exista nenhum
relatório processado relacionado aos cursos, o sistema acusará um erro.
<a href="{% url 'submission:SubmissionCreateView' %}">Submeter relatório</a></a>,
<a href="{% url 'submission:SubmissionCreateView' %}">Upload de relatórios</a>,
que podem ser gerenciados na página <a href="{% url 'submission:SubmissionListView' %}"> Gerenciar relatórios</a>.
-->
<br>Para começar a utilizar o ADEGA, você precisa enviar um relatório do SIE com os dados que você gostaria de analisar.
<br><br>
<div class="row button-adega" >
<div class="col-xl-3 mb-4 ">
<a href="{% url 'submission:SubmissionCreateView' %}">
<div class="card text-white bg-upload o-hidden h-100">
<div class="card-body pt-4 pb-4">
<div class="card-body-icon">
<i class="fas fa-upload">
</i>
</div>
<div class="mr-5" style="font-size: 145%">Upload de Dados
</div>
</div>
</div>
</a>
</div>
<div class="col-xl-3 mb-4">
<a href="{% url 'submission:SubmissionListView' %}">
<div class="card text-white bg-mananger o-hidden h-100">
<div class="card-body pt-4 pb-4" >
<div class="card-body-icon">
<i class="fas fa-cog">
</i>
</div>
<div class="mr-5" style="font-size: 145%">Listar Relatórios
</div>
</div>
</div>
</a>
</div>
</div>
{% if degrees_last_submissions|length > 0 %}
<p> Para acessar dados já enviados, clique nos links a seguir.</p>
{% endif %}
</div>
<br>
{% for degree in degrees_last_submissions %}
<a href="{% url 'degree:index' submission_id=degree.last_submission.id %}">{{degree.name}} ({{degree.code}})</a><br>
{% endfor %}
......
from django import template
from django.utils.safestring import mark_safe
from django.template import Library
import json
import numpy as np
register = template.Library()
......@@ -21,4 +26,10 @@ def remove_spaces(value):
try:
return value.replace(' ', '')
except:
return value
\ No newline at end of file
return value
@register.filter
def safe_js(value):
if type(value) is np.ndarray:
return mark_safe(json.dumps(value.tolist()))
return mark_safe(json.dumps(value))
\ No newline at end of file
......@@ -14,11 +14,12 @@ def dashboard(request):
last_submission = Submission.objects.filter(
degree=degree
).last()
degrees_last_submissions.append({
"name": degree.name,
"code": degree.code,
"last_submission": last_submission
})
if not (last_submission is None):
degrees_last_submissions.append({
"name": degree.name,
"code": degree.code,
"last_submission": last_submission
})
return render(request, 'adega/dashboard.html', {"title": "Dashboard",
"degrees_last_submissions":degrees_last_submissions,
"hide_navbar": True
......
......@@ -6,7 +6,28 @@
{% block content %}
<div class="row">
<div class="col-md-12">
<h1>Informações Gerais - Turma Ingresso</h1>
<h1>
Informações Gerais - Turma Ingresso
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Para o cálculo do IRA, somente as situações consideradas como <b>Aprovação</b> ou <b>Reprovação</b> são consideradas.<br>
Também, alguns casos como o cálculo do índice de reprovação utilizam o conceito de disciplians cursadas.
<br>
Situações consideradas como <b>Aprovação:</b><br>
{% for x in situations_pass %}
{{x}}<br>
{% endfor %}
<br>
Situações consideradas como <b>Reprovação:</b><br>
{% for x in situations_fail %}
{{x}}<br>
{% endfor %}
<br>
Situações consideradas como <b>Cursada:</b><br>
{% for x in situations_coursed %}
{{x}}<br>
{% endfor %}
"></a>
</h1>
<table class="table">
<tr>
<td>Ano/Semestre</td>
......@@ -15,22 +36,42 @@
<tr>
<td>Quantidade de alunos</td>
<td> {{admission_info.quantidade_alunos}} </td>
<td>
<a tabindex="0" class=" fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Quantidade de alunos que possuem ano e semestre de matrícula referente a esta turma ingresso."></a>
</td>
</tr>
<tr>
<td>IRA Médio</td>
<td> {{admission_info.ira|floatformat:2}} &plusmn {{admission_info.std|floatformat:2}} </td>
<td>
<a tabindex="0" class=" fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="IRA médio e desvio padrão dos alunos desta turma. São apenas consideradas as disciplinas cujas situações são classificadas como <b>Reprovação</b> ou <b>Aprovação</b>."></a>
</td>
</tr>
<tr>
<td>Tempo médio de formatura em anos <b>atual</b></td>
<td> {{admission_info.formatura_media}} </td>
<td>
<a tabindex="0" class=" fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Tempo médio de formatura em anos (dentre aqueles que se formaram)."></a>
</td>
</tr>
<tr>
<td>Índice de Reprovação</td>
<td> {{admission_info.taxa_reprovacao|to_percent}} </td>
<td>
<a tabindex="0" class=" fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Valor que representa a taxa de reprovação de disciplinas cursadas pelos alunos desta turma. É calculado a partir da razão entre disciplinas consideradas como <b>Reprovação</b> e disciplinas consideradas como <b>Cursada</b>."></a>
</td>
</tr>
<tr>
<td>Indice de Evasão</td>
<td> {{admission_info.taxa_evasao|to_percent}} </td>
<td>
<a tabindex="0" class=" fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Valor que representa a taxa de de evasão desta turma. É calculado a partir da razão entre alunos ativos e a quantidade total de alunos da turma."></a>
</td>
</tr>
<tr>
<td>Quantidade de Evadidos</td>
......@@ -83,11 +124,23 @@
<div id="graficos">
<div class="row">
<div class="col-md-12">
<h3>IRA/Semestre</h3>
<h3>
IRA por Semestre
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Média e desvio padrão do IRA semestral dos alunos desta turma em diferentes períodos. O valor do IRA é calculado individualmente
para cada semestre, ou seja, os valores das notas não são acumulados.
São apenas consideradas as disciplinas cujas situações são classificadas como
<b>Reprovação</b> ou <b>Aprovação</b>."></a>
</h3>
<div id="ira_semestral"></div>
</div>
<div class="col-md-12">
<h3>Quantidade de alunos/Semestre</h3>
<h3>
Quantidade de alunos por Semestre
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Calcula, para cada período, o número de alunos desta turma que realizaram ao menos uma matrícula em alguma disciplina.">
</a>
</h3>
<div id="students_per_semester"></div>
</div>
</div>
......
......@@ -8,12 +8,27 @@
<div class="row">
<div class="col-md-12">
<h2>Turmas de Ingresso</h2>
<h2>
Turmas de Ingresso
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Para o cálculo do IRA, somente as situações consideradas como <b>Aprovação</b> ou <b>Reprovação</b> são consideradas.<br>
<br>
Situações consideradas como <b>Aprovação:</b><br>
{% for x in situations_pass %}
{{x}}<br>
{% endfor %}
<br>
Situações consideradas como <b>Reprovação:</b><br>
{% for x in situations_fail %}
{{x}}<br>
{% endfor %}">
</a>
</h2>
<table class="table table-striped table-bordered" id="admission_table">
<thead>
<tr>
<th>Ano/Semestre</th>
<th>Ira médio</th>
<th>IRA médio</th>
<th>Quantidade Ingresso</th>
<th>Alunos Evadidos</th>
<th>Alunos Formados</th>
......
......@@ -8,14 +8,22 @@ from report_api.views import get_list_admission, get_admission_detail
from submission.models import Submission
from guardian.decorators import permission_required_or_403
from submission.analysis.utils.situations import Situation
situations_pass = Situation.SITUATION_PASS
situations_pass = [Situation.code_to_str(c) for c in situations_pass]
situations_fail = Situation.SITUATION_FAIL
situations_fail = [Situation.code_to_str(c) for c in situations_fail]
situations_coursed = Situation.SITUATION_COURSED
situations_coursed = [Situation.code_to_str(c) for c in situations_coursed]
@permission_required_or_403('view_admission', (Submission, 'id', 'submission_id'))
def detail(request, submission_id, ano, semestre):
submission_id = int(submission_id)
submission = Submission.objects.get(id=submission_id)
degree = submission.degree
for admission in get_list_admission(request.session, degree, submission_id):
if(admission["ano"] == ano and admission["semestre"] == semestre):
......@@ -35,11 +43,16 @@ def detail(request, submission_id, ano, semestre):
if(admission_info["formatura_media"] == -1):
admission_info["formatura_media"] = "Não há alunos formados nesta turma"
else:
admission_info["formatura_media"] = str(admission_info["formatura_media"]) + " anos"
return render(request, 'admission/detail.html',{
"degree": degree,
"admission_info": admission_info,
"submission": submission
"submission": submission,
"situations_pass": situations_pass,
"situations_fail": situations_fail,
"situations_coursed": situations_coursed,
})
......@@ -54,8 +67,10 @@ def index(request, submission_id):
"listage_admissions": get_list_admission(
request.session,
degree,
submission_id
submission_id,
),
"situations_pass": situations_pass,
"situations_fail": situations_fail,
"degree": degree,
"submission": submission
})
......@@ -126,7 +126,11 @@
<div id="aprovacao_semestre"></div>
</div>
<div class="col-md-12">
<!-- <h3>Quantidade de Alunos/Vezes Cursadas</h3> -->
<h3>
Reincidência de matrículas
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Contagem de alunos que cursaram a disciplina X vezes."></a>
</h3>
<div id="qtd_cursada_aprov"></div>
</div>
</div>
......
......@@ -8,7 +8,9 @@
<div class="row">
<div class="col-md-12">
<h2>Disciplinas</h2>
<h2>
Listagem de Disciplinas
</h2>
<table id="course_table" class="table table-striped table-bordered">
<thead>
<tr>
......
This diff is collapsed.
from django.shortcuts import render, redirect
from django.views.generic import View
from django.contrib.auth import logout as process_logout
from report_api.views import get_degree_information
from report_api.views import get_degree_information, get_list_students, get_student_detail, get_list_courses
from degree.models import Degree
from submission.models import Submission
import json
from student.grid import DegreeGrid
from guardian.decorators import permission_required_or_403
from submission.analysis.utils.situations import Situation
......@@ -21,8 +23,20 @@ def index(request, submission_id):
submission = Submission.objects.get(id=submission_id)
degree = submission.degree
analysis_result = get_list_courses(request.session, degree, submission_id)
courses_list = analysis_result["cache"]
dg = DegreeGrid(DegreeGrid.bcc_grid_2011)
grid_info = dg.get_degree_situation(courses_list)
prerequisites = dg.grid_detail.prerequisites
prerequisites_rev = {}
for c1 in prerequisites:
for c2 in prerequisites[c1]:
if not (c2 in prerequisites_rev):
prerequisites_rev[c2] = []
prerequisites_rev[c2].append(c1)
degree_data = get_degree_information(request.session, degree, submission_id=submission_id)
return render(request, "degree/index.html", {
......@@ -31,5 +45,8 @@ def index(request, submission_id):
"degree_data": degree_data,
"situations_pass": situations_pass,
"situations_fail": situations_fail,
"grid_info": grid_info,
"prerequisites": prerequisites,
"prerequisites_rev": prerequisites_rev,
})
......@@ -158,6 +158,8 @@ class DegreeGridDescription:
self.code_to_name = obj["code_to_name"]
self.equiv_codes = obj["equiv_codes"]
self.fake_codes = obj["fake_codes"]
self.prerequisites = obj["prerequisites"]
self.phases = obj["phases"]
# Codes that show more then one time on grid, like OPT
self.repeated_codes = obj["repeated_codes"]
......@@ -243,6 +245,33 @@ class DegreeGrid:
cgc = self.compute_cgc(hist)
return self.get_grid(cgc), self.get_repeated_course_info(cgc)
def get_degree_situation(self, courses_hist):
'''
Computes the degree grid with courses analysis summaries.
The informations are the same that index course page.
Parameters:
courses_hist: Cache object with each course description. Same instance
used into index course page.
Returns:
A matrix of objects. Each row represents a semester.
'''
# Create an empty grid with instances of Grid Collection
cgc = self.compute_cgc([])
grid = self.get_grid(cgc)
# Uses courses analysis summary to populate details
for code in courses_hist:
for semester in grid:
for course in semester:
if code == course["code"]:
course["detail"] = courses_hist[code]
return grid
bcc_grid_2011 = DegreeGridDescription({
"year": 2011,
"grid": [
......@@ -495,5 +524,71 @@ class DegreeGrid:
"CI259": ["TG II"],
"CI260": ["TG I"],
"CI261": ["TG II"],
}
},
"prerequisites":{
# Pre-barreira
"CI057": ["CI056", "CI055"],
"CI056": ["CI055"],
"CI212": ["CI210", "CI068"],
"CI210": ["CI068"],
"CI064": ["CI055"],
"CI067": ["CI055"],
"CI237": ["CM046"],
"CM005": ["CI045"],
"CM202": ["CM201"],
##
# Pos-Barreira
"CI215": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI162": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI163": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI221": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI062": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI065": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI165": ["CI065", "CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI211": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CE003": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI059": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI209": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI058": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI061": ["CI058", "CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI218": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI164": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"SA214": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"CI220": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"OPT": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"TG I": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
"TG II": ["CI068", "CI210", "CI212", "CI055", "CI056", "CI057", "CM046", "CI067",
"CI064", "CM045", "CM005", "CI237", "CM201", "CM202", "CI166"],
},
"phases":{
"Barreira": ["CI068", "CI055", "CM046", "CM045", "CM201",
"CI210", "CI056", "CI067", "CM005", "CM202",
"CI212", "CI057", "CI064", "CI237", "CI166",]
},
})
......@@ -144,12 +144,21 @@
<td>Período pretendido</td>
<td>
{% if analysis_result.periodo_pretendido %}
<span class="data">{{ analysis_result.periodo_pretendido }}</span>
<span class="data">
{{ analysis_result.periodo_pretendido }}
</span>
{% else %}
<span class="data">Formado</span>
<span class="data">Formado</span>
{% endif %}
</td>
</tr>
{% for phase_name, phase_value in grid_phases %}
<tr>
<td>{{phase_value.description_name}} ({{phase_name}})</td>
<td><span class="data">{{phase_value.description_value}}</span></td>
</tr>
{% endfor %}
</table>
</div>
......@@ -185,28 +194,76 @@
<div id="graficos">
<div class="row">
<h3>Relação entre IRA e a quantidade de disciplinas por semestre
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="IRA médio do estudante e quantidade de disciplinas cursadas em cada semestre. O valor do IRA é calculado individualmente
para cada semestre, ou seja, os valores apresentados não são acumulados.
São apenas consideradas as disciplinas cujas situações são classificadas como
<b>Reprovação</b> ou <b>Aprovação</b>."></a>
</h3>
<div class="col-md-11">
<div id="ira_disciplinas_semestre"></div>
</div>
</div>
<br>
<!-- <div class="row">
<h3>IRA/Semestre</h3>
<div class="col-md-12">
<div class="col-md-11">
<div id="ira_semestral"></div>
</div>
<div class="col-md-12">
<h3>Índice de aprovação/Semestre</h3>
<div class="col-md-1">
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="IRA médio do estudante em cada semestre. O valor é calculado individualmente
para cada semestre, logo os valores apresentados não são acumulados.
São apenas consideradas as disciplinas cujas situações são classificadas como
<b>Reprovação</b> ou <b>Aprovação</b>."></a>
</div>
</div>
<br> -->
<div class="row">
<div class="col-md-11">
<h3>Índice de aprovação por Semestre
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Quantidade de disciplinas cursadas e aprovadas em cada semestre.
São apenas consideradas as disciplinas cujas situações são classificadas como
<b>Reprovação</b> ou <b>Aprovação</b>."></a>
</h3>
<div id="aprovacao_semestral"></div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<h3>Posição do aluno em relação a turma de ingresso/Semestre(%)</h3>
<div class="col-md-11">
<h3>Posição do aluno em relação a Turma de Ingresso por Semestre
<a tabindex="0" class="fa fa-info-circle" data-toggler="popover" data-html="true"
data-content="Posição do aluno em relação à própria turma de ingresso em cada semestre.