Blog

  • Mind Over Video Game

    Via her majesty. Using brainpower alone to control computers. I was kind of dismayed to hear they are already working on a wireless system. The whole cyber, wire’s in you, Johnny Mnemonic thing was always a future fetish of mine, but the last thing I’d want to do is apply Neosporin simply because I was plugged into Unreal for 8+ hours at a LAN party, and my neck got infected.

    Mind Over Video Game

  • Flash MX 2004 Framework Component Tutorial

    Want to learn how to create an ActionScript 2.0 based component that utilizes the Flash MX 2004 Professional framework? Then follow this tutorial in creating a simple Sign In dialogue. Let’s dissect this mutha…

    Class

    First thing’s first. You have to inherit, at least, from UIObject. Now, he’s cool and all with nifty extensions, built in methods, call backs, invalidation, the whole 9 yards (…or 8.2 meters). UIComponent is even better. So, let’s plug into the framework, shall we? Make an AS file, and save the mug in a folder somewhere. He should start like this:

    class SignInView extends mx.core.UIComponent
    

    Variables

    Next, we have to define/dim our main framework variables. The first is symbolName which is used in some of the factory construction methods (functions that create components within components; createClassObject for example). Next is symbolOnwer who is used mainly in createClassObject to determine who the base/super class is. Typically, this is the same as your class path. Finally, you have className, which is used createClassObject as well as when calculating style values. It’s also nice for debugging. Instead of using typeof or instanceof, you can just trace out className to figure out what the heck your component is.

    // standard mx 2004 framework variables
    static var symbolName:String = "SignInView";
    static var symbolOwner:Object = SignInView;
    public var className:String = "SignInView";
    

    Next up is the variables we’ll use to hold our data, as miniscule as that is for something as simple as a View; view being the GUI that the user interacts with to tell the Controller, “Yo, user changed some stuff.”

    Typically, Flash MX 2004 components have getter/setters for their main public variables since this allows them easy integration with the IDE. If your not going to dynamically attach your component, or you think a potential user would, it’s best to provide getter/setters so they can be inspectable by the IDE, and more easily settable.

    We know our component will have a username, password, and some form of state. What happens behind the scenes, however, is that your public getter/setters are merely publicly accessible functions that set internal private variable values. This is number 1, controlled access, and number 2, a way to have addProperty co-chill on the prototype. In the past, the only way to get addProperty (the getter/setter functions used to set your class’ property) to be set on the prototype, and thus not be added to each and every instance (and therefore wasting memory/RAM) was to have a go between variable. In our case, it’s just a private variable.

    Finally, I like to use a base class with Grant Skinner’s GDispatcher, but to start simple, we’ll assume for this class only, you’d like to utilize the EventDispatcher. To do so, you typically define a static private, one time use boolean to determine if you’ve initialized the EventDispatcher. So, we’ll add him too.

    So, let’s setup the privates first. I use an underscore to designate them as privates (as if the word private wasn’t enough… hey man, you never know…).

    // dim them there vars boi!
    static private var inited:Boolean = false;
    private var _state:String = "sign in";
    private var _username:String;
    private var _password:String;
    
    

    Before we start littering our class with some functions, let’s finish defining the rest of our variables. The rest are just controls. Now, me personally I don’t like using import in my classes. I had a bug once where a class wasn’t exported because I didn’t use it. Using an asterisk(*) at the end of a package could sometimes crash Flash, and there is a big difference between Button and mx.controls.Button; if your just short cutting it to Button, Flash thinks it’s the intrinsic one. So, I just write my fully qualified class paths.

    Now, the controls. We’ll be using some labels, text input fields, 2 buttons, a progress bar, and a dead preview movie clip.

    // controls
    private var deadPreview_mc:MovieClip;
    
    private var main_lbl:mx.controls.Label;
    private var username_lbl:mx.controls.Label;
    private var password_lbl:mx.controls.Label;
    private var username_ti:mx.controls.TextInput;
    private var password_ti:mx.controls.TextInput;
    private var signIn_pb:mx.controls.Button;
    
    private var progress_pr:mx.controls.ProgressBar;
    
    private var done_lbl:mx.controls.Label;
    private var signOut_pb:mx.controls.Button;
    

    Ok, now let’s setup the getter/setters. They are merely public functions that set and get at our private variables. You’ll notice, however, I treat each variable a different way. Let’s talk about state first.

    // getter/setters
    // ---------------------------------------
    public function get state():String
    {
            return _state;
    }
    
    public function set state(str:String):Void
    {
            _state = str;
            draw();
    }
    

    This is your basic getter/setter. The getter returns the private’s value, and the setter sets it. The difference here is that since changing state actually changes the visual & graphical layout of the component, rather than call size, which just sizes your component, I call draw, which physically redraws component elements; in our case removing and attach components as necessary. The draw method calls size once it’s done.

    Next is username and password. They, however, have 2 entry points into how the values are set. The first, is outside access, and thus why we are using gettter/settters. If someone outside the component wants to set the username, they can via the setter, and this will trigger a refresh. However, components inside our component can also set the value. I don’t want components internally causing a refresh upon themselves, but I also don’t want them directly accessing the private either. There are a couple of ways of handling this. You can just have the component set the private, with the knowledge that at least it’s an internal class component doing so, so it’s not illegal in OOP necessarily. However, you’ve broken whatever internal protective access you may have had in place. Additionally, if you had specific component update stuff you wanted to happen just by running the setter, it will no longer get triggered since your no longer using the setter. Some methods actually have a 2nd or 3rd parameter to prevent the event from being triggered. The setSize method does this; you can pass in true for the 3rd parameter, and a redraw event will not get triggered. Finally, my way is to merely make an additional couple getter/setter methods that merely set the variable, but nothing else. If the setter needs to update the GUI, so be it, but if internal components just need to update the value, they have their route as well.

    public function get username():String
    {
            return getUsername();
    }
    
    public function set username(str:String):Void
    {
            setUsername(str);
            size();
    }
    
    private function setUsername(str:String):Void
    {
            _username = str;
    }
    
    private function getUsername(Void):String
    {
            return _username;
    }
    
    public function get password():String
    {
            return getPassword();
    }
    
    public function set password(str:String):Void
    {
            setPassword(str);
            size();
    }
    
    private function getPassword(Void):String
    {
            return _password;
    }
    
    private function setPassword(str:String):Void
    {
            _password = str;
    }
    
    

    Since we’re going to be using a mix-in class, EventDispatcher, I need to at least define his methods, as properties, so the class will assume it has them when trying to compile.

    public var addEventListener:Function;
    public var removeEventListener:Function;
    private var dispatchEvent:Function;
    
    

    Methods

    One unique feature of the framework is that your class’ init method is automatically called for you so there is no need to call an init method inside your class’ constructor like in the past. It is, however, good practice to at least define your constructor.

    function SignInView()
    {
    }
    

    Next, we define our init method that set’s up our class. The first thing you do is call your super class’s init method. I also initialize, only once, my class to have event broadcasting capabilities via EventDispatcher. One thing I found in testing is that the component doesn’t really look good when it’s too small, so I set a min width and height. These variables are already getter/setters in UIObject, so you don’t have to define them, just set them. If your component requires extra logic to calculate those sizes, feel free to overwrite the getter/setters with your own as most classes don’t really use them.

    I also need a default size for my component. One big change from Flash MX to Flash MX 2004 is that width and height are now merely getters to _width and _height. Those properties of a movie clip are a little too accurate. By that, strokes can can half-pixel widths to your component, mask’s even if they show only a small part are still added to the total size, and invisible content can do the same. With components that aren’t dynamic, this typically isn’t a problem, but a good Flash practice is to have nothing beyond “stop();” actions on the timeline, so that doesn’t help us. The deadPreview movie clip, something merely used to give a LivePreview a defined drawing rect, is the authortime content, but he won’t last long enough to be of much use, hence calling setSize. The deadPreview used to be removed automatically for you in Flash MX, but in Flash MX 2004, he’s not, so you can either make a base class of your own like I do, or just put the 2 lines of code in there to remove him. Finally, I ensure my setSize call has a true as the 3rd parameter so it doesn’t trigger a redraw since the component framework will call size for me anyway initially.

    public function init(Void):Void
    {
            super.init();
            
            if(!inited)
            {
                    inited = true;
                    mx.events.EventDispatcher.initialize(SignInView.prototype);
            }
            
            deadPreview_mc.swapDepths(0);
            deadPreview_mc.removeMovieClip();
            
            minWidth = 100;
            minHeight = 244;
            
            setSize(240, 240, true);
    }
    

    The next method is createChildren. Now, typically, this method is called first and you use it to lay out all the components and graphics in your component. However, since our’s is so dynamic because it’s state directly affects what it shows, I’ve chosen to use draw primarily for this purpose. The only component that actually stays throughout the entire life of the component is the label stating what this component is, so it is the only one I’ll create in this instance.

    private function createChildren(Void):Void
    {
            createClassObject(mx.controls.Label, "main_lbl", getNextHighestDepth());
            main_lbl.text = "Sign In";
            main_lbl.setStyle("fontWeight", "bold");
    }
    

    Next is draw. He’s the main hub of actually updating the visuals when the state changes. I first remove everything, and then based on state, attach what is appropriate, and initialize their properties as necessary. Finally, I call size to position everything.

    private function draw(Void):Void
    {
            username_lbl.removeMovieClip();
            password_lbl.removeMovieClip();
            username_ti.removeMovieClip();
            password_ti.removeMovieClip();
            signIn_pb.removeMovieClip();
            
            progress_pr.removeMovieClip();
            
            done_lbl.removeMovieClip();
            signOut_pb.removeMovieClip();
            
            if(state == "sign in")
            {
                    createClassObject(mx.controls.Label, "username_lbl", getNextHighestDepth());
                    username_lbl.text = "Username";
                    username_lbl.autoSize = "left";
                    
                    createClassObject(mx.controls.Label, "password_lbl", getNextHighestDepth());
                    password_lbl.text = "Password";
                    password_lbl.autoSize = "left";
                    
                    createClassObject(mx.controls.TextInput, "username_ti", getNextHighestDepth());
                    username_ti.addEventListener("change", this);
                    
                    createClassObject(mx.controls.TextInput, "password_ti", getNextHighestDepth());
                    password_ti.addEventListener("change", this);
                    
                    createClassObject(mx.controls.Button, "signIn_pb", getNextHighestDepth());
                    signIn_pb.addEventListener("click", this);
                    signIn_pb.label = "Sign In";
            }
            else if(state == "signing in")
            {
                    createClassObject(mx.controls.ProgressBar, "progress_pr", getNextHighestDepth());
                    progress_pr.indeterminate = true;
                    progress_pr.label = "Signing In...";
                    
            }
            else if(state == "signed in")
            {
                    createClassObject(mx.controls.Label, "done_lbl", getNextHighestDepth());
                    done_lbl.autoSize = "center";
                    done_lbl.text = "Signed In";
                    
                    createClassObject(mx.controls.Button, "signOut_pb", getNextHighestDepth());
                    signOut_pb.addEventListener("click", this);
                    signOut_pb.label = "Sign Out";
            }
            
            size();
    }
    
    

    Next is size. He is the one who positions everyone based on state. Size is where your component merely changes the size of your components based on a component width and height change, mainly from setSize. That way, your whole component doesn’t have to redraw, re-attach, and re-initialize things based on a setting of the size. I use a built in method called “drawRect” to have a simple background for the component.

    private function size(Void):Void
    {
            clear();
            lineStyle(2, 0x666666);
            beginFill(0xEEEEEE);
            drawRect(0, 0, width, height);
            endFill();
            
            main_lbl.move(10, 10);
            
            if(state == "sign in")
            {
                    username_lbl.move(main_lbl.x, main_lbl.y + main_lbl.height + 10);
                    
                    username_ti.move(username_lbl.x, username_lbl.y + username_lbl.height + 10);
                    username_ti.setSize(width - 20, 22);
                    username_ti.text = (username == null) ? "" : username;
                    
                    password_lbl.move(username_lbl.x, username_ti.y + username_ti.height + 10);
                    
                    password_ti.move(password_lbl.x, password_lbl.y + password_lbl.height + 10);
                    password_ti.setSize(width - 20, 22);
                    password_ti.text = (password == null) ? "" : password;
                    
                    signIn_pb.setSize(60, 22);
                    signIn_pb.move((width / 2) - (signIn_pb.width / 2), password_ti._y + password_ti.height + 10);
            }
            else if(state == "signing in")
            {
                    var w = width - 20;
                    var h = progress_pr.height;
                    // progress bar is not respecting the setSize width nor height...freak
                    progress_pr.setSize(w, h);
                    progress_pr.move((width / 2) - (w / 2), main_lbl.y + main_lbl.height + 10);
            }
            else if(state == "signed in")
            {
                    done_lbl.setSize(100, 22);
                    done_lbl.move((width / 2) - (done_lbl.width / 2), main_lbl.y + main_lbl.height + 10);
                    
                    signOut_pb.setSize(60, 22);
                    signOut_pb.move((width / 2) - (signOut_pb.width / 2), done_lbl._y + done_lbl.height + 10);
            }
    }
    

    Next, I extend the setSize function to incorporate my minWidth and minHeight variables.

    public function setSize(w:Number, h:Number, noEvent:Boolean):Void
    {
            var w = Math.max(w, minWidth);
            var h = Math.max(h, minHeight);
            super.setSize(w, h, noEvent);
    }
    
    

    Events

    Now for the events. My form has 2 click events that it responds to. First, when the user clicks the sign in button to sign in, and when they click the sign out button to sign out.

    // Events
    private function click(event_obj:Object):Void
    {
            if(event_obj.target == signIn_pb)
            {
                    var u = username_ti.text;
                    var p = password_ti.text;
                    dispatchEvent({type: "signIn",
                                          target: this,
                                          username: username_ti.text,
                                          password: password_ti.text});
            }
            else if(event_obj.target == signOut_pb)
            {
                    dispatchEvent({type: "signOut", target: this});
            }
    }
    
    

    Lastly, I need to make sure when the user changes the username or password in the input text fields, it updates the variables in the class, but does not trigger to setter’s redraw function. In the draw method, I registered for change events, so when text in the fields is changed, it triggers an event. This event checks to see which field it was that changed, and uses the simple setter functions to merely update the value, and generates events in case someone needs to know if the values have changed.

    private function change(event_obj:Object):Void
    {
            var t = event_obj.target;
            var str = t.text;
            switch(t)
            {
                    case username_ti:
                    setUsername(str);
                    dispatchEvent({type: "usernameChanged", target: this, username: str});
                    break;
                    case password_ti:
                    setPassword(str);
                    dispatchEvent({type: "passwordChanged", target: this, password: str});
                    break;
            }
    }
    
    

    Class in Total

    And our class, in total, looks like so:

    /*
    SignInView
    
    Sign In form; used for signing into things.
    Provides a GUI to generate events + values.
    
    */
    
    class SignInView extends mx.core.UIComponent
    {
            // Variables
            
            // standard mx 2004 framework variables
            static var symbolName:String = "SignInView";
            static var symbolOwner:Object = SignInView;
            public var className:String = "SignInView";
            
            // dim them there vars boi!
            static private var inited:Boolean = false;
            private var _state:String = "sign in";
            private var _username:String;
            private var _password:String;
            
            // controls
            private var deadPreview_mc:MovieClip;
            
            private var main_lbl:mx.controls.Label;
            private var username_lbl:mx.controls.Label;
            private var password_lbl:mx.controls.Label;
            private var username_ti:mx.controls.TextInput;
            private var password_ti:mx.controls.TextInput;
            private var signIn_pb:mx.controls.Button;
            
            private var progress_pr:mx.controls.ProgressBar;
            
            private var done_lbl:mx.controls.Label;
            private var signOut_pb:mx.controls.Button;
            
            // getter/setters
            // --------------------------------------------------------------------------------------
            public function get state():String
            {
                    return _state;
            }
            
            public function set state(str:String):Void
            {
                    _state = str;
                    draw();
            }
            
            public function get username():String
            {
                    return getUsername();
            }
            
            public function set username(str:String):Void
            {
                    setUsername(str);
                    size();
            }
            
            private function setUsername(str:String):Void
            {
                    _username = str;
            }
            
            private function getUsername(Void):String
            {
                    return _username;
            }
            
            public function get password():String
            {
                    return getPassword();
            }
            
            public function set password(str:String):Void
            {
                    setPassword(str);
                    size();
            }
            
            private function getPassword(Void):String
            {
                    return _password;
            }
            
            private function setPassword(str:String):Void
            {
                    _password = str;
            }
            
            // --------------------------------------------------------------------------------------
            
            public var addEventListener:Function;
            public var removeEventListener:Function;
            private var dispatchEvent:Function;
            
            function SignInView()
            {
            }
            
            public function init(Void):Void
            {
                    super.init();
                    
                    if(!inited)
                    {
                            inited = true;
                            mx.events.EventDispatcher.initialize(SignInView.prototype);
                    }
                    
                    deadPreview_mc.swapDepths(0);
                    deadPreview_mc.removeMovieClip();
                    
                    minWidth = 100;
                    minHeight = 244;
                    
                    setSize(240, 240, true);
            }
            
            private function createChildren(Void):Void
            {
                    createClassObject(mx.controls.Label, "main_lbl", getNextHighestDepth());
                    main_lbl.text = "Sign In";
                    main_lbl.setStyle("fontWeight", "bold");
            }
            
            private function draw(Void):Void
            {
                    username_lbl.removeMovieClip();
                    password_lbl.removeMovieClip();
                    username_ti.removeMovieClip();
                    password_ti.removeMovieClip();
                    signIn_pb.removeMovieClip();
                    
                    progress_pr.removeMovieClip();
                    
                    done_lbl.removeMovieClip();
                    signOut_pb.removeMovieClip();
                    
                    if(state == "sign in")
                    {
                            createClassObject(mx.controls.Label, "username_lbl", getNextHighestDepth());
                            username_lbl.text = "Username";
                            username_lbl.autoSize = "left";
                            
                            createClassObject(mx.controls.Label, "password_lbl", getNextHighestDepth());
                            password_lbl.text = "Password";
                            password_lbl.autoSize = "left";
                            
                            createClassObject(mx.controls.TextInput, "username_ti", getNextHighestDepth());
                            username_ti.addEventListener("change", this);
                            
                            createClassObject(mx.controls.TextInput, "password_ti", getNextHighestDepth());
                            password_ti.addEventListener("change", this);
                            
                            createClassObject(mx.controls.Button, "signIn_pb", getNextHighestDepth());
                            signIn_pb.addEventListener("click", this);
                            signIn_pb.label = "Sign In";
                    }
                    else if(state == "signing in")
                    {
                            createClassObject(mx.controls.ProgressBar, "progress_pr", getNextHighestDepth());
                            progress_pr.indeterminate = true;
                            progress_pr.label = "Signing In...";
                            
                    }
                    else if(state == "signed in")
                    {
                            createClassObject(mx.controls.Label, "done_lbl", getNextHighestDepth()); 
                            done_lbl.autoSize = "center";
                            done_lbl.text = "Signed In";
                            
                            createClassObject(mx.controls.Button, "signOut_pb", getNextHighestDepth());
                            signOut_pb.addEventListener("click", this);
                            signOut_pb.label = "Sign Out";
                    }
                    
                    size();
            }
            
            private function size(Void):Void
            {
                    clear();
                    lineStyle(2, 0x666666);
                    beginFill(0xEEEEEE);
                    drawRect(0, 0, width, height);
                    endFill();
                    
                    main_lbl.move(10, 10);
                    
                    if(state == "sign in")
                    {
                            username_lbl.move(main_lbl.x, main_lbl.y + main_lbl.height + 10);
                            
                            username_ti.move(username_lbl.x, username_lbl.y + username_lbl.height + 10);
                            username_ti.setSize(width - 20, 22);
                            username_ti.text = (username == null) ? "" : username;
                            
                            password_lbl.move(username_lbl.x, username_ti.y + username_ti.height + 10);
                            
                            password_ti.move(password_lbl.x, password_lbl.y + password_lbl.height + 10);
                            password_ti.setSize(width - 20, 22);
                            password_ti.text = (password == null) ? "" : password;
                            
                            signIn_pb.setSize(60, 22);
                            signIn_pb.move((width / 2) - (signIn_pb.width / 2), password_ti._y + password_ti.height + 10);
                    }
                    else if(state == "signing in")
                    {
                            var w = width - 20;
                            var h = progress_pr.height;
                            // progress bar is not respecting the setSize width nor height...freak
                            progress_pr.setSize(w, h);
                            progress_pr.move((width / 2) - (w / 2), main_lbl.y + main_lbl.height + 10);
                    }
                    else if(state == "signed in")
                    {
                            done_lbl.setSize(100, 22);
                            done_lbl.move((width / 2) - (done_lbl.width / 2), main_lbl.y + main_lbl.height + 10);
                            
                            signOut_pb.setSize(60, 22);
                            signOut_pb.move((width / 2) - (signOut_pb.width / 2), done_lbl._y + done_lbl.height + 10);
                    }
            }
            
            public function setSize(w:Number, h:Number, noEvent:Boolean):Void
            {
                    var w = Math.max(w, minWidth);
                    var h = Math.max(h, minHeight);
                    super.setSize(w, h, noEvent);
            }
            
            // Events
            private function click(event_obj:Object):Void
            {
                    if(event_obj.target == signIn_pb)
                    {
                            var u = username_ti.text;
                            var p = password_ti.text;
                            dispatchEvent({type: "signIn",
                                                  target: this,
                                                  username: username_ti.text,
                                                  password: password_ti.text});
                    }
                    else if(event_obj.target == signOut_pb)
                    {
                            dispatchEvent({type: "signOut", target: this});
                    }
            }
            
            private function change(event_obj:Object):Void
            {
                    var t = event_obj.target;
                    var str = t.text;
                    switch(t)
                    {
                            case username_ti:
                            setUsername(str);
                            dispatchEvent({type: "usernameChanged", target: this, username: str});
                            break;
                            case password_ti:
                            setPassword(str);
                            dispatchEvent({type: "passwordChanged", target: this, password: str});
                            break;
                    }
            }
    }
    

    Lastly, we want our LivePreview to redraw correctly, so we add a setSize every time the component is resized.

    // LivePreview
    function onUpdate()
    {
            setSize(Stage.width, Stage.height);
    }
    

    Authortime Setup

    The last thing to do is package her up into an SWC for faster compile time, portability, and ease of use. Do the following:

    – create a movie clip and call it “SignInView”
    – name the layer “actions” and put a stop(); action on frame 1
    – make a new layer called “dead preview”
    – draw a 240 by 240 gray square
    – select the square, and convert to a movie clip, and call it dead preview
    – give it an instance name of “deadPreview_mc”
    – make a new layer called “assets”
    – make a blank keyframe on frame 2
    – select the frame, and drag the following components to the stage (doesn’t matter where)
    + Label
    + Button
    + ProgressBar
    + TextInput
    – right click on the movie clip “SignInView” and select “Linkage…”
    – make its Indentifer “SignInView”
    – make its AS 2.0 Class “SignInView”
    – click OK
    – right click on the movie clip symbol “SignInView” in the library again, and select “Component Definition…”
    – First, type “SignInView” in the AS 2.0 Class field. Second, check the “Display in Components Panel” check box, and type in “SignInView” and click OK
    – finally, right click on the symbol a 3rd time, and select “Export SWC File…”
    – Find your components directory. On PC WinXP, it’s:

    C:\Documents and Settings\[user]\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Components

    Once you find the directory, hit save.

    To test:

    – make a new FLA
    – open the Components panel, and in the drop down menu it has on the top right of it, select “Reload”
    – find your SignInView component, and drop on stage
    – you can either test from here, or use attachMovie. You can addEventListener for your events, etc.

    Conclusion

    I hope that helps build your first AS2, Flash MX 2004 framework based component and you learned how to make them yourself!

    Tutorial Source

  • Blessing & Curse

    The wet tears are clouding my vision. I furiously eat over-peppered, 5 hour old franch fries combined with the sweetness of a 180 calorie Hawaiin Punch (canned in Florida), hoping the odd combination will stem the flow of the horrible reaction I get from petting that damn cat. Instead, my sinus’ release, and my breathing becomes ragged as I constantly inhale to stem the flow.

    …the whole time I’m frustrated. Being a geek, knowing shiot you can capitalize on in a year, still leaves you with little to do right now… assuming you’ve already capitalized on what you thought of last year, or are still working for another 6 months. Either way, being in the mix of tech things allows you a futurist’s ability to know what opportunity tomorrow holds.

    I’m a man of action… at least, I keep telling myself that. And yet, there are so many things “coming down the pipe” that I’m afraid that my complacency while friggin’ waiting will cause me to become a lump in the middle of the road when the next waves of change come, crushing me into a sludge, which operating at the same speed attempting to reconvene my mass in an attempt to catch up to the current technology curve that changed in a blink of an eye. I get the same feeling everytime a new version of Flash is released. I wonder how the .NET people feel… or is that VB people. Geez, does that mean Flash people will start changing tech-species too?

    I look at how service based architectures, inside of companies, are changing how things work. At this point, my experience has been with online stuff, but it’s funny… almost horrifyingly sobering to see their expectant attitudes towards occasionally connected content requiring to have some form of offline content… something, anything beyond a 404. Oh yeah… duh… I think to myself. I’ve been in the whole occasionally connected “thing” for awhile now. Well, if I have, I’ve taken little, tangible lessons away from whatever dellusional escapade I went on. Maybe I’m being too harsh. It is my first occasionaly connected project, but you would think I’d would of already had practice that would pay off. Guess not.

    Still, I see where Macromedia is going with Central positioning, not placing. With all the made-more-visual trip ups of Avalon, it’s nice to have the extra time for better digging in. I guess, most of us, feel that for the here and now, are expectations are pretty high. We’ve raced so fast to the top of the hill, and kicked mad 180’s off of it, and are like, so… uh… Macromedia, gonna make a bigger hill? But instead, they go off and build shock-absorbers, market knee pads, chisel their back-ho’s teeth. (They invest in a new way to develop Flash form-based applications, build other technologies based on the Flash player, and enhance the current version of Flash).

    I know that Central’s “time” isn’t now. Flash’s is, but Central’s isn’t. Director had his, and Authorware before that. For a geek, having your favorite “prog” have it’s time is a big deal for stroking your ego. My problem is… my attention span is about the length of a sneeze (yes, 2 of them), so my green pasture syndrome kicks in, and I wonder what’s next. I can seen Central as the next big thing, but my current job puts a monkey wrench in things. I’m building my own version, but way more specialized to my needs, and that is: our app is customized to the current technological goals. Less techno-bs, our Flash GUI is based around our web-services, and vice-versa. So, there are some Central elements, but nothing as large as the scope as Central in trying a plethora of needs. However, the repeating pattern I’m seeing is companies use service based architectures internally.

    …and that is not what Central is based on. I hear that in a year, most business’ will be based on service based architectures (CNET/ZDNET, other biz-tech things per Erik). A fuggin year!?

    As far as I’m concerned, Centrals main capacity in terms of value as it applies to me is a nice platform for building applications around web services. With some new tech rumblings coming down the pipe, I can see how Central’s technical challenges are being annihilated before it even breaks out of the infancy of a v1 app… an awesome stride.

    But wtf is public AND useful? I can think of a couple… if I sat here for about 5 minutes, maybe a few… I’m sure people could commit even more over time perusing Central MX’s archives.

    I shouldn’t have to think, though. There should be 50 million services making you drool and lament because of lack of time, lack of energy, lack of a clone. I don’t want to wait a year while this stuff is so bloody commonplace that it’s a matter of finding the time and place to plan out your attack, and execute within a reasonable couple week timeframe.

    Securing a foothold, fortifying positions, ensuring future victories… don’t fight the battle unless you know you can win. Sun Tzu? Whatever, close enough. I agree with the decision.

    I don’t want to wait a year.

  • Drinking Tip

    When doing shots, don’t keep your gum in your mouth. First, it absorbs the salt, and becomes pretty nasty to chew. Later, it retains Tequila flavor when you least want it. bleh, poo, blaaaahh….