gt: 		if (extraELConditionToAnd != null) {
context: package org.skyve.impl.web.faces.pipeline;
  
  import javax.el.ELContext;
  import javax.el.ExpressionFactory;
  import javax.el.ValueExpression;
  import javax.faces.application.Application;
  import javax.faces.component.UIComponent;
  import javax.faces.component.html.HtmlPanelGroup;
  import javax.faces.context.FacesContext;
  
  import org.primefaces.component.column.Column;
  import org.primefaces.component.message.Message;
  import org.skyve.impl.bind.BindUtil;
  import org.skyve.impl.metadata.view.HorizontalAlignment;
  import org.skyve.impl.metadata.view.LayoutUtil;
  import org.skyve.impl.sail.mock.MockFacesContext;
  import org.skyve.impl.web.faces.FacesUtil;
  import org.skyve.impl.web.faces.beans.FacesView;
  import org.skyve.metadata.view.TextOutput.Sanitisation;
  import org.skyve.web.UserAgentType;
  
  public abstract class AbstractFacesBuilder {
  	protected static final Integer ONE_HUNDRED = Integer.valueOf(100);
  	protected static final Integer NINETY_EIGHT = Integer.valueOf(98);
  	protected static final Integer NINETY_FIVE = Integer.valueOf(95);
  
  	protected static final String PROCESS_KEY = "process";
  	protected static final String UPDATE_KEY = "update";
  
  	// NOTE:- Any of this protected state needs to be set in the ComponentBuilderChain and LayoutBuilderChain.
  	//			Otherwise the protected utility methods in this class that rely on this state wont work.
  	
  	protected FacesContext fc = (FacesContext.getCurrentInstance() != null) ? 
  									FacesContext.getCurrentInstance() : 
  									new MockFacesContext();
  	protected Application a = fc.getApplication();
  	protected ExpressionFactory ef = a.getExpressionFactory();
  	protected ELContext elc = fc.getELContext();
  	protected String managedBeanName = "skyve";
  	protected FacesView<?> managedBean;
  	protected String process = "@form";
  	protected String update = "@(form)";
  	protected UserAgentType userAgentType;
  	
  	public void setManagedBeanName(String managedBeanName) {
  		if (managedBeanName != null) {
  			this.managedBeanName = managedBeanName;
  		}
  		// Do nothing if this is being executed through SAIL
  		if (FacesContext.getCurrentInstance() != null) {
  			managedBean = FacesUtil.getManagedBean(managedBeanName);
  		}
  	}
  	
  	public void setSAILManagedBean(FacesView<?> managedBean) {
  		this.managedBean = managedBean;
  	}
  	
  	public void setProcess(String process) {
  		if (process != null) {
  			this.process = process;
  		}
  	}
  	public void setUpdate(String update) {
  		if (update != null) {
  			this.update = update;
  		}
  	}
  	public void setUserAgentType(UserAgentType userAgentType) {
  		this.userAgentType = userAgentType;
  	}
  
  	protected void setId(UIComponent component, String widgetId) {
  		component.setId((widgetId == null) ? managedBean.nextId() : widgetId);
  	}
  	
  	protected void setDisabled(UIComponent component, String disabledConditionName, String formDisabledConditionName) {
  		if (disabledConditionName != null) {
  			if (formDisabledConditionName == null) {
  				component.setValueExpression("disabled", createValueExpressionFromCondition(disabledConditionName, null));
  			}
  			else {
  				component.setValueExpression("disabled", createOredValueExpressionFromConditions(new String[] {disabledConditionName, formDisabledConditionName}));
  			}
  		}
  		else if (formDisabledConditionName != null) {
  			component.setValueExpression("disabled", createValueExpressionFromCondition(formDisabledConditionName, null));
  		}
  	}
  
  	protected void setInvisible(UIComponent component, String invisibleConditionName, String extraELToAnd) {
  		if (invisibleConditionName != null) {
  			String visible = BindUtil.negateCondition(invisibleConditionName);
  			component.setValueExpression("rendered", createValueExpressionFromCondition(visible, extraELToAnd));
  		}
  	}
  
  	protected void setInvisible(UIComponent component, String dataWidgetVar, String invisibleConditionName, String extraELToAnd) {
  		if (invisibleConditionName != null) {
  			final String visible = BindUtil.negateCondition(invisibleConditionName);
  			component.setValueExpression("rendered",  createValueExpressionFromFragment(dataWidgetVar,
  																							true,
  																							visible,
  																							false,
  																							extraELToAnd,
  																							Boolean.class,
  																							false,
  																							Sanitisation.none));
  		}
  	}
  
  	protected void setTextAlign(UIComponent component, HorizontalAlignment textAlignment) {
  		String styleClass = null;
  		if (HorizontalAlignment.left.equals(textAlignment)) {
  			styleClass = "left";
  		} 
  		else if (HorizontalAlignment.centre.equals(textAlignment)) {
  			styleClass = "center";
  		} 
  		else if (HorizontalAlignment.right.equals(textAlignment)) {
  			styleClass = "right";
  		}
  		if (styleClass != null) {
  			component.setValueExpression("styleClass", ef.createValueExpression(styleClass, String.class));
  		}
  	}
  	
  	protected void setSize(UIComponent component, 
  							String existingStyle, 
  							Integer pixelWidth, 
  							Integer responsiveWidth,
  							Integer percentageWidth,
  							Integer pixelHeight, 
  							Integer percentageHeight, 
  							Integer defaultPercentageWidth) {
  		StringBuilder style = new StringBuilder(64);
  		boolean noWidth = true;
  		if (existingStyle != null) {
  			style.append(existingStyle);
  		}
  		if (pixelWidth != null) {
  			noWidth = false;
  			style.append("width:").append(pixelWidth).append("px");
  		} 
  		else if (responsiveWidth != null) {
  			noWidth = false;
  			style.append("width:");
  			style.append(LayoutUtil.responsiveWidthToPercentageWidth(responsiveWidth.doubleValue()));
  			style.append('%');
  		}
  		else if (percentageWidth != null) {
  			noWidth = false;
  			style.append("width:").append(percentageWidth).append('%');
  		}
  		if (noWidth && (defaultPercentageWidth != null)) {
  			style.append("width:").append(defaultPercentageWidth).append('%');
  		}
  		if (pixelHeight != null) {
  			if (style.length() > 0) {
  				style.append(';');
  			}
  			style.append("height:").append(pixelHeight).append("px");
  		}
  		else if (percentageHeight != null) {
  			if (style.length() > 0) {
  				style.append(';');
  			}
  			style.append("height:").append(percentageHeight).append("%");
  		}
  		component.setValueExpression("style", ef.createValueExpression(style.toString(), String.class));
  	}
  
  	protected ValueExpression createValueExpressionFromFragment(String fragment, 
  																	boolean map,
  																	String extraELConditionToAnd, 
  																	Class<?> typeReturned,
  																	boolean escape,
  																	Sanitisation sanitise) {
  		return createValueExpressionFromFragment(managedBeanName + ".currentBean",
  													false,
  													fragment, 
  													map, 
  													extraELConditionToAnd,
  													typeReturned,
  													escape,
  													sanitise);
  	}
  
  	protected ValueExpression createValueExpressionFromFragment(String expressionPrefix, 
  																	boolean dataWidgetVar,
  																	String fragment, 
  																	boolean map,
  																	String extraELConditionToAnd, 
  																	Class<?> typeReturned,
  																	boolean escape,
  																	Sanitisation sanitise) {
  		// default sanitisation is relaxed, for widgets that have no sanitisation set
  		Sanitisation finalSanitise = (sanitise == null) ? Sanitisation.relaxed : sanitise;
  		boolean escapeOrSanitise = escape || (! Sanitisation.none.equals(finalSanitise));
  		StringBuilder sb = new StringBuilder(64);
  		sb.append("#{");
  		if (expressionPrefix != null) {
  			sb.append(dataWidgetVar ? BindUtil.sanitiseBinding(expressionPrefix) : expressionPrefix);
  			sb.append(escapeOrSanitise ? ".get('" : (map ? "['" : "."));
  		}
  		sb.append(fragment);
  		if (expressionPrefix != null) {
  			if (escapeOrSanitise) {
  				sb.append("',").append(escape).append(",'").append(finalSanitise).append("')");
  			}
  			else if (map) {
  				sb.append("']");
  			}
  		}
  