=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveService.java 2010-10-01 09:05:32 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveService.java 2010-10-24 15:41:13 +0000 @@ -39,4 +39,8 @@ int archiveData( Date startDate, Date endDate, DataArchiveOperation operation, DataEliminationStrategy strategy ); int getNumberOfOverlappingValues(); + + int archivePatientData( Date startDate, Date endDate, DataArchiveOperation operation, DataEliminationStrategy strategy ); + + int getNumberOfOverlappingPatientValues(); } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveStore.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveStore.java 2010-04-12 21:23:33 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataarchive/DataArchiveStore.java 2010-10-24 15:41:13 +0000 @@ -35,16 +35,35 @@ public interface DataArchiveStore { void archiveData( Date startDate, Date endDate ); - + void unArchiveData( Date startDate, Date endDate ); - + int getNumberOfOverlappingValues(); - + int getNumberOfArchivedValues(); - + void deleteRegularOverlappingData(); - + void deleteArchivedOverlappingData(); - + void deleteOldestOverlappingData(); + + // ------------------------------------------------------------------------- + // Archive for patient data value + // ------------------------------------------------------------------------- + + void archivePatientData( Date startDate, Date endDate ); + + void unArchivePatientData( Date startDate, Date endDate ); + + int getNumberOfOverlappingPatientValues(); + + int getNumberOfArchivedPatientValues(); + + void deleteRegularOverlappingPatientData(); + + void deleteArchivedOverlappingPatientData(); + + void deleteOldestOverlappingPatientData(); + } === modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/DefaultDataArchiveService.java' --- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/DefaultDataArchiveService.java 2010-10-01 09:05:32 +0000 +++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/DefaultDataArchiveService.java 2010-10-24 15:41:13 +0000 @@ -92,4 +92,46 @@ { return dataArchiveStore.getNumberOfOverlappingValues(); } + + @Transactional + public int archivePatientData( Date startDate, Date endDate, DataArchiveOperation operation, DataEliminationStrategy strategy ) + { + // --------------------------------------------------------------------- + // Eliminate duplicate data + // --------------------------------------------------------------------- + + if ( DataEliminationStrategy.ARCHIVE.equals( strategy ) ) + { + dataArchiveStore.deleteArchivedOverlappingPatientData(); + } + else if ( DataEliminationStrategy.REGULAR.equals( strategy ) ) + { + dataArchiveStore.deleteRegularOverlappingPatientData(); + } + else // OLDEST + { + dataArchiveStore.deleteOldestOverlappingPatientData(); + } + + // --------------------------------------------------------------------- + // Archive data + // --------------------------------------------------------------------- + + if ( DataArchiveOperation.ARCHIVE.equals( operation ) ) + { + dataArchiveStore.archivePatientData( startDate, endDate ); + } + else // UNARCHIVE + { + dataArchiveStore.unArchivePatientData( startDate, endDate ); + } + + return dataArchiveStore.getNumberOfArchivedPatientValues(); + } + + public int getNumberOfOverlappingPatientValues() + { + return dataArchiveStore.getNumberOfOverlappingPatientValues(); + } + } === modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/jdbc/JdbcDataArchiveStore.java' --- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/jdbc/JdbcDataArchiveStore.java 2010-10-04 08:56:54 +0000 +++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataarchive/jdbc/JdbcDataArchiveStore.java 2010-10-24 15:41:13 +0000 @@ -57,22 +57,20 @@ private StatementBuilder statementBuilder; // ------------------------------------------------------------------------- - // Dependencies + // Implementation methods for Data values // ------------------------------------------------------------------------- public void archiveData( Date startDate, Date endDate ) { // Move data from datavalue to datavaluearchive - - String sql = "INSERT INTO datavaluearchive ( " - + "SELECT d.* FROM datavalue AS d " - + "JOIN period AS p ON d.periodid=p.periodid " - + "WHERE p.startdate>='" + getMediumDateString( startDate ) + "' " - + "AND p.enddate<='" + getMediumDateString( endDate ) + "' );"; + + String sql = "INSERT INTO datavaluearchive ( " + "SELECT d.* FROM datavalue AS d " + + "JOIN period AS p ON d.periodid=p.periodid " + "WHERE p.startdate>='" + getMediumDateString( startDate ) + "' " + + "AND p.enddate<='" + getMediumDateString( endDate ) + "' );"; log.info( sql ); jdbcTemplate.execute( sql ); - + // Delete data from datavalue sql = statementBuilder.archiveData( getMediumDateString( startDate ), getMediumDateString( endDate ) ); @@ -85,11 +83,9 @@ { // Move data from datavalue to datavaluearchive - String sql = "INSERT INTO datavalue ( " - + "SELECT a.* FROM datavaluearchive AS a " - + "JOIN period AS p ON a.periodid=p.periodid " - + "WHERE p.startdate>='" + getMediumDateString( startDate )+ "' " - + "AND p.enddate<='" + getMediumDateString( endDate ) + "' );"; + String sql = "INSERT INTO datavalue ( " + "SELECT a.* FROM datavaluearchive AS a " + + "JOIN period AS p ON a.periodid=p.periodid " + "WHERE p.startdate>='" + getMediumDateString( startDate ) + "' " + + "AND p.enddate<='" + getMediumDateString( endDate ) + "' );"; log.info( sql ); jdbcTemplate.execute( sql ); @@ -105,13 +101,11 @@ public int getNumberOfOverlappingValues() { String sql = "SELECT COUNT(*) FROM datavaluearchive AS a " - + "JOIN datavalue AS d ON a.dataelementid=d.dataelementid " - + "AND a.periodid=d.periodid " - + "AND a.sourceid=d.sourceid " - + "AND a.categoryoptioncomboid=d.categoryoptioncomboid;"; + + "JOIN datavalue AS d ON a.dataelementid=d.dataelementid " + "AND a.periodid=d.periodid " + + "AND a.sourceid=d.sourceid " + "AND a.categoryoptioncomboid=d.categoryoptioncomboid;"; log.info( sql ); - + return jdbcTemplate.queryForInt( sql ); } @@ -120,7 +114,7 @@ String sql = "SELECT COUNT(*) as dem FROM datavaluearchive;"; log.info( sql ); - return jdbcTemplate.queryForInt( sql ); + return jdbcTemplate.queryForInt( sql ); } public void deleteRegularOverlappingData() @@ -155,4 +149,108 @@ log.info( sql ); jdbcTemplate.execute( sql ); } + + // ------------------------------------------------------------------------- + // Implementation methods for Patient data values + // ------------------------------------------------------------------------- + + public void archivePatientData( Date startDate, Date endDate ) + { + // Move data from patientdatavalue to patientdatavaluearchive + + String sql ="INSERT INTO patientdatavaluearchive ( " + "SELECT pdv.* FROM patientdatavalue AS pdv " + + "INNER JOIN programstageinstance AS psi " + + "ON pdv.programstageinstanceid = psi.programstageinstanceid " + + "INNER JOIN programinstance AS pi " + + "ON pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + getMediumDateString( startDate ) + "' " + + "AND pi.enddate <= '" + getMediumDateString( endDate ) + "' );"; + + log.info( sql ); + jdbcTemplate.execute( sql ); + + // Delete data from patientdatavalue + + sql = statementBuilder.archivePatientData( getMediumDateString( startDate ), getMediumDateString( endDate ) ); + + log.info( sql ); + jdbcTemplate.execute( sql ); + } + + public void unArchivePatientData( Date startDate, Date endDate ) + { + // Move data from patientdatavalue to patientdatavaluearchive + + String sql ="INSERT INTO patientdatavalue ( " + "SELECT * FROM patientdatavaluearchive AS pdv " + + "INNER JOIN programstageinstance AS psi " + + "ON pdv.programstageinstanceid = psi.programstageinstanceid " + + "INNER JOIN programinstance AS pi " + + "ON pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + getMediumDateString( startDate ) + "' " + + "AND pi.enddate <= '" + getMediumDateString( endDate ) + "' );"; + + log.info( sql ); + jdbcTemplate.execute( sql ); + + // Delete data from patientdatavalue + + sql = statementBuilder.unArchivePatientData( getMediumDateString( startDate ), getMediumDateString( endDate ) ); + + log.info( sql ); + jdbcTemplate.execute( sql ); + } + + public int getNumberOfOverlappingPatientValues() + { + String sql = "SELECT COUNT(*) FROM patientdatavaluearchive AS pdv " + + "INNER JOIN programstageinstance AS psi " + + "ON pdv.programstageinstanceid = psi.programstageinstanceid " + + "INNER JOIN programinstance AS pi " + + "ON pi.programinstanceid = psi.programinstanceid"; + log.info( sql ); + + return jdbcTemplate.queryForInt( sql ); + } + + public int getNumberOfArchivedPatientValues() + { + String sql = "SELECT COUNT(*) as dem FROM patientdatavaluearchive;"; + + log.info( sql ); + return jdbcTemplate.queryForInt( sql ); + } + + public void deleteRegularOverlappingPatientData() + { + String sql = statementBuilder.deleteRegularOverlappingPatientData(); + + log.info( sql ); + jdbcTemplate.execute( sql ); + } + + public void deleteArchivedOverlappingPatientData() + { + String sql = statementBuilder.deleteArchivedOverlappingPatientData(); + + log.info( sql ); + jdbcTemplate.execute( sql ); + } + + public void deleteOldestOverlappingPatientData() + { + // Delete overlaps from patientdatavalue which are older than patientdatavaluearchive + + String sql = statementBuilder.deleteOldestOverlappingPatientDataValue(); + + log.info( sql ); + jdbcTemplate.execute( sql ); + + // Delete overlaps from patientdatavaluearchive which are older than patientdatavalue + + sql = statementBuilder.deleteOldestOverlappingPatientArchiveData(); + + log.info( sql ); + jdbcTemplate.execute( sql ); + } + } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableCreator.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableCreator.java 2010-05-12 16:27:25 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableCreator.java 2010-10-24 15:41:13 +0000 @@ -160,5 +160,34 @@ { log.info( "Table datavaluearchive exists" ); } + + // ----------------------------------------------------------------- + // ArchivedPatientDataValue + // ----------------------------------------------------------------- + + try + { + final String sql = + "CREATE TABLE patientdatavaluearchive ( " + + " programstageinstanceid integer NOT NULL, " + + " dataelementid integer NOT NULL, " + + " organisationunitid integer NOT NULL, " + + " categoryoptioncomboid integer default NULL, " + + " value varchar(255) default NULL, " + + " providedbyanotherfacility boolean NOT NULL, " + + " timestamp TIMESTAMP, " + + " PRIMARY KEY (programstageinstanceid,dataelementid,organisationunitid), " + + " CONSTRAINT fk_patientdatavaluearchive_organisationunitid FOREIGN KEY (organisationunitid) REFERENCES organisationunit (organisationunitid), " + + " CONSTRAINT fk_patientdatavaluearchive_programstageinstanceid FOREIGN KEY (programstageinstanceid) REFERENCES programstageinstance (programstageinstanceid) " + + " );"; + + jdbcTemplate.execute( sql ); + + log.info( "Created table patientdatavaluearchive" ); + } + catch ( Exception ex ) + { + log.info( "Table patientdatavaluearchive exists" ); + } } } === modified file 'dhis-2/dhis-services/dhis-service-options/src/main/resources/help_content.xml' --- dhis-2/dhis-services/dhis-service-options/src/main/resources/help_content.xml 2010-09-24 13:23:08 +0000 +++ dhis-2/dhis-services/dhis-service-options/src/main/resources/help_content.xml 2010-10-24 15:41:13 +0000 @@ -555,6 +555,13 @@ To unarchive data, first enter a start date and an end date for the time span of the data which should be unarchived. Then press the unarchive button. The operation might take a few minutes. In some cases you might end up with overlapping data. For instance one might archive data for a given timespan, then later enter data for a period in that timespan. In such cases the system will automatically overwrite the oldest of the overlapping values with the newest during the archive or unarchive operation. +
+ Patient Data Archive + The purpose of the patient data archive function is to move patient data value which is currently not being used for analysis to a secondary storage location in order to improve performance of the application. Data can be both archived and unarchived. When archiving data one moves it from the primary storage to the secondary storage location, while unarchiving moves it from the secondary storage location to the primary. Analysis functionality in DHIS 2 heavily utilizes queries to the data value database table, and by reducing the size of this table these operations will be significantly faster. Typically one would want to archive patient data that is older than two years. + To archive patient data, first enter a start date and an end date for the time span of the data which should be archived. Then press the archive button. The operation might take a few minutes. + To unarchive patient data, first enter a start date and an end date for the time span of the data which should be unarchived. Then press the unarchive button. The operation might take a few minutes. + In some cases you might end up with overlapping data. For instance one might archive patient data for a given timespan, then later enter data for a period in that timespan. In such cases the system will automatically overwrite the oldest of the overlapping values with the newest during the archive or unarchive operation. +
Maintenance The data maintenance module has five options, each described below. === modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/patientdatavalue/hibernate/PatientDataValue.hbm.xml' --- dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/patientdatavalue/hibernate/PatientDataValue.hbm.xml 2009-10-28 19:47:26 +0000 +++ dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/patientdatavalue/hibernate/PatientDataValue.hbm.xml 2010-10-24 15:41:13 +0000 @@ -22,7 +22,7 @@ - + === modified file 'dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/StatementBuilder.java' --- dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/StatementBuilder.java 2010-09-30 06:06:17 +0000 +++ dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/StatementBuilder.java 2010-10-24 15:41:13 +0000 @@ -131,4 +131,16 @@ String deleteOldestOverlappingDataValue(); String deleteOldestOverlappingArchiveData(); + + String archivePatientData ( String startDate, String endDate ); + + String unArchivePatientData ( String startDate, String endDate ); + + String deleteRegularOverlappingPatientData(); + + String deleteArchivedOverlappingPatientData(); + + String deleteOldestOverlappingPatientDataValue(); + + String deleteOldestOverlappingPatientArchiveData(); } === modified file 'dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/statementbuilder/DerbyStatementBuilder.java' --- dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/statementbuilder/DerbyStatementBuilder.java 2010-09-30 06:06:17 +0000 +++ dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/statementbuilder/DerbyStatementBuilder.java 2010-10-24 15:41:13 +0000 @@ -281,4 +281,67 @@ "AND a.categoryoptioncomboid=d.categoryoptioncomboid " + "AND a.lastupdated<=d.lastupdated"; } + + public String archivePatientData ( String startDate, String endDate ) + { + return "DELETE FROM patientdatavalue AS pdv " + + "USING programstageinstance AS psi , programinstance AS pi " + + "WHERE pdv.programstageinstanceid = psi.programstageinstanceid " + + "AND pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String unArchivePatientData ( String startDate, String endDate ) + { + return "DELETE FROM patientdatavaluearchive AS pdv " + + "USING programstageinstance AS psi , programinstance AS pi " + + "WHERE pdv.programstageinstanceid = psi.programstageinstanceid " + + "AND pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String deleteRegularOverlappingPatientData() + { + return "DELETE FROM patientdatavalue AS d " + + "USING patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid " + + "AND d.timestamp= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String unArchivePatientData ( String startDate, String endDate ) + { + return "DELETE FROM patientdatavaluearchive AS pdv " + + "USING programstageinstance AS psi , programinstance AS pi " + + "WHERE pdv.programstageinstanceid = psi.programstageinstanceid " + + "AND pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String deleteRegularOverlappingPatientData() + { + return "DELETE FROM patientdatavalue AS d " + + "USING patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid " + + "AND d.timestamp= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String unArchivePatientData ( String startDate, String endDate ) + { + return "DELETE pdv FROM patientdatavaluearchive AS pdv " + + "INNER JOIN programstageinstance AS psi " + + "ON pdv.programstageinstanceid = psi.programstageinstanceid " + + "INNER JOIN programinstance AS pi " + + "ON pi.programinstanceid = psi.programinstanceid " + + "WHERE pi.enddate >= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String deleteRegularOverlappingPatientData(){ + return "DELETE d FROM patientdatavalue AS d " + + "INNER JOIN patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid;"; + } + + public String deleteArchivedOverlappingPatientData() + { + return "DELETE a FROM patientdatavaluearchive AS a " + + "INNER JOIN patientdatavalue AS d " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid "; + } + + public String deleteOldestOverlappingPatientDataValue(){ + return "DELETE d FROM patientdatavalue AS d " + + "INNER JOIN patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid " + + "AND d.timestamp= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String unArchivePatientData ( String startDate, String endDate ) + { + return "DELETE FROM patientdatavaluearchive AS pdv " + + "USING programstageinstance AS psi , programinstance AS pi " + + "WHERE pdv.programstageinstanceid = psi.programstageinstanceid " + + "AND pi.programinstanceid = psi.programinstanceid " + + "AND pi.enddate >= '" + startDate + "' " + + "AND pi.enddate <= '" + endDate + "';"; + } + + public String deleteRegularOverlappingPatientData() + { + return "DELETE FROM patientdatavalue AS d " + + "USING patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid "; + } + + public String deleteArchivedOverlappingPatientData() + { + return "DELETE FROM patientdatavaluearchive AS a " + + "USING patientdatavalue AS d " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid "; + } + + public String deleteOldestOverlappingPatientDataValue() + { + return "DELETE FROM patientdatavalue AS d " + + "USING patientdatavaluearchive AS a " + + "WHERE d.programstageinstanceid=a.programstageinstanceid " + + "AND d.dataelementid=a.dataelementid " + + "AND d.organisationunitid=a.organisationunitid " + + "AND d.categoryoptioncomboid=a.categoryoptioncomboid " + + "AND d.timestamp + + + + + + + + === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/org/hisp/dhis/dataadmin/i18n_module.properties' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/org/hisp/dhis/dataadmin/i18n_module.properties 2010-10-21 05:41:06 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/org/hisp/dhis/dataadmin/i18n_module.properties 2010-10-24 15:41:13 +0000 @@ -314,4 +314,6 @@ portrait = Portrait data_set_list = Data Set list data_element_group_list = Data Element Group list -orgunit_group_list = Organisation Unit Group list \ No newline at end of file +orgunit_group_list = Organisation Unit Group list +patient_data_archive = Patient Data Archive +intro__patient_data_archive = Archive patient data which is not currently relevant to your system in order to improve performance. Data can also be unarchived. \ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml 2010-10-05 10:04:27 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml 2010-10-24 15:41:13 +0000 @@ -281,6 +281,27 @@ /dhis-web-maintenance-dataadmin/responseNumber.vm + + /main.vm + + /dhis-web-maintenance-dataadmin/patientDataArchiveForm.vm + /dhis-web-maintenance-dataadmin/menu.vm + javascript/dataArchive.js + + + + + /dhis-web-maintenance-dataadmin/responseNumber.vm + + + + + /dhis-web-maintenance-dataadmin/responseNumber.vm + + $i18n.getString( "data_browser" ) 
  • $i18n.getString( "data_integrity" ) 
  • $i18n.getString( "data_archive" ) 
  • +
  • $i18n.getString( "patient_data_archive" ) 
  • $i18n.getString( "maintenance" ) 
  • $i18n.getString( "resource_table" ) 
  • $i18n.getString( "sql_view" )