diving deep, component life cycle

Upload: bhbagadiya

Post on 10-Apr-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/8/2019 Diving Deep, Component Life Cycle

    1/76

    Diving Deep with the Flex

    Component LifecycleJoshua Jamison

    EffectiveUI

    www.effectiveui.com

    January 30, 2009

    http://www.effectiveui.com/http://www.effectiveui.com/http://www.effectiveui.com/
  • 8/8/2019 Diving Deep, Component Life Cycle

    2/76

    Who am I?

    Joshua Jamison

    Software Architect @ EffectiveUI

  • 8/8/2019 Diving Deep, Component Life Cycle

    3/76

    Who are you (hopefully)?

    Beginner to intermediate level developers

    Anyone who doesnt currently understand

    the lifecycle

    Anyone who wants a good review of the

    basics

  • 8/8/2019 Diving Deep, Component Life Cycle

    4/76

    Whats this about, anyway?

    Flex component lifecycleFlex frame cycle (elastic racetrack)

  • 8/8/2019 Diving Deep, Component Life Cycle

    5/76

    Flex Component Lifecycle

    What is it? The way the framework interacts with

    every Flex component

    A set of methods the framework calls toinstantiate, control, and destroy

    components

    Methods that make the most of the

    elastic racetrack

  • 8/8/2019 Diving Deep, Component Life Cycle

    6/76

    Elastic Racetrack: introduction

    Flex component lifecycle is built on this

    frame model

    More on this later

    image courtesy of Ted Patrick

  • 8/8/2019 Diving Deep, Component Life Cycle

    7/76

    A frame in AS3

    image courtesy of Sean Christmann

  • 8/8/2019 Diving Deep, Component Life Cycle

    8/76

    Phases of the Lifecycle

    3 Main Phases:

    BIRTH:

    construction, conguration,

    attachment, initialization LIFE:

    invalidation, validation, interaction

    DEATH:

    detachment, garbage collection

  • 8/8/2019 Diving Deep, Component Life Cycle

    9/76

    BirthCongratulations: Youre about to have a component.

  • 8/8/2019 Diving Deep, Component Life Cycle

    10/76

    Construction

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    11/76

    What is a constructor?

    A function called to instantiate (create in

    memory) a new instance of a class

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    12/76

    How is a constructor invoked?

    Actionscript:

    MXML:

    vartheLabel : Label =newLabel();

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    13/76

    What does a constructor have access to?

    Properties on the classMethods on the class

    Children have not yet been created!

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    14/76

    What does an ActionScript3

    constructor look like?

    No required arguments (if it will be used inMXML); zero, or all optional

    Only one per class (no overloading!)

    No return type

    Must be public

    Calls super() to invoke superclass constructor; if

    you dont, the compiler will!

    publicfunctionComponentName()

    {

    super();

    //blah blah blah

    }

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    15/76

    What does an MXML constructor

    look like?

    No need to dene one. In fact, if you tryto put one in an block, youll

    get an error.

    Why? Remember: MXML = Actionscript. Aconstructor is created by the compiler in

    the Actionscript generated from the

    MXML.

    Specify -keep in the Flex Buildercompiler arguments and look at the

    generated code to verify this.

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    16/76

    What should a constructor do?

    Not much. Since the componentschildren have not yet been created, theres

    not much that can be done.

    There are speci

    c methods (such ascreateChildren) that should be used for

    most of the things youd be tempted to

    put in a constructor.

    A good place to add event listeners to the

    object.Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    17/76

    Dont create or attach children in

    the constructor

    Its best to delay the cost of createChildrencalls for added children until its necessary

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    18/76

    Conguration

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    19/76

    Conguration

    The process of assigning values toproperties on objects

    In MXML, properties are assigned in this

    phase, before components are attached or

    initialized

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    20/76

    Hooray: Sample code!

    SampleChild constructorSampleChild.property1 setter

    Adding child SampleChild4

    ...

    Output:

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    21/76

    Conguration and Containers

    Containers must not expect their childrenhave to be instantiated when properties

    are set.

    SampleContainer constructor

    SampleContainer.property1 setter

    SampleChild constructor

    SampleChild.property1 setter

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    22/76

    Conguration Optimization

    To avoid performance bottlenecks, make

    your setters fast and defer any real work

    until validation

    Well talk more about deferment in the

    validation / invalidation section

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    23/76

    Attachment

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    24/76

    What is attachment?

    Adding a component to the display list

    (addChild, addChildAt, MXML declaration)

    The component lifecycle is stalled after

    conguration until attachment occurs.

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    25/76

    Consider this component:

    publicclassAextendsUIComponent { publicfunctionA(){ trace("CONSTRUCTOR"); super(); } overrideprotectedfunctioncreateChildren():void{ trace("CREATECHILDREN"); super.createChildren(); } overrideprotectedfunctionmeasure():void{ trace("MEASURE"); super.measure(); } overrideprotectedfunctionupdateDisplayList(width:Number, height:Number):void{ trace("UPDATEDISPLAYLIST"); super.updateDisplayList(width,height); } overrideprotectedfunctioncommitProperties():void{ trace("COMMITPROPERTIES"); super.commitProperties(); }

    (It traces all of its methods.)

  • 8/8/2019 Diving Deep, Component Life Cycle

    26/76

    And this application:

    Without attachment, the rest of the lifecycle

    doesnt happen.

    overrideprotectedfunctioncreateChildren():void{ super.createChildren(); vara:A=newA(); }

    ]]>

    CONSTRUCTOROutput:

  • 8/8/2019 Diving Deep, Component Life Cycle

    27/76

    But what about this application?

    Moral of the story: dont add components to the

    stage until you need them.

    this.addChild( a ); } ]]> Output: CONSTRUCTOR

    CREATECHILDREN

    COMMITPROPERTIES

    MEASURE

    UPDATEDISPLAYLIST

  • 8/8/2019 Diving Deep, Component Life Cycle

    28/76

    Initialization

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    29/76

    Initialization

    2 phases, 3 events:

    1. preInitialize dispatched

    2. createChildren(); called3. initialize dispatched

    4. rst validation pass occurs

    5. creationComplete dispatched

    Create

    Validate

    Birth

    construction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    30/76

    createChildren()

    MXML uses the createChildren() method to add

    children to containers Override this method to add children using AS

    Follow MXMLs creation strategy: create,

    congure, attach

    overrideprotectedfunctioncreateChildren():void

    {

    ...

    textField=newUITextField();

    textField.enabled=enabled;

    textField.ignorePadding=true;

    textField.addEventListener("textFieldStyleChange",

    textField_textFieldStyleChangeHandler);

    ...

    ...

    addChild(DisplayObject(textField));

    }

    create

    congure

    attach

  • 8/8/2019 Diving Deep, Component Life Cycle

    31/76

    rst validation pass

    Invalidation is not part of initialization -only Validation

    Validation consists of 3 methods:

    commitProperties() measure()

    updateDisplayList()

    more on these laterBirthconstruction

    conguration

    attachment

    initialization

    LifeDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    32/76

    LifeThey grow up so fast.

  • 8/8/2019 Diving Deep, Component Life Cycle

    33/76

    Invalidation

    Birth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    34/76

    Invalidation / Validation cycle

    Flex imposes deferred validation on the

    Flash API

    goal: defer screen updates until all

    properties have been set

    3 main method pairs to be aware of: invalidateProperties() ->

    commitProperties()

    invalidateSize() -> measure() invalidateDisplayList() ->

    updateDisplayList()

  • 8/8/2019 Diving Deep, Component Life Cycle

    35/76

    Invalidation / Validation theory

    First, a little theory.

  • 8/8/2019 Diving Deep, Component Life Cycle

    36/76

    Deferment

    Deferment is the central concept to

    understand in the component Life-cycle

    Use private variables and boolean ags todefer setting any render-related

    properties until the proper validation

    method

  • 8/8/2019 Diving Deep, Component Life Cycle

    37/76

    Text-book example

    publicfunctionsettext(value:String):void

    {

    myLabel.text=value;

    // Possible Error! during first config phase,

    // myLabel might not exist!

    }

    privatevar_text:String="";

    publicfunctionsettext(value:String):void

    {

    textSet=true;

    _text=value; textChanged=true;

    invalidateProperties();

    invalidateSize();

    invalidateDisplayList();

    }

    overrideprotectedfunction

    commitProperties():void{

    {

    if(textChanged){myLabel.text=_text;

    textChanged=false;

    }

    super.commitProperties();

    }

    Bad:

    Good:

  • 8/8/2019 Diving Deep, Component Life Cycle

    38/76

    The Elastic Racetrack revisited

    Invalidation occurs here

    image courtesy of Sean Christmann

  • 8/8/2019 Diving Deep, Component Life Cycle

    39/76

    Invalidation methods

    invalidateProperties() Any property changes

    invalidateSize()

    Changes to width or height

    invalidateDisplayList()

    Changes to child component size or

    positionBirth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    40/76

    Invalidation example 1

  • 8/8/2019 Diving Deep, Component Life Cycle

    41/76

    Invalidation example 2publicclassBadListextendsVBox { privatevar_dataProvider:ArrayCollection;

    publicfunctionsetdataProvider(arr:ArrayCollection):void{ this._dataProvider=arr; arr.addEventListener(CollectionEvent.COLLECTION_CHANGE,dataProviderChangeHandler); } privatefunctiondataProviderChangeHandler(e:Event):void{

    this.removeAllChildren(); foreach(varn:Numberinthis._dataProvider){ varl:Label=newLabel(); l.text=n.toString(); this.addChild(l); }

    } publicfunctionBadList(){} }Result: dataProviderChangeHandler called 20 times

  • 8/8/2019 Diving Deep, Component Life Cycle

    42/76

    Invalidation example 3publicclassGoodListextendsVBox { privatevar_dataProvider:ArrayCollection; privatevar_dataProviderChanged:Boolean=false;

    publicfunctionsetdataProvider(arr:ArrayCollection):void{ this._dataProvider=arr; arr.addEventListener(CollectionEvent.COLLECTION_CHANGE,dataProviderChangeHandler); this._dataProviderChanged=true; this.invalidateProperties(); } overrideprotectedfunctioncommitProperties():void{

    super.commitProperties(); if(this._dataProviderChanged){ this.removeAllChildren(); foreach(varn:Numberinthis._dataProvider){ varl:Label=newLabel(); l.text=n.toString(); this.addChild(l); } this._dataProviderChanged=false; } } privatefunctiondataProviderChangeHandler(e:Event):void{ this._dataProviderChanged=true; this.invalidateProperties(); } publicfunctionGoodList(){} }

    Result: commitProperties

    called only twice (once

    during initialization)

  • 8/8/2019 Diving Deep, Component Life Cycle

    43/76

    Validation

    Birth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    44/76

    The Elastic Racetrack revisited

    Validation occurs here

  • 8/8/2019 Diving Deep, Component Life Cycle

    45/76

    Validation

    Apply the changes deferred duringinvalidation

    Update all visual aspects of the

    application in preparation for the render

    phase

    3 methods:

    commitProperties()

    measure()

    updateDisplayList()Birth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    46/76

    commitProperties()

    Ely says: Calculate and commit the effects

    of changes to properties and underlying

    data. Invoked rst - immediately before

    measurement and layout

    Birth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    47/76

    commitProperties() cont.

    ALL changes based on property and data

    events go here

    Even creating and destroying children, so

    long as theyre based on changes toproperties or underlying data

    Example: any list based component with

    empty renderers on the screenBirth

    Life

    invalidation

    validation

    interactionDeath

  • 8/8/2019 Diving Deep, Component Life Cycle

    48/76

    measure()

    Component calculates its preferred(default) and minimum proportions

    based on content, layout rules,

    constraints.

    Measure is called bottom up - lowest

    children rst

    Caused by invalidateSize()

    NEVER called for explicitly sized

    componentsBirth

    Life

    invalidation

    validation

    interactionDeath

    idi ()

  • 8/8/2019 Diving Deep, Component Life Cycle

    49/76

    overriding measure()

    Used for dynamic layout containers (VBox,etc.)

    Use getExplicitOrMeasuredWidth() (or

    height) to get child proportionsALWAYS called during initialization

    Call super.measure() rst!

    Set measuredHeight, measuredWidth forthe default values; measuredMinHeight

    and measuredMinWidth for the minimum.Birth

    Life

    invalidation

    validation

    interactionDeath

    ()

  • 8/8/2019 Diving Deep, Component Life Cycle

    50/76

    measure() cont.

    Not reliable - Framework optimizes awayany calls to measure it deems

    unecessary

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    d Di l Li ()

  • 8/8/2019 Diving Deep, Component Life Cycle

    51/76

    updateDisplayList()

    All drawing and layout code goes here,making this the core method for all

    container objects

    Caused by invalidateDisplayList();Concerned with repositioning and

    resizing children

    updateDisplayList() is called top-downBirth

    Life

    invalidation

    validation

    interaction

    Death

    O idi d Di l Li ()

  • 8/8/2019 Diving Deep, Component Life Cycle

    52/76

    Overriding updateDisplayList()

    Usually call super.updateDisplayList() rst

    super() is optional - dont call it if youre

    overriding everything it does

    Size and lay out children using move(x,y)and setActualSize(w,h) if possible

    I never have good luck with

    setActualSize()Birth

    Life

    invalidation

    validation

    interaction

    Death

    El ti R t k t

  • 8/8/2019 Diving Deep, Component Life Cycle

    53/76

    Elastic Racetrack cont.

    User Actions Dispatch invalidation events

    Interact with any non-validation events

    from this frame (mouse movements,timers, etc.)

    El ti R t k C t

  • 8/8/2019 Diving Deep, Component Life Cycle

    54/76

    Elastic Racetrack Cont.

    Invalidate Action Process all validation calls

    Render Action

    Do the heavy lifting - actually draw onthe screen

    Th El ti R t k i it d

  • 8/8/2019 Diving Deep, Component Life Cycle

    55/76

    The Elastic Racetrack revisited

    Queued Invalidation

    Deferred ValidationRender!

  • 8/8/2019 Diving Deep, Component Life Cycle

    56/76

    Interaction

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    How do objects know when

  • 8/8/2019 Diving Deep, Component Life Cycle

    57/76

    How do objects know when

    something happens?

    Events: objects passed around whenanything interesting goes on (clicks,

    moves, changes, timers...)

    If something happens to a component, itres or dispatches the event

    If another component wants to know

    when something happens, it listens for

    events

    Event-based architecture is loosely-

    coupled

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Benets of Loosely-Coupled

  • 8/8/2019 Diving Deep, Component Life Cycle

    58/76

    Benets of Loosely Coupled

    Architectures

    Everything becomes more reusable

    Components dont have to know anythingabout the components in which theyre

    used

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Who can dispatch e ents?

  • 8/8/2019 Diving Deep, Component Life Cycle

    59/76

    Who can dispatch events?

    Subclasses of EventDispatcher

    EventDispatcher inherits directly from

    ObjectSimply call dispatchEvent(event) to re off

    an event when something happens

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    How to tell events apart?

  • 8/8/2019 Diving Deep, Component Life Cycle

    60/76

    How to tell events apart?

    Event class

    Different classes allow for customized

    payloads

    typeeld: a constant

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Common Events

  • 8/8/2019 Diving Deep, Component Life Cycle

    61/76

    Common Events

    Event.CHANGE

    MouseEvent.CLICK

    FlexEvent.CREATION_COMPLETEEvent.RESIZE

    MouseEvent.ROLL_OUT

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Handling Events

  • 8/8/2019 Diving Deep, Component Life Cycle

    62/76

    Handling Events

    theButton.addEventListener( MouseEvent

    .CLICK, callThisFunction )

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Event Propagation

  • 8/8/2019 Diving Deep, Component Life Cycle

    63/76

    Event Propagation

    CapturingPhase

    Target

    Application Application

    BubblingPhase

    TargetingPhase

    Three phases: Capturing, Targeting, Bubbling

    Birth

    Life

    invalidation

    validation

    interaction

    Death

  • 8/8/2019 Diving Deep, Component Life Cycle

    64/76

    Event Propagation Three phases: Capturing, Targeting, Bubbling

    button.addEventListener(MouseEvent.CLICK,clickHandler,false); } publicfunctionclickHandler(e:Event):void{ trace("----------------------------------------------------------"); trace("TARGET: "+e.target.id); trace("CURRENT TARGET: "+e.currentTarget.id); trace("PHASE: "+(e.eventPhase==1 ?"CAPTURE":(e.eventPhase==2?"TARGET":"BUBBLE"))); } ]]>

    Birth

    Life

    invalidation

    validation

    interaction

    Death

  • 8/8/2019 Diving Deep, Component Life Cycle

    65/76

    Event Propagation----------------------------------------------------------

    TARGET: button

    CURRENT TARGET: eventTest

    PHASE: CAPTURE----------------------------------------------------------

    TARGET: buttonCURRENT TARGET: outer

    PHASE: CAPTURE

    ----------------------------------------------------------

    TARGET: buttonCURRENT TARGET: inner

    PHASE: CAPTURE----------------------------------------------------------

    TARGET: button

    CURRENT TARGET: button

    PHASE: TARGET----------------------------------------------------------

    TARGET: buttonCURRENT TARGET: inner

    PHASE: BUBBLE

    ----------------------------------------------------------

    TARGET: button

    CURRENT TARGET: outerPHASE: BUBBLE----------------------------------------------------------

    TARGET: buttonCURRENT TARGET: eventTest

    PHASE: BUBBLE

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Stopping events from propagating

  • 8/8/2019 Diving Deep, Component Life Cycle

    66/76

    Stopping events from propagating

    stopPropagation() : Prevents processingof any event listeners in nodes

    subsequent to the current node in the

    event ow

    stopImmediatePropagation() : Prevents

    processing of any event listeners in the

    current node and any subsequent nodes

    in the event owBirth

    Life

    invalidation

    validation

    interaction

    Death

    target vs currentTarget

  • 8/8/2019 Diving Deep, Component Life Cycle

    67/76

    target vs. currentTarget

    target: the object that dispatched the

    event (doesnt change)

    currentTarget: the object who is currentlybeing checked for specic event listeners

    (changes)

    Birth

    Life

    invalidation

    validation

    interaction

    Death

    Dispatching events from custom

  • 8/8/2019 Diving Deep, Component Life Cycle

    68/76

    Dispatching events from custom

    components

    MXML:

    Actionscript:

    [Event(name="atePizza", type="flash.events.JoshEvent")]

    [Event(name="atePizza", type="flash.events.JoshEvent")]

    public class MyComponent extends UIComponent

    {

    ...

    }

    Birth

    Life

    invalidation

    validation

    interaction

    Death

  • 8/8/2019 Diving Deep, Component Life Cycle

    69/76

    DeathAll good things come to an end.

  • 8/8/2019 Diving Deep, Component Life Cycle

    70/76

    Detachment

    Birth

    Life

    Death

    detachment

    garbage

    collection

    Detachment

  • 8/8/2019 Diving Deep, Component Life Cycle

    71/76

    Detachment

    Detachment refers to the process ofremoving a child from the display list

    These children can be re-parented

    (brought back to life) or abandoned to dieAbandoned components dont get

    validation calls and arent drawn

    If an abandoned component has no moreactive references, it *should* be garbage-

    collectedBirth

    Life

    Death

    detachment

    garbage

    collection

    Detachment cont

  • 8/8/2019 Diving Deep, Component Life Cycle

    72/76

    Detachment cont.

    Re-parenting isnt cheap, but its cheaperthan re-creating the same component

    twice

    Children do not need to be removed from

    their parent before being re-parented, butalways should be

    Consider hiding rather than removing

    set visible and includeInLayout to falseBirth

    Life

    Death

    detachment

    garbage

    collection

  • 8/8/2019 Diving Deep, Component Life Cycle

    73/76

    Garbage Collection

    Birth

    Life

    Death

    detachment

    garbage

    collection

    Garbage Collection

  • 8/8/2019 Diving Deep, Component Life Cycle

    74/76

    Garbage Collection

    The process by which memory is returned

    to the system

    Only objects with no remaining references

    to them will be gcd Set references to detached children to

    null to mark them for GC

    Talk to Grant Skinner about forcing GC http://gskinner.com/blog/archives/2006/08/as3_resource_ma_2.htmlBirth

    Life

    Death

    detachment

    garbage

    collection

    Conclusion

    http://gskinner.com/blog/archives/2006/08/as3_resource_ma_2.htmlhttp://gskinner.com/blog/archives/2006/08/as3_resource_ma_2.html
  • 8/8/2019 Diving Deep, Component Life Cycle

    75/76

    Conclusion

    Defer, Defer, DEFER!

    Use validation methods correctlyRemember the elastic racetrack

    References

  • 8/8/2019 Diving Deep, Component Life Cycle

    76/76

    References

    Ely Greeneld: Building a Flex Component

    http://www.onex.org/ACDS/BuildingAFlexComponent.pdf

    Chac Kazoun, Joey Lott: Programming Flex 2 by

    OReilly http://oreilly.com/catalog/9780596526894/

    Colin Moock: Essential Actionscript 3.0 by OReilly

    http://oreilly.com/catalog/9780596526948/

    index.html

    http://oreilly.com/catalog/9780596526948/index.htmlhttp://oreilly.com/catalog/9780596526948/index.htmlhttp://oreilly.com/catalog/9780596526948/index.htmlhttp://oreilly.com/catalog/9780596526948/index.htmlhttp://oreilly.com/catalog/9780596526894/http://oreilly.com/catalog/9780596526894/http://www.onflex.org/ACDS/BuildingAFlexComponent.pdfhttp://www.onflex.org/ACDS/BuildingAFlexComponent.pdfhttp://www.onflex.org/ACDS/BuildingAFlexComponent.pdfhttp://www.onflex.org/ACDS/BuildingAFlexComponent.pdf