<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/halo" 
               xmlns:fl="rw.*"
               minWidth="600" minHeight="400"
               creationComplete="onLoad()"
               viewSourceURL="srcview/index.html">
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <fx:Script>
    <![CDATA[
        import flare.animate.*;
        import flare.display.TextSprite;
        import flare.util.Shapes;
        import flare.util.Strings;
        import flare.vis.Visualization;
        import flare.vis.controls.ClickControl;
        import flare.vis.controls.HoverControl;
        import flare.vis.controls.TooltipControl;
        import flare.vis.data.*;
        import flare.vis.events.SelectionEvent;
        import flare.vis.events.TooltipEvent;
        import flare.vis.operator.label.Labeler;
        
        import rw.*;
        
        import spark.components.Button;
        
        private var _vis:Visualization;
        private var _layout:TreeMapLayout;
        private var _labeler:TreeMapLabeler;
        private var _data:Tree;
        
        [Bindable]
        private var _rootData:NodeSprite;
            
        [Bindable]
        private var _currentRootData:NodeSprite;
        
        private var _minAge:int = 0;
        private var _maxAge:int = 21;
        
        private var _showMale:Boolean = true;
        private var _showFemale:Boolean = true;
        
        private var _maleHighlight:Sprite;
        private var _femaleHighlight:Sprite;
        
        private var _showLabels:Boolean = true;
        
        public function onLoad():void {            
            _data = buildData();
            _rootData = _data.root;
            
            // we're only drawing rectangles, so no one should notice...
            callLater(function():void {
                stage.quality = StageQuality.LOW;
            });
        
            // create and add visualization
            _vis = new TreeVisuakization(_data);
            //_vis = flexVis.visualization;
            flexVis.visualization = _vis;
            //_vis.data = _data;
            _rootData = _data.root;
            _vis.bounds = getSizeRect();
            // -- initialize visual items ----------------------
            
            //sexFilter
            
            var renderer:PeopleRenderer = new PeopleRenderer;
            
            // nodes are blocks, lower depths have thicker edges
            _vis.data.nodes.visit(function(n:NodeSprite):void {
                n.buttonMode = true;
                n.shape = Shapes.BLOCK;
                n.renderer = renderer;
                if(n.childDegree > 0) {
                    n.fillColor = 0;
                    n.mouseEnabled = false;
                } else {
                    n.fillColor = ICD10.colorMap(String(n.data.path).substr(1,7));//0xff4444ff;
                    n.fillAlpha = 0.7;//n.depth / 10;
                }
                n.lineColor = 0xffcccccc;
                n.lineWidth = n.depth==1 ? 2 : (n.childDegree ? 1 : 0);
            });
            updateSizes();
            
            // no fill or mouse interaction for nodes with children
            /*_vis.data.nodes.setProperties({
                fillColor: 0,
                mouseEnabled: false
            }, null, "childDegree");
            */
            // don't show any edges
            _vis.data.edges["visible"] = false;
            
            
            // -- define operators -----------------------------
            
            // perform a tree map layout
            _layout = new TreeMapLayout();
            _vis.setOperator('layout', _layout);
            
            // label top-level packages in new layer
            _labeler = new TreeMapLabeler(
            // strip off the "flare." prefix
            "data.name",
            Data.NODES, new TextFormat("Arial", 14, 0, true),
            function(n:NodeSprite):Boolean {
                return _showLabels && (n.depth == _currentRootData.depth+1);
            },
            Labeler.LAYER); //Comparison.Equal('depth', 1)
            _labeler.xOffset = 5;
            _labeler.yOffset = 3;
             _vis.setOperator('labeler', _labeler);
                 
            /*
            // add drop shadow to generated labels
            _vis.operators.add(new PropertyEncoder({
            "props.label.filters": [new DropShadowFilter(3,45,0x888888)]
            }, Data.NODES, Comparison.Equal('depth', 1)));
            */
            // run the operators
            _currentRootData = _rootData;
            _vis.update(null, 'layout').play();            
            _vis.update(null, 'labeler').play();            
            _vis.update();
            updateLabels();
            
            // -- define interactive controls -----------------
            
            // highlight nodes on mouse over
            _vis.controls.add(new HoverControl(NodeSprite,
                // don't change drawing order of nodes
                HoverControl.MOVE_AND_RETURN,
                // highlight
                function(evt:SelectionEvent):void {
                    var n:NodeSprite = evt.node;
                    //n.lineColor = 0xffFF0000;
                    //n.fillColor = 0xffFFAAAA;
                    n.props['highlight'] = true;
                    n.dirty();
                },
                // unhighlight
                function(evt:SelectionEvent):void {
                    var n:NodeSprite = evt.node;
                    //n.lineColor = 0xffcccccc;
                    //n.fillColor = n.fillColor = ICD10.colorMap(String(n.data.path).substr(1,7));
                    //n.fillAlpha = 0.5;//n.depth / 10;
                    n.props['highlight'] = false;
                    n.dirty();
                }
            ));
            
            // provide tooltip on mouse hover
            _vis.controls.add(new TooltipControl(NodeSprite, null,
                function(evt:TooltipEvent):void {
                    var maleDeaths:int = getMaleDeaths(evt.node);
                    var femaleDeaths:int = getFemleDeaths(evt.node);
                    var descPath:String = '';
                    var iterNode:NodeSprite = evt.node.parentNode;
                    while(iterNode !== _rootData) {
                        descPath += iterNode.data.name + ' <i>[' + iterNode.data.code + ']</i><br>';
                        iterNode = iterNode.parentNode;
                    }
                    TextSprite(evt.tooltip).htmlText = Strings.format("<b>{0:,0} deaths</b> (<font color='#4DA3C1'>Male: {1:,0}</font>, <font color='#FC90A5'>Female: {2:,0}</font>)<br/><b>{3}</b> <i>[{4}]</i><br/>{5}",
                        maleDeaths + femaleDeaths,
                        maleDeaths,
                        femaleDeaths,
                        evt.node.data.name,
                        evt.node.data.code,
                        descPath
                    );
                }
            ));
            
            _vis.controls.add(new ClickControl(NodeSprite, 1, onDataClick));
        }
        
        public function updateSizes():void {
            _rootData.visitTreeDepthFirst(function(n:NodeSprite):void {
                n.data.deathsMale = 0;
                n.data.deathsFemale = 0;
                n.size = 0;
            }, false);
            
            _rootData.visitTreeDepthFirst(function(n:NodeSprite):void {
                if (n.childDegree == 0) {
                    var dm:int = getMaleDeaths(n);
                    var df:int = getFemleDeaths(n);
                    n.data.deathsMale = dm;
                    n.data.deathsFemale = df;
                    n.size = dm + df;
                    var p:NodeSprite = n.parentNode;
                    while(p) {
                        p.data.deathsMale += dm;
                        p.data.deathsFemale += df;
                        p.size += dm + df;
                        p = p.parentNode;
                    }
                }
            }, false);
        }
    
        public function getMaleDeaths(n:NodeSprite):int {
            var deaths:int = 0;
            if(_showMale && n.data.male) {
                for(var i:int = _minAge; i < _maxAge; i++) {
                    deaths += n.data.male[i];
                }
            }
            return deaths;
        }
        
        public function getFemleDeaths(n:NodeSprite):int {
            var deaths:int = 0;
            if(_showFemale && n.data.female) {
                for(var i:int = _minAge; i < _maxAge; i++) {
                    deaths += n.data.female[i];
                }
            }
            return deaths;
        }

        public function onDataClick(evt:SelectionEvent):void {
            var newRoot:NodeSprite = evt.node;
            var newRootDapth:int = NodeSprite(_layout.layoutRoot).depth+1;
            while(newRoot.depth > newRootDapth) newRoot = newRoot.parentNode;
            
            updateRootNode(true, newRoot);
        }
        
        public function updateRootNode(useTrans:Boolean, newRoot:NodeSprite = null):void {
            if(!newRoot) newRoot = _currentRootData;
            // update bread crumbs
            breadCrumbs.removeAllElements();
            var parentNode:NodeSprite = newRoot.parentNode;
            while(parentNode) {
                var newButton:Button = new Button;
                newButton.label = parentNode.data.code;
                newButton.toolTip = parentNode.data.name;
                newButton.addEventListener(MouseEvent.CLICK, onCrumbClick);
                breadCrumbs.addElementAt(newButton, 0);
                parentNode = parentNode.parentNode;
            }
            
            // make everything that is not not part of the sub tree invisible
            _vis.data.nodes.visit(function(n:NodeSprite):void {
                if(!inSubtree(newRoot, n) || n.size <= 0) {
                    n.visible = false;
                }
            });
            _labeler.makeAllLablesInvisible();
            
            _layout.layoutRoot = newRoot;
            _currentRootData = newRoot;
            updateLabels();
            
            if(useTrans) {
                var trans:Transitioner =new Transitioner(1);
                trans.easing = Easing.easeInOutSine;
                trans.addEventListener(TransitionEvent.END, onTransitionEndMakeVisible);
                _vis.update(trans, 'layout').play();
            } else {
                _vis.update(null, 'layout').play();
                onTransitionEndMakeVisible();
            }
            
            function onTransitionEndMakeVisible(e:TransitionEvent = null):void {
                _vis.data.nodes.visit(function(n:NodeSprite):void {
                    n.lineWidth = (n.depth==_currentRootData.depth+1) ? 2 : (n.childDegree ? 1 : 0);
                    if(n.size > 0 && inSubtree(newRoot, n)) {
                        n.visible = true;
                    }
                });
                
                _vis.update(null, 'labeler').play(); // reposition the labels + make visible
            }
            
            function inSubtree(root:NodeSprite, node:NodeSprite):Boolean {
                var parentAtRootDeapth:NodeSprite = node;
                while(parentAtRootDeapth.depth > root.depth) parentAtRootDeapth = parentAtRootDeapth.parentNode;
                // at this point parentAtRootDeapth is ether:
                // 1. root if none is in it's sub tree
                // 2. a different node if node is in a different subtree
                // 3. node itself if it is shalower than root
                
                return (parentAtRootDeapth === newRoot);
            }
            
            function onCrumbClick(e:MouseEvent):void {
                var found:NodeSprite = null;
                _vis.data.nodes.visit(function(n:NodeSprite):Boolean {
                    if(n.data.name == e.target.toolTip) {
                        found = n;
                        return true;
                    } else {
                        return false;
                    }
                });
                
                if(found) {
                    updateRootNode(true, found);
                } else {
                    throw new Error('Unknown code: ' + e.target.toolTip);
                }
            }
        }
        
        public function onResize():void
        {
            if(!_vis) return;
            _vis.bounds = getSizeRect();
            updateRootNode(false);
        }
            
        public function getSizeRect():Rectangle {
            return new Rectangle(
                0,
                0,
                width - Number(flexVis.left) - Number(flexVis.right),
                height - Number(flexVis.top) - Number(flexVis.bottom)
            );
        }
        
        public function containsCode(parent:String, child:String):Boolean {
            if(parent == child) return true;
            var childMain:String = child.split('.')[0];
            if(parent.indexOf('-') > 0) {
                var bounds:Array = parent.split('-');
                return (bounds[0] <= childMain) && (childMain <= bounds[1]);
            } else {
                return (parent == childMain);
            }
        }
        
        public function buildData():Tree {
            var startTime:Number = (new Date).time;
            
            var tree:Tree = new Tree();
            var root:NodeSprite = tree.addRoot();
            root.data = {name:"All deaths", code:'A00-Z99', path:'/'};
            
            var map:Object = {};
            
            for each(var code:String in ICD10.sortedCodes) {
                // FAST:
                var attach:NodeSprite = root;
                switch(code.length) {
                    case 7:
                        if(ICD10.attachMap.hasOwnProperty(code)) {
                            attach = map[ICD10.attachMap[code]];
                        } // else root
                        break;
                    
                    case 3:
                        attach = map[ICD10.attachMap[code]];
                        break;
                    
                    case 5:
                        attach = map[code.substr(0, 3)];
                        break;
                    
                    default:
                        throw new Error('Invalid ICD10 code');
                }
                /*
                // SLOW: (spec)
                for each(var mappedCode:String in ICD10.sortedCodes) {
                    if(!map.hasOwnProperty(mappedCode)) continue;
                    if(containsCode(mappedCode, code)) {
                        attach = map[mappedCode];    
                    }
                }
                */
                var description:String = ICD10.codes[code];
                var path:String = attach.data.path + code + '/';
                var newNode:NodeSprite = tree.addChild(attach);
                newNode.data = {name:description, code:code, path:path};
                delete attach.data.male;
                delete attach.data.female;
                
                // create a male and female node
                var deathValues:Object = ICD10.deaths[code];
                if(deathValues) {
                    if(deathValues.male) newNode.data['male'] = deathValues.male;
                    if(deathValues.female) newNode.data['female'] = deathValues.female;
                }
                
                if(code.length != 5) {
                    //if(1 <= death && death <= 50 && code.length == 3) {
                    //    map[code] = null;
                    //} else {
                    map[code] = newNode;
                    //}
                }
                //trace(code, ',', death);
                //if(attach !== root && code.length != 5) trace("'" + code + "': '" + attach.data.code + "',"); // helper
                //if(attach === root) trace(code); // helper
            }
            
            //trace("Time taken:", (new Date).time - startTime);
            ICD10.codes = null;
            ICD10.sortedCodes = null;
            ICD10.deaths = null;
            //trace("Time taken:", (new Date).time - startTime);
            return tree;
        }
        
        public function updateLabels():void {
            if(codeLabel) {
                codeLabel.text = _currentRootData.data.code + ' /';
            }
            
            if(titleLabel) {
                titleLabel.text = _currentRootData.data.name;
            }
            
            if(numbersLabel) {
                numbersLabel.text = Strings.format("(T:{0:,0} M:{1:,0} F:{2:,0})",
                    _currentRootData.size,
                    _currentRootData.data.deathsMale,
                    _currentRootData.data.deathsFemale
                );
            }
        }
        
        public function onSliderChange():void {
            _minAge = ageSlider.values[0];
            _maxAge = ageSlider.values[1];
            
            updateSizes();
            updateRootNode(true);
        }
        
        public function onSexFilterChange():void {
            if(!_rootData) return;
            
            switch(sexFilter.selectedIndex) {
            case 0:
                _showMale = true;
                _showFemale = true;
                break;
            
            case 1:
                _showMale = true;
                _showFemale = false;
                break;
            
            case 2:
                _showMale = false;
                _showFemale = true;
                break;
            
            default:
                _showMale = true;
                _showFemale = true;
                break;
            }
            
            updateSizes();
            updateRootNode(true);
        }
        
        public function onTextChange():void {
            var filter:String = filterInput.text.toLowerCase();
            
            var queryParts:Array = filter.split(' ');
            var codeParts:Array = new Array;
            var filterParts:Array = new Array;
            for each(var q:String in queryParts) {
                if(q == '') continue;
                if(isCode(q)) {
                    codeParts.push(q.toUpperCase());
                } else if(isPartialCode(q)) {
                    // do nothing
                } else {
                    filterParts.push(q.toLowerCase());
                }
            }
                        
            _vis.data.nodes.visit(function(n:NodeSprite):void {
                if(n.childDegree > 0) return;
                
                // construct all descriptions
                var descPath:String = '';
                var iterNode:NodeSprite = n;
                while(iterNode !== _rootData) {
                    descPath += iterNode.data.name + ' ';
                    iterNode = iterNode.parentNode;
                }
                descPath = descPath.toLowerCase();
                
                var strikes:int = 0;
                var maxStrikes:int = 0;
                if(codeParts.length > 0) {
                    maxStrikes += 2;
                    var codeCont:Boolean = false;
                    for each(var c:String in codeParts) {
                        if(containsCode(c, n.data.code)) {
                            codeCont = true;
                            break;
                        }
                    }
                    if(!codeCont) strikes += 2;
                }
                
                for each(var f:String in filterParts) {
                    maxStrikes += 1;
                    if(descPath.indexOf(f) == -1) strikes += 1;
                }
                
                if (strikes == 0) {
                    n.fillColor = ICD10.colorMap(String(n.data.path).substr(1,7));//0xff4444ff;
                } else {
                    n.fillSaturation = 0;
                    n.fillValue = (1 - strikes/maxStrikes)/2;
                }
                //n.lineColor = 0xffcccccc;
                //n.lineWidth = n.depth==1 ? 2 : n.childDegree ? 1 : 0;
                n.fillAlpha = 0.7;//n.depth / 10;
            });
            
            function isCode(code:String):Boolean {
                var pattern:RegExp;
                switch(code.length) {
                case 7:
                    pattern = /\w\d\d-\w\d\d/;
                    break;
                case 5:
                    pattern = /\w\d\d\.\d/;
                    break;
                case 3:
                    pattern = /\w\d\d/;
                    break;
                
                default:
                    return false;
                }
                
                return Boolean(pattern.exec(code));
            }
            
            function isPartialCode(code:String):Boolean {
                var pattern:RegExp;
                switch(code.length) {
                case 6:
                case 5:
                    pattern = /^\w\d\d-\w?\d?$/;
                    break;
                case 4:
                    pattern = /^\w\d\d[\.-]/;
                    break;
                case 3:
                case 2:
                case 1:
                    pattern = /^\w\d?\d?$/;
                    break;
                
                default:
                    return false;
                }
                
                return Boolean(pattern.exec(code));
            }
        }
    
        public function onShowLabelsClick():void {
            _showLabels = showLabelsCheckBox.selected;
            
            if(_showLabels) {
                _vis.update(null, 'labeler').play();
            } else {
                _labeler.makeAllLablesInvisible();
            }
        }
    ]]>
    </fx:Script>
    
    <s:states>
        <s:State name="Default"/>
        <s:State name="More"/>
    </s:states>
    
    <s:HGroup id="breadCrumbs" left="20" top="10">
        <!-- Bread crumb buttons go here -->
    </s:HGroup>
              
    <!--          
    <s:Button label="&lt;&lt; All Deaths" left="20" top="10" enabled="{_rootData !== _currentRootData}" click="onRootClick()"/>
    -->
              
    <s:HGroup horizontalCenter="0" top="35" verticalAlign="middle">
        <s:Label id="codeLabel" text="N/A" fontSize="14"/>
        <s:Label id="titleLabel" fontSize="22" fontWeight="bold"/>
        <s:Label id="numbersLabel" text="N/A" fontSize="14"/>
    </s:HGroup>
    
    <fl:FlexVis id="flexVis" left="20" right="20" top="60" bottom="75" resize="onResize()"/>

    <s:Button top="10" right="20" label="More..." click="currentState = 'More'"/>

    <s:Label text="Filter:" fontSize="18" bottom="10" left="20" text.Default="Highlight:"/>
    <s:TextInput id="filterInput" bottom="10" left="74" change="{onTextChange()}" left.Default="100" restrict="0-9A-Za-z-. " bottom.Default="10" right="306"/>
    <s:Button label="X" bottom="10" right="277" width="30" height="22" click="{filterInput.text = ''; onTextChange()}" cornerRadius="0"/>
    <s:Label text="Show:" fontSize="18" bottom="10" right="218"/>
    <s:DropDownList id="sexFilter" labelField="name" right="20" bottom="11" selectedIndex="0" change="onSexFilterChange()" width="190" fontSize="14">
        <mx:ArrayCollection>
            <fx:Object name="both males and females" value="0"/>
            <fx:Object name="males only" value="1"/>
            <fx:Object name="females only" value="2"/>
        </mx:ArrayCollection>
    </s:DropDownList>

    <s:Group left="25" right="25" bottom="53">
        <s:layout><s:TileLayout requestedColumnCount="21" columnAlign="justifyUsingWidth"/></s:layout>    

        <s:Label textAlign="center" text="&lt; 1"/>
        <s:Label textAlign="center" text="1-4"/>
        <s:Label textAlign="center" text="5-9"/>
        <s:Label textAlign="center" text="10-14"/>
        <s:Label textAlign="center" text="15-19"/>
        <s:Label textAlign="center" text="20-24"/>
        <s:Label textAlign="center" text="25-29"/>
        <s:Label textAlign="center" text="30-34"/>
        <s:Label textAlign="center" text="35-39"/>
        <s:Label textAlign="center" text="40-44"/>
        <s:Label textAlign="center" text="45-49"/>
        <s:Label textAlign="center" text="50-54"/>
        <s:Label textAlign="center" text="55-59"/>
        <s:Label textAlign="center" text="60-64"/>
        <s:Label textAlign="center" text="65-69"/>
        <s:Label textAlign="center" text="70-74"/>
        <s:Label textAlign="center" text="75-79"/>
        <s:Label textAlign="center" text="80-84"/>
        <s:Label textAlign="center" text="85-89"/>
        <s:Label textAlign="center" text="90-94"/>
        <s:Label textAlign="center" text="95+"/>
    </s:Group>
    
    <mx:HSlider
        id="ageSlider"
        toolTip="Select the age range to display"
        thumbCount="2"
        minimum="0"
        maximum="21"
        values="{[0, 21]}"
        left="20" right="20" bottom="38"
        snapInterval="1"
        tickColor="0x222222"
        showDataTip="false"
        showTrackHighlight="true"
        labelOffset="2"
        tickOffset="0"
        tickValues="{[0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5, 19.5, 20.5]}"
        change="onSliderChange()"
    />
    
    <s:Group includeIn="More" left="0" right="0" top="0" bottom="0">
        <s:Rect left="0" right="0" top="0" bottom="0">
            <s:fill><s:SolidColor color="0x000000" alpha="0.4"/></s:fill>
        </s:Rect>
        <s:Group width="400" height="400" horizontalCenter="0" verticalCenter="-40">
            <s:Rect left="0" right="0" top="0" bottom="0">
                <s:fill><s:SolidColor color="0xFFFFFF"/></s:fill>
                <s:stroke><s:SolidColorStroke color="0x000000" weight="2"/></s:stroke>
            </s:Rect>
            
            <s:Label text="Deaths by cause and sex" horizontalCenter="0" top="12" fontSize="24"/>
            <s:Label text="England and Wales 2007" horizontalCenter="0" top="39" fontSize="18"/>
            <s:VGroup top="70" bottom="100" left="10" right="10" gap="10">
                <s:VGroup gap="3">
                    <s:Label text="Description:" fontSize="14"/>
                    <s:Group width="100%">
                        <s:Label left="20" width="360" text="Deaths, repeatedly grouped by cause, are represented as rectangles where the area is proportional to the number of fatalities." textDecoration="none"/>
                    </s:Group>
                </s:VGroup>
                
                <s:VGroup gap="3">
                    <s:Label text="Highlighter usage:" fontSize="14"/>
                    <s:Group width="100%">
                        <s:Label left="20" width="360" text="Enter search terms and/or ICD10 code ranges separated by space. Example: “V20-V80 V90 driver” will highlight every datum whose code is ether between V20 and V80 or is V90 and whose description contains ‘driver’." textDecoration="none"/>
                    </s:Group>
                </s:VGroup>

                <s:VGroup gap="3">
                    <s:Label text="Visualization by Vadim Ogievetsky" fontSize="14"/>
                    <s:Group width="100%" buttonMode="true" useHandCursor="true" click="{navigateToURL(new URLRequest('mailto:vadim.ogievetsky@cs.stanford.edu'), '_blank')}">
                        <s:Label left="20" width="360" text="vadim.ogievetsky@cs.stanford.edu" color="#5AC85A" textDecoration="none"/>
                    </s:Group>
                </s:VGroup>
                
                <s:VGroup gap="3">
                    <s:Label text="Submited as Assignment 3 of CS488b Data Visualization" fontSize="14"/>
                    <s:Label text="(project updated after grading)" fontSize="12"/>
                    <s:Group width="100%" buttonMode="true" useHandCursor="true" click="{navigateToURL(new URLRequest('https://graphics.stanford.edu/wikis/cs448b-09-fall'), '_blank')}">
                        <s:Label left="20" width="360" text="https://graphics.stanford.edu/wikis/cs448b-09-fall" color="#5AC85A" textDecoration="none"/>
                    </s:Group>
                </s:VGroup>
                
                <s:VGroup gap="3">
                    <s:Label text="Data taken from the British death register" fontSize="14"/>
                    <s:Group width="100%" buttonMode="true" useHandCursor="true" click="{navigateToURL(new URLRequest('http://www.statistics.gov.uk/downloads/theme_health/DR2007/DR_07_2007.pdf'), '_blank')}">
                        <s:Label left="20" width="360" text="http://www.statistics.gov.uk/downloads/theme_health/DR2007/DR_07_2007.pdf" color="#5AC85A" textDecoration="none"/>
                    </s:Group>
                </s:VGroup>
                
                <s:CheckBox id="showLabelsCheckBox" x="15" y="323" label="Show labels" selected="true" click="onShowLabelsClick()"/>
            </s:VGroup>
            
            <s:Button label="Close" horizontalCenter="0" bottom="10" click="currentState = 'Default'"/>            
        </s:Group>
    </s:Group>
</s:Application>