text: /*
  Feathers
  Copyright 2012-2020 Bowler Hat LLC. All Rights Reserved.
  
  This program is free software. You can redistribute and/or modify it in
  accordance with the terms of the accompanying license agreement.
  */
  package feathers.controls
  {
  	import feathers.core.FeathersControl;
  	import feathers.core.ITextBaselineControl;
  	import feathers.core.PropertyProxy;
  	import feathers.data.IListCollection;
  	import feathers.events.CollectionEventType;
  	import feathers.events.FeathersEventType;
  	import feathers.layout.Direction;
  	import feathers.layout.FlowLayout;
  	import feathers.layout.HorizontalAlign;
  	import feathers.layout.HorizontalLayout;
  	import feathers.layout.ILayout;
  	import feathers.layout.IVirtualLayout;
  	import feathers.layout.LayoutBoundsResult;
  	import feathers.layout.VerticalAlign;
  	import feathers.layout.VerticalLayout;
  	import feathers.layout.ViewPortBounds;
  	import feathers.skins.IStyleProvider;
  
  	import flash.utils.Dictionary;
  
  	import starling.display.DisplayObject;
  	import starling.events.Event;
  
  	/**
  	 * A style name to add to all buttons in this button group. Typically
  	 * used by a theme to provide different styles to different button groups.
  	 *
  	 * <p>The following example provides a custom button style name:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.customButtonStyleName = "my-custom-button";</listing>
  	 *
  	 * <p>In your theme, you can target this sub-component style name to
  	 * provide different styles than the default:</p>
  	 *
  	 * <listing version="3.0">
  	 * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-button", setCustomButtonStyles );</listing>
  	 *
  	 * @default null
  	 *
  	 * @see #DEFAULT_CHILD_STYLE_NAME_BUTTON
  	 * @see feathers.core.FeathersControl#styleNameList
  	 */
  	[Style(name="customButtonStyleName",type="String")]
  
  	/**
  	 * A style name to add to the first button in this button group.
  	 * Typically used by a theme to provide different styles to the first
  	 * button.
  	 *
  	 * <p>The following example provides a custom first button style name:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.customFirstButtonStyleName = "my-custom-first-button";</listing>
  	 *
  	 * <p>In your theme, you can target this sub-component style name to
  	 * provide different styles than the default:</p>
  	 *
  	 * <listing version="3.0">
  	 * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-first-button", setCustomFirstButtonStyles );</listing>
  	 *
  	 * @default null
  	 *
  	 * @see feathers.core.FeathersControl#styleNameList
  	 */
  	[Style(name="customFirstButtonStyleName",type="String")]
  
  	/**
  	 * A style name to add to the last button in this button group.
  	 * Typically used by a theme to provide different styles to the last
  	 * button.
  	 *
  	 * <p>The following example provides a custom last button style name:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.customLastButtonStyleName = "my-custom-last-button";</listing>
  	 *
  	 * <p>In your theme, you can target this sub-component style name to
  	 * provide different styles than the default:</p>
  	 *
  	 * <listing version="3.0">
  	 * getStyleProviderForClass( Button ).setFunctionForStyleName( "my-custom-last-button", setCustomLastButtonStyles );</listing>
  	 *
  	 * @default null
  	 *
  	 * @see feathers.core.FeathersControl#styleNameList
  	 */
  	[Style(name="customLastButtonStyleName",type="String")]
  
  	/**
  	 * The button group layout is either vertical or horizontal.
  	 *
  	 * <p>If the <code>direction</code> is
  	 * <code>Direction.HORIZONTAL</code> and
  	 * <code>distributeButtonSizes</code> is <code>false</code>, the buttons
  	 * may be displayed in multiple rows, if they won't fit in one row
  	 * horizontally.</p>
  	 *
  	 * <p>The following example sets the layout direction of the buttons
  	 * to line them up horizontally:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.direction = Direction.HORIZONTAL;</listing>
  	 * 
  	 * <p><strong>Note:</strong> The <code>Direction.NONE</code>
  	 * constant is not supported.</p>
  	 *
  	 * @default feathers.layout.Direction.VERTICAL
  	 *
  	 * @see feathers.layout.Direction#HORIZONTAL
  	 * @see feathers.layout.Direction#VERTICAL
  	 */
  	[Style(name="direction",type="String")]
  
  	/**
  	 * If <code>true</code>, the buttons will be equally sized in the
  	 * direction of the layout. In other words, if the button group is
  	 * horizontal, each button will have the same width, and if the button
  	 * group is vertical, each button will have the same height. If
  	 * <code>false</code>, the buttons will be sized to their ideal
  	 * dimensions.
  	 *
  	 * <p>The following example doesn't distribute the button sizes:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.distributeButtonSizes = false;</listing>
  	 *
  	 * @default true
  	 */
  	[Style(name="distributeButtonSizes",type="Boolean")]
  
  	/**
  	 * Space, in pixels, between the first two buttons. If <code>NaN</code>,
  	 * the default <code>gap</code> property will be used.
  	 *
  	 * <p>The following example sets the gap between the first and second
  	 * button to a different value than the standard gap:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.firstGap = 30;
  	 * group.gap = 20;</listing>
  	 *
  	 * @default NaN
  	 *
  	 * @see #style:gap
  	 * @see #style:lastGap
  	 */
  	[Style(name="firstGap",type="Number")]
  
  	/**
  	 * Space, in pixels, between buttons.
  	 *
  	 * <p>The following example sets the gap used for the button layout to
  	 * 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.gap = 20;</listing>
  	 *
  	 * @default 0
  	 * 
  	 * @see #style:firstGap
  	 * @see #style:lastGap
  	 */
  	[Style(name="gap",type="Number")]
  
  	/**
  	 * Determines how the buttons are horizontally aligned within the bounds
  	 * of the button group (on the x-axis).
  	 *
  	 * <p>The following example aligns the group's content to the left:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.horizontalAlign = HorizontalAlign.LEFT;</listing>
  	 *
  	 * @default feathers.layout.HorizontalAlign.JUSTIFY
  	 *
  	 * @see feathers.layout.HorizontalAlign#LEFT
  	 * @see feathers.layout.HorizontalAlign#CENTER
  	 * @see feathers.layout.HorizontalAlign#RIGHT
  	 * @see feathers.layout.HorizontalAlign#JUSTIFY
  	 */
  	[Style(name="horizontalAlign",type="String")]
  
  	/**
  	 * Space, in pixels, between the last two buttons. If <code>NaN</code>,
  	 * the default <code>gap</code> property will be used.
  	 *
  	 * <p>The following example sets the gap between the last and next to last
  	 * button to a different value than the standard gap:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.lastGap = 30;
  	 * group.gap = 20;</listing>
  	 *
  	 * @default NaN
  	 *
  	 * @see #style:gap
  	 * @see #style:firstGap
  	 */
  	[Style(name="lastGap",type="Number")]
  
  	/**
  	 * Quickly sets all padding properties to the same value. The
  	 * <code>padding</code> getter always returns the value of
  	 * <code>paddingTop</code>, but the other padding values may be
  	 * different.
  	 *
  	 * <p>In the following example, the padding of all sides of the group
  	 * is set to 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.padding = 20;</listing>
  	 *
  	 * @default 0
  	 *
  	 * @see #style:paddingTop
  	 * @see #style:paddingRight
  	 * @see #style:paddingBottom
  	 * @see #style:paddingLeft
  	 */
  	[Style(name="padding",type="Number")]
  
  	/**
  	 * The minimum space, in pixels, between the group's top edge and the
  	 * group's buttons.
  	 *
  	 * <p>In the following example, the padding on the top edge of the
  	 * group is set to 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.paddingTop = 20;</listing>
  	 *
  	 * @default 0
  	 * 
  	 * @see #style:padding
  	 */
  	[Style(name="paddingTop",type="Number")]
  
  	/**
  	 * The minimum space, in pixels, between the group's right edge and the
  	 * group's buttons.
  	 *
  	 * <p>In the following example, the padding on the right edge of the
  	 * group is set to 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.paddingRight = 20;</listing>
  	 *
  	 * @default 0
  	 *
  	 * @see #style:padding
  	 */
  	[Style(name="paddingRight",type="Number")]
  
  	/**
  	 * The minimum space, in pixels, between the group's bottom edge and the
  	 * group's buttons.
  	 *
  	 * <p>In the following example, the padding on the bottom edge of the
  	 * group is set to 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.paddingBottom = 20;</listing>
  	 *
  	 * @default 0
  	 *
  	 * @see #style:padding
  	 */
  	[Style(name="paddingBottom",type="Number")]
  
  	/**
  	 * The minimum space, in pixels, between the group's left edge and the
  	 * group's buttons.
  	 *
  	 * <p>In the following example, the padding on the left edge of the
  	 * group is set to 20 pixels:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.paddingLeft = 20;</listing>
  	 *
  	 * @default 0
  	 *
  	 * @see #style:padding
  	 */
  	[Style(name="paddingLeft",type="Number")]
  
  	/**
  	 * Determines how the buttons are vertically aligned within the bounds
  	 * of the button group (on the y-axis).
  	 *
  	 * <p>The following example aligns the group's content to the top:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.verticalAlign = VerticalAlign.TOP;</listing>
  	 *
  	 * @default feathers.layout.VerticalAlign.JUSTIFY
  	 *
  	 * @see feathers.layout.VerticalAlign#TOP
  	 * @see feathers.layout.VerticalAlign#MIDDLE
  	 * @see feathers.layout.VerticalAlign#BOTTOM
  	 * @see feathers.layout.VerticalAlign#JUSTIFY
  	 */
  	[Style(name="verticalAlign",type="String")]
  
  	/**
  	 * Dispatched when one of the buttons is triggered. The <code>data</code>
  	 * property of the event contains the item from the data provider that is
  	 * associated with the button that was triggered.
  	 *
  	 * <p>The following example listens to <code>Event.TRIGGERED</code> on the
  	 * button group instead of on individual buttons:</p>
  	 *
  	 * <listing version="3.0">
  	 * group.dataProvider = new ArrayCollection(
  	 * [
  	 *     { label: "Yes" },
  	 *     { label: "No" },
  	 *     { label: "Cancel" },
  	 * ]);
  	 * group.addEventListener( Event.TRIGGERED, function( event:Event, data:Object ):void
  	 * {
  	 *    trace( "The button with label \"" + data.label + "\" was triggered." );
  	 * }</listing>
  	 *
  	 * <p>The properties of the event object have the following values:</p>
  	 * <table class="innertable">
  	 * <tr><th>Property</th><th>Value</th></tr>
  	 * <tr><td><code>bubbles</code></td><td>false</td></tr>
  	 * <tr><td><code>currentTarget</code></td><td>The Object that defines the
  	 *   event listener that handles the event. For example, if you use
  	 *   <code>myButton.addEventListener()</code> to register an event listener,
  	 *   myButton is the value of the <code>currentTarget</code>.</td></tr>
  	 * <tr><td><code>data</code></td><td>The item associated with the button
  	 *   that was triggered.</td></tr>
  	 * <tr><td><code>target</code></td><td>The Object that dispatched the event;
  	 *   it is not always the Object listening for the event. Use the
  	 *   <code>currentTarget</code> property to always access the Object
  	 *   listening for the event.</td></tr>
  	 * </table>
  	 *
  	 * @eventType starling.events.Event.TRIGGERED
  	 */
  	[Event(name="triggered", type="starling.events.Event")]
  
  	/**
  	 * A set of related buttons with layout, customized using a data provider.
  	 *
  	 * <p>The following example creates a button group with a few buttons:</p>
  	 *
  	 * <listing version="3.0">
  	 * var group:ButtonGroup = new ButtonGroup();
  	 * group.dataProvider = new ArrayCollection(
  	 * [
  	 *     { label: "Yes", triggered: yesButton_triggeredHandler },
  	 *     { label: "No", triggered: noButton_triggeredHandler },
  	 *     { label: "Cancel", triggered: cancelButton_triggeredHandler },
  	 * ]);
  	 * this.addChild( group );</listing>
  	 *
  	 * @see ../../../help/button-group.html How to use the Feathers ButtonGroup component
  	 * @see feathers.controls.TabBar
  	 *
  	 * @productversion Feathers 1.0.0
  	 */
  	public class ButtonGroup extends FeathersControl implements ITextBaselineControl
  	{
  		/**
  		 * The default <code>IStyleProvider</code> for all <code>ButtonGroup</code>
  		 * components.
  		 *
  		 * @default null
  		 * @see feathers.core.FeathersControl#styleProvider
  		 */
  		public static var globalStyleProvider:IStyleProvider;
  
  		/**
  		 * @private
  		 */
  		protected static const INVALIDATION_FLAG_BUTTON_FACTORY:String = "buttonFactory";
  
  		/**
  		 * @private
  		 */
  		protected static const LABEL_FIELD:String = "label";
  
  		/**
  		 * @private
  		 */
  		protected static const ENABLED_FIELD:String = "isEnabled";
  
  		/**
  		 * @private
  		 */
  		private static const DEFAULT_BUTTON_FIELDS:Vector.<String> = new <String>
  		[
  			"defaultIcon",
  			"upIcon",
  			"downIcon",
  			"hoverIcon",
  			"disabledIcon",
  			"defaultSelectedIcon",
  			"selectedUpIcon",
  			"selectedDownIcon",
  			"selectedHoverIcon",
  			"selectedDisabledIcon",
  			"isSelected",
  			"isToggle",
  			"isLongPressEnabled",
  			"name",
  		];
  
  		/**
  		 * @private
  		 */
  		private static const DEFAULT_BUTTON_EVENTS:Vector.<String> = new <String>
  		[
  			Event.TRIGGERED,
  			Event.CHANGE,
  			FeathersEventType.LONG_PRESS,
  		];
  
  		/**
  		 * The default value added to the <code>styleNameList</code> of the buttons.
  		 *
  		 * @see feathers.core.FeathersControl#styleNameList
  		 */
  		public static const DEFAULT_CHILD_STYLE_NAME_BUTTON:String = "feathers-button-group-button";
  
  		/**
  		 * @private
  		 */
  		protected static function defaultButtonFactory():Button
  		{
  			return new Button();
  		}
  
  		/**
  		 * Constructor.
  		 */
  		public function ButtonGroup()
  		{
  			super();
  		}
  
  		/**
  		 * The value added to the <code>styleNameList</code> of the buttons.
  		 * This variable is <code>protected</code> so that sub-classes can
  		 * customize the button style name in their constructors instead of
  		 * using the default style name defined by
  		 * <code>DEFAULT_CHILD_STYLE_NAME_BUTTON</code>.
  		 *
  		 * <p>To customize the button style name without subclassing, see
  		 * <code>customButtonStyleName</code>.</p>
  		 *
  		 * @see #style:customButtonStyleName
  		 * @see feathers.core.FeathersControl#styleNameList
  		 */
  		protected var buttonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON;
  
  		/**
  		 * The value added to the <code>styleNameList</code> of the first button.
  		 *
  		 * <p>To customize the first button name without subclassing, see
  		 * <code>customFirstButtonStyleName</code>.</p>
  		 *
  		 * @see #style:customFirstButtonStyleName
  		 * @see feathers.core.FeathersControl#styleNameList
  		 */
  		protected var firstButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON;
  
  		/**
  		 * The value added to the <code>styleNameList</code> of the last button.
  		 *
  		 * <p>To customize the last button style name without subclassing, see
  		 * <code>customLastButtonStyleName</code>.</p>
  		 *
  		 * @see #style:customLastButtonStyleName
  		 * @see feathers.core.FeathersControl#styleNameList
  		 */
  		protected var lastButtonStyleName:String = DEFAULT_CHILD_STYLE_NAME_BUTTON;
  
  		/**
  		 * @private
  		 */
  		protected var activeFirstButton:Button;
  
  		/**
  		 * @private
  		 */
  		protected var inactiveFirstButton:Button;
  
  		/**
  		 * @private
  		 */
  		protected var activeLastButton:Button;
  
  		/**
  		 * @private
  		 */
  		protected var inactiveLastButton:Button;
  
  		/**
  		 * @private
  		 */
  		protected var _layoutItems:Vector.<DisplayObject> = new <DisplayObject>[];
  
  		/**
  		 * @private
  		 */
  		protected var activeButtons:Vector.<Button> = new <Button>[];
  
  		/**
  		 * @private
  		 */
  		protected var inactiveButtons:Vector.<Button> = new <Button>[];
  
  		/**
  		 * @private
  		 */
  		protected var _buttonToItem:Dictionary = new Dictionary(true);
  
  		/**
  		 * @private
  		 */
  		override protected function get defaultStyleProvider():IStyleProvider
  		{
  			return ButtonGroup.globalStyleProvider;
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _dataProvider:IListCollection;
  
  		/**
  		 * The collection of data to be displayed with buttons.
  		 *
  		 * <p>The following example sets the button group's data provider:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.dataProvider = new ArrayCollection(
  		 * [
  		 *     { label: "Yes", triggered: yesButton_triggeredHandler },
  		 *     { label: "No", triggered: noButton_triggeredHandler },
  		 *     { label: "Cancel", triggered: cancelButton_triggeredHandler },
  		 * ]);</listing>
  		 *
  		 * <p>By default, items in the data provider support the following
  		 * properties from <code>Button</code></p>
  		 *
  		 * <ul>
  		 *     <li>label</li>
  		 *     <li>defaultIcon</li>
  		 *     <li>upIcon</li>
  		 *     <li>downIcon</li>
  		 *     <li>hoverIcon</li>
  		 *     <li>disabledIcon</li>
  		 *     <li>defaultSelectedIcon</li>
  		 *     <li>selectedUpIcon</li>
  		 *     <li>selectedDownIcon</li>
  		 *     <li>selectedHoverIcon</li>
  		 *     <li>selectedDisabledIcon</li>
  		 *     <li>isSelected (only supported by <code>ToggleButton</code>)</li>
  		 *     <li>isToggle (only supported by <code>ToggleButton</code>)</li>
  		 *     <li>isEnabled</li>
  		 *     <li>name</li>
  		 * </ul>
  		 *
  		 * <p>Additionally, you can add the following event listeners:</p>
  		 *
  		 * <ul>
  		 *     <li>Event.TRIGGERED</li>
  		 *     <li>Event.CHANGE (only supported by <code>ToggleButton</code>)</li>
  		 * </ul>
  		 * 
  		 * <p>Event listeners may have one of the following signatures:</p>
  		 * <pre>function(event:Event):void</pre>
  		 * <pre>function(event:Event, eventData:Object):void</pre>
  		 * <pre>function(event:Event, eventData:Object, dataProviderItem:Object):void</pre>
  		 *
  		 * <p>To use properties and events that are only supported by
  		 * <code>ToggleButton</code>, you must provide a <code>buttonFactory</code>
  		 * that returns a <code>ToggleButton</code> instead of a <code>Button</code>.</p>
  		 *
  		 * <p>You can pass a function to the <code>buttonInitializer</code>
  		 * property that can provide custom logic to interpret each item in the
  		 * data provider differently. For example, you could use it to support
  		 * additional properties or events.</p>
  		 *
  		 * @default null
  		 *
  		 * @see feathers.controls.Button
  		 * @see #buttonInitializer
  		 * @see feathers.data.ArrayCollection
  		 * @see feathers.data.VectorCollection
  		 * @see feathers.data.XMLListCollection
  		 */
  		public function get dataProvider():IListCollection
  		{
  			return this._dataProvider;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set dataProvider(value:IListCollection):void
  		{
  			if(this._dataProvider == value)
  			{
  				return;
  			}
  			if(this._dataProvider)
  			{
  				this._dataProvider.removeEventListener(CollectionEventType.UPDATE_ALL, dataProvider_updateAllHandler);
  				this._dataProvider.removeEventListener(CollectionEventType.UPDATE_ITEM, dataProvider_updateItemHandler);
  				this._dataProvider.removeEventListener(Event.CHANGE, dataProvider_changeHandler);
  			}
  			this._dataProvider = value;
  			if(this._dataProvider)
  			{
  				this._dataProvider.addEventListener(CollectionEventType.UPDATE_ALL, dataProvider_updateAllHandler);
  				this._dataProvider.addEventListener(CollectionEventType.UPDATE_ITEM, dataProvider_updateItemHandler);
  				this._dataProvider.addEventListener(Event.CHANGE, dataProvider_changeHandler);
  			}
  			this.invalidate(INVALIDATION_FLAG_DATA);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var layout:ILayout;
  
  		/**
  		 * @private
  		 */
  		protected var _viewPortBounds:ViewPortBounds = new ViewPortBounds();
  
  		/**
  		 * @private
  		 */
  		protected var _layoutResult:LayoutBoundsResult = new LayoutBoundsResult();
  
  		/**
  		 * @private
  		 */
  		protected var _direction:String = Direction.VERTICAL;
  
  		[Inspectable(type="String",enumeration="horizontal,vertical")]
  		/**
  		 * @private
  		 */
  		public function get direction():String
  		{
  			return _direction;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set direction(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._direction === value)
  			{
  				return;
  			}
  			this._direction = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _horizontalAlign:String = HorizontalAlign.JUSTIFY;
  
  		[Inspectable(type="String",enumeration="left,center,right,justify")]
  		/**
  		 * @private
  		 */
  		public function get horizontalAlign():String
  		{
  			return this._horizontalAlign;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set horizontalAlign(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._horizontalAlign === value)
  			{
  				return;
  			}
  			this._horizontalAlign = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _verticalAlign:String = VerticalAlign.JUSTIFY;
  
  		[Inspectable(type="String",enumeration="top,middle,bottom,justify")]
  		/**
  		 * @private
  		 */
  		public function get verticalAlign():String
  		{
  			return _verticalAlign;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set verticalAlign(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._verticalAlign === value)
  			{
  				return;
  			}
  			this._verticalAlign = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _distributeButtonSizes:Boolean = true;
  
  		/**
  		 * @private
  		 */
  		public function get distributeButtonSizes():Boolean
  		{
  			return this._distributeButtonSizes;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set distributeButtonSizes(value:Boolean):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._distributeButtonSizes === value)
  			{
  				return;
  			}
  			this._distributeButtonSizes = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _gap:Number = 0;
  
  		/**
  		 * @private
  		 */
  		public function get gap():Number
  		{
  			return this._gap;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set gap(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._gap == value)
  			{
  				return;
  			}
  			this._gap = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _firstGap:Number = NaN;
  
  		/**
  		 * @private
  		 */
  		public function get firstGap():Number
  		{
  			return this._firstGap;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set firstGap(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._firstGap == value)
  			{
  				return;
  			}
  			this._firstGap = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _lastGap:Number = NaN;
  
  		/**
  		 * @private
  		 */
  		public function get lastGap():Number
  		{
  			return this._lastGap;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set lastGap(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._lastGap == value)
  			{
  				return;
  			}
  			this._lastGap = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		public function get padding():Number
  		{
  			return this._paddingTop;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set padding(value:Number):void
  		{
  			this.paddingTop = value;
  			this.paddingRight = value;
  			this.paddingBottom = value;
  			this.paddingLeft = value;
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _paddingTop:Number = 0;
  
  		/**
  		 * @private
  		 */
  		public function get paddingTop():Number
  		{
  			return this._paddingTop;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set paddingTop(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._paddingTop == value)
  			{
  				return;
  			}
  			this._paddingTop = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _paddingRight:Number = 0;
  
  		/**
  		 * @private
  		 */
  		public function get paddingRight():Number
  		{
  			return this._paddingRight;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set paddingRight(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._paddingRight == value)
  			{
  				return;
  			}
  			this._paddingRight = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _paddingBottom:Number = 0;
  
  		/**
  		 * @private
  		 */
  		public function get paddingBottom():Number
  		{
  			return this._paddingBottom;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set paddingBottom(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._paddingBottom == value)
  			{
  				return;
  			}
  			this._paddingBottom = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _paddingLeft:Number = 0;
  
  		/**
  		 * @private
  		 */
  		public function get paddingLeft():Number
  		{
  			return this._paddingLeft;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set paddingLeft(value:Number):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._paddingLeft == value)
  			{
  				return;
  			}
  			this._paddingLeft = value;
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _buttonFactory:Function = defaultButtonFactory;
  
  		/**
  		 * Creates each button in the group. A button must be an instance of
  		 * <code>Button</code>. This factory can be used to change properties on
  		 * the buttons when they are first created. For instance, if you are
  		 * skinning Feathers components without a theme, you might use this
  		 * factory to set skins and other styles on a button.
  		 *
  		 * <p>Optionally, the first button and the last button may be different
  		 * than the other buttons that are in the middle. Use the
  		 * <code>firstButtonFactory</code> and/or the
  		 * <code>lastButtonFactory</code> to customize one or both of these
  		 * buttons.</p>
  		 *
  		 * <p>This function is expected to have the following signature:</p>
  		 *
  		 * <pre>function():Button</pre>
  		 *
  		 * <p>The following example skins the buttons using a custom button
  		 * factory:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.buttonFactory = function():Button
  		 * {
  		 *     var button:Button = new Button();
  		 *     button.defaultSkin = new Image( texture );
  		 *     return button;
  		 * };</listing>
  		 *
  		 * @default null
  		 *
  		 * @see feathers.controls.Button
  		 * @see #firstButtonFactory
  		 * @see #lastButtonFactory
  		 */
  		public function get buttonFactory():Function
  		{
  			return this._buttonFactory;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set buttonFactory(value:Function):void
  		{
  			if(this._buttonFactory == value)
  			{
  				return;
  			}
  			this._buttonFactory = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _firstButtonFactory:Function;
  
  		/**
  		 * If not <code>null</code>, creates the first button. If the
  		 * <code>firstButtonFactory</code> is <code>null</code>, then the button
  		 * group will use the <code>buttonFactory</code>. The first button must
  		 * be an instance of <code>Button</code>. This factory can be used to
  		 * change properties on the first button when it is initially created.
  		 * For instance, if you are skinning Feathers components without a
  		 * theme, you might use this factory to set skins and other styles on
  		 * the first button.
  		 *
  		 * <p>This function is expected to have the following signature:</p>
  		 *
  		 * <pre>function():Button</pre>
  		 *
  		 * <p>The following example skins the first button using a custom
  		 * factory:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.firstButtonFactory = function():Button
  		 * {
  		 *     var button:Button = new Button();
  		 *     button.defaultSkin = new Image( texture );
  		 *     return button;
  		 * };</listing>
  		 *
  		 * @default null
  		 *
  		 * @see feathers.controls.Button
  		 * @see #buttonFactory
  		 * @see #lastButtonFactory
  		 */
  		public function get firstButtonFactory():Function
  		{
  			return this._firstButtonFactory;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set firstButtonFactory(value:Function):void
  		{
  			if(this._firstButtonFactory == value)
  			{
  				return;
  			}
  			this._firstButtonFactory = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _lastButtonFactory:Function;
  
  		/**
  		 * If not <code>null</code>, creates the last button. If the
  		 * <code>lastButtonFactory</code> is <code>null</code>, then the button
  		 * group will use the <code>buttonFactory</code>. The last button must
  		 * be an instance of <code>Button</code>. This factory can be used to
  		 * change properties on the last button when it is initially created.
  		 * For instance, if you are skinning Feathers components without a
  		 * theme, you might use this factory to set skins and other styles on
  		 * the last button.
  		 *
  		 * <p>This function is expected to have the following signature:</p>
  		 *
  		 * <pre>function():Button</pre>
  		 *
  		 * <p>The following example skins the last button using a custom
  		 * factory:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.lastButtonFactory = function():Button
  		 * {
  		 *     var button:Button = new Button();
  		 *     button.defaultSkin = new Image( texture );
  		 *     return button;
  		 * };</listing>
  		 *
  		 * @default null
  		 *
  		 * @see feathers.controls.Button
  		 * @see #buttonFactory
  		 * @see #firstButtonFactory
  		 */
  		public function get lastButtonFactory():Function
  		{
  			return this._lastButtonFactory;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set lastButtonFactory(value:Function):void
  		{
  			if(this._lastButtonFactory == value)
  			{
  				return;
  			}
  			this._lastButtonFactory = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _buttonInitializer:Function = defaultButtonInitializer;
  
  		/**
  		 * Modifies a button, perhaps by changing its label and icons, based on the
  		 * item from the data provider that the button is meant to represent. The
  		 * default buttonInitializer function can set the button's label and icons if
  		 * <code>label</code> and/or any of the <code>Button</code> icon fields
  		 * (<code>defaultIcon</code>, <code>upIcon</code>, etc.) are present in
  		 * the item. You can listen to <code>Event.TRIGGERED</code> and
  		 * <code>Event.CHANGE</code> by passing in functions for each.
  		 *
  		 * <p>This function is expected to have the following signature:</p>
  		 *
  		 * <pre>function( button:Button, item:Object ):void</pre>
  		 *
  		 * <p>The following example provides a custom button initializer:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.buttonInitializer = function( button:Button, item:Object ):void
  		 * {
  		 *     button.label = item.label;
  		 * };</listing>
  		 *
  		 * @see #dataProvider
  		 */
  		public function get buttonInitializer():Function
  		{
  			return this._buttonInitializer;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set buttonInitializer(value:Function):void
  		{
  			if(this._buttonInitializer == value)
  			{
  				return;
  			}
  			this._buttonInitializer = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _buttonReleaser:Function = defaultButtonReleaser;
  
  		/**
  		 * Resets the properties of an individual button, using the item from the
  		 * data provider that was associated with the button.
  		 *
  		 * <p>This function is expected to have one of the following signatures:</p>
  		 * <pre>function( tab:Button ):void</pre>
  		 * <pre>function( tab:Button, oldItem:Object ):void</pre>
  		 *
  		 * <p>In the following example, a custom button releaser is passed to the
  		 * button group:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.buttonReleaser = function( button:Button, oldItem:Object ):void
  		 * {
  		 *     button.label = null;
  		 * };</listing>
  		 *
  		 * @see #buttonInitializer
  		 */
  		public function get buttonReleaser():Function
  		{
  			return this._buttonReleaser;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set buttonReleaser(value:Function):void
  		{
  			if(this._buttonReleaser == value)
  			{
  				return;
  			}
  			this._buttonReleaser = value;
  			this.invalidate(INVALIDATION_FLAG_DATA);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _customButtonStyleName:String;
  
  		/**
  		 * @private
  		 */
  		public function get customButtonStyleName():String
  		{
  			return this._customButtonStyleName;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set customButtonStyleName(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._customButtonStyleName === value)
  			{
  				return;
  			}
  			this._customButtonStyleName = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _customFirstButtonStyleName:String;
  
  		/**
  		 * @private
  		 */
  		public function get customFirstButtonStyleName():String
  		{
  			return this._customFirstButtonStyleName;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set customFirstButtonStyleName(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._customFirstButtonStyleName === value)
  			{
  				return;
  			}
  			this._customFirstButtonStyleName = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _customLastButtonStyleName:String;
  
  		/**
  		 * @private
  		 */
  		public function get customLastButtonStyleName():String
  		{
  			return this._customLastButtonStyleName;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set customLastButtonStyleName(value:String):void
  		{
  			if(this.processStyleRestriction(arguments.callee))
  			{
  				return;
  			}
  			if(this._customLastButtonStyleName === value)
  			{
  				return;
  			}
  			this._customLastButtonStyleName = value;
  			this.invalidate(INVALIDATION_FLAG_BUTTON_FACTORY);
  		}
  
  		/**
  		 * @private
  		 */
  		protected var _buttonProperties:PropertyProxy;
  
  		/**
  		 * An object that stores properties for all of the button group's
  		 * buttons, and the properties will be passed down to every button when
  		 * the button group validates. For a list of available properties,
  		 * refer to <a href="Button.html"><code>feathers.controls.Button</code></a>.
  		 * 
  		 * <p>These properties are shared by every button, so anything that cannot
  		 * be shared (such as display objects, which cannot be added to multiple
  		 * parents) should be passed to buttons using the
  		 * <code>buttonFactory</code> or in the theme.</p>
  		 *
  		 * <p>If the subcomponent has its own subcomponents, their properties
  		 * can be set too, using attribute <code>&#64;</code> notation. For example,
  		 * to set the skin on the thumb which is in a <code>SimpleScrollBar</code>,
  		 * which is in a <code>List</code>, you can use the following syntax:</p>
  		 * <pre>list.verticalScrollBarProperties.&#64;thumbProperties.defaultSkin = new Image(texture);</pre>
  		 *
  		 * <p>The following example sets some properties on all of the buttons:</p>
  		 *
  		 * <listing version="3.0">
  		 * group.buttonProperties.horizontalAlign = HorizontalAlign.LEFT;
  		 * group.buttonProperties.verticalAlign = VerticalAlign.TOP;</listing>
  		 *
  		 * <p>Setting properties in a <code>buttonFactory</code> function instead
  		 * of using <code>buttonProperties</code> will result in better
  		 * performance.</p>
  		 *
  		 * @default null
  		 *
  		 * @see #buttonFactory
  		 * @see #firstButtonFactory
  		 * @see #lastButtonFactory
  		 * @see feathers.controls.Button
  		 */
  		public function get buttonProperties():Object
  		{
  			if(!this._buttonProperties)
  			{
  				this._buttonProperties = new PropertyProxy(childProperties_onChange);
  			}
  			return this._buttonProperties;
  		}
  
  		/**
  		 * @private
  		 */
  		public function set buttonProperties(value:Object):void
  		{
  			if(this._buttonProperties == value)
  			{
  				return;
  			}
  			if(!value)
  			{
  				value = new PropertyProxy();
  			}
  			if(!(value is PropertyProxy))
  			{
  				var newValue:PropertyProxy = new PropertyProxy();
  				for(var propertyName:String in value)
  				{
  					newValue[propertyName] = value[propertyName];
  				}
  				value = newValue;
  			}
  			if(this._buttonProperties)
  			{
  				this._buttonProperties.removeOnChangeCallback(childProperties_onChange);
  			}
  			this._buttonProperties = PropertyProxy(value);
  			if(this._buttonProperties)
  			{
  				this._buttonProperties.addOnChangeCallback(childProperties_onChange);
  			}
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @inheritDoc
  		 */
  		public function get baseline():Number
  		{
  			if(!this.activeButtons || this.activeButtons.length == 0)
  			{
  				return this.scaledActualHeight;
  			}
  			var firstButton:Button = this.activeButtons[0];
  			return this.scaleY * (firstButton.y + firstButton.baseline);
  		}
  
  		/**
  		 * @private
  		 */
  		override public function dispose():void
  		{
  			this.dataProvider = null;
  			super.dispose();
  		}
  
  		/**
  		 * @private
  		 */
  		override protected function draw():void
  		{
  			var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
  			var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
  			var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
  			var buttonFactoryInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_BUTTON_FACTORY);
  			var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE);
  
  			if(dataInvalid || stateInvalid || buttonFactoryInvalid)
  			{
  				this.refreshButtons(buttonFactoryInvalid);
  			}
  
  			if(dataInvalid || buttonFactoryInvalid || stylesInvalid)
  			{
  				this.refreshButtonStyles();
  			}
  
  			if(dataInvalid || stateInvalid || buttonFactoryInvalid)
  			{
  				this.commitEnabled();
  			}
  
  			if(stylesInvalid)
  			{
  				this.refreshLayoutStyles();
  			}
  
  			this.layoutButtons();
  		}
  
  		/**
  		 * @private
  		 */
  		protected function commitEnabled():void
  		{
  			var buttonCount:int = this.activeButtons.length;
  			for(var i:int = 0; i < buttonCount; i++)
  			{
  				var button:Button = this.activeButtons[i];
  				button.isEnabled &&= this._isEnabled;
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function refreshButtonStyles():void
  		{
  			for(var propertyName:String in this._buttonProperties)
  			{
  				var propertyValue:Object = this._buttonProperties[propertyName];
  				for each(var button:Button in this.activeButtons)
  				{
  					button[propertyName] = propertyValue;
  				}
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function refreshLayoutStyles():void
  		{
  			if(this._direction == Direction.VERTICAL)
  			{
  				var verticalLayout:VerticalLayout = this.layout as VerticalLayout;
  				if(!verticalLayout)
  				{
  					this.layout = verticalLayout = new VerticalLayout();
  				}
  				verticalLayout.distributeHeights = this._distributeButtonSizes;
  				verticalLayout.horizontalAlign = this._horizontalAlign;
  				verticalLayout.verticalAlign = (this._verticalAlign == VerticalAlign.JUSTIFY) ? VerticalAlign.TOP : this._verticalAlign;
  				verticalLayout.gap = this._gap;
  				verticalLayout.firstGap = this._firstGap;
  				verticalLayout.lastGap = this._lastGap;
  				verticalLayout.paddingTop = this._paddingTop;
  				verticalLayout.paddingRight = this._paddingRight;
  				verticalLayout.paddingBottom = this._paddingBottom;
  				verticalLayout.paddingLeft = this._paddingLeft;
  			}
  			else //horizontal
  			{
  				if(this._distributeButtonSizes)
  				{
  					var horizontalLayout:HorizontalLayout = this.layout as HorizontalLayout;
  					if(!horizontalLayout)
  					{
  						this.layout = horizontalLayout = new HorizontalLayout();
  					}
  					horizontalLayout.distributeWidths = true;
  					horizontalLayout.horizontalAlign = (this._horizontalAlign == HorizontalAlign.JUSTIFY) ? HorizontalAlign.LEFT : this._horizontalAlign;
  					horizontalLayout.verticalAlign = this._verticalAlign;
  					horizontalLayout.gap = this._gap;
  					horizontalLayout.firstGap = this._firstGap;
  					horizontalLayout.lastGap = this._lastGap;
  					horizontalLayout.paddingTop = this._paddingTop;
  					horizontalLayout.paddingRight = this._paddingRight;
  					horizontalLayout.paddingBottom = this._paddingBottom;
  					horizontalLayout.paddingLeft = this._paddingLeft;
  				}
  				else
  				{
  					var flowLayout:FlowLayout = this.layout as FlowLayout;
  					if(!flowLayout)
  					{
  						this.layout = flowLayout = new FlowLayout();
  					}
  					flowLayout.horizontalAlign = (this._horizontalAlign == HorizontalAlign.JUSTIFY) ? HorizontalAlign.LEFT : this._horizontalAlign;
  					flowLayout.verticalAlign = this._verticalAlign;
  					flowLayout.gap = this._gap;
  					flowLayout.firstHorizontalGap = this._firstGap;
  					flowLayout.lastHorizontalGap = this._lastGap;
  					flowLayout.paddingTop = this._paddingTop;
  					flowLayout.paddingRight = this._paddingRight;
  					flowLayout.paddingBottom = this._paddingBottom;
  					flowLayout.paddingLeft = this._paddingLeft;
  				}
  			}
  			if(layout is IVirtualLayout)
  			{
  				IVirtualLayout(layout).useVirtualLayout = false;
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function defaultButtonInitializer(button:Button, item:Object):void
  		{
  			if(item is Object)
  			{
  				if(item.hasOwnProperty(LABEL_FIELD))
  				{
  					button.label = item.label as String;
  				}
  				else
  				{
  					button.label = item.toString();
  				}
  				if(item.hasOwnProperty(ENABLED_FIELD))
  				{
  					button.isEnabled = item.isEnabled as Boolean;
  				}
  				else
  				{
  					button.isEnabled = this._isEnabled;
  				}
  				for each(var field:String in DEFAULT_BUTTON_FIELDS)
  				{
  					if(item.hasOwnProperty(field))
  					{
  						button[field] = item[field];
  					}
  				}
  				for each(field in DEFAULT_BUTTON_EVENTS)
  				{
  					var removeListener:Boolean = true;
  					if(item.hasOwnProperty(field))
  					{
  						var listener:Function = item[field] as Function;
  						if(listener === null)
  						{
  							continue;
  						}
  						removeListener = false;
  						//we can't add the listener directly because we don't
  						//know how to remove it later if the data provider
  						//changes and we lose the old item. we'll use another
  						//event listener that we control as a delegate, and
  						//we'll be able to remove it later.
  						button.addEventListener(field, defaultButtonEventsListener);
  					}
  					if(removeListener)
  					{
  						button.removeEventListener(field, defaultButtonEventsListener);
  					}
  				}
  			}
  			else
  			{
  				button.label = "";
  				button.isEnabled = this._isEnabled;
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function defaultButtonReleaser(button:Button, oldItem:Object):void
  		{
  			button.label = null;
  			for each(var field:String in DEFAULT_BUTTON_FIELDS)
  			{
  				if(oldItem.hasOwnProperty(field))
  				{
  					button[field] = null;
  				}
  			}
  			for each(field in DEFAULT_BUTTON_EVENTS)
  			{
  				var removeListener:Boolean = true;
  				if(oldItem.hasOwnProperty(field))
  				{
  					var listener:Function = oldItem[field] as Function;
  					if(listener === null)
  					{
  						continue;
  					}
  					button.removeEventListener(field, defaultButtonEventsListener);
  				}
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function refreshButtons(isFactoryInvalid:Boolean):void
  		{
  			var temp:Vector.<Button> = this.inactiveButtons;
  			this.inactiveButtons = this.activeButtons;
  			this.activeButtons = temp;
  			this.activeButtons.length = 0;
  			this._layoutItems.length = 0;
  			temp = null;
  			if(isFactoryInvalid)
  			{
  				this.clearInactiveButtons();
  			}
  			else
  			{
  				if(this.activeFirstButton)
  				{
  					this.inactiveButtons.shift();
  				}
  				this.inactiveFirstButton = this.activeFirstButton;
  
  				if(this.activeLastButton)
  				{
  					this.inactiveButtons.pop();
  				}
  				this.inactiveLastButton = this.activeLastButton;
  			}
  			this.activeFirstButton = null;
  			this.activeLastButton = null;
  
  			var pushIndex:int = 0;
  			var itemCount:int = this._dataProvider ? this._dataProvider.length : 0;
  			var lastItemIndex:int = itemCount - 1;
  			for(var i:int = 0; i < itemCount; i++)
  			{
  				var item:Object = this._dataProvider.getItemAt(i);
  				if(i == 0)
  				{
  					var button:Button = this.activeFirstButton = this.createFirstButton(item);
  				}
  				else if(i == lastItemIndex)
  				{
  					button = this.activeLastButton = this.createLastButton(item);
  				}
  				else
  				{
  					button = this.createButton(item);
  				}
  				this.activeButtons[pushIndex] = button;
  				this._layoutItems[pushIndex] = button;
  				pushIndex++;
  			}
  			this.clearInactiveButtons();
  		}
  
  		/**
  		 * @private
  		 */
  		protected function clearInactiveButtons():void
  		{
  			var itemCount:int = this.inactiveButtons.length;
  			for(var i:int = 0; i < itemCount; i++)
  			{
  				var button:Button = this.inactiveButtons.shift();
  				this.destroyButton(button);
  			}
  
  			if(this.inactiveFirstButton)
  			{
  				this.destroyButton(this.inactiveFirstButton);
  				this.inactiveFirstButton = null;
  			}
  
  			if(this.inactiveLastButton)
  			{
  				this.destroyButton(this.inactiveLastButton);
  				this.inactiveLastButton = null;
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function createFirstButton(item:Object):Button
  		{
  			var isNewInstance:Boolean = false;
  			if(this.inactiveFirstButton !== null)
  			{
  				var button:Button = this.inactiveFirstButton;
  				this.releaseButton(button);
  				this.inactiveFirstButton = null;
  			}
  			else
  			{
  				isNewInstance = true;
  				var factory:Function = this._firstButtonFactory != null ? this._firstButtonFactory : this._buttonFactory;
  				button = Button(factory());
  				if(this._customFirstButtonStyleName)
  				{
  					button.styleNameList.add(this._customFirstButtonStyleName);
  				}
  				else if(this._customButtonStyleName)
  				{
  					button.styleNameList.add(this._customButtonStyleName);
  				}
  				else
  				{
  					button.styleNameList.add(this.firstButtonStyleName);
  				}
  				this.addChild(button);
  			}
  			this._buttonInitializer(button, item);
  			this._buttonToItem[button] = item;
  			if(isNewInstance)
  			{
  				//we need to listen for Event.TRIGGERED after the initializer
  				//is called to avoid runtime errors because the button may be
  				//disposed by the time listeners in the initializer are called.
  				button.addEventListener(Event.TRIGGERED, button_triggeredHandler);
  			}
  			return button;
  		}
  
  		/**
  		 * @private
  		 */
  		protected function createLastButton(item:Object):Button
  		{
  			var isNewInstance:Boolean = false;
  			if(this.inactiveLastButton !== null)
  			{
  				var button:Button = this.inactiveLastButton;
  				this.releaseButton(button);
  				this.inactiveLastButton = null;
  			}
  			else
  			{
  				isNewInstance = true;
  				var factory:Function = this._lastButtonFactory != null ? this._lastButtonFactory : this._buttonFactory;
  				button = Button(factory());
  				if(this._customLastButtonStyleName)
  				{
  					button.styleNameList.add(this._customLastButtonStyleName);
  				}
  				else if(this._customButtonStyleName)
  				{
  					button.styleNameList.add(this._customButtonStyleName);
  				}
  				else
  				{
  					button.styleNameList.add(this.lastButtonStyleName);
  				}
  				this.addChild(button);
  			}
  			this._buttonInitializer(button, item);
  			this._buttonToItem[button] = item;
  			if(isNewInstance)
  			{
  				//we need to listen for Event.TRIGGERED after the initializer
  				//is called to avoid runtime errors because the button may be
  				//disposed by the time listeners in the initializer are called.
  				button.addEventListener(Event.TRIGGERED, button_triggeredHandler);
  			}
  			return button;
  		}
  
  		/**
  		 * @private
  		 */
  		protected function createButton(item:Object):Button
  		{
  			var isNewInstance:Boolean = false;
  			if(this.inactiveButtons.length == 0)
  			{
  				isNewInstance = true;
  				var button:Button = this._buttonFactory();
  				if(this._customButtonStyleName)
  				{
  					button.styleNameList.add(this._customButtonStyleName);
  				}
  				else
  				{
  					button.styleNameList.add(this.buttonStyleName);
  				}
  				this.addChild(button);
  			}
  			else
  			{
  				button = this.inactiveButtons.shift();
  				this.releaseButton(button);
  			}
  			this._buttonInitializer(button, item);
  			this._buttonToItem[button] = item;
  			if(isNewInstance)
  			{
  				//we need to listen for Event.TRIGGERED after the initializer
  				//is called to avoid runtime errors because the button may be
  				//disposed by the time listeners in the initializer are called.
  				button.addEventListener(Event.TRIGGERED, button_triggeredHandler);
  			}
  			return button;
  		}
  
  		/**
  		 * @private
  		 */
  		protected function releaseButton(button:Button):void
  		{
  			var item:Object = this._buttonToItem[button];
  			delete this._buttonToItem[button];
  			if(this._buttonReleaser.length == 1)
  			{
  				this._buttonReleaser(button);
  			}
  			else
  			{
  				this._buttonReleaser(button, item);
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function destroyButton(button:Button):void
  		{
  			button.removeEventListener(Event.TRIGGERED, button_triggeredHandler);
  			this.releaseButton(button);
  			this.removeChild(button, true);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function layoutButtons():void
  		{
  			this._viewPortBounds.x = 0;
  			this._viewPortBounds.y = 0;
  			this._viewPortBounds.scrollX = 0;
  			this._viewPortBounds.scrollY = 0;
  			this._viewPortBounds.explicitWidth = this._explicitWidth;
  			this._viewPortBounds.explicitHeight = this._explicitHeight;
  			this._viewPortBounds.minWidth = this._explicitMinWidth;
  			this._viewPortBounds.minHeight = this._explicitMinHeight;
  			this._viewPortBounds.maxWidth = this._explicitMaxWidth;
  			this._viewPortBounds.maxHeight = this._explicitMaxHeight;
  			this.layout.layout(this._layoutItems, this._viewPortBounds, this._layoutResult);
  			
  			var contentWidth:Number = this._layoutResult.contentWidth;
  			var contentHeight:Number = this._layoutResult.contentHeight;
  			//minimum dimensions are the same as the measured dimensions
  			this.saveMeasurements(contentWidth, contentHeight, contentWidth, contentHeight);
  			
  			//final validation to avoid juggler next frame issues
  			for each(var button:Button in this.activeButtons)
  			{
  				button.validate();
  			}
  		}
  
  		/**
  		 * @private
  		 */
  		protected function childProperties_onChange(proxy:PropertyProxy, name:String):void
  		{
  			this.invalidate(INVALIDATION_FLAG_STYLES);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function dataProvider_changeHandler(event:Event):void
  		{
  			this.invalidate(INVALIDATION_FLAG_DATA);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function dataProvider_updateAllHandler(event:Event):void
  		{
  			this.invalidate(INVALIDATION_FLAG_DATA);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function dataProvider_updateItemHandler(event:Event, index:int):void
  		{
  			this.invalidate(INVALIDATION_FLAG_DATA);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function button_triggeredHandler(event:Event):void
  		{
  			//if this was called after dispose, ignore it
  			if(!this._dataProvider || !this.activeButtons)
  			{
  				return;
  			}
  			var button:Button = Button(event.currentTarget);
  			var index:int = this.activeButtons.indexOf(button);
  			var item:Object = this._dataProvider.getItemAt(index);
  			this.dispatchEventWith(Event.TRIGGERED, false, item);
  		}
  
  		/**
  		 * @private
  		 */
  		protected function defaultButtonEventsListener(event:Event):void
  		{
  			var button:Button = Button(event.currentTarget);
  			var index:int = this.activeButtons.indexOf(button);
  			var item:Object = this._dataProvider.getItemAt(index);
  			var field:String = event.type;
  			if(item.hasOwnProperty(field))
  			{
  				var listener:Function = item[field] as Function;
  				if(listener == null)
  				{
  					return;
  				}
  				var argCount:int = listener.length;
  				switch(argCount)
  				{
  					case 3:
  					{
  						listener(event, event.data, item);
  						break;
  					}
  					case 2:
  					{
  						listener(event, event.data);
  						break;
  					}
  					case 1:
  					{
  						listener(event);
  						break;
  					}
  					default:
  					{
  						listener();
  					}
  				}
  			}
  		}
  	}
  }
  