← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13910: Impl support for count of org units in groups in indicator formulas. Step 1 of 2.

 

------------------------------------------------------------
revno: 13910
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-01-31 20:08:43 +0200
message:
  Impl support for count of org units in groups in indicator formulas. Step 1 of 2.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java
  dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2013-10-08 17:20:57 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2014-01-31 18:08:43 +0000
@@ -37,6 +37,7 @@
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.indicator.Indicator;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
 import org.hisp.dhis.period.Period;
 
 /**
@@ -61,6 +62,7 @@
     final String DATAELEMENT_DOES_NOT_EXIST = "data_element_does_not_exist";
     final String CATEGORYOPTIONCOMBO_DOES_NOT_EXIST = "category_option_combo_does_not_exist";
     final String CONSTANT_DOES_NOT_EXIST = "constant_does_not_exist";
+    final String OU_GROUP_DOES_NOT_EXIST = "org_unit_group_does_not_exist";
     final String EXPRESSION_NOT_WELL_FORMED = "expression_not_well_formed";
 
     final String DAYS_DESCRIPTION = "[Number of days]";
@@ -71,12 +73,14 @@
     final String OPERAND_UID_EXPRESSION = "(\\w+)\\.?(\\w*)";
     final String DATA_ELEMENT_TOTAL_EXPRESSION = "#\\{(\\w+)\\}";
     final String CONSTANT_EXPRESSION = "C\\{(\\w+)\\}";
+    final String OU_GROUP_EXPRESSION = "OUG\\{(\\w+)\\}";
     final String DAYS_EXPRESSION = "\\[days\\]";
 
     final Pattern OPERAND_PATTERN = Pattern.compile( OPERAND_EXPRESSION );
     final Pattern OPERAND_UID_PATTERN = Pattern.compile( OPERAND_UID_EXPRESSION );
     final Pattern DATA_ELEMENT_TOTAL_PATTERN = Pattern.compile( DATA_ELEMENT_TOTAL_EXPRESSION );
     final Pattern CONSTANT_PATTERN = Pattern.compile( CONSTANT_EXPRESSION );
+    final Pattern OU_GROUP_PATTERN = Pattern.compile( OU_GROUP_EXPRESSION );
     final Pattern DAYS_PATTERN = Pattern.compile( DAYS_EXPRESSION );
 
     final String DAYS_SYMBOL = "[days]";
@@ -119,7 +123,7 @@
     Collection<Expression> getAllExpressions();
     
     Double getIndicatorValue( Indicator indicator, Period period, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days );
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days );
     
     /**
      * Generates the calculated value for the given expression base on the values
@@ -130,11 +134,12 @@
      *        use in the calculation.
      * @param constantMap the mapping between the constant uid and value to use
      *        in the calculation.
+     * @param orgUnitCount the number of org units to use in the calculation.
      * @param days the number of days to use in the calculation.
      * @return the calculated value as a double.
      */
     Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days );
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days );
     
     /**
      * Generates the calculated value for the given expression base on the values
@@ -145,6 +150,7 @@
      *        use in the calculation.
      * @param constantMap the mapping between the constant uid and value to use
      *        in the calculation.
+     * @param orgUnitCount the number of org units to use in the calculation.
      * @param days the number of days to use in the calculation.
      * @param set of data element operands that have values but they are incomplete
      *        (for example due to aggregation from organisationUnit children where
@@ -152,7 +158,7 @@
      * @return the calculated value as a double.
      */
     Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days, Set<DataElementOperand> incompleteValues );
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days, Set<DataElementOperand> incompleteValues );
     
     /**
      * Returns the uids of the data element totals in the given expression.
@@ -171,6 +177,14 @@
     Set<DataElement> getDataElementsInExpression( String expression );
     
     /**
+     * Returns all OrganisationUnitGroups in the given expression string.
+     * 
+     * @param expression the expression string.
+     * @return a Set of OrganisationUnitGroups included in the expression string.
+     */
+    Set<OrganisationUnitGroup> getOrganisationUnitGroupsInExpresion( String expression );
+    
+    /**
      * Returns all CategoryOptionCombos in the given expression string.
      * 
      * @param expression the expression string.
@@ -230,7 +244,7 @@
      *         CONSTANT_DOES_NOT_EXIST if the constant does not exist.
      *         EXPRESSION_NOT_WELL_FORMED if the expression is not well-formed.
      */
