http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductCatalogPanel.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductCatalogPanel.mxml 
b/FlexStore/mx/src/productsView/ProductCatalogPanel.mxml
new file mode 100644
index 0000000..63754ba
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductCatalogPanel.mxml
@@ -0,0 +1,534 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"; 
+    xmlns:productsView="productsView.*"
+    layout="vertical" 
+    currentState="browse"
+    verticalScrollPolicy="off"
+    horizontalScrollPolicy="off"
+    styleName="catalogPanel">
+    
+    <mx:Metadata>
+        [Event(name="purchase", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="compare", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="details", type="samples.flexstore.ProductThumbEvent")]
+    </mx:Metadata>
+    
+    <mx:Script>
+        <![CDATA[
+        import flash.utils.Dictionary;
+        
+        import mx.collections.ArrayCollection;
+        import mx.collections.IViewCursor;
+        import mx.core.DragSource;
+        import mx.core.IUIComponent;
+        import mx.effects.Effect;
+        import mx.effects.Fade;
+        import mx.effects.Move;
+        import mx.events.EffectEvent;
+        import mx.events.DragEvent;
+        import mx.managers.DragManager;
+
+        import samples.flexstore.Product;
+        import samples.flexstore.ProductFilter;
+        import samples.flexstore.ProductFilterEvent;
+        import samples.flexstore.ProductThumbEvent;
+       
+     
+        private var accepted:Dictionary = new Dictionary();
+        private var thumbnails:Array;
+        private var filterCount:int;
+        private var thumbnailState:String = 'browse'; //either 'browse' or 
'compare'
+        [Bindable]
+        private var titleButtons:CatalogTitleButtons; //the buttons that also 
allow the panel to switch sides
+        
+        override protected function createChildren():void
+        {
+            super.createChildren();
+            titleButtons = new CatalogTitleButtons();
+            titleBar.addChild(titleButtons);
+            
+        }
+
+        override protected function layoutChrome(unscaledWidth:Number, 
unscaledHeight:Number):void
+        {        
+            super.layoutChrome(unscaledWidth, unscaledHeight);
+            //when adding to a UIComponent (not a Container) need explicit 
width/height
+            titleButtons.width = unscaledWidth / 2; //make it big so as we add 
cart items we can stretch)
+            titleButtons.height = titleButtons.measuredHeight;
+            //this placement algorithm is pretty hacky, there are better ways 
that probably
+            //involve copying more of the Panel layoutChrome method and 
supporting methods
+            titleButtons.move(statusTextField.x - titleButtons.width, 
titleTextField.y);
+        }
+        
+        
+        [Bindable]
+        public var cartCount:int;
+        
+        //-----------------------------
+        // catalog
+        //-----------------------------
+        
+        private var _catalog:ArrayCollection;
+        
+        [Bindable]
+        public function set catalog(c:ArrayCollection):void
+        {
+            _catalog = c;
+            createThumbnails();
+        }
+        
+        public function get catalog():ArrayCollection
+        {
+            return _catalog;
+        }
+        
+        
//----------------------------------------------------------------------
+        // methods
+        
//----------------------------------------------------------------------
+       
+        private function createThumbnails():void
+        {
+            var i:int; //variables are hoisted up in scope so declare here to 
avoid warning
+            if (thumbnails != null)
+            {
+                for (i=0; i < thumbnails.length; i++)
+                {
+                    thumbContent.removeChild(thumbnails[i]);
+                }
+            }
+            
+            var row:int = 0;
+            var col:int = -1;
+            var n:int = catalog.length;
+            thumbnails = new Array(n);
+            filterCount = n;
+            
+            for (i=0; i < n; i++)
+            {
+                var thumb:ProductCatalogThumbnail = new 
ProductCatalogThumbnail();
+                thumbnails[i] = thumb;
+                thumbnails[i].showInAutomationHierarchy = true;
+                thumb.product = catalog.getItemAt(i) as Product;
+                accepted[thumb.product] = true;
+                thumbContent.addChild(thumb);
+                thumb.addEventListener(ProductThumbEvent.PURCHASE, 
productThumbEventHandler);
+                thumb.addEventListener(ProductThumbEvent.COMPARE, 
productThumbEventHandler);
+                thumb.addEventListener(ProductThumbEvent.DETAILS, 
productThumbEventHandler);
+                
thumb.addEventListener(DragEvent.DRAG_START,thumbDragStartHandler);
+            }
+
+            layoutCatalog();
+        }
+        
+        private function thumbDragStartHandler(event:MouseEvent):void
+        {
+            if (DragManager.isDragging == false)
+            {
+                var thumb:ProductCatalogThumbnail = event.target as 
ProductCatalogThumbnail;
+                var ds:DragSource = new DragSource();
+                ds.addData(thumb.product, "product");
+
+                var di:ProductCatalogThumbnail = new ProductCatalogThumbnail();
+                di.product = thumb.product;
+                
+                //the offset logic is honestly not the most intuitive but
+                //it's necessary to get the dragProxy positioned correctly
+                DragManager.doDrag(thumbContent, ds, event, di, -thumb.x, 
+                                              -thumb.y + 
thumbContent.verticalScrollPosition, 
+                                              0.5, false);
+            }    
+        }
+        
+        public function filter(productFilter:ProductFilter, live:Boolean):void
+        {
+            currentState = "browse";
+            thumbnailState = "browse";
+            var count:int=0;
+            var n:int = thumbnails.length;
+            var fadeOut:Fade = new Fade();
+            fadeOut.alphaFrom = 1;
+            fadeOut.alphaTo = .1;
+            var targets:Array = [];
+            for (var i:int = 0; i < n; i++)
+            {
+                var thumb:ProductCatalogThumbnail = thumbnails[i];
+                var product:Product = thumb.product;
+                if (productFilter.accept(product))
+                {
+                    accepted[product] = true;
+                    thumb.alpha = 1;    
+                    count++;
+                }
+                else
+                {
+                    accepted[product] = false;
+                    if (live)
+                    {
+                        thumb.alpha = .1;
+                    }
+                    else if (thumb.alpha == 1) //only fade if we hadn't started
+                    {
+                        targets.push(thumb);
+                    }
+                }
+            }
+            productFilter.count = count;
+            filterCount = count;
+
+            if (targets.length > 0)    
+            {
+                fadeOut.targets = targets;
+                fadeOut.play();
+                fadeOut.addEventListener(EffectEvent.EFFECT_END,
+                    function(event:EffectEvent):void
+                    {
+                        layoutCatalog();
+                    });
+            }
+            else if (!live)
+            {
+                layoutCatalog();
+            }
+        }
+        
+        private function layoutCatalog():Effect
+        {
+            var tileWidth:Number;
+            var tileHeight:Number;
+            var numCols:int;
+
+            if (filterCount > 9 || currentState == "compare")
+            {
+                numCols = 4;
+                tileWidth = ProductCatalogThumbnail.COL_WIDTH_4;
+                tileWidth = currentState == "compare"
+                    ? ProductCatalogThumbnail.COMPARE_WIDTH
+                    : ProductCatalogThumbnail.COL_WIDTH_4
+                tileHeight = currentState == "compare"
+                    ? height - 4
+                    : ProductCatalogThumbnail.COL_HEIGHT_4;
+            }
+            else if (filterCount > 4)
+                       {
+                numCols = 3;
+                tileWidth = ProductCatalogThumbnail.COL_WIDTH_3;
+                tileHeight = ProductCatalogThumbnail.COL_HEIGHT_3;
+            }
+                       else if (filterCount <= 9)
+                       {
+                numCols = 2;
+                tileWidth = ProductCatalogThumbnail.COL_WIDTH_2;
+                tileHeight = ProductCatalogThumbnail.COL_HEIGHT_2;
+            }
+                       else
+                       {
+            }
+            
+            var row:int = 0;
+            var col:int = -1;
+
+                       var move:Move = null;
+
+            var n:int = catalog.length;
+                       for (var i:int = 0 ; i < n ; i++)
+                       {
+                var product:Product = catalog.getItemAt(i) as Product;
+                var thumb:ProductCatalogThumbnail = thumbnails[i];
+                if (accepted[product])
+                {
+                    thumb.currentState = "" + numCols + "cols";
+                    col++;
+                    if (col > numCols - 1)
+                                       {
+                        row++;
+                        col = 0;
+                    }
+
+                    var xTo:Number = col * (tileWidth + 
ProductCatalogThumbnail.HORIZONTAL_GAP);
+                    var yTo:Number = row * (tileHeight + 
ProductCatalogThumbnail.VERTICAL_GAP);
+
+                    // If the thumbnail is already visible
+                                       // animate it to its new position.
+                    if (thumb.visible)
+                                       {
+                        // Animate only if the position is different
+                                               // from its current position.
+                        if (thumb.x != xTo || thumb.y != yTo)
+                                               {
+                            move = new Move(thumb);
+                            move.xTo = xTo;
+                            move.yTo = yTo;
+                            move.play();
+                        }
+                    }
+
+                    // If the thumbnail was not previously visible, sets its
+                                       // x and y coordinates. We'll make it 
reappear after all
+                    // the visible thumbnails have reached their new position.
+                                       else
+                                       {
+                        thumb.x = xTo;
+                        thumb.y = yTo;
+                        thumb.includeInLayout = true;
+                    }
+                }
+                               else
+                               {
+                    thumb.visible = false;
+                    thumb.includeInLayout = false;
+                }
+            }
+
+            if (!move)
+                       {
+                // No visible thumbnails were animated to a new position;
+                               // fade in newly selected thumbnails right away.
+                fadeInThumbnails();
+            }
+                       else
+                       {
+                           //since movement is happening get the scrollbar 
back to the top
+                               thumbContent.verticalScrollPosition = 0;
+                // Fade in newly selected thumbnails after the last
+                               // visible thumbnail has moved to its new 
position.
+                move.addEventListener(EffectEvent.EFFECT_END,
+                                       function(event:EffectEvent):void
+                                       {
+                                               fadeInThumbnails();
+                                       });
+            }
+            //return the last move to watch
+            return move;
+        }
+        
+        //return the last effect so we could add effectEnd handler if desired
+        private function fadeInThumbnails():void
+               {
+                       var n:int = thumbnails.length;
+                       var effect:Fade = new Fade();
+                       effect.alphaTo = 1;
+                       var targets:Array = [];
+                       for (var i:int = 0; i < n ; i++)
+                       {
+                           var thumb:ProductCatalogThumbnail = thumbnails[i];
+                           if (accepted[thumb.product] && !thumb.visible)
+                               {
+                    thumb.alpha = 0;
+                    thumb.visible = true;
+                    targets.push(thumb);
+                }
+            }
+            if (targets.length > 0)
+            {
+                effect.targets = targets;
+                effect.play();
+            }
+        }
+        
+        private function showDetails(product:Product):void
+        {
+            if (currentState == "details")
+                       {
+                details.product = product;
+                return;
+            }
+
+            var row:int = -1;
+
+            //should be computed using border metrics instead of hard-coding 
the 20, but...
+                       var xTo:Number = thumbContent.width - 
ProductCatalogThumbnail.COL_WIDTH_4 - 20;
+            var yTo:Number;
+
+            var move:Move;
+            var first:Boolean = true;
+            var selectedThumb:ProductCatalogThumbnail;
+
+            var n:int = thumbnails.length;
+                       for (var i:int = 0; i < n; i++)
+                       {
+                           var thumb:ProductCatalogThumbnail = thumbnails[i];
+                if (thumb.visible)
+                               {
+                    row++;
+                    yTo = row * (ProductCatalogThumbnail.COL_HEIGHT_4 + 
ProductCatalogThumbnail.VERTICAL_GAP);
+
+                    thumb.currentState = "4cols";
+
+                    if (thumb.x != xTo || thumb.y != yTo)
+                                       {
+                        move = new Move(thumb);
+                        if (first)
+                                               {
+                            move.addEventListener(EffectEvent.EFFECT_END,
+                                                               
function(event:EffectEvent):void
+                                                               {
+                                                                       
details.product = product;
+                                    currentState = "details";
+                                                               });
+
+                            first = false;
+                        }
+                        move.xTo = xTo;
+                        move.yTo = yTo;
+                        move.play();
+                    }
+                    
+                    if (thumb.product == product)
+                    {
+                        selectedThumb = thumb;
+                    }
+                }
+            }
+            if (selectedThumb != null)
+            {
+                //make sure that the selected thumb is visible in the list on 
the right
+                move.addEventListener(EffectEvent.EFFECT_END,
+                                       function(e:EffectEvent):void
+                                       {
+                                           var curpos:int = 
thumbContent.verticalScrollPosition;
+                                           if (selectedThumb.y < curpos)
+                                           {
+                                               
thumbContent.verticalScrollPosition = y;
+                                           }
+                                           else if (selectedThumb.y + 
ProductCatalogThumbnail.COL_HEIGHT_4 > curpos + thumbContent.height)
+                                           {
+                                               //this logic doesn't seem to be 
perfect but it will do
+                                               var diff:int = selectedThumb.y 
- (curpos + thumbContent.height)
+                                               
thumbContent.verticalScrollPosition += diff + 
ProductCatalogThumbnail.COL_HEIGHT_4 + ProductCatalogThumbnail.VERTICAL_GAP;
+                                           }
+                                       });
+            }
+            
+        }
+        
+        private function productThumbEventHandler(event:ProductThumbEvent):void
+        {
+            if (event.type == ProductThumbEvent.DETAILS)
+            {
+                showDetails(event.product);
+            }
+            else if (event.type == ProductThumbEvent.BROWSE)
+            {
+                if (thumbnailState == "browse")
+                {                
+                    currentState = "browse";
+                    layoutCatalog();
+                }
+                else
+                {
+                    compare();
+                }
+            }
+            else
+            {
+                dispatchEvent(event);
+            }
+        }
+        
+        public function compare(toCompare:Array=null):void
+        {
+            currentState = "compare";
+            thumbnailState = "compare";
+            if (toCompare != null)
+            {
+                var n:int = thumbnails.length;
+                for (var i:int = 0; i < n; i++)
+                {
+                    accepted[thumbnails[i].product] = false;
+                }
+                for (i=0; i < toCompare.length; i++)
+                {
+                    accepted[toCompare[i]] = true;
+                }
+            }
+            var lastEffect:Effect = layoutCatalog();
+            if (lastEffect != null)
+            {
+                lastEffect.addEventListener(EffectEvent.EFFECT_END,
+                    function (event:EffectEvent):void
+                    {
+                        setCompareState();
+                    });
+            }
+            else
+            {
+                setCompareState();
+            }
+        }
+        
+        private function setCompareState():void
+        {
+            //avoid an issue if the user clicks quickly where we move into
+            //compare state even though we're no longer in compare
+            if (currentState == "compare") 
+            {
+                var n:int = thumbnails.length;
+                for (var i:int = 0; i < n; i++)
+                {
+                    var thumb:ProductCatalogThumbnail = thumbnails[i];
+                    if (accepted[thumb.product])
+                    {
+                        thumb.currentState = "compare";
+                    }
+                }
+                
+            }
+        }
+        
+        ]]>
+    </mx:Script>
+    
+    <mx:Binding source="cartCount" destination="titleButtons.cartCount" />
+    <!-- two-way binding between the states of panel title buttons and the 
product view state -->
+    <mx:Binding source="ProductsView(parentDocument).currentState" 
destination="titleButtons.currentState" />
+    <mx:Binding destination="ProductsView(parentDocument).currentState" 
source="titleButtons.currentState" />
+
+    <mx:Canvas width="100%" height="100%" 
+        verticalScrollPolicy="off"
+        horizontalScrollPolicy="off"
+        >
+        <mx:Canvas id="thumbContent" width="100%" height="100%" 
+            horizontalScrollPolicy="off"/>
+        <productsView:ProductDetails id="details"
+            width="{ProductCatalogThumbnail.COL_WIDTH_4 * 3}"
+            height="100%"
+            visible="false"
+            compare="productThumbEventHandler(event)"
+            purchase="productThumbEventHandler(event)"
+            browse="productThumbEventHandler(event)" />
+    </mx:Canvas>
+    
+    <mx:states>
+        <mx:State name="browse">
+            <mx:SetProperty name="title" value="Browse"/>
+        </mx:State>
+
+        <mx:State name="compare">
+            <mx:SetProperty name="title" value="Product Comparison"/>
+        </mx:State>
+
+        <mx:State name="details">
+            <mx:SetProperty name="title" value="Product Details"/>
+            <mx:SetProperty target="{details}" name="visible" value="true"/>
+        </mx:State>
+    </mx:states>
+    
+</mx:Panel>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductCatalogThumbnail.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductCatalogThumbnail.mxml 
b/FlexStore/mx/src/productsView/ProductCatalogThumbnail.mxml
new file mode 100644
index 0000000..88a8f0a
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductCatalogThumbnail.mxml
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml";
+    width="{COL_WIDTH_4}" height="{COL_HEIGHT_4}"
+    borderStyle="solid"
+    borderColor="#FFFFFF"
+    horizontalScrollPolicy="off" verticalScrollPolicy="off"
+    rollOver="rollOverHandler(event)"
+    rollOut="rollOutHandler(event)"
+    mouseDown="mouseDownHandler(event)"
+    mouseMove="mouseMoveHandler(event)"
+    mouseUp="mouseUpHandler(event)"
+    click="clickHandler(event)"
+    currentState="4cols"
+    automationName="{product.name}"
+    dropShadowColor="#000000"
+    shadowDistance="2"
+    >
+
+    <mx:Metadata>
+        [Event(name="purchase", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="compare", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="details", type="samples.flexstore.ProductThumbEvent")]
+    </mx:Metadata>
+
+    <mx:Script>
+        <![CDATA[
+
+               import mx.events.*;
+        import mx.core.*;
+        
+        import samples.flexstore.Product;
+        import samples.flexstore.ProductThumbEvent;
+        
+        public static const COL_WIDTH_4:int = 162;
+        public static const COL_HEIGHT_4:int = 122;
+        public static const COL_WIDTH_3:int = 217;
+        public static const COL_HEIGHT_3:int = 165;
+        public static const COL_WIDTH_2:int = 327;
+        public static const COL_HEIGHT_2:int = 250;
+        public static const COMPARE_WIDTH:int = 162;
+        public static const HORIZONTAL_GAP:int = 2;
+        public static const VERTICAL_GAP:int = 3;
+
+        [Bindable]
+        public var product:Product;
+
+        private function rollOverHandler(event:MouseEvent):void
+               {
+            setStyle("borderColor", "#CCCCCC");
+            setStyle("dropShadowEnabled", true);
+            buttons.visible = true;
+        }
+
+        private function rollOutHandler(event:MouseEvent):void
+               {
+            setStyle("borderColor", "#FFFFFF");
+            setStyle("dropShadowEnabled", false);
+                       buttons.visible = false;
+        }
+
+        private var dragStartPoint:Point;
+
+        public function mouseDownHandler(event:MouseEvent):void
+        {
+            if (event.target != purchase &&
+                event.target != compare &&
+                event.target != details)
+            {
+                dragStartPoint = new Point(event.stageX, event.stageY);
+                dragStartPoint = globalToLocal(dragStartPoint);
+
+            }
+        }
+
+        public function mouseMoveHandler(event:MouseEvent):void
+        {
+            if (dragStartPoint != null)
+            {
+                var dragEvent:DragEvent = new DragEvent(DragEvent.DRAG_START, 
true);
+                dragEvent.localX = dragStartPoint.x;
+                dragEvent.localY = dragStartPoint.y;
+                dragEvent.buttonDown = true;
+                dispatchEvent(dragEvent);
+
+                rollOutHandler(event);
+
+                dragStartPoint = null;
+            }
+        }
+
+        public function mouseUpHandler(event:MouseEvent):void
+        {
+            if (dragStartPoint != null)
+            {
+                dragStartPoint = null;
+            }
+        }
+
+        public function clickHandler(event:MouseEvent):void
+        {
+            if (event.target != purchase &&
+                event.target != compare &&
+                event.target != details)
+            {
+                dispatchEvent(new ProductThumbEvent(ProductThumbEvent.DETAILS, 
product));
+            }
+        }
+
+       ]]>
+    </mx:Script>
+
+    <mx:CurrencyFormatter currencySymbol="$" id="cf" precision="2"/>
+
+    <mx:VBox id="vb" width="100%" height="100%"
+        paddingLeft="6" paddingTop="4" paddingRight="8" paddingBottom="4"
+        verticalGap="0">
+
+        <mx:Label text="{product.name}" fontWeight="bold"/>
+
+        <mx:HBox width="100%" paddingTop="0" horizontalGap="4">
+
+            <mx:Image id="img" height="90" width="45" source="{product.image}" 
/>
+
+            <mx:VBox id="descr" width="100%" height="100%" verticalGap="0" 
paddingTop="0">
+                <mx:Text text="{product.featureString}" selectable="false" 
width="80" height="48"/>
+                <mx:Label text="{cf.format(product.price)}" fontWeight="bold"/>
+                               <mx:Spacer height="4"/>
+            </mx:VBox>
+
+        </mx:HBox>
+
+        <mx:Spacer height="8"/>
+
+    </mx:VBox>
+
+    <mx:VBox id="buttons" visible="false" verticalGap="4" paddingRight="8" 
right="8" top="12">
+        <mx:Button id="purchase" icon="@Embed('/assets/icon_cart_empty.png')" 
+            click="dispatchEvent(new 
ProductThumbEvent(ProductThumbEvent.PURCHASE, product))" 
+            width="30" toolTip="Add to cart"/>
+        <mx:Button id="compare" icon="@Embed('/assets/icon_compare.png')" 
+            click="dispatchEvent(new 
ProductThumbEvent(ProductThumbEvent.COMPARE, product))" 
+            width="30" toolTip="Add to compare list"/>
+        <mx:Button id="details" icon="@Embed('/assets/icon_details.png')" 
+            click="dispatchEvent(new 
ProductThumbEvent(ProductThumbEvent.DETAILS, product))" 
+            width="30" toolTip="Show details"/>
+    </mx:VBox>
+
+    <mx:states>
+
+        <mx:State name="compare">
+            <mx:SetProperty name="height" value="502"/>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Years: {product.experience}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="BlazeDS: {product.blazeds}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Mobile: {product.mobile}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Video: {product.video}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Highlight: {product.highlight1}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Highlight: {product.highlight2}"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Label text="Description:"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Text text="{product.description}" width="100%"/>
+            </mx:AddChild>
+        </mx:State>
+
+        <mx:State name="4cols">
+            <mx:SetProperty name="width" value="{COL_WIDTH_4}"/>
+            <mx:SetProperty name="height" value="{COL_HEIGHT_4}"/>
+        </mx:State>
+
+        <mx:State name="3cols">
+            <mx:SetProperty name="width" value="{COL_WIDTH_3}"/>
+            <mx:SetProperty name="height" value="{COL_HEIGHT_3}"/>
+            <mx:SetProperty target="{img}" name="width" value="60"/>
+            <mx:SetProperty target="{img}" name="height" value="120"/>
+            <mx:AddChild relativeTo="{descr}">
+                       <mx:Label text="{product.highlight1}" color="#EE8D0C"/>
+            </mx:AddChild>
+            <mx:AddChild relativeTo="{descr}">
+                       <mx:Label text="{product.highlight2}" color="#EE8D0C"/>
+            </mx:AddChild>
+        </mx:State>
+
+        <mx:State name="2cols" basedOn="3cols">
+            <mx:SetProperty name="width" value="{COL_WIDTH_2}"/>
+            <mx:SetProperty name="height" value="{COL_HEIGHT_2}"/>
+            <mx:SetProperty target="{img}" name="width" value="60"/>
+            <mx:SetProperty target="{img}" name="height" value="120"/>
+            <mx:AddChild relativeTo="{vb}">
+                <mx:Text width="100%" text="{product.description}"/>
+            </mx:AddChild>
+        </mx:State>
+
+    </mx:states>
+
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductDetails.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductDetails.mxml 
b/FlexStore/mx/src/productsView/ProductDetails.mxml
new file mode 100644
index 0000000..ac80b11
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductDetails.mxml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"; 
+    xmlns:productsView="productsView.*"
+    horizontalScrollPolicy="off" verticalScrollPolicy="off">
+
+    <mx:Metadata>
+        [Event(name="purchase", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="compare", type="samples.flexstore.ProductThumbEvent")]
+        [Event(name="browse", type="samples.flexstore.ProductThumbEvent")]
+    </mx:Metadata>
+
+    <mx:Script>
+        <![CDATA[
+
+               import mx.events.*;
+               
+               import samples.flexstore.Product;
+               import samples.flexstore.ProductThumbEvent;
+
+        private var _product:Product;
+        
+        [Bindable]
+        public function get product():Product
+        {
+            return _product;
+        }
+        
+        public function set product(p:Product):void
+        {
+            _product = p;
+            tn.selectedIndex = 0;
+        }
+        
+       ]]>
+    </mx:Script>
+
+    <mx:CurrencyFormatter currencySymbol="$" id="cf" precision="2"/>
+
+    <mx:TabNavigator id="tn" width="100%" height="100%" 
+                    left="4" right="8" top="4" bottom="4">
+
+        <mx:VBox width="100%" height="100%" label="Features" verticalGap="8"
+            paddingLeft="8" paddingTop="8" paddingRight="8" paddingBottom="8" 
showEffect="Fade" hideEffect="Fade">
+
+            <mx:HBox width="100%" horizontalGap="12">
+
+                <mx:Image id="img" width="101" height="200" 
source="{product.image}"/>
+
+                <mx:VBox id="descr" width="100%" height="100%" paddingTop="0" 
verticalGap="4">
+
+                    <mx:Label text="{product.name}" fontSize="11" 
fontWeight="bold"/>
+
+                       <mx:Text text="{product.featureString}" width="80" 
height="48"/>
+
+                    <mx:Label text="{product.highlight1}" color="#EE8D0C"/>
+
+                    <mx:Label text="{product.highlight2}" color="#EE8D0C"/>
+
+                    <mx:Label text="{cf.format(product.price)}" 
fontWeight="bold"/>
+
+                </mx:VBox>
+            </mx:HBox>
+
+            <mx:Text id="descriptionText" width="100%" height="100%" 
text="{product.description}"/>
+
+        </mx:VBox>
+
+        <productsView:ProductSupport width="100%" height="100%" 
label="Support" showEffect="Fade" hideEffect="Fade"/>
+
+    </mx:TabNavigator>
+
+    <mx:VBox verticalGap="4" right="16" top="36">
+        <mx:Spacer width="100%"/>
+        <mx:Button icon="@Embed('/assets/icon_cart_empty.png')" 
click="dispatchEvent(new ProductThumbEvent(ProductThumbEvent.PURCHASE, 
product))" width="30" toolTip="Add to cart"/>
+        <mx:Button icon="@Embed('/assets/icon_compare.png')" 
click="dispatchEvent(new ProductThumbEvent(ProductThumbEvent.COMPARE, 
product))" width="30" toolTip="Add to compare list"/>
+        <mx:Button icon="@Embed('/assets/icon_tiles.png')" 
click="dispatchEvent(new ProductThumbEvent(ProductThumbEvent.BROWSE, 
product));" width="30" toolTip="Back to thumbnail view"/>
+    </mx:VBox>
+
+</mx:Canvas>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductFilterPanel.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductFilterPanel.mxml 
b/FlexStore/mx/src/productsView/ProductFilterPanel.mxml
new file mode 100644
index 0000000..794d0d3
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductFilterPanel.mxml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"; 
+    xmlns:productsView="productsView.*"
+    xmlns:flexstore="samples.flexstore.*"
+    height="100%" 
+    paddingLeft="4" 
+    paddingRight="12" 
+    paddingTop="12" 
+    paddingBottom="8" 
+    verticalGap="0"
+    currentState="showingThumbnails">
+    
+    <mx:Metadata>
+       [Event(name="filter", type="samples.flexstore.ProductFilterEvent")] 
+       [Event("compare")]
+    </mx:Metadata>
+    
+    <mx:Script>
+        <![CDATA[
+        import mx.controls.sliderClasses.Slider;
+        import mx.controls.Alert; 
+        import samples.flexstore.ProductFilterEvent;
+           
+        private var thumbBeingPressed:Boolean;
+           
+        private function dispatchFilter():void
+        {
+            var event:ProductFilterEvent = 
+                new ProductFilterEvent(filter, thumbBeingPressed);
+            dispatchEvent(event);
+            currentState = "showingThumbnails";
+        }
+        
+        private function sliderValue(values:Array, index:int):Number
+        {
+            return values[index];
+        }
+        
+        private function productRemoved():void
+        {
+            if (currentState == "showingComparison")
+            {
+                if (productList.items.length == 0)
+                {
+                    dispatchFilter();
+                }
+                else
+                {
+                    attemptCompare();
+                }
+            }
+        }
+        
+        private function attemptCompare():void
+        {
+            if (productList.items.length > 0)
+            {
+                dispatchEvent(new Event("compare"));
+                currentState = "showingComparison";
+            }
+            else
+            {
+                Alert.show("There are no items to compare.", "Compare");
+            }
+        }
+        
+        ]]>
+    </mx:Script>
+    
+    <flexstore:ProductFilter id="filter">
+        <flexstore:experience>{series.selectedItem}</flexstore:experience>
+        <flexstore:minPrice>{sliderValue(priceSlider.values, 
0)}</flexstore:minPrice>
+        <flexstore:maxPrice>{sliderValue(priceSlider.values, 
1)}</flexstore:maxPrice>
+        <flexstore:blazeds>{cbBlazeDS.selected}</flexstore:blazeds>
+        <flexstore:mobile>{cbMobile.selected}</flexstore:mobile>
+        <flexstore:video>{cbVideo.selected}</flexstore:video>
+    </flexstore:ProductFilter>
+
+    <mx:CurrencyFormatter currencySymbol="$" id="cf"/>    
+    
+    <mx:Label text="Find" styleName="sectionHeader"/>
+    
+    <mx:HBox width="100%">
+        <mx:TextInput styleName="glass" width="100%"/>
+        <mx:Button styleName="glass" label="Go" click="Alert.show('This 
feature is not implemented in this sample', 'Find')"/>
+    </mx:HBox>
+
+    <mx:Spacer height="18"/>
+
+    <mx:HRule width="100%"/>
+
+    <mx:Spacer height="8"/>
+
+    <mx:HBox paddingTop="0" paddingLeft="0" verticalAlign="bottom">
+        <mx:Label text="Filter" styleName="sectionHeader"/>
+        <mx:Label text="({filter.count} items selected)" 
color="{getStyle('themeColor')}" fontWeight="bold"/>
+    </mx:HBox>
+
+    <mx:Spacer height="8"/>
+
+    <mx:Label text="Years of Experience"/>
+
+    <mx:ComboBox id="series" styleName="glass" width="140" 
change="dispatchFilter();">
+        <mx:dataProvider>
+            <mx:Array>
+                <mx:String>All</mx:String>
+                <mx:String>3</mx:String>
+                <mx:String>5</mx:String>
+                <mx:String>7</mx:String>
+                <mx:String>9</mx:String>
+            </mx:Array>
+        </mx:dataProvider>
+    </mx:ComboBox>
+
+    <mx:Spacer height="18"/>
+
+    <mx:Label text="Price"/>
+
+    <mx:HSlider id="priceSlider" styleName="glassSlider" minimum="0" 
maximum="200" tickInterval="10" snapInterval="10"
+        width="100%" thumbCount="2" values="[0,200]" labels="[$0,$200]" 
liveDragging="true" dataTipFormatFunction="{cf.format}"
+        change="dispatchFilter()"
+        thumbPress="thumbBeingPressed=true"
+        thumbRelease="thumbBeingPressed=false;dispatchFilter()"
+        />
+
+    <mx:Spacer height="18"/>
+
+    <mx:Label text="Required Features"/>
+
+    <mx:Spacer height="4"/>
+
+    <mx:CheckBox id="cbBlazeDS" styleName="glass" label="BlazeDS" 
click="dispatchFilter();"/>
+    <mx:Spacer height="4"/>
+    <mx:CheckBox id="cbMobile" styleName="glass" label="Mobile" 
click="dispatchFilter()"/>
+    <mx:Spacer height="4"/>
+    <mx:CheckBox id="cbVideo" styleName="glass" label="Video" 
click="dispatchFilter();"/>
+
+    <mx:Spacer height="18"/>
+
+    <mx:HRule width="100%"/>
+
+    <mx:Spacer height="8"/>
+
+        <mx:HBox>
+            <mx:Label text="Compare" styleName="sectionHeader"/>
+            <mx:Label text="(Drag items here to compare)" 
styleName="instructions"/>
+        </mx:HBox>
+
+
+    <mx:Spacer height="4"/>
+
+    <!-- height is maxItems * ProductListItem.HEIGHT + 2px border -->
+    <productsView:ProductList id="productList" height="{productList.maxItems * 
ProductListItem.HEIGHT + 2}" width="100%"
+        newItemStartX="300" newItemStartY="-100" maxItems="4" 
+        removeProduct="productRemoved()"/>
+
+    <mx:Spacer height="8"/>
+    
+    <mx:Button id="compareButton" styleName="glass" />
+    
+    <mx:states>
+       <mx:State name="showingThumbnails">
+          <mx:SetProperty target="{compareButton}" name="label" value="Compare 
Items" />
+          <mx:SetStyle target="{compareButton}" name="icon" 
value="@Embed('/assets/icon_compare.png')" />
+          <mx:SetEventHandler target="{compareButton}" name="click" 
handler="attemptCompare()" />
+       </mx:State>
+       <mx:State name="showingComparison">
+           <mx:SetProperty target="{compareButton}" name="label" value="Back 
to thumbnail view" />
+           <mx:SetStyle target="{compareButton}" name="icon" 
value="@Embed('/assets/icon_tiles.png')" />
+           <mx:SetEventHandler target="{compareButton}" name="click" 
handler="dispatchFilter()" />
+       </mx:State>
+    </mx:states>
+
+</mx:VBox>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductList.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductList.mxml 
b/FlexStore/mx/src/productsView/ProductList.mxml
new file mode 100644
index 0000000..b0498e7
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductList.mxml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml";
+    borderStyle="solid"
+    horizontalScrollPolicy="off"
+    dragEnter="doDragEnter(event)"
+    dragDrop="doDragDrop(event)"
+    backgroundAlpha="0" backgroundColor="#FF0000"> <!-- need a background 
color for drag and drop but can set alpha to 0 -->
+    
+    <mx:Metadata>
+       [Event(name="addProduct", type="samples.flexstore.ProductListEvent")]
+       [Event(name="duplicateProduct", 
type="samples.flexstore.ProductListEvent")]
+       [Event(name="productQtyChange", 
type="samples.flexstore.ProductListEvent")]
+       [Event(name="removeProduct", type="samples.flexstore.ProductListEvent")]
+    </mx:Metadata>
+
+    <mx:Script>
+        <![CDATA[
+        import mx.core.*;
+        import mx.effects.*;
+        import mx.events.*;
+        import mx.managers.DragManager;
+        import mx.effects.EffectManager;
+        
+        import samples.flexstore.Product;
+        import samples.flexstore.ProductListEvent;
+        
+        public var items:Array = [];
+        
+        public var newItemStartX:int;
+        public var newItemStartY:int;
+        [Bindable]
+        public var maxItems:int;
+        public var showQuantity:Boolean;
+        
+        private var playingEffects:Dictionary = new Dictionary(true);
+        
+        public function addProduct(product:Product):void
+               {
+            var index:int = indexOf(product.productId);
+            var event:ProductListEvent;
+            var item:ProductListItem;
+            
+            if (index != -1)
+                       {
+                           item = items[index] as ProductListItem;
+                           //if we don't keep track of what's playing a 
double-click can
+                           //cause the list item to keep rising
+                           if (playingEffects[item] == null)
+                           {
+                    var jump:Sequence = new Sequence();
+                    var m1:Move = new Move(item)
+                    m1.yBy = -5;
+                    var m2:Move = new Move(item)
+                    m2.yBy = 5;
+                    jump.addChild(m1);
+                    jump.addChild(m2);
+                    jump.duration = 150;
+                    playingEffects[item] = jump;
+                    jump.addEventListener(EffectEvent.EFFECT_END, 
function(event:Event):void
+                    {
+                       delete playingEffects[item];
+                    });
+                    jump.play();
+                }
+                event = new 
ProductListEvent(ProductListEvent.DUPLICATE_PRODUCT);
+                event.product = item.product;
+                dispatchEvent(event);
+            }
+                       else
+                       {
+                index = items.length;
+                if (maxItems <= 0 || index < maxItems)
+                               {
+                                   item = new ProductListItem();
+                                   if (showQuantity)
+                                   {
+                                       item.currentState = 'showQuantity';
+                                   }
+                                   item.product = product;
+                                   item.percentWidth = 100;
+                                   
item.addEventListener(ProductListEvent.REMOVE_PRODUCT, removeItemHandler);
+                    items[index] = item;
+                    addChild(item);
+                    layoutItems(index, true);
+                    event = new ProductListEvent(ProductListEvent.ADD_PRODUCT);
+                    event.product = product;
+                    dispatchEvent(event);
+                }
+            }
+        }
+        
+        public function getProducts():Array
+        {
+            var ret:Array = [];
+            for (var i:int = 0; i < items.length; i++)
+            {
+                ret[i] = items[i].product;
+            }
+            return ret;
+        }
+        
+        private function removeItemHandler(event:Event):void
+        {
+            var item:ProductListItem = event.target as ProductListItem;
+            var index:int = indexOf(item.product.productId);
+            items.splice(index, 1);
+            removeChild(item);
+            layoutItems(index);
+        }
+            
+        private function layoutItems(startIndex:int, 
scrollToBottom:Boolean=false):void
+               {
+            var n:int = items.length;
+            var e:Move;
+                       for (var i:int = startIndex; i < n ; i++)
+                       {
+                           var item:ProductListItem = items[i];
+                var yTo:Number = i * (item.height);
+                //still need to prevent items that are already in motion from 
getting
+                //jumpy
+                           if (playingEffects[item] == null)
+                           {
+                    e = new Move(item);
+                    if (item.x == 0 && item.y == 0)
+                               {
+                                       e.xFrom = newItemStartX;
+                                       e.yFrom = newItemStartY;
+                    }
+    
+                    e.xTo = 0;
+                    e.yTo = yTo;
+                    playingEffects[item] = e;
+                    e.addEventListener(EffectEvent.EFFECT_END, 
function(event:Event):void
+                    {
+                       delete playingEffects[item];
+                    });
+                    e.play();
+                }
+                else
+                {
+                    playingEffects[item].pause();
+                    playingEffects[item].yTo = yTo;
+                    playingEffects[item].play();
+                }
+            }
+            //get the last event and if we should scroll make sure we can 
validate
+            //and scroll to maxVPosition
+            if (scrollToBottom)
+            {
+                e.addEventListener(EffectEvent.EFFECT_END, 
function(event:Event):void
+                {
+                    validateNow();
+                    verticalScrollPosition = maxVerticalScrollPosition;    
+                });
+            }
+        }
+        
+        private function indexOf(productId:int):int
+               {
+            var index:int = -1;
+
+            var n:int = items.length;
+                       for (var i:int = 0; i < items.length; i++)
+                       {
+                if (items[i].product.productId == productId)
+                               {
+                    index = i;
+                    break;
+                }
+            }
+
+            return index;
+        }     
+
+        private function doDragEnter(event:DragEvent):void
+        {
+            if (event.dragSource.hasFormat("product"))
+            {
+                DragManager.acceptDragDrop(IUIComponent(event.target));
+            }
+        }
+
+        private function doDragDrop(event:DragEvent):void
+        {
+            var product:Product = event.dragSource.dataForFormat("product") as 
Product;
+            addProduct(product);
+        }  
+ 
+        ]]>
+    </mx:Script>
+    
+</mx:Canvas>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductListItem.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductListItem.mxml 
b/FlexStore/mx/src/productsView/ProductListItem.mxml
new file mode 100644
index 0000000..40aeb20
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductListItem.mxml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"; 
+    styleName="listItem"
+    height="{ProductListItem.HEIGHT}"
+    automationName="{product.name}">
+
+    <mx:Metadata>
+       [Event(name="productQtyChange", 
type="samples.flexstore.ProductListEvent")]
+       [Event(name="removeProduct", type="samples.flexstore.ProductListEvent")]
+    </mx:Metadata>
+    
+    <mx:Script>
+    <![CDATA[
+    
+        import samples.flexstore.Product;
+        import samples.flexstore.ProductListEvent;
+        
+        public static const HEIGHT:int = 30;
+        
+        [Bindable]
+        public var product:Product;
+        
+        private function qtyChange():void
+       {
+            product.qty = int(qty.text);
+            var event:ProductListEvent = new 
ProductListEvent(ProductListEvent.PRODUCT_QTY_CHANGE);
+            event.product = product;
+               dispatchEvent(event);
+        }
+        
+        private function removeItem():void
+        {
+            var event:ProductListEvent = new 
ProductListEvent(ProductListEvent.REMOVE_PRODUCT);
+            event.product = product;
+               dispatchEvent(event);
+        }
+        
+    ]]>
+    </mx:Script>
+    
+    <mx:CurrencyFormatter currencySymbol="$" id="cf" precision="2"/>
+    
+    <mx:Button id="removeButton"
+        width="14" height="14" 
+        icon="@Embed('/assets/trashcan.png')"
+        toolTip="Remove from cart"
+        click="removeItem()"/>
+
+    <mx:Image id="productImage" width="12" height="24" 
source="{product.image}"/>
+
+    <mx:Label id="productName" maxWidth="100" text="{product.name}"/>
+
+    <mx:Spacer width="100%" />
+
+    <mx:Label id="productPrice" 
+        text="{cf.format(product.price)}" textAlign="right"/>
+        
+    <mx:states>
+        <mx:State name="showQuantity">
+            <mx:AddChild>
+                <mx:TextInput id="qty" width="25" text="{product.qty}" 
+                    textAlign="right" maxChars="3" change="qtyChange()" />
+           </mx:AddChild>
+       </mx:State>        
+    </mx:states>
+    
+</mx:HBox>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/productsView/ProductSupport.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/productsView/ProductSupport.mxml 
b/FlexStore/mx/src/productsView/ProductSupport.mxml
new file mode 100644
index 0000000..1d9aab9
--- /dev/null
+++ b/FlexStore/mx/src/productsView/ProductSupport.mxml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml";
+                paddingLeft="4" paddingRight="8" paddingBottom="4"
+                horizontalScrollPolicy="off" verticalScrollPolicy="off">
+
+    <mx:Script>
+       <![CDATA[
+
+        private function toggle():void
+               {
+                       /*
+            if (vd.playing)
+                       {
+                vd.stop();
+                list.visible = true;
+            }
+                       else
+                       {
+                list.visible = false;
+                vd.play();
+            }
+                       */
+        }
+
+       ]]>
+    </mx:Script>
+
+    <mx:Parallel id="hideList">
+        <mx:children>
+            <mx:Array>
+                <mx:Resize target="{list}" widthTo="0"/>
+                <!--<mx:Resize target="{vd}" widthTo="400" heightTo="314"/>-->
+            </mx:Array>
+        </mx:children>
+    </mx:Parallel>
+
+    <mx:Parallel id="showList">
+        <mx:children>
+            <mx:Array>
+                <mx:Resize target="{list}" widthTo="130"/>
+                <!--<mx:Resize target="{vd}" widthTo="270" heightTo="217"/>-->
+            </mx:Array>
+        </mx:children>
+    </mx:Parallel>
+
+    <mx:List id="list" width="130" height="100%" selectedIndex="0"
+                        hideEffect="hideList" showEffect="showList">
+        <mx:dataProvider>
+            <mx:Array>
+                <mx:Object label="Install SIM Card"/>
+            </mx:Array>
+        </mx:dataProvider>
+    </mx:List>
+
+    <mx:Canvas width="100%" verticalScrollPolicy="off" 
horizontalScrollPolicy="off">
+
+               <!--<mx:VideoDisplay id="vd" width="270" height="217" 
source="assets/phone.flv"
+                                                autoPlay="false" 
complete="list.visible=true"/>
+
+               <mx:Button label="{vd.playing ? 'Stop' : 'Play'}" 
click="toggle()" left="8" bottom="8" includeInLayout="false">
+               </mx:Button>
+               -->
+       </mx:Canvas>
+
+
+</mx:HBox>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/ButtonBarButtonSkin.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/ButtonBarButtonSkin.as 
b/FlexStore/mx/src/samples/flexstore/ButtonBarButtonSkin.as
new file mode 100644
index 0000000..5e94b58
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/ButtonBarButtonSkin.as
@@ -0,0 +1,298 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package samples.flexstore
+{
+
+import flash.display.GradientType;
+import mx.containers.BoxDirection;
+import mx.controls.Button;
+import mx.controls.ButtonBar;
+import mx.skins.Border;
+import mx.skins.halo.*;
+import mx.styles.StyleManager;
+import mx.utils.ColorUtil;
+
+/**
+ *  Adapted from mx.skins.halo.ButtonBarButtonSkin.
+ *  This version of the ButtonBarButtonSkin is applied for the
+ *  selectedOver, selectedUp, and over states to use the 2nd two
+ *  values of the fillColors for the selected state of the
+ *  button.  The over state then uses a computed value from
+ *  the themeColor to show emphasis.  The border of the selected
+ *  button also uses a computed value from the themeColor, but
+ *  is partially transparent.
+ */
+public class ButtonBarButtonSkin extends Border
+{
+       
//--------------------------------------------------------------------------
+       //
+       //  Class variables
+       //
+       
//--------------------------------------------------------------------------
+
+       /**
+        *  @private
+        */
+       private static var cache:Object = {};
+
+       
//--------------------------------------------------------------------------
+       //
+       //  Class methods
+       //
+       
//--------------------------------------------------------------------------
+
+       /**
+        *  @private
+        *  Several colors used for drawing are calculated from the base colors
+        *  of the component (themeColor, borderColor and fillColors).
+        *  Since these calculations can be a bit expensive,
+        *  we calculate once per color set and cache the results.
+        */
+       private static function calcDerivedStyles(themeColor:uint,
+                                                                               
          fillColor0:uint,
+                                                                               
          fillColor1:uint):Object
+       {
+               var key:String = HaloColors.getCacheKey(themeColor,
+                                                                               
                fillColor0, fillColor1);
+
+               if (!cache[key])
+               {
+                       var o:Object = cache[key] = {};
+
+                       // Cross-component styles.
+                       HaloColors.addHaloColors(o, themeColor, fillColor0, 
fillColor1);
+
+                       // Button-specific styles.
+                       o.innerEdgeColor1 = 
ColorUtil.adjustBrightness2(fillColor0, -10);
+                       o.innerEdgeColor2 = 
ColorUtil.adjustBrightness2(fillColor1, -25);
+               }
+
+               return cache[key];
+       }
+
+       
//--------------------------------------------------------------------------
+       //
+       //  Constructor
+       //
+       
//--------------------------------------------------------------------------
+
+       /**
+        *  @private
+        *  Constructor.
+        */
+       public function ButtonBarButtonSkin()
+       {
+               super();
+       }
+
+       
//--------------------------------------------------------------------------
+       //
+       //  Overridden properties
+       //
+       
//--------------------------------------------------------------------------
+
+       //----------------------------------
+       //  measuredWidth
+       //----------------------------------
+
+       /**
+        *  @private
+        */
+       override public function get measuredWidth():Number
+       {
+               return 50;
+       }
+
+       //----------------------------------
+       //  measuredHeight
+       //----------------------------------
+
+       /**
+        *  @private
+        */
+       override public function get measuredHeight():Number
+       {
+               return 22;
+       }
+
+       
//--------------------------------------------------------------------------
+       //
+       //  Overridden methods
+       //
+       
//--------------------------------------------------------------------------
+
+       /**
+        *  @private
+        */
+       override protected function updateDisplayList(w:Number, h:Number):void
+       {
+               super.updateDisplayList(w, h);
+
+               // User-defined styles.
+               var borderColor:uint = getStyle("borderColor");
+               var cornerRadius:Number = getStyle("cornerRadius");
+               var fillAlphas:Array = getStyle("fillAlphas");
+               var fillColors:Array = getStyle("fillColors");
+               styleManager.getColorNames(fillColors);
+               var highlightAlphas:Array = getStyle("highlightAlphas");
+               var themeColor:uint = getStyle("themeColor");
+
+               // Derivative styles.
+               var derStyles:Object = calcDerivedStyles(themeColor, 
fillColors[0],
+                                                                               
                 fillColors[1]);
+
+               var borderColorDrk1:Number =
+                       ColorUtil.adjustBrightness2(borderColor, -50);
+
+               var themeColorDrk1:Number =
+                       ColorUtil.adjustBrightness2(themeColor, -25);
+
+               var emph:Boolean = false;
+
+               if (parent is Button)
+                       emph = (parent as Button).emphasized;
+
+               var tmp:Number;
+
+               var bar:ButtonBar = parent ? ButtonBar(parent.parent) : null;
+               var horizontal:Boolean = true;
+               var pos:int = 0;
+
+               if (bar)
+               {
+                       if (bar.direction == BoxDirection.VERTICAL)
+                               horizontal = false;
+
+                       // first: -1, middle: 0, last: 1
+                       var index:int = bar.getChildIndex(parent);
+                       pos = (index == 0 ? -1 : (index == bar.numChildren - 1 
? 1 : 0));
+               }
+
+               var radius:Object = getCornerRadius(pos, horizontal, 
cornerRadius);
+               var cr:Object = getCornerRadius(pos, horizontal, cornerRadius);
+               var cr1:Object = getCornerRadius(pos, horizontal, cornerRadius 
- 1);
+               var cr2:Object = getCornerRadius(pos, horizontal, cornerRadius 
- 2);
+               var cr3:Object = getCornerRadius(pos, horizontal, cornerRadius 
- 3);
+
+               graphics.clear();
+
+               switch (name)
+               {
+                       case "selectedUpSkin":
+                       case "selectedOverSkin":
+                       {
+                               var overFillColors:Array;
+                               if (fillColors.length > 2)
+                                       overFillColors = [ fillColors[2], 
fillColors[3] ];
+                               else
+                                       overFillColors = [ fillColors[0], 
fillColors[1] ];
+
+                               var overFillAlphas:Array;
+                               if (fillAlphas.length > 2)
+                                       overFillAlphas = [ fillAlphas[2], 
fillAlphas[3] ];
+                               else
+                                       overFillAlphas = [ fillAlphas[0], 
fillAlphas[1] ];
+
+                               // button border/edge
+                               drawRoundRect(
+                                       0, 0, w, h, cr,
+                                       [ themeColor, derStyles.themeColDrk1 ], 
0.5,
+                                       verticalGradientMatrix(0, 0, w , h),
+                                       GradientType.LINEAR, null,
+                                       { x: 1, y: 1, w: w - 2, h: h - 2, r: 
cr1 });
+
+                               // button fill
+                               drawRoundRect(
+                                       1, 1, w - 2, h - 2, cr1,
+                                       overFillColors, overFillAlphas,
+                                       verticalGradientMatrix(0, 0, w - 2, h - 
2));
+
+                               // top highlight
+                               if (!(radius is Number))
+                                       { radius.bl = radius.br = 0;}
+                               drawRoundRect(
+                                       1, 1, w - 2, (h - 2) / 2, radius,
+                                       [ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+                                       verticalGradientMatrix(1, 1, w - 2, (h 
- 2) / 2));
+                               break;
+                       }
+
+                       case "overSkin":
+                       {
+                               // button border/edge
+                               drawRoundRect(
+                                       0, 0, w, h, cr,
+                                       [ themeColor, derStyles.themeColDrk1 ], 
0.5,
+                                       verticalGradientMatrix(0, 0, w, h));
+
+                               // button fill
+                               drawRoundRect(
+                                       1, 1, w - 2, h - 2, cr1,
+                                       [ derStyles.fillColorPress1, 
derStyles.fillColorPress2 ], 1,
+                                       verticalGradientMatrix(0, 0, w - 2, h - 
2));
+
+                               // top highlight
+                               if (!(radius is Number))
+                                       { radius.bl = radius.br = 0;}
+                               drawRoundRect(
+                                       1, 1, w - 2, (h - 2) / 2, radius,
+                                       [ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+                                       verticalGradientMatrix(1, 1, w - 2, (h 
- 2) / 2));
+
+                               break;
+                       }
+               }
+       }
+
+       
//--------------------------------------------------------------------------
+       //
+       //  Methods
+       //
+       
//--------------------------------------------------------------------------
+
+       /**
+        *  @private
+        */
+       private function getCornerRadius(pos:int, horizontal:Boolean,
+                                                                        
radius:Number):Object
+       {
+               if (pos == 0)
+                       return 0;
+
+               radius = Math.max(0, radius);
+
+               if (horizontal)
+               {
+                       if (pos == -1)
+                               return { tl: radius, tr: 0, bl: radius, br: 0 };
+                       else // pos == 1
+                               return { tl: 0, tr: radius, bl: 0, br: radius };
+               }
+               else
+               {
+                       if (pos == -1)
+                               return { tl: radius, tr: radius, bl: 0, br: 0 };
+                       else // pos == 1
+                               return { tl: 0, tr: 0, bl: radius, br: radius };
+               }
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/Product.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/Product.as 
b/FlexStore/mx/src/samples/flexstore/Product.as
new file mode 100644
index 0000000..040fb8f
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/Product.as
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package samples.flexstore
+{
+
+[Bindable]
+public class Product
+{
+
+    public var productId:int;
+    public var name:String;
+    public var description:String;
+    public var price:Number;
+    public var image:String;
+    public var experience:String;
+    public var blazeds:Boolean;
+    public var mobile:Boolean;
+    public var video:Boolean;
+    public var highlight1:String;
+    public var highlight2:String;
+    public var qty:int;
+
+    public function Product()
+    {
+
+    }
+
+    public function fill(obj:Object):void
+    {
+        for (var i:String in obj)
+        {
+            this[i] = obj[i];
+        }
+    }
+
+    [Bindable(event="propertyChange")]
+    public function get featureString():String
+    {
+       var str:String = "";
+       if (blazeds)
+               str += "BlazeDS";
+
+               if (mobile)
+               {
+                       if (str.length > 0)
+                               str += "\n";
+                       str += "Mobile";
+               }
+
+               if (video)
+               {
+                       if (str.length > 0)
+                               str += "\n";
+                       str += "Video";
+               }
+
+               return str;
+    }
+
+}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/ProductFilter.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/ProductFilter.as 
b/FlexStore/mx/src/samples/flexstore/ProductFilter.as
new file mode 100644
index 0000000..d182371
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/ProductFilter.as
@@ -0,0 +1,56 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package samples.flexstore
+{
+
+[Bindable]
+public class ProductFilter
+{
+    public var count:int;
+    public var experience:String;
+    public var minPrice:Number;
+    public var maxPrice:Number;
+    public var blazeds:Boolean;
+    public var mobile:Boolean;
+    public var video:Boolean;
+    
+    public function ProductFilter()
+    {
+        super();
+    }
+    
+    public function accept(product:Product):Boolean
+    {
+        //price is often the first test so let's fail fast if possible
+        if (minPrice > product.price || maxPrice < product.price)
+            return false;
+        if (experience != "All" && experience > product.experience)
+            return false;
+        if (blazeds && !product.blazeds)
+            return false;
+        if (mobile && !product.mobile)
+            return false;
+        if (video && !product.video)
+            return false;
+        
+        return true;
+    }
+}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/ProductFilterEvent.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/ProductFilterEvent.as 
b/FlexStore/mx/src/samples/flexstore/ProductFilterEvent.as
new file mode 100644
index 0000000..b13af3e
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/ProductFilterEvent.as
@@ -0,0 +1,39 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package samples.flexstore
+{
+
+import flash.events.Event;
+
+public class ProductFilterEvent extends Event
+{
+    public static const FILTER:String = "filter";
+    
+    public var live:Boolean;
+    public var filter:ProductFilter;
+    
+    public function ProductFilterEvent(filter:ProductFilter, live:Boolean)
+    {
+        super(FILTER);
+        this.filter = filter;
+        this.live = live;
+    }
+}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/ProductListEvent.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/ProductListEvent.as 
b/FlexStore/mx/src/samples/flexstore/ProductListEvent.as
new file mode 100644
index 0000000..fb4992f
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/ProductListEvent.as
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package samples.flexstore
+{
+
+import flash.events.Event;
+
+public class ProductListEvent extends Event
+{
+    public static const ADD_PRODUCT:String = "addProduct";
+    public static const DUPLICATE_PRODUCT:String = "duplicateProduct";
+    public static const REMOVE_PRODUCT:String = "removeProduct";
+    public static const PRODUCT_QTY_CHANGE:String = "productQtyChange";
+    
+    public var product:Product;
+    
+    //making the default bubbles behavior of the event to true since we want
+    //it to bubble out of the ProductListItem and beyond
+    public function ProductListEvent(type:String, bubbles:Boolean=true, 
cancelable:Boolean=false)
+    {
+        super(type, bubbles, cancelable);
+    }
+    
+}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/mx/src/samples/flexstore/ProductThumbEvent.as
----------------------------------------------------------------------
diff --git a/FlexStore/mx/src/samples/flexstore/ProductThumbEvent.as 
b/FlexStore/mx/src/samples/flexstore/ProductThumbEvent.as
new file mode 100644
index 0000000..e967daf
--- /dev/null
+++ b/FlexStore/mx/src/samples/flexstore/ProductThumbEvent.as
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package samples.flexstore
+{
+    
+import flash.events.Event;
+
+public class ProductThumbEvent extends Event
+{
+    public static const PURCHASE:String = "purchase";
+    public static const COMPARE:String = "compare";
+    public static const DETAILS:String = "details";
+    public static const BROWSE:String = "browse";
+    
+    public var product:Product;
+    
+    public function ProductThumbEvent(type:String, product:Product)
+    {
+        super(type);
+        this.product = product;
+    }
+    
+    override public function clone():Event
+    {
+        return new ProductThumbEvent(type, product);
+    }
+}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/c652cfba/FlexStore/spark/src/FlexStore.mxml
----------------------------------------------------------------------
diff --git a/FlexStore/spark/src/FlexStore.mxml 
b/FlexStore/spark/src/FlexStore.mxml
new file mode 100644
index 0000000..7a82cb9
--- /dev/null
+++ b/FlexStore/spark/src/FlexStore.mxml
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009";
+               xmlns:s="library://ns.adobe.com/flex/spark" 
+               xmlns="*"
+                               minWidth="990" minHeight="550"
+                               preinitialize="loadStyle()"
+                               creationComplete="startService()"
+                stateChangeComplete="chainStatesIfNeeded()"
+                               pageTitle="FlexStore">
+       
+       <fx:Script>
+               <![CDATA[
+                       import mx.collections.IViewCursor;
+                       import mx.collections.ArrayCollection;
+                       import samples.flexstore.Product;
+                       import mx.rpc.events.ResultEvent;
+                       import mx.events.StyleEvent;
+                       import mx.styles.StyleManager;
+            import mx.managers.LayoutManager;
+                       
+                       [Bindable]
+                       private var catalog:ArrayCollection;
+                       
+                       private var currentTheme:String = "beige";
+                       
+                       private function toggleTheme():void
+                       {
+                               if (currentTheme == "beige")
+                               {
+                                       currentTheme = "blue";
+                               }
+                               else
+                               {
+                                       currentTheme = "beige";
+                               }
+                               
+                               loadStyle();
+                       }
+                       
+                       private function startService():void
+                       {
+                               productService.send();
+                       }
+                       
+                       private function loadStyle():void
+                       {
+                               var eventDispatcher:IEventDispatcher =
+                                       
styleManager.loadStyleDeclarations(currentTheme + ".swf");
+                               
eventDispatcher.addEventListener(StyleEvent.COMPLETE, completeHandler);
+                       }
+                       
+                       private function completeHandler(event:StyleEvent):void
+                       {
+                               image.source = acb.getStyle("storeLogo");
+                               homeView.updateMapImage();
+                               super.initialized = true;
+                callLater(prebake);
+                       }
+                       
+                       private function 
productServiceResultHandler(event:ResultEvent):void
+                       {
+                               //HTTPService returns an ArrayCollection for 
nested arrays
+                               var products:ArrayCollection = 
event.result.catalog.product;
+                               var temp:ArrayCollection = new 
ArrayCollection();
+                               var cursor:IViewCursor = 
products.createCursor();
+                               while (!cursor.afterLast)
+                               {
+                                       var product:Product = new Product();
+                                       product.fill(cursor.current);
+                                       temp.addItem(product);
+                                       cursor.moveNext();
+                               }
+                               catalog = temp;
+                       }
+                       
+                       override public function set 
initialized(value:Boolean):void
+                       {
+                               // Hold off until the Runtime CSS SWF is done 
loading.
+                       }
+            
+            private var stateChain:Array;
+            
+            private function headHome():void
+            {
+                homeButton.selected = true;
+                if (currentState == "ProductsState")
+                {
+                    productsButton.selected = false;
+                    stateChain = ["ProductsWipeUp", "HomeWipeDown", 
"HomeState"];
+                    currentState = "ProductsWipeUp";
+                }
+                else if (currentState == "SupportState")
+                {
+                    supportButton.selected = false;
+                    stateChain = ["SupportWipeUp", "HomeWipeDown", 
"HomeState"];
+                    currentState = "SupportWipeUp";                    
+                }
+            }
+            
+            private function headToProducts():void
+            {
+                productsButton.selected = true;
+                if (currentState == "SupportState")
+                {
+                    supportButton.selected = false;
+                    stateChain = ["SupportWipeUp", "ProductsWipeDown", 
"ProductsState"];
+                    currentState = "SupportWipeUp";                    
+                }
+                if (currentState == "HomeState")
+                {
+                    homeButton.selected = false;
+                    stateChain = ["HomeWipeUp", "ProductsWipeDown", 
"ProductsState"];
+                    currentState = "HomeWipeUp";                    
+                }
+            }
+            
+            private function headToSupport():void
+            {
+                supportButton.selected = true;
+                if (currentState == "ProductsState")
+                {
+                    productsButton.selected = false;
+                    stateChain = ["ProductsWipeUp", "SupportWipeDown", 
"SupportState"];
+                    currentState = "ProductsWipeUp";                    
+                }
+                if (currentState == "HomeState")
+                {
+                    homeButton.selected = false;
+                    stateChain = ["HomeWipeUp", "SupportWipeDown", 
"SupportState"];
+                    currentState = "HomeWipeUp";                    
+                }
+            }
+            
+            private function prebake():void
+            {
+                if (LayoutManager.getInstance().isInvalid())
+                {
+                    callLater(prebake);
+                    return;
+                }
+                addEventListener("enterFrame", prebake2);
+            }
+            
+            private function prebake2(event:Event):void
+            {
+                removeEventListener("enterFrame", prebake2);
+                trace("prebake2");
+                stateChain = ["ProductsPreBake", "HomeState"];
+                currentState = "ProductsPreBake";
+            }
+                
+            private function chainStatesIfNeeded():void
+            {
+                if (LayoutManager.getInstance().isInvalid())
+                {
+                    callLater(chainStatesIfNeeded);
+                    return;
+                }
+                if (stateChain != null)
+                {
+                    if (currentState == stateChain[0])
+                    {
+                        addEventListener("enterFrame", nextState);
+                    }
+                }
+            }
+            
+            private function nextState(event:Event):void
+            {
+                removeEventListener("enterFrame", nextState);
+                stateChain.shift();
+                if (stateChain.length)
+                    currentState = stateChain[0];
+                else
+                    stateChain == null;
+            }
+               ]]>
+       </fx:Script>
+       
+       <fx:Style source="main.css"/>
+       
+    <fx:Declarations>
+        <s:HTTPService id="productService" url="data/catalog.xml"
+                       result="productServiceResultHandler(event)"/>        
+    </fx:Declarations>
+       
+    <s:controlBarContent>
+        <s:HGroup id="acb" width="100%" styleName="storeControlBar">
+            <s:Image id="image" 
+                     click="toggleTheme()"
+                     toolTip="Change Theme"/>
+            <s:ToggleButton id="homeButton"
+                            label="Home"
+                            height="100%"
+                            selected="true"
+                            styleName="storeButtonBar"
+                            click="headHome()" />
+            <s:ToggleButton id="productsButton"
+                            label="Products"
+                            height="100%"
+                            styleName="storeButtonBar"
+                            click="headToProducts()"/>
+            <s:ToggleButton id="supportButton"
+                            label="Support"
+                            height="100%"
+                            styleName="storeButtonBar"
+                            click="headToSupport()"/>            
+        </s:HGroup>
+    </s:controlBarContent>
+    
+    <s:states>
+        <s:State name="HomeState" stateGroups="['Home']" />
+        <s:State name="HomeWipeUp" stateGroups="['Home']" />
+        <s:State name="HomeWipeDown" stateGroups="['Home']" />
+        <s:State name="ProductsPreBake" stateGroups="['Home', 'Products']" />
+        <s:State name="ProductsState" stateGroups="['Products']" />
+        <s:State name="ProductsWipeUp" stateGroups="['Products']" />
+        <s:State name="ProductsWipeDown" stateGroups="['Products']" />
+        <s:State name="SupportState" stateGroups="['Support']" />
+        <s:State name="SupportWipeUp" stateGroups="['Support']" />
+        <s:State name="SupportWipeDown" stateGroups="['Support']" />
+    </s:states>
+    
+    <s:transitions>
+        <s:Transition fromState="HomeState" toState="HomeWipeUp">
+            <s:Wipe direction="up" target="{homeView}" />
+        </s:Transition>
+        <s:Transition fromState="HomeWipeDown" toState="HomeState">
+            <s:Wipe direction="down" target="{homeView}" />
+        </s:Transition>
+        <s:Transition fromState="ProductsState" toState="ProductsWipeUp">
+            <s:Wipe direction="up" target="{pView}" />
+        </s:Transition>
+        <s:Transition fromState="ProductsWipeDown" toState="ProductsState">
+            <s:Wipe direction="down" target="{pView}" />
+        </s:Transition>
+        <s:Transition fromState="SupportState" toState="SupportWipeUp">
+            <s:Wipe direction="up" target="{supportView}" />
+        </s:Transition>
+        <s:Transition fromState="SupportWipeDown" toState="SupportState">
+            <s:Wipe direction="down" target="{supportView}" />
+        </s:Transition>
+    </s:transitions>
+       <s:VGroup width="990" paddingLeft="0" paddingRight="0" 
horizontalCenter="0" top="12">
+                               
+                       <HomeView id="homeView" width="100%" height="550" 
includeIn="Home"
+                      visible.HomeWipeUp="false"
+                      visible.HomeWipeDown="false"
+                                         />
+                       <ProductsView id="pView" includeIn="Products" 
visible.ProductsPreBake="false"
+                          visible.ProductsWipeUp="false"
+                          visible.ProductsWipeDown="false"
+                          width="100%" height="550" 
creationComplete="pView.catalog = catalog"
+                                                 />
+                       <SupportView id="supportView" includeIn="Support"
+                         visible.SupportWipeUp="false"
+                         visible.SupportWipeDown="false"
+                         width="100%" height="550"
+                                                />
+       </s:VGroup>
+       
+</s:Application>

Reply via email to