Posts Tagged development

Software List For New MacBook Pro Laptop

My partner and I just received our new MBPs and we’re pretty pumped about them — 17in, 8GB Ram, stateless HDs — very speedy. Startup is like 3 seconds, and I’m not kidding.

As we all know, getting a new computer is awesome, but it’s also a double edged sword…as my other partner Joe noted: “The worst thing about getting a new laptop is…well…getting a new laptop.” Sure the thing flies and all, but man there’s a good amount of hrs getting it ready for primetime development…think of all the little tools you’ve collected to make your laptop rock…

My partner and I have started to compile a live list of dev tools, goodies, IDEs,and whatevs we use on a regular basis and we thought we’d share — if you have others, please add to this list:

Basic Software & IDEs

Connectivity & Tools

IM & Social

Post to Twitter Tweet This Post

, , , , , , ,

1 Comment

WASI AIR Logging Console v0.1.3.0 & Logging Util Tools UPDATE

Introduction

While there are several updates and changes I made to the underlying implementation, the overall functionality remains the same so please read my original post WASI AIR Logging Console & Logging Util Tools for a general overview.

See It In Action!

  • Logging Test Application — Small test app that uses the logging framework and spits out log statements every second. I have a link to the console below for quick testing.
  • Logging Console Test Application — Allows you to see the Console in action when you run it and the Logging Test Application at the same time.

Assets

Updates & Changes

  • The name of the SWC has changed from WASILogConsoleLibrary.swc to  WASILoggingLibrary.swc.
  • The LocalConnection Logger is no longer a wrapper class, but now an actual logging target called LocalConnectionTarget.
  • Added a Firebug (FireFox extension) Logging Target that outputs the same log message as the LocalConnectionTarget.
  • Created a base WASILoggingTarget with several, common helper methods for creating targets.

Since I mentioned that some of the actual impl changed a bit I’m going to show some code illustrating the changes.

Setting Up in Main App :: Example Code

The difference between this one and last version I shared has to do with the use of targets as opposed to a wrapper class. I also put all of my logging specifics into a helper class for the Test App called Logging — I could’ve just as easily put this all into the main app file, but I decided to move it into a new class for better organization.

<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	creationComplete="this.init()">

	<mx:Script>
		<![CDATA[
			import com.webappsolution.controller.FilterControllerTest;
			import com.webappsolution.delegate.FilterDelegateTest;
			import com.webappsolution.logging.Logging;

			private static var loggerSetup:* = Logging.setupLogging();

			private function init():void
			{
				var filterDelegateTest:FilterDelegateTest = new FilterDelegateTest();
				var filterControllerTest:FilterControllerTest = new FilterControllerTest();
			}

		]]>
	</mx:Script>

</mx:Application>

The line to make note of is

private static var loggerSetup:* = Logging.setupLogging();

which calls my helper Logging class that actually creates the logging targets, levels, and filters.

Helper Logger Class (Not Required)

/**
 * Web App Solution Confidential Information
 * Copyright 2010, Web App Solution, Inc.
 *
 * @date Apr 26, 2010
 */
package com.webappsolution.logging
{
	import com.webappsolution.logging.LoggingUtils;
	import com.webappsolution.logging.target.FirebugTarget;
	import com.webappsolution.logging.target.LocalConnectionTarget;

	import mx.logging.LogEventLevel;
	import mx.logging.targets.TraceTarget;

	public class Logging
	{
		/**
		 * Create your list of targets here.
		 */
		public static function setupLogging():void
		{
			var level:int = LogEventLevel.ALL;
			var filters:Array = createFilters();
			var targets:Array = createTargets();

			// set up logging for the application
			LoggingUtils.setupLogging(level, filters, targets);
		}

		/**
		 * Create your list of compile-time filters here.
		 */
		public static function createFilters():Array
		{
			var filters:Array = ["*"];

			return filters;
		}

		/**
		 * Create your list of targets here.
		 */
		public static function createTargets():Array
		{
			var traceTarget:TraceTarget;
			var firebugTarget:FirebugTarget;
			var lcTarget:LocalConnectionTarget;
			var targets:Array;

			traceTarget = new TraceTarget();
			traceTarget.level = LogEventLevel.ALL;
			traceTarget.includeDate = true;
			traceTarget.includeTime = true;
			traceTarget.includeCategory = true;
			traceTarget.includeLevel = true;

			firebugTarget = new FirebugTarget();
			firebugTarget.level = LogEventLevel.ALL;
			firebugTarget.includeDate = true;
			firebugTarget.includeTime = true;
			firebugTarget.includeCategory = true;
			firebugTarget.includeLevel = true;

			lcTarget = new LocalConnectionTarget();
			lcTarget.level = LogEventLevel.ALL;
			lcTarget.includeDate = true;
			lcTarget.includeTime = true;
			lcTarget.includeCategory = true;
			lcTarget.includeLevel = true;

			// create a list of targets
			targets = [traceTarget, firebugTarget, lcTarget];

			return targets;
		}
	}
}