-    String expressionIsValid( String formula, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants );
+    String expressionIsValid( String formula, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants, Set<String> orgUnitGroups );
     
     /**
      * Creates an expression string containing DataElement names and the names of
@@ -295,11 +309,12 @@
      * by the aggregated value for the relevant combination of data element,
      * period, and source.
      * 
-     * @param formula The formula to parse.
-     * @param valueMap The map containing data element identifiers and aggregated value.
+     * @param formula formula to parse.
+     * @param valueMap map containing data element identifiers and aggregated value.
+     * @param constantMap map between constants and values.  
      * @param days The number to be substituted with the days expression in the formula.
      */
-    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<String, Double> constantMap, Integer days, boolean nullIfNoValues );
+    String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<String, Double> constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues );
     
     /**
      * Returns all Operands included in the formulas for the given collection of

=== modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java	2014-01-28 12:20:49 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java	2014-01-31 18:08:43 +0000
@@ -360,10 +360,11 @@
         Set<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
         Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
         Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+        Set<String> orgUnitGroups = new HashSet<String>( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) );
         
         for ( Indicator indicator : indicatorService.getAllIndicators() )
         {
-            String result = expressionService.expressionIsValid( indicator.getNumerator(), dataElements, categoryOptionCombos, constants );
+            String result = expressionService.expressionIsValid( indicator.getNumerator(), dataElements, categoryOptionCombos, constants, orgUnitGroups );
 
             if ( !result.equals( ExpressionService.VALID ) )
             {
@@ -381,10 +382,11 @@
         Set<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
         Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
         Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+        Set<String> orgUnitGroups = new HashSet<String>( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) );
         
         for ( Indicator indicator : indicatorService.getAllIndicators() )
         {
-            String result = expressionService.expressionIsValid( indicator.getDenominator(), dataElements, categoryOptionCombos, constants );
+            String result = expressionService.expressionIsValid( indicator.getDenominator(), dataElements, categoryOptionCombos, constants, orgUnitGroups );
 
             if ( !result.equals( ExpressionService.VALID ) )
             {
@@ -541,10 +543,11 @@
         Set<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
         Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
         Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+        Set<String> orgUnitGroups = new HashSet<String>( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) );
         
         for ( ValidationRule rule : validationRuleService.getAllValidationRules() )
         {
-            String result = expressionService.expressionIsValid( rule.getLeftSide().getExpression(), dataElements, categoryOptionCombos, constants );
+            String result = expressionService.expressionIsValid( rule.getLeftSide().getExpression(), dataElements, categoryOptionCombos, constants, orgUnitGroups );
 
             if ( !result.equals( ExpressionService.VALID ) )
             {
@@ -563,10 +566,11 @@
         Set<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
         Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
         Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+        Set<String> orgUnitGroups = new HashSet<String>( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) );
         
         for ( ValidationRule rule : validationRuleService.getAllValidationRules() )
         {
-            String result = expressionService.expressionIsValid( rule.getRightSide().getExpression(), dataElements, categoryOptionCombos, constants );
+            String result = expressionService.expressionIsValid( rule.getRightSide().getExpression(), dataElements, categoryOptionCombos, constants, orgUnitGroups );
 
             if ( !result.equals( ExpressionService.VALID ) )
             {

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2014-01-07 15:52:34 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2014-01-31 18:08:43 +0000
@@ -31,6 +31,7 @@
 import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME;
 import static org.hisp.dhis.analytics.AnalyticsTableManager.COMPLETENESS_TABLE_NAME;
 import static org.hisp.dhis.analytics.AnalyticsTableManager.COMPLETENESS_TARGET_TABLE_NAME;
+import static org.hisp.dhis.analytics.AnalyticsTableManager.ORGUNIT_TARGET_TABLE_NAME;
 import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_CATEGORYOPTIONCOMBO;
 import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_DATA_X;
 import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_ORGUNIT;
@@ -259,7 +260,7 @@
 
                     int days = daysBetween( period.getStartDate(), period.getEndDate() );
                     
-                    Double value = expressionService.getIndicatorValue( indicator, period, valueMap, constantMap, days );
+                    Double value = expressionService.getIndicatorValue( indicator, period, valueMap, constantMap, null, days ); //TODO oug
 
                     if ( value != null )
                     {
@@ -545,14 +546,31 @@
     }
 
     /**
+     * Generates a mapping between the the data set dimension key and the count
+     * of expected data sets to report.
      * 
-     * @param params
-     * @return
+     * @param params the data query parameters.
+     * @return a mapping between the the data set dimension key and the count of
+     *         expected data sets to report.
      */
     private Map<String, Double> getAggregatedCompletenessTargetMap( DataQueryParams params )
     {
         return getAggregatedValueMap( params, COMPLETENESS_TARGET_TABLE_NAME );
     }
