diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe0690db56d75af7e3fcb3c2bd3c8f68ecb74d05..794e49b1e118abfaa6a8fe16af4af04a8597c8df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,25 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## 1.6.0 - 2018-08-17
+### Added
+- Dimension state in route `enrollment` now returns state name and id
+- `school` route now has a `search` parameter. You can search by city name or state abbreviation
+- Added all age range convertion
+- Added special class and all age range to id2str
+- Added `school infratructure` route
+- Added `INEP` route for Portal MEC
+### Changed
+- Fix `auxiliar` indicator
+- Add property "don't group" in RQF to dismiss the group by and order by clause
+- Change RQF filters in `auxiliar` route
+- Fix total classrooms needed bug in classroom count
+- Add special class and all age range to enrollment route
+
 ## 1.5.0 - 2018-07-30
 ### Added
 - Add portaMec route
+- Fix bug in diagnosis and projection routes
 
 ## 1.4.2 - 2018-07-23
 ### Added
diff --git a/src/libs/convert/ageRangeAll.js b/src/libs/convert/ageRangeAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b4cab9cbf786a1a568912d9b3f7085e2789d26a
--- /dev/null
+++ b/src/libs/convert/ageRangeAll.js
@@ -0,0 +1,28 @@
+module.exports = function ageRange(id) {
+    switch (id) {
+        case 1:
+        return '0 a 3 anos';
+        case 2:
+        return '4 a 5 anos';
+        case 3:
+        return '6 a 10 anos';
+        case 4:
+        return '11 a 14 anos';
+        case 5:
+        return '15 a 17 anos';
+        case 6:
+        return '18 a 24 anos';
+        case 7:
+        return '25 a 29 anos';
+        case 8:
+        return '30 a 40 anos';
+        case 9:
+        return '41 a 50 anos';
+        case 10:
+        return '51 a 64 anos';
+        case 11:
+        return 'Mais que 64 anos';
+        default:
+        return 'Não declarada';
+    }
+};
diff --git a/src/libs/middlewares/id2str.js b/src/libs/middlewares/id2str.js
index c2fa1fab15eded3a1190bdbe5c918275b2e9b5c5..0a0c2af993a392d86b185e234c2eae448992d1b9 100644
--- a/src/libs/middlewares/id2str.js
+++ b/src/libs/middlewares/id2str.js
@@ -20,6 +20,7 @@ const stateName = require(`${libs}/convert/stateName`);
 const contractType = require(`${libs}/convert/contractType`);
 const ethnicGroupPnad = require(`${libs}/convert/ethnicGroupPnad`);
 const ageRange = require(`${libs}/convert/ageRange`);
+const ageRangeAll = require(`${libs}/convert/ageRangeAll`);
 const fullAgeRange = require(`${libs}/convert/fullAgeRange`);
 const genderPnad = require(`${libs}/convert/genderPnad`);
 const fifthHouseholdIncome = require(`${libs}/convert/fifthHouseholdIncome`);
@@ -28,6 +29,7 @@ const educationLevelBasic = require(`${libs}/convert/educationLevelBasic`);
 const useTransport = require(`${libs}/convert/booleanVariable`);
 const useTransportPublic = require(`${libs}/convert/booleanVariable`);
 const transportationManager = require(`${libs}/convert/transportationManager`);