Here I’m just creating the specific logging targets for my application:

  • TraceTarget — ouputs to your Flex IDE’s console
  • FirebugTarget — ouputs to your FireFox’s Firebug plugin’s console
  • LocalConnectionTarget — ouputs to WASI AIR Logging Console

The other change to make note of is the actual definition of the logger in each class you’re implementing logging. Let’s take a quick look here.

New Logger Instantiation

The OLD way was like this:

private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);;

The NEW way was like this:

private static const logger:ILogger = Log.getLogger(LoggingUtils.getFullyQualifiedClassName(FilterControllerTest));

The new design decouples the logging from our custom wrapper class LocalConnectionLog and now uses the out of the box mx.logging.Log to create a category for each logger instantiation. Notice the use of LoggingUtils.getFullyQualifiedClassName(clazz:Class):String to get the fully qualified string name for the object; one can also just pass in a string category of their choice instead of using the class name.

Post to Twitter Tweet This Post

, , , , ,

1 Comment

WASI AIR Logging Console & Logging Util Tools

Introduction

About a year ago I revisited an old friend — a simple SWF with a TextArea that outputs log messages from another SWF via the LocalConnection. I wrote it for Xcelsius since it’s a black box when you’re running custom Flex Connectors and UI Components and I needed a way to not only see the errors in the Flash Debug Player, but get more info…thus, the reemergence of my old-school Flash Logger that I originally wrote in Flash 5. You can read more about it here.

Recently, however, I realized that this simple tool was actually much more valuable than I had remembered, as I’ve had several clients that have had some difficulties logging in or running the app as expected for the first time…you know the schpeel…it’s all hooked up and ready to go and you’ve been logging into the app for months from your dev machine and it works great…but then suddenly the client tries to run it and nada…and since they don’t have a Flash/Flex Builder IDE all ready to rock with debugging, you might be stuck wondering why they can’t get in…ah-ha, just fire up the good-ole WASI Logging Console and suddenly your mystery is solved.

See It In Action!

  • Logging Test Application — Small test app that uses the logging framework and spits out log statements every second. I have a link to the console below for quick testing.
  • Logging Console Test Application — Allows you to see the Console in action when you run it and the Logging Test Application at the same time.

Assets

Quick Explanation…How Does it Work?

The WASI LocalConnection (LC) Logger  consists of 2 parts:

  1. A SWF with a LC that receives messages — ie, logs statements — and displays them in a simple Flex List.
  2. A Logging Framework that provides basic logging methods you’d expect (debug, info, warn, error, and fatal) with a LC sender that pushes these messages to the receiving SWF.

Logger Basics

The WASI Logger outputs log statements to both the Flex/Flash builder IDE and the WASI AIR Logging Console with the same-old, friendly Flex logging sytax you;d expect. Here’s some sample code using it in an application:

logger.debug("entering myMethod"); // log statement in myMethod

And here’s what the output looks like to both the IDE’s console and the AIR Console:

4/12/2010 07:03:57 PM [DEBUG] com.webappsolution.controller.FilterControllerTest myMethod // output to the Flex IDE console

Compile-Time & Run-Time Logging Configuration

The Logging Framework also provides the ability to set up logging configuration for log levels and log filters at both compile-time and run-time. To configure logging for Compile time, simply add the following import and variable to your main application’s script block:

import com.webappsolution.logging.LoggingUtils;
private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