+
+    /**
+     * Generates a mapping between the the org unit dimension key and the count
+     * of org units inside the subtree of the given organisation units and
+     * members of the given organisation unit groups.
+     * 
+     * @param params the data query parameters.
+     * @return a mapping between the the data set dimension key and the count of
+     *         expected data sets to report.
+     */
+    private Map<String, Double> getAggregatedOrganisationUnitTargetMap( DataQueryParams params )
+    {
+        return getAggregatedValueMap( params, ORGUNIT_TARGET_TABLE_NAME );
+    }
     
     /**
      * Generates a mapping between a dimension key and the aggregated value. The

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java	2014-01-24 08:41:50 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java	2014-01-31 18:08:43 +0000
@@ -32,13 +32,13 @@
 import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT;
 import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT_DISAGGREGATION;
 import static org.hisp.dhis.analytics.AggregationType.COUNT;
-import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP;
 import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID;
 import static org.hisp.dhis.analytics.MeasureFilter.EQ;
 import static org.hisp.dhis.analytics.MeasureFilter.GE;
 import static org.hisp.dhis.analytics.MeasureFilter.GT;
 import static org.hisp.dhis.analytics.MeasureFilter.LE;
 import static org.hisp.dhis.analytics.MeasureFilter.LT;
+import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP;
 import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids;
 import static org.hisp.dhis.system.util.TextUtils.getQuotedCommaDelimitedString;
 import static org.hisp.dhis.system.util.TextUtils.trimEnd;

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java	2014-01-30 10:13:58 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java	2014-01-31 18:08:43 +0000
@@ -36,7 +36,6 @@
 import java.util.concurrent.Future;
 
 import org.hisp.dhis.analytics.AnalyticsTable;
-import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
 import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.transaction.annotation.Transactional;
@@ -135,18 +134,9 @@
     {
         List<String[]> columns = new ArrayList<String[]>();
 
-        Collection<OrganisationUnitGroupSet> orgUnitGroupSets = 
-            organisationUnitGroupService.getDataDimensionOrganisationUnitGroupSets();
-        
         Collection<OrganisationUnitLevel> levels =
             organisationUnitService.getOrganisationUnitLevels();
-        
-        for ( OrganisationUnitGroupSet groupSet : orgUnitGroupSets )
-        {
-            String[] col = { quote( groupSet.getUid() ), "character(11)", "ougs." + quote( groupSet.getUid() ) };
-            columns.add( col );
-        }
-        
+                
         for ( OrganisationUnitLevel level : levels )
         {
             String column = quote( PREFIX_ORGUNITLEVEL + level.getLevel() );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2014-01-30 10:13:58 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2014-01-31 18:08:43 +0000
@@ -58,6 +58,8 @@
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.indicator.Indicator;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.system.util.DateUtils;
 import org.hisp.dhis.system.util.MathUtils;
@@ -107,6 +109,13 @@
     {
         this.categoryService = categoryService;
     }
+    
+    private OrganisationUnitGroupService organisationUnitGroupService;
+
+    public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService )
+    {
+        this.organisationUnitGroupService = organisationUnitGroupService;
+    }
 
     // -------------------------------------------------------------------------
     // Expression CRUD operations
@@ -147,14 +156,14 @@
     // -------------------------------------------------------------------------
     
     public Double getIndicatorValue( Indicator indicator, Period period, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days )
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days )
     {
         if ( indicator == null || indicator.getExplodedNumeratorFallback() == null || indicator.getExplodedDenominatorFallback() == null )
         {
             return null;
         }
         
-        final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap, constantMap, days, false );
+        final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap, constantMap, orgUnitCount, days, false );
         
         if ( denominatorExpression == null )
         {
@@ -165,7 +174,7 @@
         
         if ( !isEqual( denominatorValue, 0d ) )
         {
-            final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap, constantMap, days, false );
+            final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap, constantMap, orgUnitCount, days, false );
             
             if ( numeratorExpression == null )
             {
@@ -185,18 +194,18 @@
     }
 
     public Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap,
-        Map<String, Double> constantMap, Integer days )
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days )
     {
-        final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, days,
-            expression.isNullIfBlank() );
+        final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, 
+            orgUnitCount, days, expression.isNullIfBlank() );
 
         return expressionString != null ? calculateExpression( expressionString ) : null;
     }
 
     public Double getExpressionValue( Expression expression, Map<DataElementOperand, Double> valueMap,
-        Map<String, Double> constantMap, Integer days, Set<DataElementOperand> incompleteValues )
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days, Set<DataElementOperand> incompleteValues )
     {
-        final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, days,
+        final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, orgUnitCount, days,
             expression.isNullIfBlank(), incompleteValues );
 
         return expressionString != null ? calculateExpression( expressionString ) : null;
@@ -227,6 +236,30 @@
         return dataElementsInExpression;
     }
     
+    public Set<OrganisationUnitGroup> getOrganisationUnitGroupsInExpresion( String expression )
+    {
+        Set<OrganisationUnitGroup> groupsInExpression = null;
+        
+        if ( expression != null )
+        {
+            groupsInExpression = new HashSet<OrganisationUnitGroup>();
+            
+            final Matcher matcher = OU_GROUP_PATTERN.matcher( expression );
+            
+            while ( matcher.find() )
+            {
+                final OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( matcher.group( 1 ) );
+                
+                if ( group != null )
+                {
+                    groupsInExpression.add( group );
+                }
+            }
+        }
+        
+        return groupsInExpression;
+    }
+    
     public Set<String> getDataElementTotalUids( String expression )
     {
         Set<String> uids = new HashSet<String>();
@@ -338,11 +371,11 @@
     @Transactional
     public String expressionIsValid( String formula )
     {
-        return expressionIsValid( formula, null, null, null );
+        return expressionIsValid( formula, null, null, null, null );
     }
 
     @Transactional
-    public String expressionIsValid( String expression, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants )
+    public String expressionIsValid( String expression, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> orgUnitGroups, Set<String> constants )
     {
         if ( expression == null || expression.isEmpty() )
         {
@@ -398,6 +431,31 @@
 
         expression = appendTail( matcher, sb );
 
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+        
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+        sb = new StringBuffer();
+        
+        while ( matcher.find() )
+        {
+            String group = matcher.group( 1 );
+            
+            if ( orgUnitGroups != null ? !orgUnitGroups.contains( group ) : organisationUnitGroupService.getOrganisationUnitGroup( group ) == null )
+            {
+                return OU_GROUP_DOES_NOT_EXIST;
+            }
+
+            matcher.appendReplacement( sb, "1.1" );
+        }
+
+        expression = appendTail( matcher, sb );
+        
+        // ---------------------------------------------------------------------
+        // Days
+        // ---------------------------------------------------------------------
+        
         expression = expression.replaceAll( DAYS_EXPRESSION, "1.1" );
         
         // ---------------------------------------------------------------------
@@ -474,6 +532,29 @@
         expression = appendTail( matcher, sb );
 
         // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+        
+        while ( matcher.find() )
+        {
+            String oug = matcher.group( 1 );
+            
+            OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug );
+            
+            if ( group == null )
+            {
+                throw new IllegalArgumentException( "Identifier does not reference an organisation unit group: " + oug );
+            }
+            
+            matcher.appendReplacement( sb, group.getDisplayName() );
+        }
+
+        expression = appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
         // Days
         // ---------------------------------------------------------------------
 
@@ -630,6 +711,28 @@
         }
 
         expression = appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+        
+        while ( matcher.find() )
+        {
+            String oug = matcher.group( 1 );
+            
+            OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug );
+            
+            String replacement = group != null ? String.valueOf( group.getMembers().size() ) : NULL_REPLACEMENT;
+
+            matcher.appendReplacement( sb, replacement );            
+            
+            //TODO sub tree
+        }
+
+        expression = appendTail( matcher, sb );
         
         // ---------------------------------------------------------------------
         // Days
@@ -650,13 +753,13 @@
 
     @Transactional
     public String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days, boolean nullIfNoValues )
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues )
     {
-    	return generateExpression( expression, valueMap, constantMap, days, nullIfNoValues, null );
+    	return generateExpression( expression, valueMap, constantMap, orgUnitCount, days, nullIfNoValues, null );
     }
 
     private String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, 
-        Map<String, Double> constantMap, Integer days, boolean nullIfNoValues, Set<DataElementOperand> incompleteValues )
+        Map<String, Double> constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues, Set<DataElementOperand> incompleteValues )
     {
         if ( expression == null || expression.isEmpty() )
         {
@@ -705,6 +808,22 @@
         }
         
         expression = appendTail( matcher, sb );
+
+        // ---------------------------------------------------------------------
+        // Org unit groups
+        // ---------------------------------------------------------------------
+
+        sb = new StringBuffer();
+        matcher = OU_GROUP_PATTERN.matcher( expression );
+        
+        while ( matcher.find() )
+        {
+            String replacement = orgUnitCount != null ? String.valueOf( orgUnitCount ) : NULL_REPLACEMENT;
+            
+            matcher.appendReplacement( sb, replacement );
+        }
+
+        expression = appendTail( matcher, sb );        
         
         // ---------------------------------------------------------------------
         // Days

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java	2013-10-17 04:03:14 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java	2014-01-31 18:08:43 +0000
@@ -121,7 +121,7 @@
                             if ( evaluateCheck( lastUpdatedMap, rule, context ) )
                             {
                                 Double leftSide = context.getExpressionService().getExpressionValue( rule.getLeftSide(),
-                                    currentValueMap, context.getConstantMap(), null, incompleteValues );
+                                    currentValueMap, context.getConstantMap(), null, null, incompleteValues );
 
                                 if ( leftSide != null || Operator.compulsory_pair.equals( rule.getOperator() ) )
                                 {
@@ -319,7 +319,7 @@
             || rule.getRightSide().getDataElementsInExpression().isEmpty() )
         {
             rightSideValue = context.getExpressionService().getExpressionValue( rule.getRightSide(),
-            		currentValueMap, context.getConstantMap(), null );
+            		currentValueMap, context.getConstantMap(), null, null );
         }
         else
         // ruleType equals SURVEILLANCE, and there are some data elements in the
@@ -416,7 +416,7 @@
             Map<DataElementOperand, Double> dataValueMap = getDataValueMapRecursive( periodTypeX, dataElements,
                 sourceDataElements, dataElements, allowedPeriodTypes, period, source, null, incompleteValues );
             Double value = context.getExpressionService().getExpressionValue( rule.getRightSide(), dataValueMap,
-                context.getConstantMap(), null, incompleteValues );
+                context.getConstantMap(), null, null, incompleteValues );
             
             if ( value != null )
             {

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-01-29 13:39:43 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-01-31 18:08:43 +0000
@@ -449,6 +449,7 @@
     <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
     <property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
     <property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
+    <property name="organisationUnitGroupService" ref="org.hisp.dhis.organisationunit.OrganisationUnitGroupService" />
   </bean>
 
   <bean id="org.hisp.dhis.validation.ValidationRuleService" class="org.hisp.dhis.validation.DefaultValidationRuleService">

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java	2013-12-19 18:12:57 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java	2014-01-31 18:08:43 +0000
@@ -56,6 +56,8 @@
 import org.hisp.dhis.indicator.Indicator;
 import org.hisp.dhis.indicator.IndicatorType;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Period;
 import org.junit.Test;
@@ -84,12 +86,16 @@
 
     private Period period;
 
-    private OrganisationUnit source;
+    private OrganisationUnit unitA;
+    private OrganisationUnit unitB;
+    private OrganisationUnit unitC;
 
     private DataElementCategoryOptionCombo categoryOptionCombo;
     
     private Constant constantA;
     
+    private OrganisationUnitGroup groupA;
+    
     private String expressionA;
     private String expressionB;
     private String expressionC;
@@ -97,6 +103,7 @@
     private String expressionE;
     private String expressionF;
     private String expressionG;
+    private String expressionH;
 
     private String descriptionA;
     private String descriptionB;
@@ -124,6 +131,8 @@
         dataValueService = (DataValueService) getBean( DataValueService.ID );
 
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
+        
+        organisationUnitGroupService = (OrganisationUnitGroupService) getBean( OrganisationUnitGroupService.ID );
 
         categoryOptionA = new DataElementCategoryOption( "Under 5" );
         categoryOptionB = new DataElementCategoryOption( "Over 5" );
@@ -171,13 +180,24 @@
 
         period = createPeriod( getDate( 2000, 1, 1 ), getDate( 2000, 2, 1 ) );
 
-        source = createOrganisationUnit( 'A' );
+        unitA = createOrganisationUnit( 'A' );
+        unitB = createOrganisationUnit( 'B' );
+        unitC = createOrganisationUnit( 'C' );
 
-        organisationUnitService.addOrganisationUnit( source );
+        organisationUnitService.addOrganisationUnit( unitA );
+        organisationUnitService.addOrganisationUnit( unitB );
+        organisationUnitService.addOrganisationUnit( unitC );
 
         constantA = new Constant( "ConstantA", 2.0 );
-        
+                
         constantService.saveConstant( constantA );
+
+        groupA = createOrganisationUnitGroup( 'A' );
+        groupA.addOrganisationUnit( unitA );
+        groupA.addOrganisationUnit( unitB );
+        groupA.addOrganisationUnit( unitC );
+        
+        organisationUnitGroupService.addOrganisationUnitGroup( groupA );
         
         expressionA = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}+#{" + dataElementB.getUid() + SEPARATOR
             + categoryOptionCombo.getUid() + "}";
@@ -188,6 +208,7 @@
         expressionE = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}*C{" + constantA.getUid() + "}";
         expressionF = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}";
         expressionG = expressionF + "+#{" + dataElementB.getUid() + "}-#{" + dataElementC.getUid() + "}";
+        expressionH = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}*OUG{" + groupA.getUid() + "}";
 
         descriptionA = "Expression A";
         descriptionB = "Expression B";
@@ -198,8 +219,8 @@
         dataElements.add( dataElementD );
         dataElements.add( dataElementE );
 
-        dataValueService.addDataValue( createDataValue( dataElementA, period, source, "10", categoryOptionCombo, categoryOptionCombo ) );
-        dataValueService.addDataValue( createDataValue( dataElementB, period, source, "5", categoryOptionCombo, categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, period, unitA, "10", categoryOptionCombo, categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementB, period, unitA, "5", categoryOptionCombo, categoryOptionCombo ) );
     }
 
     // -------------------------------------------------------------------------
@@ -276,6 +297,7 @@
         assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionC ) );
         assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionD ) );
         assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionE ) );
+        assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionH ) );
 
         expressionA = "#{NonExistingUid" + SEPARATOR + categoryOptionCombo.getUid() + "} + 12";
 
@@ -297,6 +319,10 @@
         expressionA = "12 + C{999999}";
 
         assertEquals( ExpressionService.CONSTANT_DOES_NOT_EXIST, expressionService.expressionIsValid( expressionA ) );
+        
+        expressionA = "12 + OUG{999999}";
+        
+        assertEquals( ExpressionService.OU_GROUP_DOES_NOT_EXIST, expressionService.expressionIsValid( expressionA ) );
     }
 
     @Test
@@ -313,6 +339,10 @@
         description = expressionService.getExpressionDescription( expressionE );
         
         assertEquals( "DataElementA*ConstantA", description );
+        
+        description = expressionService.getExpressionDescription( expressionH );
+        
+        assertEquals( "DataElementA*OrganisationUnitGroupA", description );
     }
 
     @Test
@@ -325,9 +355,10 @@
         Map<String, Double> constantMap = new HashMap<String, Double>();
         constantMap.put( constantA.getUid(), 2.0 );
 
-        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, false ) );
-        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, 5, false ) );
-        assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, false ) );
+        assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, false ) );
+        assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, false ) );
+        assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) );
+        assertEquals( "12.0*3", expressionService.generateExpression( expressionH, valueMap, constantMap, 3, null, false ) );
     }
 
     @Test
@@ -337,9 +368,9 @@
         
         Map<String, Double> constantMap = new HashMap<String, Double>();
 
-        assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, true ) );
-        assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, 5, true ) );
-        assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, false ) );
+        assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, true ) );
+        assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, true ) );
+        assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) );
     }
     
     @Test
@@ -348,6 +379,7 @@
         Expression expA = createExpression( 'A', expressionA, null, null );
         Expression expD = createExpression( 'D', expressionD, null, null );
         Expression expE = createExpression( 'E', expressionE, null, null );
+        Expression expH = createExpression( 'H', expressionH, null, null );
         
         Map<DataElementOperand, Double> valueMap = new HashMap<DataElementOperand, Double>();
         valueMap.put( new DataElementOperand( dataElementA.getUid(), categoryOptionCombo.getUid() ), new Double( 12 ) );
@@ -356,9 +388,10 @@
         Map<String, Double> constantMap = new HashMap<String, Double>();
         constantMap.put( constantA.getUid(), 2.0 );
         
-        assertEquals( 46d, expressionService.getExpressionValue( expA, valueMap, constantMap, null ), DELTA );
-        assertEquals( 17d, expressionService.getExpressionValue( expD, valueMap, constantMap, 5 ), DELTA );
-        assertEquals( 24d, expressionService.getExpressionValue( expE, valueMap, constantMap, null ), DELTA );
+        assertEquals( 46d, expressionService.getExpressionValue( expA, valueMap, constantMap, null, null ), DELTA );
+        assertEquals( 17d, expressionService.getExpressionValue( expD, valueMap, constantMap, null, 5 ), DELTA );
+        assertEquals( 24d, expressionService.getExpressionValue( expE, valueMap, constantMap, null, null ), DELTA );
+        assertEquals( 36d, expressionService.getExpressionValue( expH, valueMap, constantMap, 3, null ), DELTA );
     }
     
     @Test
@@ -376,7 +409,7 @@
         Map<String, Double> constantMap = new HashMap<String, Double>();
         constantMap.put( constantA.getUid(), 2.0 );
         
-        assertEquals( 200d, expressionService.getIndicatorValue( indicatorA, period, valueMap, constantMap, null ), DELTA );        
+        assertEquals( 200d, expressionService.getIndicatorValue( indicatorA, period, valueMap, constantMap, null, null ), DELTA );        
     }
     
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java'
--- dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java	2013-08-23 16:05:01 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java	2014-01-31 18:08:43 +0000
@@ -164,11 +164,11 @@
                     {                
                         for ( final Indicator indicator : indicators )
                         {
-                            final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, days, false ) );
+                            final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, null, days, false ) );
     
                             if ( !isEqual( denominatorValue, 0d ) )
                             {
-                                final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, days, false ) );
+                                final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, null, days, false ) );
                              
                                 if ( !( omitZeroNumerator && isEqual( numeratorValue, 0d ) ) )
                                 {

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties	2014-01-23 19:05:43 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties	2014-01-31 18:08:43 +0000
@@ -27,7 +27,7 @@
 data_element=Data Element
 data_element_group=Data Element Group
 data_element_groups=Data Element Groups
-list_of_data_elements=Data elements
+data_elements=Data elements
 indicator=Indicator
 indicator_group=Indicator Group
 indicator_groups=Indicator Groups
@@ -215,4 +215,5 @@
 disaggregation=Disaggregation
 attribute=Attribute
 option_set_for_data_values=Option set for data values
-option_set_for_comments=Option set for comments
\ No newline at end of file
+option_set_for_comments=Option set for comments
+organisation_unit_counts=Organisation unit counts
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm	2013-08-09 10:02:06 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm	2014-01-31 18:08:43 +0000
@@ -16,6 +16,7 @@
 		});
 		
 		getConstantsPage();
+		getOrgUnitGroupsPage();
 		getOperandsPage();
 	});	
 
@@ -62,14 +63,27 @@
 		var target = jQuery( "#indicator-expression-container select[id=constantId]" );
 		target.children().remove();
 		
-		jQuery.get( '../api/constants.json?paging=false&links=false', {},
+		jQuery.get( '../api/constants.json?paging=false&links=false',
 			function( json ) {
 				jQuery.each( json.constants, function(i, item) {
-					target.append( '<option value="C{'+item.id+'}">' + item.name + '</option>' );
+					target.append( '<option value="C{' + item.id + '}">' + item.name + '</option>' );
 				});
 			});
 	}
 	
+	function getOrgUnitGroupsPage()
+	{
+        var target = jQuery( "#indicator-expression-container select[id=orgUnitGroupId]" );
+        target.children().remove();
+        
+        jQuery.get( '../api/organisationUnitGroups.json?paging=false&links=false',
+            function( json ) {
+                jQuery.each( json.organisationUnitGroups, function(i, item) {
+                    target.append( '<option value="OUG{' + item.id + '}">' + item.name + '</option>' );
+                });
+            });
+	}
+	
 	function getOperandsPage()
 	{	
 		var key = getFieldValue( "indicator-expression-container input[id=filter]");
@@ -149,11 +163,13 @@
 	<colgroup>
 		<col width="250"/>
 		<col width="10"/>
+        <col width="250"/>
 		<col/>
 	</colgroup>
 	<tr>
 		<th colspan="2">$i18n.getString( "description" )</th>
 		<th>$i18n.getString( "constants" )</th>
+        <th>$i18n.getString( "organisation_unit_counts" )</th>
 	</tr>
 	<tr>
 		<td>
@@ -162,16 +178,18 @@
 		</td>
 		<td></td>
 		<td>
-			<select id="constantId" name="constantId" size="3" style="width:500px" ondblclick="insertText( 'expression', this.value )">
-			</select>
+			<select id="constantId" name="constantId" size="3" style="width:250px" ondblclick="insertText( 'expression', this.value )"></select>
 		</td>
+        <td>
+            <select id="orgUnitGroupId" name="orgUnitGroupId" size="3" style="width:270px" ondblclick="insertText( 'expression', this.value )"></select>
+        </td>
 	</tr>
 	<tr>
-		<td colspan="3"></td>
+		<td colspan="4"></td>
 	</tr>
 	<tr>
 		<th colspan="2">$i18n.getString( "formula" )</th>
-		<th style="width:100%">$i18n.getString( "list_of_data_elements" )</th>
+		<th colspan="2" style="width:100%">$i18n.getString( "data_elements" )</th>
 	</tr>
 	<tr>
 		<td valign="top">
@@ -185,7 +203,7 @@
 		<a href="javascript:insertText( 'expression', '[days]' )"><img src="../images/no_of_days.png" title="$i18n.getString( 'no_of_days' )"/></a>
 		</td>
 		<td></td>
-		<td valign="top" style="width:100%">
+		<td colspan="2" valign="top" style="width:100%">
 			<input type="text" id="filter" name="filter" style="width:370px">
 			<input type="button" value="$i18n.getString( 'filter' )" onclick="getOperandsPage()" style="width:60px">
 			<input type="button" value="$i18n.getString( 'clear' )" onclick="clearSearchText();" style="width:60px"><br/>
@@ -195,16 +213,16 @@
 		</td>
 	</tr>
 	<tr>
-		<th colspan="3" style="width:100%">$i18n.getString( "description" )</th>		
-	</tr>
-	<tr>
-		<td colspan="3" style="width:100%"><div id="formulaText" style="width:740px;height:100px;overflow:auto"></div></td>
-	</tr>
-	<tr>
-		<td colspan="3"></td>
-	</tr>
-	<tr>
-		<td colspan="3">
+		<th colspan="4" style="width:100%">$i18n.getString( "description" )</th>		
+	</tr>
+	<tr>
+		<td colspan="4" style="width:100%"><div id="formulaText" style="width:740px;height:100px;overflow:auto"></div></td>
+	</tr>
+	<tr>
+		<td colspan="4"></td>
+	</tr>
+	<tr>
+		<td colspan="4">
 			<input type="submit" value="$i18n.getString( 'save' )" style="width:125px"/>
 			<input type="button" value="$i18n.getString( 'cancel' )" style="width:125px" onclick="closeExpressionBuilder()"/>
 		</td>