+const specialClass = require(`${libs}/convert/booleanVariable`);
 
 const ids = {
     gender_id: gender,
@@ -61,13 +63,15 @@ const ids = {
     contract_type_id: contractType,
     ethnic_group_pnad_id: ethnicGroupPnad,
     age_range_id: ageRange,
+    age_range_all_id: ageRangeAll,
     full_age_range_id: fullAgeRange,
     gender_pnad_id: genderPnad,
     fifth_household_income_id: fifthHouseholdIncome,
     extremes_household_income_id: extremesHouseholdIncome,
     use_transport_id: useTransport,
     use_transport_public_id: useTransportPublic,
-    transportation_manager_id: transportationManager
+    transportation_manager_id: transportationManager,
+    special_class_id: specialClass
 };
 
 function transform(removeId=false) {
@@ -130,10 +134,12 @@ module.exports = {
     contractType,
     ethnicGroupPnad,
     ageRange,
+    ageRangeAll,
     fullAgeRange,
     genderPnad,
     fifthHouseholdIncome,
     extremesHouseholdIncome,
     useTransport,
-    transportationManager
+    transportationManager,
+    specialClass
 };
diff --git a/src/libs/middlewares/reqQueryFields.js b/src/libs/middlewares/reqQueryFields.js
index 5b28567fcf5ded59647c712a2a3dbd17719bab00..61f989630effb5bd5a03519641eb0ca94bf781b0 100644
--- a/src/libs/middlewares/reqQueryFields.js
+++ b/src/libs/middlewares/reqQueryFields.js
@@ -240,13 +240,17 @@ class ReqQueryFields {
                         if (Array.isArray(value.resultField)) {
                             value.tableField.forEach((f, i) => {
                                 sql.field(table+'.'+f, value.resultField[i] || f)
-                                    .group(table+'.'+f)
+                                if(!value.dontGroup) {
+                                    sql.group(table+'.'+f)
                                     .order(table+'.'+f);
+                                }
                             })
                         }else{
                             sql.field(table+'.'+value.tableField, value.resultField || value.tableField)
-                                .order(table+'.'+value.tableField)
+                            if(!value.dontGroup) {
+                                sql.order(table+'.'+value.tableField)
                                 .group(table+'.'+value.tableField);
+                            }
                         }
                     }
                     // Se o valor é um campo para ser usado no WHERE
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 49fc2a8d312c439317c235c7f94d8e00dba01406..9d87348408354548ad57e9bec031bfbb71839fec 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -56,6 +56,8 @@ const downloads = require(`${libs}/routes/downloads`);
 
 const infrastructure = require(`${libs}/routes/infrastructure`);
 
+const schoolInfrastructure = require(`${libs}/routes/schoolInfrastructure`);
+
 const distributionFactor = require(`${libs}/routes/distributionFactor`);
 
 const siope = require(`${libs}/routes/siope`);
@@ -74,6 +76,9 @@ const dailyChargeAmount = require(`${libs}/routes/dailyChargeAmount`);
 
 const cub = require(`${libs}/routes/cub`);
 
+const portalMecInep = require(`${libs}/routes/portalMecInep`);
+
+
 api.get('/', (req, res) => {
     res.json({ msg: 'SimCAQ API is running' });
 });
@@ -104,6 +109,7 @@ api.use('/reset', resetToken);
 api.use('/education_years', educationYears);
 api.use('/downloads', downloads);
 api.use('/infrastructure', infrastructure);
+api.use('/school_infrastructure', schoolInfrastructure);
 api.use('/distribution_factor', distributionFactor);
 api.use('/siope', siope);
 api.use('/out_of_school', outOfSchool);
@@ -113,5 +119,6 @@ api.use('/transport', transport);
 api.use('/cub', cub);
 api.use('/auxiliar', auxiliar);
 api.use('/verify_teacher', verifyTeacher);
+api.use('/portal_mec_inep', portalMecInep);
 
 module.exports = api;
diff --git a/src/libs/routes/auxiliar.js b/src/libs/routes/auxiliar.js
index 21e7c5f59074435489bbf5a44d07cc2bbe6bd6ac..a52ce99d6cc55562bc719f93ccc11f92e0d72ecc 100644
--- a/src/libs/routes/auxiliar.js
+++ b/src/libs/routes/auxiliar.js
@@ -238,6 +238,36 @@ rqf.addField({
         foreign: 'escola_municipio_id',
         foreignTable: 'docente'
     }
+}, 'filter').addValueToField({
+    name: 'school',
+    table: 'escola',
+    tableField: ['nome_escola', 'id'],
+    resultField: ['school_name', 'school_id'],
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: ['id', 'ano_censo'],
+        foreign: ['escola_id', 'ano_censo'],
+        foreignTable: 'docente'
+    }
+}, 'dims').addValueToField({
+    name: 'school',
+    table: 'escola',
+    tableField: 'nome_escola',
+    resultField: 'school_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: ['id', 'ano_censo'],
+        foreign: ['escola_id', 'ano_censo'],
+        foreignTable: 'docente'
+    }
 }, 'filter').addValue({
     name: 'location',
     table: 'docente',
@@ -298,7 +328,7 @@ auxiliarApp.get('/', rqf.parse(), (req, res, next) => {
   .from('docente')
   .group('docente.ano_censo')
   .order('docente.ano_censo')
-  .where('(docente.tipo_turma_id <= 3 AND docente.dependencia_adm_id > 1 AND docente.tipo_docente = 2)');
+  .where('(docente.tipo_turma_id <= 3 AND docente.tipo_docente = 2)');
   next();
 }, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar'));
 
@@ -310,7 +340,7 @@ auxiliarApp.get('/count', rqf.parse(), (req, res, next) => {
   .from('docente')
   .group('docente.ano_censo')
   .order('docente.ano_censo')
-  .where('((docente.tipo_turma_id <= 3) AND (docente.dependencia_adm_id = 2 OR docente.dependencia_adm_id = 3) AND (docente.tipo_docente = 2))');
+  .where('(docente.tipo_turma_id <= 3 AND docente.dependencia_adm_id <= 3 AND docente.tipo_docente = 2)');
   next();
 }, rqf.build(), query, addMissing(rqf), id2str.transform(), response('auxiliar'));
 
diff --git a/src/libs/routes/classCount.js b/src/libs/routes/classCount.js
new file mode 100644
index 0000000000000000000000000000000000000000..d415d5a3fdf40d15a70be2a15b505adbeed79901
--- /dev/null
+++ b/src/libs/routes/classCount.js
@@ -0,0 +1,407 @@
+const express = require('express');
+
+const classCountApp = express.Router();
+
+const libs = `${process.cwd()}/libs`;
+
+const squel = require('squel');
+
+const query = require(`${libs}/middlewares/query`).query;
+
+const response = require(`${libs}/middlewares/response`);
+
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+const id2str = require(`${libs}/middlewares/id2str`);
+
+const addMissing = require(`${libs}/middlewares/addMissing`);
+
+const config = require(`${libs}/config`);
+
+const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware;
+
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+  name: 'filter',
+  field: false,
+  where: true
+}).addField({
+  name: 'dims',
+  field: true,
+  where: false
+}).addValueToField({
+  name: 'city',
+  table: 'municipio',
+  tableField: ['nome', 'id'],
+  resultField: ['city_name', 'city_id'],
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'municipio_id',
+    table: 'turma'
+  },
+  join: {
+    primary: 'id',
+    foreign: 'municipio_id',
+    foreignTable: 'turma'
+  }
+}, 'dims').addValueToField({
+  name: 'city',
+  table: 'municipio',
+  tableField: 'nome',
+  resultField: 'city_name',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'municipio_id',
+    table: 'turma'
+  },
+  join: {
+    primary: 'id',
+    foreign: 'municipio_id',
+    foreignTable: 'turma'
+  }
+}, 'filter')
+.addValue({
+  name: 'state',
+  table: 'estado',
+  tableField: 'nome',
+  resultField: 'state_name',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'estado_id',
+    table: 'turma'
+  },
+  join: {
+    primary: 'id',
+    foreign: 'estado_id',
+    foreignTable: 'turma'
+  }
+}).addValue({
+  name: 'region',
+  table: 'regiao',
+  tableField: 'nome',
+  resultField: 'region_name',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'id'
+  },
+  join: {
+    primary: 'id',
+    foreign: 'regiao_id',
+    foreignTable: 'turma'
+  }
+}).addValue({
+  name: 'min_year',
+  table: 'turma',
+  tableField: 'ano_censo',
+  resultField: 'year',
+  where: {
+    relation: '>=',
+    type: 'integer',
+    field: 'ano_censo'
+  }
+}).addValue({
+  name: 'max_year',
+  table: 'turma',
+  tableField: 'ano_censo',
+  resultField: 'year',
+  where: {
+    relation: '<=',
+    type: 'integer',
+    field: 'ano_censo'
+  }
+}).addValue({
+  name:'adm_dependency',
+  table: 'turma',
+  tableField: 'dependencia_adm_id',
+  resultField: 'adm_dependency_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'dependencia_adm_id'
+  }
+}).addValue({
+  name: 'location',
+  table: 'turma',
+  tableField: 'localizacao_id',
+  resultField: 'location_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'localizacao_id'
+  }
+}).addValue({
+  name: 'rural_location',
+  table: 'turma',
+  tableField: 'localidade_area_rural',
+  resultField: 'rural_location_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'localidade_area_rural'
+  }
+}).addValue({
+  name:'education_level_mod',
+  table: 'turma',
+  tableField: 'etapas_mod_ensino_segmento_id',
+  resultField: 'education_level_mod_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'etapas_mod_ensino_segmento_id'
+  }
+}).addValue({
+  name:'education_level_short',
+  table: 'turma',
+  tableField: 'etapa_resumida',
+  resultField: 'education_level_short_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'etapa_resumida'
+  }
+}).addValue({
+  name: 'adm_dependency_detailed',
+  table: 'turma',
+  tableField: 'dependencia_adm_priv',
+  resultField: 'adm_dependency_detailed_id',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'dependencia_adm_priv'
+  }
+}).addValueToField({
+  name: 'school',
+  table: 'escola',
+  tableField: ['nome_escola', 'id'],
+  resultField: ['school_name', 'school_id'],
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'id'
+  },
+  join: {
+    primary: ['id', 'ano_censo'],
+    foreign: ['escola_id', 'ano_censo'],
+    foreignTable: 'turma'
+  }
+}, 'dims').addValueToField({
+  name: 'school',
+  table: 'escola',
+  tableField: 'nome_escola',
+  resultField: 'school_name',
+  where: {
+    relation: '=',
+    type: 'integer',
+    field: 'id'
+  },
+  join: {
+    primary: ['id', 'ano_censo'],
+    foreign: ['escola_id', 'ano_censo'],
+    foreignTable: 'turma'
+  }
+}, 'filter');
+
+classCountApp.get('/year_range', (req, res, next) => {
+  req.sql.from('escola')
+  .field('MIN(escola.ano_censo)', 'start_year')
+  .field('MAX(escola.ano_censo)', 'end_year');
+  next();
+}, query, response('range'));
+
+classCountApp.get('/years', (req, res, next) => {
+  req.sql.from('escola')
+  .field('DISTINCT escola.ano_censo', 'year');
+  next();
+}, query, response('years'));
+
+classCountApp.get('/adm_dependency', (req, res, next) => {
+  req.result = [];
+  for(let i = 1; i <= 4; ++i) {
+    req.result.push({
+      id: i,
+      name: id2str.admDependency(i)
+    });
+  };
+  next();
+}, response('adm_dependency'));
+
+classCountApp.get('/adm_dependency_detailed', (req, res, next) => {
+  req.result = [];
+  for(let i = 1; i <= 6; ++i) {
+    req.result.push({
+      id: i,
+      name: id2str.admDependencyPriv(i)
+    });
+  };
+  next();
+}, response('adm_dependency_detailed'));
+
+classCountApp.get('/location', (req, res, next) => {
+  req.result = [
+    {id: 1, name: 'Urbana'},
+    {id: 2, name: 'Rural'}
+  ];
+  next();
+}, response('location'));
+
+classCountApp.get('/rural_location', (req, res, next) => {
+  req.result = [
+    {id: 1, name: "Urbana"},
+    {id: 2, name: "Rural"},
+    {id: 3, name: "Rural - Área de assentamento"},
+    {id: 4, name: "Rural - Terra indígena"},
+    {id: 5, name: "Rural - Área remanescente de quilombos"},
+    {id: 6, name: "Rural - Unidade de uso sustentável"}
+  ];
+  next();
+}, response('rural_location'));
+
+classCountApp.get('/education_level_mod', (req, res, next) => {
+  req.result = [];
+  for(let i = 1; i <= 10; ++i) {
+    req.result.push({
+      id: i,
+      name: id2str.educationLevelMod(i)
+    });
+  }
+  req.result.push({
+    id: 99,
+    name: id2str.educationLevelMod(99)
+  });
+  next();
+}, response('education_level_mod'));
+
+classCountApp.get('/education_level_short', (req, res, next) => {
+  req.result = [];
+  for(let i = 1; i <= 7; ++i) {
+    req.result.push({
+      id: i,
+      name: id2str.educationLevelShort(i)
+    });
+  }
+  req.result.push({
+    id: 99,
+    name: id2str.educationLevelShort(99)
+  });
+  next();
+}, response('education_level_short'));
+
+classCountApp.get('/source', (req, res, next) => {
+  req.sql.from('fonte')
+  .field('fonte', 'source')
+  .where('tabela = \'turma\'');
+  next();
+}, query, response('source'));
+
+function mediaCalc(response) {
+  let obj = [];
+  response.forEach((result) => {
+    let newObj = {};
+    let keys = Object.keys(result);
+    keys.forEach((key) => {
+      if(key !== "total_classes" && key !== "total_enrollment")
+        newObj[key] = result[key]
+    })
+    newObj.total = result.total_enrollment / result.total_classes;
+    obj.push(newObj);
+  });
+  return(obj);
+}
+
+classCountApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
+  if(("education_level_mod" in req.dims) || ("education_level_mod" in req.filter)) {
+    req.sql.field('COUNT(turma.id)', 'total_classes')
+     .field('SUM(turma.num_matricula)', 'total_enrollment')
+     .field("'Brasil'", 'name')
+     .field('turma.ano_censo', 'year')
+     .from('turma')
+     .group('turma.ano_censo')
+     .order('turma.ano_censo')
+     .where('turma.tipo_turma_id = 0 AND turma.etapas_mod_ensino_segmento_id >= 1 AND turma.etapas_mod_ensino_segmento_id <= 10');
+     next();
+  } else {
+    res.status(400);
+    next({
+      status: 400,
+      message: 'Wrong/No filter specified'
+    });
+  }
+}, rqf.build(), query, id2str.transform(), (req, res, next) => {
+    req.partial = req.result;
+    req.resetSql();
+    req.dims = {};
+    req.filter = {};
+    req.sql.field('COUNT(turma.id)', 'total_classes')
+     .field('SUM(turma.num_matricula)', 'total_enrollment')
+     .field("'Brasil'", 'name')
+     .field('turma.ano_censo', 'year')
+     .from('turma')
+     .group('turma.ano_censo')
+     .order('turma.ano_censo')
+     .where('turma.tipo_turma_id = 0 AND turma.etapas_mod_ensino_segmento_id >= 1 AND turma.etapas_mod_ensino_segmento_id <= 10');
+     next();
+}, query, addMissing(rqf), id2str.transform(), (req, res, next) => {
+  const classCount = mediaCalc(req.partial);
+  const yearClassCount = mediaCalc(req.result);
+  req.result = classCount;
+  yearClassCount.forEach((result) => {
+    let obj = {};
+    obj = result;
+    obj.label = "total_year_media";
+    req.result.push(obj);
+  })
+  next();
+}, response('class_count'));
+
+classCountApp.get('/count', rqf.parse(), rqf.build(), (req, res, next) => {
+  req.sql.field('COUNT(turma.id)', 'total_classes')
+   .field('SUM(turma.num_matricula)', 'total_enrollment')
+   .field("'Brasil'", 'name')
+   .field('turma.ano_censo', 'year')
+   .from('turma')
+   .group('turma.ano_censo')
+   .order('turma.ano_censo')
+   .where('turma.tipo_turma_id = 0 AND turma.dependencia_adm_id <= 3 AND ((turma.etapa_resumida >= 1 AND turma.etapa_resumida <= 7) OR turma.etapa_resumida = 99)');
+   next();
+}, query, id2str.transform(), (req, res, next) => {
+      req.partial = [];
+      if(Object.keys(req.dims).length > 0 || Object.keys(req.filter).length > 0) {
+        req.partial = req.result;
+        req.resetSql();
+        req.dims = {};
+        req.filter = {};
+        req.sql.field('COUNT(turma.id)', 'total_classes')
+         .field('SUM(turma.num_matricula)', 'total_enrollment')
+         .field("'Brasil'", 'name')
+         .field('turma.ano_censo', 'year')
+         .from('turma')
+         .group('turma.ano_censo')
+         .order('turma.ano_censo')
+         .where('turma.tipo_turma_id = 0 AND turma.dependencia_adm_id <= 3 AND ((turma.etapa_resumida >= 1 AND turma.etapa_resumida <= 7) OR turma.etapa_resumida = 99)');
+     }
+     next();
+}, query, addMissing(rqf), id2str.transform(), (req, res, next) => {
+  if(req.partial.length > 0) {
+    const classCount = mediaCalc(req.partial);
+    const yearClassCount = mediaCalc(req.result);
+    req.result = classCount;
+    yearClassCount.forEach((result) => {
+      let obj = {};
+      obj = result;
+      obj.label = "total_year_media";
+      req.result.push(obj);
+    })
+  }
+  else {
+    const classCount = mediaCalc(req.result);
+    req.result = classCount;
+  }
+  next();
+}, response('class_count'));
+
+module.exports = classCountApp;
diff --git a/src/libs/routes/classroomCount.js b/src/libs/routes/classroomCount.js
index e3144507debb9c080a9893304bd50fd05eb68aa0..bdec29e54dca56e3f0eb71184e89645002edf0de 100644
--- a/src/libs/routes/classroomCount.js
+++ b/src/libs/routes/classroomCount.js
@@ -393,7 +393,7 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => {
             // Total de salas
             educationLevel.enrollment.total_classrooms_needed = (educationLevel.enrollment.full_period_classes + educationLevel.enrollment.day_classes/2);
 
-            if(educationLevel.enrollment.night_classes > educationLevel.enrollment.day_classes) educationLevel.enrollment.total_classrooms_needed += (educationLevel.enrollment.night_classes - educationLevel.enrollment.day_classes);
+            if(educationLevel.enrollment.night_classes > (educationLevel.enrollment.day_classes/2)) educationLevel.enrollment.total_classrooms_needed += (educationLevel.enrollment.night_classes - (educationLevel.enrollment.day_classes/2));
 
             educationLevel.enrollment.total_classrooms_needed = Math.ceil(educationLevel.enrollment.total_classrooms_needed);
 
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 839eaba2f0fdc66b09caba1487ae7d04396d2b6e..66268b11409cf918ce8de61779a16b5323669639 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -214,6 +214,32 @@ enrollmentApp.get('/integral_time', (req, res, next) => {
     next();
 }, response('integral_time'));
 
+enrollmentApp.get('/special_class', (req, res, next) => {
+    req.result = [
+        {id: null, name: 'Não Declarado'},
+        {id: 0, name: 'Não'},
+        {id: 1, name: 'Sim'}
+    ];
+    next();
+}, response('special_class'));
+
+enrollmentApp.get('/age_range_all', (req, res, next) => {
+    req.result = [
+        {id: 1, name: '0 a 3 anos'},
+        {id: 2, name: '4 a 5 anos'},
+        {id: 3, name: '6 a 10 anos'},
+        {id: 4, name: '11 a 14 anos'},
+        {id: 5, name: '15 a 17 anos'},
+        {id: 6, name: '18 a 24 anos'},
+        {id: 7, name: '25 a 29 anos'},
+        {id: 8, name: '30 a 40 anos'},
+        {id: 9, name: '41 a 50 anos'},
+        {id: 10, name: '51 a 64 anos'},
+        {id: 11, name: 'Mais que 64 anos'}
+    ];
+    next();
+}, response('age_range_all'));
+
 rqf.addField({
     name: 'filter',
     field: false,
@@ -297,7 +323,22 @@ rqf.addField({
         foreign: 'regiao_id',
         foreignTable: 'matricula'
     }
-}).addValue({
+}).addValueToField({
+    name: 'state',
+    table: 'estado',
+    tableField: ['nome', 'id'],
+    resultField: ['state_name', 'state_id'],
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'estado_id',
+        foreignTable: 'matricula'
+    }
+}, 'dims').addValueToField({
     name: 'state',
     table: 'estado',
     tableField: 'nome',
@@ -312,7 +353,7 @@ rqf.addField({
         foreign: 'estado_id',
         foreignTable: 'matricula'
     }
-}).addValueToField({
+}, 'filter').addValueToField({
     name: 'city',
     table: 'municipio',
     tableField: ['nome', 'id'],
@@ -452,6 +493,26 @@ rqf.addField({
       type: 'boolean',
       field: 'tempo_integral'
   }
+}).addValue({
+  name:'age_range_all',
+  table: 'matricula',
+  tableField: 'faixa_etaria_31_03',
+  resultField: 'age_range_all_id',
+  where: {
+      relation: '=',
+      type: 'integer',
+      field: 'faixa_etaria_31_03'
+  }
+}).addValue({
+  name:'special_class',
+  table: 'matricula',
+  tableField: 'exclusiva_especial',
+  resultField: 'special_class_id',
+  where: {
+      relation: '=',
+      type: 'boolean',
+      field: 'exclusiva_especial'
+  }
 });
 
 enrollmentApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
@@ -469,6 +530,8 @@ enrollmentApp.get('/download', passport.authenticate('bearer', { session: false
 
 enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => {
     req.dims = {};
+    req.dims.state = true;
+    req.dims.city = true;
     req.dims.school_year = true;
     req.dims.location = true;
     req.dims.adm_dependency_detailed = true;
@@ -503,8 +566,12 @@ enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => {
     let i = 0;
     while(i < enrollments.length) {
         let enrollment = enrollments[i];
-        let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id;
-        let schoolYearHash = '' + enrollment.year + enrollment.school_year_id;
+        if(!educationSchoolYear[enrollment.school_year_id]) {
+            ++i;
+            continue;
+        }
+        let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id + enrollment.city_id;
+        let schoolYearHash = '' + enrollment.year + enrollment.school_year_id + enrollment.city_id;
 
         let currentEducation = null;
         // Busca ou cria a etapa de ensino adequada
@@ -524,6 +591,10 @@ enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => {
             let obj = {
                 year: enrollment.year,
                 name: enrollment.name,
+                state_id: enrollment.state_id,
+                state_name: enrollment.state_name,
+                city_id: enrollment.city_id,
+                city_name: enrollment.city_name,
                 education_level_school_year_id: educationSchoolYear[enrollment.school_year_id].id,
                 education_level_school_year_name: educationSchoolYear[enrollment.school_year_id].name,
                 total: 0,
@@ -565,6 +636,10 @@ enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => {
             let obj = {
                 year: enrollment.year,
                 name: enrollment.name,
+                state_id: enrollment.state_id,
+                state_name: enrollment.state_name,
+                city_id: enrollment.city_id,
+                city_name: enrollment.city_name,
                 education_level_school_year_id: enrollment.school_year_id,
                 education_level_school_year_name: enrollment.school_year_name,
                 total: 0,
@@ -672,6 +747,8 @@ enrollmentApp.get('/diagnosis', rqf.parse(), (req, res, next) => {
 
 enrollmentApp.get('/projection', rqf.parse(), (req, res, next) => {
     req.dims = {};
+    req.dims.state = true;
+    req.dims.city = true;
     req.dims.location = true;
     req.dims.school_year = true;
     req.dims.adm_dependency = true;
@@ -702,17 +779,23 @@ enrollmentApp.get('/projection', rqf.parse(), (req, res, next) => {
         }
     }
 
+    console.log(educationSchoolYear);
+
     let result = [];
     let educationLevelSet = new Set();
     let schoolYearSet = new Set();
     let i = 0;
     while(i < enrollments.length) {
         let enrollment = enrollments[i];
-        let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id;
-        let schoolYearHash = '' + enrollment.year + enrollment.school_year_id;
+        if(!educationSchoolYear[enrollment.school_year_id]) {
+            ++i;
+            continue;
+        }
+        let educationLevelHash = '' + enrollment.year + educationSchoolYear[enrollment.school_year_id].id + enrollment.city_id;
+        let schoolYearHash = '' + enrollment.year + enrollment.school_year_id + enrollment.city_id;
 
         let currentEducation = null;
-        // Busca ou cria a etada de ensino adequada
+        // Busca ou cria a etapa de ensino adequada
         if(educationLevelSet.has(educationLevelHash)) {
             let j = 0;
             let edu = result[j];
@@ -729,6 +812,10 @@ enrollmentApp.get('/projection', rqf.parse(), (req, res, next) => {
             let obj = {
                 year: enrollment.year,
                 name: enrollment.name,
+                state_id: enrollment.state_id,
+                state_name: enrollment.state_name,
+                city_id: enrollment.city_id,
+                city_name: enrollment.city_name,
                 education_level_school_year_id: educationSchoolYear[enrollment.school_year_id].id,
                 education_level_school_year_name: educationSchoolYear[enrollment.school_year_id].name,
                 urban_day_total: 0,
@@ -758,6 +845,10 @@ enrollmentApp.get('/projection', rqf.parse(), (req, res, next) => {
             let obj = {
                 year: enrollment.year,
                 name: enrollment.name,
+                state_id: enrollment.state_id,
+                state_name: enrollment.state_name,
+                city_id: enrollment.city_id,
+                city_name: enrollment.city_name,
                 education_level_school_year_id: enrollment.school_year_id,
                 education_level_school_year_name: enrollment.school_year_name,
                 urban_day_total: 0,
diff --git a/src/libs/routes/portalMecInep.js b/src/libs/routes/portalMecInep.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b23589130d1775c89520af1b8ee2827ac31add7
--- /dev/null
+++ b/src/libs/routes/portalMecInep.js
@@ -0,0 +1,60 @@
+const express = require('express');
+
+const portalMecInepApp = express.Router();
+
+const libs = `${process.cwd()}/libs`;
+
+const squel = require('squel');
+
+const query = require(`${libs}/middlewares/query`).query;
+
+const response = require(`${libs}/middlewares/response`);
+
+const id2str = require(`${libs}/middlewares/id2str`);
+
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+const addMissing = require(`${libs}/middlewares/addMissing`);
+
+const config = require(`${libs}/config`);
+
+const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware;
+
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addField({
+    name: 'dims',
+    field: true,
+    where: false
+}).addValue({
+    name: 'school_cod',
+    table: 'escola',
+    tableField: 'id',
+    resultField: 'school_cod_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        table: 'escola',
+        field: 'id'
+    }
+});
+
+portalMecInepApp.get('/', rqf.parse(), (req, res, next) => {
+
+    req.sql.field('DISTINCT escola.id', 'id')
+    .field('escola.nome_escola', 'name')
+    .from('escola')
+    .join('estado', null, 'estado.id=escola.estado_id')
+    .field('estado.nome', 'state_name')
+    .join('municipio', null, 'municipio.id=escola.municipio_id')
+    .field('municipio.nome', 'city_name')
+
+    next();
+
+}, rqf.build(), query, response('portalMec_inep'));
+
+module.exports = portalMecInepApp;
diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js
index 33b5e1cf983e146e30c928f50a22af6d1f98e813..830697742406491451539276261c468cc4024f04 100644
--- a/src/libs/routes/school.js
+++ b/src/libs/routes/school.js
@@ -219,7 +219,44 @@ rqf.addField({
         field: 'ano_censo',
         table: 'escola'
     }
-});
+}).addField({
+    name: 'search',
+    field: true,
+    where: true
+}).addValueToField({
+    name: 'city_name',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    dontGroup: true,
+    where: {
+        relation: 'LIKE',
+        type: 'string',
+        field: 'nome'
+    },
+    join: {
+      primary: 'id',
+      foreign: 'municipio_id',
+      foreignTable: 'escola'
+    }
+}, 'search')
+.addValueToField({
+    name: 'state_name',
+    table: 'estado',
+    tableField: 'nome',
+    resultField: 'state_name',
+    dontGroup: true,
+    where: {
+        relation: 'LIKE',
+        type: 'string',
+        field: 'sigla'
+    },
+    join: {
+      primary: 'id',
+      foreign: 'estado_id',
+      foreignTable: 'escola'
+    }
+}, 'search');
 
 rqfCount.addField({
     name: 'filter',
@@ -464,13 +501,7 @@ rqfCount.addField({
     }
 });
 schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
-    if(typeof req.filter === 'undefined' || Object.keys(req.filter).length === 0) {
-        res.status(400);
-        next({
-            status: 400,
-            message: 'Wrong/No filter specified'
-        });
-    }
+
     req.sql.from('escola')
         .field('escola.id')
         .field('escola.ano_censo', 'year')
diff --git a/src/libs/routes/schoolInfrastructure.js b/src/libs/routes/schoolInfrastructure.js
new file mode 100644
index 0000000000000000000000000000000000000000..c53a02afcef8f9a29c3089ec70241341d030d1fd
--- /dev/null
+++ b/src/libs/routes/schoolInfrastructure.js
@@ -0,0 +1,691 @@
+const express = require('express');
+
+const infrastructureApp = express.Router();
+
+const libs = `${process.cwd()}/libs`;
+
+const log = require(`${libs}/log`)(module);
+
+const squel = require('squel');
+
+const query = require(`${libs}/middlewares/query`).query;
+
+const multiQuery = require(`${libs}/middlewares/multiQuery`);
+
+const response = require(`${libs}/middlewares/response`);
+
+const id2str = require(`${libs}/middlewares/id2str`);
+
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+const config = require(`${libs}/config`);
+
+const cache = require('apicache').options({ debug: config.debug, statusCodes: {include: [200]} }).middleware;
+
+let rqf = new ReqQueryFields();
+
+infrastructureApp.use(cache('15 day'));
+
+infrastructureApp.get('/year_range', (req, res, next) => {
+    req.sql.from('escola')
+    .field('MIN(escola.ano_censo)', 'start_year')
+    .field('MAX(escola.ano_censo)', 'end_year');
+    next();
+}, query, response('range'));
+
+infrastructureApp.get('/years', (req, res, next) => {
+    req.sql.from('escola')
+    .field('DISTINCT escola.ano_censo', 'year');
+    next();
+}, query, response('years'));
+
+infrastructureApp.get('/source', (req, res, next) => {
+    req.sql.from('fonte')
+    .field('fonte', 'source')
+    .where('tabela = \'escola\'');
+    next();
+}, query, response('source'));
+
+infrastructureApp.get('/location', (req, res, next) => {
+    req.result = [
+        {id: 1, name: 'Urbana'},
+        {id: 2, name: 'Rural'}
+    ];
+    next();
+}, response('location'));
+
+infrastructureApp.get('/rural_location', (req, res, next) => {
+    req.result = [
+        {id: 1, name: "Urbana"},
+        {id: 2, name: "Rural"},
+        {id: 3, name: "Rural - Área de assentamento"},
+        {id: 4, name: "Rural - Terra indígena"},
+        {id: 5, name: "Rural - Área remanescente de quilombos"},
+        {id: 6, name: "Rural - Unidade de uso sustentável"}
+    ];
+    next();
+}, response('rural_location'));
+
+infrastructureApp.get('/adm_dependency', (req, res, next) => {
+    req.sql.from('dependencia_adm')
+    .field('id')
+    .field('nome', 'name')
+    .where('id <= 4');
+    next();
+}, query, response('adm_dependency'));
+
+infrastructureApp.get('/adm_dependency_detailed', (req, res, next) => {
+    req.sql.from('dependencia_adm_priv')
+    .field('id', 'id')
+    .field('nome', 'name');
+    next();
+}, query, response('adm_dependency_detailed'));
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addField({
+    name: 'dims',
+    field: true,
+    where: false
+}).addValueToField({
+    name: 'city',
+    table: 'municipio',
+    tableField: ['nome', 'id'],
+    resultField: ['city_name', 'city_id'],
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'municipio_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'municipio_id',
+        foreignTable: 'escola'
+    }
+}, 'dims').addValueToField({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'id',
+    resultField: 'city_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'municipio_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'municipio_id',
+        foreignTable: 'escola'
+    }
+}, 'filter').addValueToField({
+    name: 'state',
+    table: 'estado',
+    tableField: ['nome', 'id'],
+    resultField: ['state_name', 'state_id'],
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'estado_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'estado_id',
+        foreignTable: 'escola'
+    }
+}, 'dims').addValueToField({
+    name: 'state',
+    table: 'estado',
+    tableField: 'id',
+    resultField: 'state_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'estado_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'estado_id',
+        foreignTable: 'escola'
+    }
+}, 'filter').addValue({
+    name: 'region',
+    table: 'regiao',
+    tableField: 'nome',
+    resultField: 'region_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'id'
+    },
+    join: {
+        primary: 'id',
+        foreign: 'regiao_id',
+        foreignTable: 'escola'
+    }
+}).addValue({
+    name: 'location',
+    table: 'escola',
+    tableField: 'cod_localizacao',
+    resultField: 'location_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'cod_localizacao'
+    }
+}).addValue({
+    name: 'rural_location',
+    table: 'escola',
+    tableField: 'localidade_area_rural',
+    resultField: 'rural_location_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'localidade_area_rural'
+    }
+}).addValue({
+    name: 'adm_dependency',
+    table: 'escola',
+    tableField: 'dependencia_adm_id',
+    resultField: 'adm_dependency_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'dependencia_adm_id'
+    }
+}).addValue({
+    name: 'adm_dependency_detailed',
+    table: 'escola',
+    tableField: 'dependencia_adm_priv',
+    resultField: 'adm_dependency_detailed_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'dependencia_adm_priv'
+    }
+}).addValue({
+    name: 'min_year',
+    table: 'escola',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '>=',
+        type: 'integer',
+        field: 'ano_censo'
+    }
+}).addValue({
+    name: 'max_year',
+    table: 'escola',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '<=',
+        type: 'integer',
+        field: 'ano_censo'
+    }
+});
+
+function matchQueries(queryTotal, queryPartial, queryNeeded, zeroPercentage=false) {
+    let match = [];
+    queryTotal.forEach((result) => {
+        let newObj = {};
+        let keys = Object.keys(result);
+        keys.forEach((key) => {
+            newObj[key] = result[key];
+        });
+        let index = keys.indexOf('total');
+        if(index > -1) keys.splice(index, 1);
+        let partialMatch = null;
+        let needMatch = null;
+
+        for(let i = 0; i < queryPartial.length; ++i) {
+            let partial = queryPartial[i];
+            let foundMatch = true;
+            for(let j = 0; j < keys.length; ++j) {
+                let key = keys[j];
+                if(partial[key] !== result[key]) {
+                    foundMatch = false;
+                    break;
+                }
+            }
+            if(foundMatch) {
+                partialMatch = partial;
+                break;
+            }
+        }
+
+        for(let i = 0; i < queryNeeded.length; ++i) {
+            let needed = queryNeeded[i];
+            let foundMatch = true;
+            for(let j = 0; j < keys.length; ++j) {
+                let key = keys[j];
+                if(needed[key] !== result[key]) {
+                    foundMatch = false;
+                    break;
+                }
+            }
+            if(foundMatch) {
+                needMatch = needed;
+                break;
+            }
+        }
+
+        if(partialMatch && needMatch) {
+            newObj.percentage = (partialMatch.total / result.total) * 100;
+            if(zeroPercentage) newObj.percentage = 0;
+            newObj.partial = partialMatch.total;
+            newObj.total = result.total;
+            newObj.need_adaptation = needMatch.total;
+            match.push(newObj);
+        }
+    });
+
+    return match;
+}
+
+infrastructureApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
+    req.querySet = [];
+    req.queryIndex = {};
+
+    // Local de funcionamento
+    let allSchools = req.sql.clone();
+    allSchools.from('escola').field('COUNT(escola.id)', 'total')
+    .field("'Brasil'", 'name')
+    .field('escola.ano_censo', 'year')
+    .group('escola.ano_censo')
+    .where('escola.situacao_de_funcionamento = 1')
+    .where('escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1')
+    .where('escola.local_func_predio_escolar = 1')
+    .where('escola.dependencia_adm_id <= 3')
+    .order('escola.ano_censo');
+    req.queryIndex.allSchools = req.querySet.push(allSchools) - 1;
+
+    let allUrbanSchools = allSchools.clone();
+    allUrbanSchools.where('escola.cod_localizacao = 1');
+    req.queryIndex.allUrbanSchools = req.querySet.push(allUrbanSchools) - 1;
+
+    let allCountrySchools = allSchools.clone();
+    allCountrySchools.where('escola.cod_localizacao = 2');
+    req.queryIndex.allCountrySchools = req.querySet.push(allCountrySchools) - 1;
+
+    let allSchoolsNotSchoolBuilding = req.sql.clone();
+    allSchoolsNotSchoolBuilding.from('escola').field('COUNT(escola.id)', 'total')
+    .field("'Brasil'", 'name')
+    .field('escola.ano_censo', 'year')
+    .group('escola.ano_censo')
+    .where('escola.situacao_de_funcionamento = 1')
+    .where('escola.ensino_regular = 1 OR escola.ensino_eja = 1 OR escola.educacao_profissional = 1')
+    .where('escola.local_func_predio_escolar = 0')
+    .where('escola.dependencia_adm_id <= 3')
+    .order('escola.ano_censo');
+    req.queryIndex.allSchoolsNotSchoolBuilding = req.querySet.push(allSchoolsNotSchoolBuilding) - 1;
+
+    // Bibliotecas
+    req.queryIndex.allLibraries = req.queryIndex.allUrbanSchools;
+
+    let haveLibraries = allUrbanSchools.clone();
+    haveLibraries.where('escola.biblioteca = 1');
+    req.queryIndex.haveLibraries = req.querySet.push(haveLibraries) - 1;
+
+    let needLibraries = allUrbanSchools.clone();
+    needLibraries.where('escola.biblioteca = 0');
+    req.queryIndex.needLibraries = req.querySet.push(needLibraries) - 1;
+
+    // Bibliotecas/Sala de leitura
+    req.queryIndex.allLibrariesReadingRoom = req.queryIndex.allCountrySchools;
+
+    let haveLibrariesReadingRoom = allCountrySchools.clone();
+    haveLibrariesReadingRoom.where('escola.biblioteca_sala_leitura = 1');
+    req.queryIndex.haveLibrariesReadingRoom = req.querySet.push(haveLibrariesReadingRoom) - 1;
+
+    let needLibrariesReadingRoom = allCountrySchools.clone();
+    needLibrariesReadingRoom.where('escola.biblioteca_sala_leitura = 0');
+    req.queryIndex.needLibrariesReadingRoom = req.querySet.push(needLibrariesReadingRoom) - 1;
+
+    // Laboratório de informática
+    let allInfLab = allSchools.clone();
+    allInfLab.where('escola.reg_infantil_preescola = 1 OR escola.reg_fund_ai = 1 OR escola.reg_fund_af = 1 OR escola.reg_medio_medio = 1 OR escola.reg_medio_integrado = 1 OR escola.reg_medio_normal = 1 OR escola.ensino_eja_fund = 1 OR escola.ensino_eja_medio = 1 OR escola.ensino_eja_prof = 1');
+    req.queryIndex.allInfLab = req.querySet.push(allInfLab) - 1;
+
+    let haveInfLab = allInfLab.clone();
+    haveInfLab.where('escola.lab_informatica = 1');
+    req.queryIndex.haveInfLab = req.querySet.push(haveInfLab) - 1;
+
+    let needInfLab = allInfLab.clone();
+    needInfLab.where('escola.lab_informatica = 0');
+    req.queryIndex.needInfLab = req.querySet.push(needInfLab) - 1;
+
+    // Laboratório de ciências
+    let allScienceLab = allSchools.clone();
+    allScienceLab.where('escola.reg_fund_af = 1 OR escola.reg_medio_medio = 1 OR escola.reg_medio_integrado = 1 OR escola.reg_medio_normal = 1 OR escola.ensino_eja_fund = 1 OR escola.ensino_eja_medio = 1 OR escola.ensino_eja_prof = 1');
+    req.queryIndex.allScienceLab = req.querySet.push(allScienceLab) - 1;
+
+    let haveScienceLab = allScienceLab.clone();
+    haveScienceLab.where('escola.lab_ciencias = 1');
+    req.queryIndex.haveScienceLab = req.querySet.push(haveScienceLab) - 1;
+
+    let needScienceLab = allScienceLab.clone();
+    needScienceLab.where('escola.lab_ciencias = 0');
+    req.queryIndex.needScienceLab = req.querySet.push(needScienceLab) - 1;
+
+    // Parque infantil
+    let allKidsPark = allSchools.clone();
+    allKidsPark.where('escola.reg_infantil_creche = 1 OR escola.reg_infantil_preescola = 1 OR escola.reg_fund_ai = 1');
+    req.queryIndex.allKidsPark = req.querySet.push(allKidsPark) - 1;
+
+    let haveKidsPark = allKidsPark.clone();
+    haveKidsPark.where('escola.parque_infantil = 1');
+    req.queryIndex.haveKidsPark = req.querySet.push(haveKidsPark) - 1;
+
+    let needKidsPark = allKidsPark.clone();
+    needKidsPark.where('escola.parque_infantil = 0');
+    req.queryIndex.needKidsPark = req.querySet.push(needKidsPark) - 1;
+
+    // Berçário
+    let allCribs = allSchools.clone();
+    allCribs.where('escola.reg_infantil_creche = 1');
+    req.queryIndex.allCribs = req.querySet.push(allCribs) - 1;
+
+    let haveCribs = allCribs.clone();
+    haveCribs.where('escola.bercario = 1');
+    req.queryIndex.haveCribs = req.querySet.push(haveCribs) - 1;
+
+    let needCribs = allCribs.clone();
+    needCribs.where('escola.bercario = 0');
+    req.queryIndex.needCribs = req.querySet.push(needCribs) - 1;
+
+    // Quadra Coberta
+    let allSportsCourt = allSchools.clone();
+    allSportsCourt.where('escola.reg_fund_ai = 1 OR escola.reg_fund_af = 1 OR escola.reg_medio_medio = 1 OR escola.reg_medio_integrado OR escola.reg_medio_normal = 1 OR escola.ensino_eja_fund = 1 OR escola.ensino_eja_medio = 1 OR escola.ensino_eja_prof = 1');
+    req.queryIndex.allSportsCourt = req.querySet.push(allSportsCourt) - 1;
+
+    let haveSportsCourt = allSportsCourt.clone();
+    haveSportsCourt.where('escola.quadra_esportes = 1');
+    req.queryIndex.haveSportsCourt = req.querySet.push(haveSportsCourt) - 1;
+
+    let needSportsCourt = allSportsCourt.clone();
+    needSportsCourt.where('escola.quadra_esportes = 0');
+    req.queryIndex.needSportsCourt = req.querySet.push(needSportsCourt) - 1;
+
+    // Cobertura de quadra esportiva
+    let allSportsCourtCoverage = allSportsCourt.clone();
+    allSportsCourtCoverage.where('escola.quadra_esportes_descoberta = 1');
+    req.queryIndex.allSportsCourtCoverage = req.querySet.push(allSportsCourtCoverage);
+
+    req.queryIndex.haveSportsCourtCoverage = req.queryIndex.allSportsCourtCoverage;
+
+    req.queryIndex.needSportsCourtCoverage = req.queryIndex.allSportsCourtCoverage;
+
+    // Pátio
+    req.queryIndex.allCourtyard = req.queryIndex.allSchools;
+
+    let haveCourtyard = allSchools.clone();
+    haveCourtyard.where('escola.patio_coberto = 1 OR escola.patio_descoberto = 1');
+    req.queryIndex.haveCourtyard = req.querySet.push(haveCourtyard) - 1;
+
+    let needCourtyard = allSchools.clone();
+    needCourtyard.where('escola.patio_descoberto = 0 AND escola.patio_descoberto = 0');
+    req.queryIndex.needCourtyard = req.querySet.push(needCourtyard) - 1;
+
+    // Cobertura do Pátio
+    let allCourtyardCoverage = allSchools.clone();
+    allCourtyardCoverage.where('escola.patio_coberto=0 AND escola.patio_descoberto = 1');
+    req.queryIndex.allCourtyardCoverage = req.querySet.push(allCourtyardCoverage) - 1;
+
+    req.queryIndex.haveCourtyardCoverage = req.queryIndex.allCourtyardCoverage;
+
+    req.queryIndex.needCourtyardCoverage = req.queryIndex.allCourtyardCoverage;
+
+    // Sala de direção
+    req.queryIndex.allDirectorRoom = req.queryIndex.allLibraries;
+
+    let haveDirectorRoom = allUrbanSchools.clone();
+    haveDirectorRoom.where('escola.sala_diretoria = 1');
+    req.queryIndex.haveDirectorRoom = req.querySet.push(haveDirectorRoom) - 1;
+
+    let needDirectorRoom = allUrbanSchools.clone();
+    needDirectorRoom.where('escola.sala_diretoria = 0');
+    req.queryIndex.needDirectorRoom = req.querySet.push(needDirectorRoom) - 1;
+
+    // Secretaria
+    req.queryIndex.allSecretary = req.queryIndex.allSchools;
+
+    let haveSecretary = allSchools.clone();
+    haveSecretary.where('escola.secretaria = 1');
+    req.queryIndex.haveSecretary = req.querySet.push(haveSecretary) - 1;
+
+    let needSecretary = allSchools.clone();
+    needSecretary.where('escola.secretaria = 0');
+    req.queryIndex.needSecretary = req.querySet.push(needSecretary) - 1;
+
+    // Sala de professores
+    req.queryIndex.allTeacherRoom = req.queryIndex.allSchools;
+
+    let haveTeacherRoom = allSchools.clone();
+    haveTeacherRoom.where('escola.sala_professor = 1');
+    req.queryIndex.haveTeacherRoom = req.querySet.push(haveTeacherRoom) - 1;
+
+    let needTeacherRoom = allSchools.clone();
+    needTeacherRoom.where('escola.sala_professor = 0');
+    req.queryIndex.needTeacherRoom = req.querySet.push(needTeacherRoom) - 1;
+
+    // Cozinha
+    req.queryIndex.allKitchen = req.queryIndex.allSchools;
+
+    let haveKitchen = allSchools.clone();
+    haveKitchen.where('escola.cozinha = 1');
+    req.queryIndex.haveKitchen = req.querySet.push(haveKitchen) - 1;
+
+    let needKitchen = allSchools.clone();
+    needKitchen.where('escola.cozinha = 0');
+    req.queryIndex.needKitchen = req.querySet.push(needKitchen) - 1;
+
+    // Despensa
+    req.queryIndex.allStoreroom = req.queryIndex.allSchools;
+
+    let haveStoreroom = allSchools.clone();
+    haveStoreroom.where('escola.despensa = 1');
+    req.queryIndex.haveStoreroom = req.querySet.push(haveStoreroom) - 1;
+
+    let needStoreroom = allSchools.clone();
+    needStoreroom.where('escola.despensa = 0');
+    req.queryIndex.needStoreroom = req.querySet.push(needStoreroom) - 1;
+
+    // Almoxarifado
+    req.queryIndex.allWarehouse = req.queryIndex.allSchools;
+
+    let haveWarehouse = allSchools.clone();
+    haveWarehouse.where('escola.almoxarifado = 1');
+    req.queryIndex.haveWarehouse = req.querySet.push(haveWarehouse) - 1;
+
+    let needWarehouse = allSchools.clone();
+    needWarehouse.where('escola.almoxarifado = 1');
+    req.queryIndex.needWarehouse = req.querySet.push(needWarehouse) - 1;
+
+    // Internet
+    req.queryIndex.allInternet = req.queryIndex.allLibrariesReadingRoom;
+
+    let haveInternet = allCountrySchools.clone();
+    haveInternet.where('escola.internet = 1');
+    req.queryIndex.haveInternet = req.querySet.push(haveInternet) - 1;
+
+    let needInternet = allCountrySchools.clone();
+    needInternet.where('escola.internet = 0');
+    req.queryIndex.needInternet = req.querySet.push(needInternet) - 1;
+
+    // Internet banda larga
+    req.queryIndex.allBroadbandInternet = req.queryIndex.allLibraries;
+
+    let haveBroadbandInternet = allUrbanSchools.clone();
+    haveBroadbandInternet.where('escola.internet_banda_larga = 1');
+    req.queryIndex.haveBroadbandInternet = req.querySet.push(haveBroadbandInternet) - 1;
+
+    let needBroadbandInternet = allUrbanSchools.clone();
+    needBroadbandInternet.where('escola.internet_banda_larga = 0');
+    req.queryIndex.needBroadbandInternet = req.querySet.push(needBroadbandInternet) - 1;
+
+    // Sanitário dentro do prédio
+    req.queryIndex.allInsideBathroom = req.queryIndex.allSchools;
+
+    let haveInsideBathroom = allSchools.clone();
+    haveInsideBathroom.where('escola.sanitario_dentro_predio = 1');
+    req.queryIndex.haveInsideBathroom = req.querySet.push(haveInsideBathroom) - 1;
+
+    let needInsideBathroom = allSchools.clone();
+    needInsideBathroom.where('escola.sanitario_dentro_predio = 0');
+    req.queryIndex.needInsideBathroom = req.querySet.push(needInsideBathroom) - 1;
+
+    // Banheiro adequado para educação infantil dentro do prédio
+    req.queryIndex.allInsideKidsBathroom = req.queryIndex.allKidsPark;
+
+    let haveInsideKidsBathroom = allKidsPark.clone();
+    haveInsideKidsBathroom.where('escola.sanitario_ei = 1');
+    req.queryIndex.haveInsideKidsBathroom = req.querySet.push(haveInsideKidsBathroom) - 1;
+
+    let needInsideKidsBathroom = allKidsPark.clone();
+    needInsideKidsBathroom.where('escola.sanitario_ei = 0');
+    req.queryIndex.needInsideKidsBathroom = req.querySet.push(needInsideKidsBathroom) - 1;
+
+    // Fornecimento de energia
+    req.queryIndex.allEletricPower = req.queryIndex.allSchools;
+
+    let haveEletricPower = allSchools.clone();
+    haveEletricPower.where('escola.fornecimento_energia = 1');
+    req.queryIndex.haveEletricPower = req.querySet.push(haveEletricPower) - 1;
+
+    let needEletricPower = allSchools.clone();
+    needEletricPower.where('escola.fornecimento_energia = 0');
+    req.queryIndex.needEletricPower = req.querySet.push(needEletricPower) - 1;
+
+    // Abastecimento de água
+    req.queryIndex.allWaterSupply = req.queryIndex.allSchools;
+
+    let haveWaterSupply = allSchools.clone();
+    haveWaterSupply.where('escola.fornecimento_agua = 1');
+    req.queryIndex.haveWaterSupply = req.querySet.push(haveWaterSupply) - 1;
+
+    let needWaterSupply = allSchools.clone();
+    needWaterSupply.where('escola.fornecimento_agua = 0');
+    req.queryIndex.needWaterSupply = req.querySet.push(needWaterSupply) - 1;
+
+    // Água filtrada
+    req.queryIndex.allFilteredWater = req.queryIndex.allSchools;
+
+    let haveFilteredWater = allSchools.clone();
+    haveFilteredWater.where('escola.agua_filtrada = 1');
+    req.queryIndex.haveFilteredWater = req.querySet.push(haveFilteredWater) - 1;
+
+    let needFilteredWater = allSchools.clone();
+    needFilteredWater.where('escola.agua_filtrada = 0');
+    req.queryIndex.needFilteredWater = req.querySet.push(needFilteredWater) - 1;
+
+    // Coleta de esgoto
+    req.queryIndex.allSewage = req.queryIndex.allSchools;
+
+    let haveSewage = allSchools.clone();
+    haveSewage.where('escola.esgoto_sanitario = 1');
+    req.queryIndex.haveSewage = req.querySet.push(haveSewage) - 1;
+
+    let needSewage = allSchools.clone();
+    needSewage.where('escola.esgoto_sanitario = 0');
+    req.queryIndex.needSewage = req.querySet.push(needSewage) - 1;
+
+    // Dependências adaptada para pessoas com deficiências
+    req.queryIndex.allAdaptedBuilding = req.queryIndex.allSchools;
+
+    let haveAdaptedBuilding = allSchools.clone();
+    haveAdaptedBuilding.where('escola.dependencias_pne = 1');
+    req.queryIndex.haveAdaptedBuilding = req.querySet.push(haveAdaptedBuilding) - 1;
+
+    let needAdaptedBuilding = allSchools.clone();
+    needAdaptedBuilding.where('escola.dependencias_pne = 0');
+    req.queryIndex.needAdaptedBuilding = req.querySet.push(needAdaptedBuilding) - 1;
+
+    // Banheiros adaptados para pessoas com deficiências
+    req.queryIndex.allSpecialBathroom = req.queryIndex.allSchools;
+
+    let haveSpecialBathroom = allSchools.clone();
+    haveSpecialBathroom.where('escola.sanitario_pne = 1');
+    req.queryIndex.haveSpecialBathroom = req.querySet.push(haveSpecialBathroom) - 1;
+
+    let needSpecialBathroom = allSchools.clone();
+    needSpecialBathroom.where('escola.sanitario_pne = 1');
+    req.queryIndex.needSpecialBathroom = req.querySet.push(needSpecialBathroom) - 1;
+
+
+    next();
+}, multiQuery, (req, res, next) => {
+    let schools_in_school_buildings = req.result[req.queryIndex.allSchools];
+    let urban_schools_in_school_buildings = req.result[req.queryIndex.allUrbanSchools];
+    let country_schools_in_school_buildings = req.result[req.queryIndex.allCountrySchools];
+    let schools_not_in_school_buildings = req.result[req.queryIndex.allSchoolsNotSchoolBuilding];
+    // Faz o matching entre os resultados
+    let libraries = matchQueries(req.result[req.queryIndex.allLibraries], req.result[req.queryIndex.haveLibraries], req.result[req.queryIndex.needLibraries]);
+    let libraries_reading_room = matchQueries(req.result[req.queryIndex.allLibrariesReadingRoom], req.result[req.queryIndex.haveLibrariesReadingRoom], req.result[req.queryIndex.needLibrariesReadingRoom]);
+    let computer_lab = matchQueries(req.result[req.queryIndex.allInfLab], req.result[req.queryIndex.haveInfLab], req.result[req.queryIndex.needInfLab]);
+    let science_lab = matchQueries(req.result[req.queryIndex.allScienceLab], req.result[req.queryIndex.haveScienceLab], req.result[req.queryIndex.needScienceLab]);
+    let kids_park = matchQueries(req.result[req.queryIndex.allKidsPark], req.result[req.queryIndex.haveKidsPark], req.result[req.queryIndex.needKidsPark]);
+    let nursery = matchQueries(req.result[req.queryIndex.allCribs], req.result[req.queryIndex.haveCribs], req.result[req.queryIndex.needCribs]);
+    let sports_court = matchQueries(req.result[req.queryIndex.allSportsCourt], req.result[req.queryIndex.haveSportsCourt], req.result[req.queryIndex.needSportsCourt]);
+    let sports_court_coverage = matchQueries(req.result[req.queryIndex.allSportsCourtCoverage], req.result[req.queryIndex.haveSportsCourtCoverage], req.result[req.queryIndex.needSportsCourtCoverage], true);
+    let courtyard = matchQueries(req.result[req.queryIndex.allCourtyard], req.result[req.queryIndex.haveCourtyard], req.result[req.queryIndex.needCourtyard]);
+    let courtyard_coverage = matchQueries(req.result[req.queryIndex.allCourtyardCoverage], req.result[req.queryIndex.haveCourtyardCoverage], req.result[req.queryIndex.needCourtyardCoverage], true);
+    let director_room = matchQueries(req.result[req.queryIndex.allDirectorRoom], req.result[req.queryIndex.haveDirectorRoom], req.result[req.queryIndex.needDirectorRoom]);
+    let secretary = matchQueries(req.result[req.queryIndex.allSecretary], req.result[req.queryIndex.haveSecretary], req.result[req.queryIndex.needSecretary]);
+    let teacher_room = matchQueries(req.result[req.queryIndex.allTeacherRoom], req.result[req.queryIndex.haveTeacherRoom], req.result[req.queryIndex.needTeacherRoom]);
+    let kitchen = matchQueries(req.result[req.queryIndex.allKitchen], req.result[req.queryIndex.haveKitchen], req.result[req.queryIndex.needKitchen]);
+    let storeroom = matchQueries(req.result[req.queryIndex.allStoreroom], req.result[req.queryIndex.haveStoreroom], req.result[req.queryIndex.needStoreroom]);
+    let warehouse = matchQueries(req.result[req.queryIndex.allWarehouse], req.result[req.queryIndex.haveWarehouse], req.result[req.queryIndex.needWarehouse]);
+    let internet = matchQueries(req.result[req.queryIndex.allInternet], req.result[req.queryIndex.haveInternet], req.result[req.queryIndex.needInternet]);
+    let broadband_internet = matchQueries(req.result[req.queryIndex.allBroadbandInternet], req.result[req.queryIndex.haveBroadbandInternet], req.result[req.queryIndex.needBroadbandInternet]);
+    let inside_bathroom = matchQueries(req.result[req.queryIndex.allInsideBathroom], req.result[req.queryIndex.haveInsideBathroom], req.result[req.queryIndex.needInsideBathroom]);
+    let inside_kids_bathroom = matchQueries(req.result[req.queryIndex.allInsideKidsBathroom], req.result[req.queryIndex.haveInsideKidsBathroom], req.result[req.queryIndex.needInsideKidsBathroom]);
+    let eletrical_power = matchQueries(req.result[req.queryIndex.allEletricPower], req.result[req.queryIndex.haveEletricPower], req.result[req.queryIndex.needEletricPower]);
+    let water_supply = matchQueries(req.result[req.queryIndex.allWaterSupply], req.result[req.queryIndex.haveWaterSupply], req.result[req.queryIndex.needWaterSupply]);
+    let filtered_water = matchQueries(req.result[req.queryIndex.allFilteredWater], req.result[req.queryIndex.haveFilteredWater], req.result[req.queryIndex.needFilteredWater]);
+    let sewage = matchQueries(req.result[req.queryIndex.allSewage], req.result[req.queryIndex.haveSewage], req.result[req.queryIndex.needSewage]);
+    let adapted_building = matchQueries(req.result[req.queryIndex.allAdaptedBuilding], req.result[req.queryIndex.haveAdaptedBuilding], req.result[req.queryIndex.needAdaptedBuilding]);
+    let adapted_bathroom = matchQueries(req.result[req.queryIndex.allSpecialBathroom], req.result[req.queryIndex.haveSpecialBathroom], req.result[req.queryIndex.needSpecialBathroom]);
+
+    req.result = [{
+        schools_in_school_buildings,
+        urban_schools_in_school_buildings,
+        country_schools_in_school_buildings,
+        schools_not_in_school_buildings,
+        libraries,
+        libraries_reading_room,
+        computer_lab,
+        science_lab,
+        kids_park,
+        nursery,
+        sports_court,
+        sports_court_coverage,
+        courtyard,
+        courtyard_coverage,
+        director_room,
+        secretary,
+        teacher_room,
+        kitchen,
+        storeroom,
+        warehouse,
+        internet,
+        broadband_internet,
+        inside_bathroom,
+        inside_kids_bathroom,
+        eletric_energy: eletrical_power,
+        water_supply,
+        filtered_water,
+        sewage_treatment: sewage,
+        adapted_building,
+        special_bathroom: adapted_bathroom
+    }];
+
+    next();
+}, id2str.multitransform(false), response('infrastructure'));
+
+module.exports = infrastructureApp;
diff --git a/src/libs/routes/transport.js b/src/libs/routes/transport.js
index 3b6b38bfea68f857f09a62a6cff1e9edcaa0eb4c..04062b1ace6e1a26117b706d3a1733c984429631 100644
--- a/src/libs/routes/transport.js
+++ b/src/libs/routes/transport.js
@@ -360,7 +360,6 @@ transportApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     .where('matricula.tipo <= 3');
     req.queryIndex.allEnrollmentTransport = req.querySet.push(allEnrollmentTransport) - 1;
 
-
     let allTransports = req.sql.clone()
     allTransports.field('COUNT(*)', 'total')
     .field("'Brasil'", 'name')