In the previous example, the logger is set up with log level of All and sets the filters to include all classes (even the Flex SDKs basic messaging classes for HTTPService so you might want to consider using a package level that’s appropriate to your application.)

To configure logging for Run-time, simply add the following query string to your application’s debug configuration or URL in the browser window:

http://wasi.com/app.swf?logLevel=error&logFilters=com.webappsolution.controller.*,com.webappsolution.delegate.*

Note the 2 parameters in bold; the following depicts their use and possible values:

  • logLevel — The desired log level for logging with the following values (must be in lowercase):
    • debug
    • info
    • warn
    • error
    • fatal
  • logFilters — The desired package and/or class names you’d like to see in the logger. Examples include fully qualified class names or packages with asterisks at the end.
    • Class; eg com.webappsolution.controller.MyController — Will only show log statements for the class MyController.
    • Packages; eg com.webappsolution.controller.* – Will show the log statements for all the classes in the package “com.webappsolution.controller”

You can apply multiple filters in the url by comma separating them: com.webappsolution.controller.*,com.webappsolution.delegate.*,com. webappsolution.MyClass

Using Run-time configs will override whatever was specified in the Compile-time configs.

NOTE: You must run the application from a web server in order for runtime log configs to work since Flash/Flex Builder throws an error when you try to create debug configurations with a query string at the end (again unless running from a web server).

NOTE: applying log levels and filters only effect the log statements in the IDE — all log statements are sent to the WASI AIR Logging Console as it has it’s own set of tools to do the same filtering.

WASI AIR Logging Console Features - Top Tool Bar

Since the Console receives all the logging messages, we’ll review its set of tools that help developers achieve the same functionality as aforementioned.

Log Level ComboBox — Contains a list of all log levels and allows developers to filter the list of log messages in the console by selecting these levels.

Log Filter AutoComplete Field — Allows developers to search for classes and packages to filter the list by; the list of possible filters is automatically generated for the developer at runtime once the console starts receiving messages and sorts them by alphabetical order. Smply start tpying in the full qualified name of a class or package and you’ll be presented with all matches.

To the right of the Log Filter AutoComplete Field is a helper ComboBox that allows the developer to sort the list of filters by class name, packages, or both — this is incredibly useful if you are logging to of classes. You can delete and/or remove filters by backspace the selected item in the AutoComplete field or clicking on the “Clear Filters” button.

NOTE: You can apply both log level and log filters to the list at the same time in any order.

Right-click — Developers can right-click on an item in the list and filter directly by selecting “Filter by Item” in the context menu. Coming soon — copy the individual log message with right-click.

WASI AIR Logging Console Features - Bottom Tool Bar

Clear Log Button — Simply click this to clear the entire log list.

Copy to Clipboard Button — Clicking this copies the entire list of log messages to your clipboard for easy cut and paste.

Auto Scroll CheckBox — Selecting the checkbox forces the list of log messages to scroll automatically to the bottom o the list. This can be useful if you’re watching real-time messages with logs.

Pretty Colors CheckBox — Selecting the checkbox color codes the log levels in the log list.

What it Does NOT

  • Can’t currently accept log messages over 40k — this can easily happen if you’re trying to log a large amount of data like, XML. I’ll push this out shortly by splitting up the chunks I’m sending across the wire to be < 40k.
  • Can’t run more than one of these suckers at a time (since the LC relies on a unique ID). Could allow the developer to enter in a unique ID for each version of the console and app, but I don’t think this is necessary at the moment.
  • Can’t enter multiple filters. This wouldn’t be too hard and is scheduled to come out soon.
  • No AIR badge…I’m being lazy right now and wanted to get the bare bones out for some quick feedback.
  • Not currently on Google Code but will be by EOW as an open source project.

Getting Started

This thing is pretty simple really and requires very little setup or modification to your code:

  1. Download the WASILogConsoleLibrary.swc and drop it into the libs folder of your project.
  2. In your project add the following, imports:
    1. import com.webappsolution.logging.LoggingUtils;
    2. import mx.logging.LogEventLevel;
  3. In your main application file, add the logging setup: private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);
  4. In classes you want to log, create the following:
    1. import com.webappsolution.logging.LocalConnectionLog;
    2. import mx.logging.ILogger;
    3. private static const logger:ILogger = LocalConnectionLog.getLogger(FilterDelegateTest);
    4. Call some log methods like:
      1. logger.debug(”we are logging”);
  5. Download the WASI Logger Air Console (WASILogConsoleAIR.air).
  6. Install the AIR application, run it, and then run your project that you just added logging to.

Setting Up in Main App :: Example Code

Again, the key thing to note here is the line where we set up the logger with LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	creationComplete="this.init()">

	<mx:Script>
		<![CDATA[
			import com.webappsolution.controller.FilterControllerTest;
			import com.webappsolution.delegate.FilterDelegateTest;
			import com.webappsolution.logging.LoggingUtils;

			import mx.logging.LogEventLevel;

			private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

			private function init():void
			{
				var filterDelegateTest:FilterDelegateTest = new FilterDelegateTest();
				var filterControllerTest:FilterControllerTest = new FilterControllerTest();
			}

			protected function button1_clickHandler(event:MouseEvent):void
			{
				var urlRequest:URLRequest = new URLRequest("http://www.webappsolution.com/air/wasi-logging-console/WASILogConsole.html");
				navigateToURL(urlRequest, "_blank");
			}

		]]>
	</mx:Script>

</mx:Application>

Using the Logger :: Example Code

Here you should note the instantiation of the logger as a static constant, private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);, as well as the use thereof with normal logging syntax, logger.debug("Constructor");.

Just pass in the name of the class you’re implementing logging in in the method LocalConnectionLog.getLogger(); and you’re good to go!

package com.webappsolution.controller
{
	import com.webappsolution.logging.LocalConnectionLog;

	import flash.events.TimerEvent;
	import flash.utils.Timer;

	import mx.logging.ILogger;

	public class FilterControllerTest
	{
		private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);

		public function FilterControllerTest()
		{
			// all log levels
			logger.debug("Constructor");
			logger.info("Constructor");
			logger.warn("Constructor");
			logger.error("Constructor");
			logger.fatal("Constructor");

			var timer:Timer = new Timer(5000);
			timer.addEventListener(TimerEvent.TIMER, onTimer);
			timer.start();
		}

		private function onTimer(e:TimerEvent):void
		{
			logger.debug("Constructor");
			logger.info("Constructor");
			logger.warn("Constructor");
			logger.error("Constructor");
			logger.fatal("Constructor");
		}
	}
}

NOTE: You can also fire up this Logging Test Application that allows you to play with various filters and log levels. It has a timer that spits out logs messages every second. Simply open this link up and then open up the WASI AIR Logging Console and you should see some messages start to populate the list.

Special Thanks

  • Abdul Qabiz — I used your com.abdulqabiz.utils.QueryString class to nab the parameters out of the query string.
  • Hillel Coren — I used your AutoComplete component to create the package and class filter AutoComplete Search Field.
  • Jesse Warden — We’ve been rapping back and forth about the fact that we both had one so we decided to combine some of the functionality between the two into this final tool.
  • Final Thoughts

    We’ll continue to update this enhancement requests and fix any bugs that y’all find, so let’em fly!

    Post to Twitter Tweet This Post

, , , , ,

5 Comments

ActionScript ArrayCollection Binding and Event Dispatching

We hear this one a lot, so I’m throwing it out there as a reminder for new and old Flex and ActionScript developers…

You’ll get some new collection data say from a remote service and you simply update your model level ArrayCollection (”AC”) property by doing:


myModel.myAC = responseFromRemoteService.myNewAC;

And low and behold the objects that are either binding to it or listening for the change event don’t do anything??? What? How the? But I debugged it and I saw that the new data was getting stored in my model-level AC…how come this thing isn’t working? Stoopid Flex…bleh.

Well, it’s simply because setting the original AC to a new AC doesn’t implicitly fire off any change events (which is the underlying implementation for data binding as well.) In order to make this function as expected, one simply needs to set the source property on an AC like so:


myModel.myAC.source = responseFromRemoteService.myNewAC.source;

The source property in an AC is not only the underlying Array for an AC, but also fires off that change event (I believe it’s the listChanged type event) that’s so important to binding and anyone else listening for changes on that AC. Truth be told, this is actually done in the underlying ListCollectionView class that an AC inherits from, but that’s just details.

Post to Twitter Tweet This Post

, , ,

4 Comments