August 20, 2014
Shortening a UUID / GUID in Swift
Jeff Atwood has a helpful article on the topic. Spoiler alert: his conclusion is that ASCII85 encoding can be used to compress a UUID down to 20 characters.
I implemented a base64 solution as an excuse to get better acquainted with Swift. The downside of using base64 is that it yields a 22 character compressed UUID. The upside is that a base64 implementation is built into Cocoa / Cocoa Touch. If you go with ASCII85 you'll have to roll your own implementation.
Please keep in mind that additional changes will need to be made to this solution if the intent is to pass the compressed UUID as part of a url string (eg. '+' and '/' characters, etc will need to be dealt with). Try it out for yourself in a Swift playground!
July 16, 2013
Flutter - An iOS Dashboard for Flurry Analytics
In my previous post I discussed analytics services in the context of mobile applications. In particular, I focused on Flurry Analytics and included a code sample demonstrating how to integrate this service into an iOS application.
So what's the next step? As either a mobile developer or marketing expert, you probably want the ability monitor the data collected by Flurry Analytics so you can identify and respond to trends. To meet this need, the Flurry website offers some powerful tools for visualizing how your applications are used. It breaks down numbers by country, version, device, operating system, new user, active user, session and more. This tool is comprehensive and allows users to generate a wide variety of custom reports. While it functions on mobile devices, the experience is far from optimized.
Being a developer with several Flurry-enabled apps in the App Store, I searched for a mobile-friendly solution. I wanted a native iOS app that would make it easy to check my usage statistics on the go. I didn't want the kitchen sink, just the analytics that were most relevant and the ability to visualize trends over time. Several options already existed in the App Store, but none were elegant or easy to use. Having recently completed the iOS & Mac Application Development Certification Program through the University of Washington I thought I'd try my hand at writing an app in objective-c to address this need.
Two and a half months later, I finished work on Flutter and pushed it to the App Store. Flutter is a dashboard for viewing Flurry Analytics on an iOS device. It focuses on primary usage statistics such as active users, new users and sessions. Custom events and multiple companies are also supported. Graphs and totals can be evaluated over some of the most common date ranges (Today, Yesterday, 1 Week, 1 Month, 6 Months, 1 Year). Flutter makes use of many powerful open source technologies including CorePlot, PKRevealController, ESNetworking and SVProgressHUD.
Learn more and download Flutter today! I'd love to hear your feedback.
July 10, 2013
Integrating Flurry Analytics into your iOS App
Flurry Analytics is a great service for keeping tabs on mobile app usage. They help over 100,000 companies monitor 300,000 apps that run on a variety of platforms (iOS, Android, Windows Phone and more). Best of all, it's free to use Flurry Analytics in your own apps.
My goal with this blog entry isn't to come across like a sales pitch. If you have a different analytics service that fits your needs, then more power to you. The point is to use something. Measuring unique users, sessions, new users and then visualizing these attributes over the course of time can reveal some powerful trends. The results might help you prioritize certain features or bug fixes. Maybe the information will help you plan the timing of your next sale. The data adds value as an anonymous source of feedback from your users that'll enable you to be an even better steward of your app.
So what do you need to do to get started with Flurry? First go to their website and sign up (or log in if you already have an account). In the "Applications" tab click the "Add a New Application" link and choose a platform. On the next page name the app and assign a category. You'll be greeted with a "Unique Application Key". Save this key for later and then click the button to download the SDK.
The code sample in this post will illustrate how to use the iOS SDK to integrate Flurry into your app. For MonoTouch (aka Xamarin.iOS) developers I'd advise taking a look at the FlurryAnalytics folder in the monotouch-bindings project. For other platforms, visit Flurry's "Getting Started" documentation.
Continuing with our objective-c / iOS example, add the Flurry lib (found in the SDK you downloaded) to your project. You will also need to link your project against the SystemConfiguration.framework. Now move into your app delegate code, replacing YOUR_API_KEY with the Application Key Flurry assigned to you:
#import "Flurry.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Flurry startSession:YOUR_API_KEY];
// Other code here...
}
This illustrates the bare minimum to get you started - very little code in exchange for some powerful analytics...
November 12, 2012
HealthGraphNet - A .NET Library for RunKeeper / HealthGraph
All of RunKeeper's data gets saved into an API known as the HealthGraph. I was starting to think up some interesting ways to use this information but was dismayed to discover that no one had written a .NET wrapper to integrate with the HealthGraph.
I wanted an easy to use, strongly-typed library, capable of communicating with this REST-based service both synchronously and asynchronously. So I started writing one, called it HealthGraphNet and put it here on GitHub.
The library is comprised of endpoint and model classes. Each endpoint represents a subject within the HealthGraph API (eg. Fitness Activities, Strength Training Activities, Nutrition, Weight, etc) while the models represent the data transfer to and from the service.
Sample use (taken straight out my documentation) in a synchronous situation might look something like this:
//Retrieve the OAuth2 access token.
var tm = new AccessTokenManager(CLIENT_ID, CLIENT_SECRET, REQUEST_URI);
tm.InitAccessToken(AUTH_CODE);
//Retrieve URIs for HealthGraph endpoints.
var userRequest = new UsersEndpoint(tm);
var user = userRequest.GetUser();
//Create a new 30 minute running activity
var newActivity = new FitnessActivitiesNewModel
{
Type = "Running",
StartTime = DateTime.Now,
Duration = 1800,
Notes = "Around the park."
};
var activitiesRequest = new FitnessActivitiesEndpoint(tm, user);
activitiesRequest.CreateActivity(newActivity);
The folks at RunKeeper were kind enough to list HealthGraphNet on their third-party library page. However, the easiest way to get started is to download the library via Nuget.
I've started to add MonoTouch support but this is still a work in progress. Please feel free to fork HealthGraphNet on GitHub. Pull requests are always welcome!
December 26, 2011
Delayed Download Prompt in ASP.NET MVC 3
How can this be accomplished using ASP.NET MVC 3? Let's make a small use case to illustrate our goal and then dig into some sample code:
- Load a "download" page.
- After a 2 second delay, prompt the user to save a PDF document. (In this case we do not want the browser to use any plugins to render the document).
$(function() {
$(window).bind('load', function() {
$("div.downloadProject").delay(2000).append(
'');
});
});
Be sure to include the following in our Html:
This code inserts an iframe into the DOM after a 2 second delay. This iframe is responsible for triggering the prompt to save the PDF. Unfortunately, I could not get this to work in ASP.NET MVC 3 by just referencing the path to the PDF in the source attribute of the iframe. To solve this, I added an action (and associated routing rules) to my Home controller for downloading the PDF as a FileContentResult.
public ActionResult DownloadPDF()
{
return File("~/FileToDownload.pdf", "application/pdf", "FileToDownload.pdf");
}
Including the third parameter in the "File" method adds the "Content-Disposition: attachment;" header - this forces the browser to handle the file using the save dialog prompt instead of any browser plugins.
To finish up, we'll revisit the jQuery code we started with and point the iframe to our new action instead of the direct path to the PDF.
$(function() {
$(window).bind('load', function() {
$("div.downloadProject").delay(2000).append(
'');
});
});
September 26, 2011
Slide to Unlock Control in MonoTouch
The goal was to derive from a UIImageView and trigger an Activate event when a specified slider image got within range of the right end of the control. I found this was fairly straightforward to implement using a pan gesture. Below is the class I came up with and the associated images that were used:
Image
Slider
public class UISlideToActivateImageView : UIImageView
{
#region Fields and Properties
public event EventHandler<EventArgs> Activate;
protected const float DEFAULT_ACTIVATION_RANGE = 20;
public float ActivationRange { get; set; }
public static Selector PanSelector
{
get
{
return new Selector("HandlePan");
}
}
private UIImageView _sliderView = null;
public UIImage Slider
{
get
{
return _sliderView.Image;
}
set
{
if (value != null)
{
if (_sliderView != null)
{
_sliderView.RemoveFromSuperview();
}
_sliderView = new UIImageView(
new RectangleF(new PointF(0, 0), value.Size));
_sliderView.Image = value;
AddSubview(_sliderView);
}
}
}
protected PointF InitialLocation { get; set; }
#endregion
#region Constructors
public UISlideToActivateImageView(PointF location, UIImage image)
: base(image)
{
ActivationRange = DEFAULT_ACTIVATION_RANGE;
Frame = new RectangleF(location, image.Size);
RegisterPanGesture();
}
public UISlideToActivateImageView(PointF location, UIImage image,
UIImage slider) : base(image)
{
ActivationRange = DEFAULT_ACTIVATION_RANGE;
Frame = new RectangleF(location, image.Size);
Slider = slider;
RegisterPanGesture();
}
#endregion
#region Events, Overrides and Delegates
[Export("HandlePan")]
public void HandlePan(UIPanGestureRecognizer panGesture)
{
const double EndedAnimationDuration = 0.2d;
PointF newLocation;
float adjX;
if (panGesture != null)
{
newLocation = panGesture.LocationInView(this);
switch (panGesture.State)
{
case UIGestureRecognizerState.Began:
//User first taps the slider
if ((newLocation.X <= (Frame.X + Slider.Size.Width))
&& (newLocation.X >= 0))
{
InitialLocation = newLocation;
}
break;
case UIGestureRecognizerState.Changed:
//Moved their finger - make slider follow horizontal movements
adjX = Frame.X + (newLocation.X - InitialLocation.X);
if ((InitialLocation != PointF.Empty) && (adjX >= 0)
&& (adjX <= (Frame.Width - Slider.Size.Width)))
{
UIView.Animate(0d, delegate() {
_sliderView.Frame = new RectangleF(new PointF(adjX, 0),
_sliderView.Frame.Size);
});
//If the Slider comes within ActivationRange of end of this
//control, fire the Activate event
if ((Activate != null)
&& (adjX >=
(Frame.Width - Slider.Size.Width - ActivationRange)))
{
//Moved the slider all the way across the image view
Activate(this, EventArgs.Empty);
}
}
break;
case UIGestureRecognizerState.Cancelled:
case UIGestureRecognizerState.Failed:
case UIGestureRecognizerState.Ended:
//Lifted up finger - return slider to original position
InitialLocation = PointF.Empty;
UIView.Animate(EndedAnimationDuration, delegate() {
_sliderView.Frame = new RectangleF(new PointF(0, 0),
_sliderView.Frame.Size);
});
break;
}
}
}
//Delegate for allowing the pan gesture recognizer to receive touch.
public class ReceiveTouchGestureRecognizerDelegate
: UIGestureRecognizerDelegate
{
public override bool ShouldReceiveTouch (
UIGestureRecognizer recognizer,
UITouch touch)
{
return true;
}
}
#endregion
#region Helper Methods
protected void RegisterPanGesture()
{
UserInteractionEnabled = true;
UIPanGestureRecognizer pan = new UIPanGestureRecognizer();
pan.AddTarget(this, PanSelector);
pan.Delegate = new ReceiveTouchGestureRecognizerDelegate();
AddGestureRecognizer(pan);
}
#endregion
}
To use this control it's simply a matter of assigning images (Image and Slider properties) and adding the class as a sub-view:
UISlideToActivateImageView slideToActivate =
new UISlideToActivateImageView(new PointF(31, 214),
UIImage.FromFile("slidetoactivate.png"), UIImage.FromFile("slider.png"));
slideToActivate.Activate += delegate(object sender, EventArgs e) {
UIAlertView alert = new UIAlertView("Congratulations!",
"You've engaged the UISlideToActivateImageView!", null, "Okay");
alert.Show();
};
View.AddSubview(slideToActivate);
August 30, 2011
Custom Animations for the UINavigationController in MonoTouch
In some areas of my UI I wanted more control over the animations in my navigation stack. This thread on Stack Overflow was a great place to start. I ported some of the Objective-C code I found to C# extension methods as follows:
//Allows a UINavigationController to push using a custom animation transition
public static void PushControllerWithTransition(this UINavigationController
target, UIViewController controllerToPush,
UIViewAnimationOptions transition)
{
UIView.Transition(target.View, 0.75d, transition, delegate() {
target.PushViewController(controllerToPush, false);
}, null);
}
//Allows a UINavigationController to pop a using a custom animation
public static void PopControllerWithTransition(this UINavigationController
target, UIViewAnimationOptions transition)
{
UIView.Transition(target.View, 0.75d, transition, delegate() {
target.PopViewControllerAnimated(false);
}, null);
}With these extensions in scope, moving between controllers with a flip animation is now as trivial as this://Pushing someController to the top of the stack NavigationController.PushControllerWithTransition(someController, UIViewAnimationOptions.TransitionFlipFromLeft); //Popping the current controller off the top of the stack NavigationController.PopControllerWithTransition( UIViewAnimationOptions.TransitionFlipFromRight);
August 19, 2011
Scheduling Local Notifications in MonoTouch
iOS 4 introduced local notifications, allowing apps to communicate brief text messages to users. In particular, a scheduled local notification can reach a user whether the app is running in the foreground, in the background or not running at all. While not as versatile as push notifications, scheduled local notifications can be helpful when an app needs to set-up predetermined alarms or reminders. Each app can have a total of 64 simultaneous scheduled local notifications (use them wisely so as to not annoy your users).
Below is an example of how to schedule a UILocalNotification using MonoTouch:
//Schedule one minute from the time of execution with no repeat
UILocalNotification notification = new UILocalNotification{
FireDate = DateTime.Now.AddMinutes(1),
TimeZone = NSTimeZone.LocalTimeZone,
AlertBody = "This is your scheduled local notification!",
RepeatInterval = 0
};
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
You might notice that scheduled local notifications are automatically displayed when the current date/time surpasses our FireDate and the app is in the background or not running at all. However, when the app is in the foreground local notifications are seemingly ignored. This is by design. If the app is in the foreground you are in charge of responding to scheduled local notifications by overriding the ReceivedLocalNotification method as follows:public override void ReceivedLocalNotification(UIApplication application,
UILocalNotification notification)
{
//Do something to respond to the scheduled local notification
UIAlertView alert = new UIAlertView("Notification Test",
notification.AlertBody, null, "Okay");
alert.Show();
}
February 26, 2011
Async Web Service Timout
To get around this issue I came up with a way to cancel an asynchronous web method request after a set period of time using a Timer object. Maybe it can help others in a similar predicament? Here's some sample code:
protected void GetServiceData()
{
//Indicates that network activity is going on
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
//Make the async call
using (MyService service = new MyService())
{
//Timer is set to go off one time after 15 seconds
Timer serviceTimer = new Timer(15000);
serviceTimer.AutoReset = false;
serviceTimer.Elapsed += delegate(object source, ElapsedEventArgs e) {
service.Abort();
throw new WebException("Timeout expired!");
};
serviceTimer.Enabled = true;
//Call the desired web method
service.WebMethodCompleted += ServiceWebMethodCompleted;
service.WebMethodAsync(serviceTimer);
}
}
//The async callback method
protected void ServiceWebMethodCompleted(object sender, WebMethodCompletedEventArgs e)
{
using (NSAutoreleasePool pool = new NSAutoreleasePool())
{
//Disable the timer that would abort this call with an exception
//if the call to this web method took too long
Timer serviceTimer = e.UserState as Timer;
if (serviceTimer != null)
{
serviceTimer.Enabled = false;
serviceTimer.Dispose();
}
if (e.Error != null)
{
if (e.Error is WebException)
{
//An error due to a timeout happened - handle it here
}
else
{
//Handle all other errors here
}
}
else
{
//Async call successful - do something cool with e.Result
}
//Indicates network activity has finished
this.InvokeOnMainThread(delegate() {
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
});
}
}
September 18, 2010
Geo Rally for the iPhone
I had a great time working on Geo Rally and was very thankful for MonoTouch. Coming from a .NET background I was a little overwhelmed at the prospect of learning a new language (Objective C) and iOS's multitude of supporting core APIs. MonoTouch eliminated one of these roadblocks so I could hit the ground running in a familiar language and branch out into unknown APIs as needed. In the end I believe this made me more productive. And now, coupled with MonoDroid and Windows Phone 7, there are even more options for code reuse (everything but the UI). It's a good time to be a C# developer!
July 10, 2010
iOS 4 and Map Kit Overlays with MonoTouch
Overlays are a special kind of annotation designed to represent an area on a map. iOS 4's Map Kit comes with some common shapes built in (rectangles, circles, polygons, etc). As I understand it it's also possible to make your own custom shapes.
Each overlay object holds data to represent the shape and has a corresponding view that tells the MKMapView's delegate how to draw the overlay. As an example here's how one might draw a circle overlay with a 100 meter radius around the Empire State Building. The code below shows how to do this in C# via MonoTouch.
CLLocationCoordinate2D empireStBld = new CLLocationCoordinate2D(40.748433, -73.985656);
double radiusInMeters = 100d;
MKCircle circle = MKCircle.Circle(empireStBld, radiusInMeters);
MapView.Delegate = new MapViewDelegate(circle);
MapView.AddOverlay(circle);
The only thing left is that the MapViewDelegate class needs to be set up to give an appropriate view for the overlay:
public class MapViewDelegate : MKMapViewDelegate
{
private MKCircle _circle = null;
private MKCircleView _circleView = null;
public MapViewDelegate(MKCircle circle)
{
_circle = circle;
}
public override MKOverlayView GetViewForOverlay(MKMapView mapView, NSObject overlay)
{
if ((_circle != null) && (_circleView == null))
{
_circleView = new MKCircleView(_circle);
_circleView.FillColor = UIColor.Cyan;
}
return _circleView;
}
}
October 14, 2009
Reading RGB Info from Images on the iPhone using MonoTouch
MonoTouch is an intriguing new software development kit from Novell. It utilizes the open source Mono project to allow developers to write code in C# that can then be statically compiled into native iPhone applications and deployed to devices or even to the App Store. A free evaluation version is available if the product interests you. I downloaded the evaluation version and decided to take this new development kit for a spin by using it to read RGB color information from all pixels in an image saved on the device. I ended up creating a CGBitmapContext to do this and then marshaling the results into a byte array. Please see the code below for more details:
//_selectedImage refers to the UIImage object of interest
int width = _selectedImage.CGImage.Width;
int height = _selectedImage.CGImage.Height;
//4 color settings for every pixel (RGBA)
int pixelDataCount = width * height * 4;
IntPtr data = Marshal.AllocHGlobal(pixelDataCount);
int bitsPerComponent = 8;
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
//Draw image to an RGB bitmap context
CGBitmapContext imgContext = new CGBitmapContext(data,
width, height, bitsPerComponent, bytesPerRow,
CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedLast);
imgContext.DrawImage(new RectangleF(0.0F, 0.0F, width, height),
_selectedImage.CGImage);
byte[] pixelData = new byte[pixelDataCount];
Marshal.Copy(data, pixelData, 0, pixelDataCount);
//Milk the color settings for each pixel in the image
int red;
int green;
int blue;
int currentPixelIndex = 0;
for (int countHeight = 0; countHeight < height; countHeight++)
{
for (int countWidth = 0; countWidth < width; countWidth++)
{
red = pixelData[currentPixelIndex];
currentPixelIndex++;
green = pixelData[currentPixelIndex];
currentPixelIndex++;
blue = pixelData[currentPixelIndex];
currentPixelIndex++;
//Currently ignoring the alpha byte
currentPixelIndex++;
//Probably will want to Cache RGB values here for later use
}
}
September 26, 2008
Closures in PHP 5.3
According to object-oriented programming expert Martin Fowler, closures are defined as a block of code that can be passed to a function. However, delegates (C#), anonymous classes (Java) and function pointers (C) don't quite qualify because the following also needs to be true:
- Closures need to be able to refer to variables already present in scope at the time they're defined.
- Closures shouldn't require complex syntax (I personally think this point is a tad subjective).
PHP's upcoming syntax for closures is shaping up to be comparable to the C# 2.0 implementation. In the .NET world closures first arrived as anonymous methods in C# 2.0 (these were later simplified into lambda expressions in C# 3.0).
For comparison's sake C# anonymous methods look something like this:
/* Returns true if tOne and tTwo are both evenlyWhen released, a comparable implementation in PHP 5.3 will probably look something like the following:
divisible by the denominator (denom) */
public bool EvenlyDivisible(int denom, int tOne, int tTwo)
{
//Define the closure
PredicateevenlyDivisible = delegate(int testNum)
{
//Note that denom is defined outside closure scope
if ((testNum % denom) == 0)
{
return true;
}
else
{
return false;
}
};
//Use the closure as necessary
if (evenlyDivisible(tOne) && (evenlyDivisible(tTwo)))
{
return true;
}
else
{
return false;
}
}
/* Returns true if $tOne and $tTwo are both evenlyFor additional information please check out the closure proposal on php.net.
divisible by the denominator ($denom) */
function EvenlyDivisible($denom, $tOne, $tTwo)
{
$evenlyDivisible = function ($testNum) use ($denom) {
//Note that $denom is defined outside closure scope
if (($testNum % $denom) == 0)
{
return true;
}
else
{
return false;
}
};
//Use the closure as necessary
if ($evenlyDivisible($tOne) && ($evenlyDivisible($tTwo)))
{
return true;
}
else
{
return false;
}
}
August 22, 2008
The ref and out Keywords in C#
protected void Sample()Note that the variable x is not changed by the Increment method. In most cases this behavior is desired. However, there are occasions when we may want to persist changes to a value type parameter beyond the scope of the method. This is where the ref and out keywords come into play. Here's our sample again but with the ref keyword used in the Increment method:
{
int x = 5;
//Writes 5 to the console
Console.WriteLine(x.ToString());
//Send a copy of x
Increment(x);
//Writes 5 to the console
Console.WriteLine(x.ToString());
}
protected void Increment(int incoming)
{
incoming++;
}
protected void Sample()Note that this time around x is 6 after the Increment method is executed.
{
int x = 5;
//Writes 5 to the console
Console.WriteLine(x.ToString());
//Send a reference of x
Increment(ref x);
//Writes 6 to the console
Console.WriteLine(x.ToString());
}
protected void Increment(ref int incoming)
{
incoming++;
}
The ref and out keywords operate identically except that ref parameters must be initialized before being passed into the method while out parameters must be initialized by the time the method returns.
August 09, 2008
SQL Server 2005 Finicky with Nested Comments
This code executes without error...but everything grinds to a halt when you try to modify or script it. Management Studio reports a Syntax error in TextHeader.
/*
/*Bad comment line*/2
*/
CREATE PROCEDURE [dbo].[GetProduct]
AS
SELECT * FROM Product
I ran into this behavior after working an hour on a fairly complex sproc. I didn't back up my work before I ran it, assuming I could always pull it out of the database to make tweaks if necessary. Needless to say I was miffed to find that I couldn't open the stored procedure and effectively lost my work.
Thankfully, it's possible to retrieve code that's lost in this manner:
SELECT
ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.Routines
WHERE
ROUTINE_Name = 'GetProduct'
May 19, 2008
Browsershots Browser Compatibility Tool
For many projects I end up developing and testing my web applications on Internet Explorer, Firefox and Safari. This strategy, though sufficient for testing common scenarios, does not take into account multiple operating systems, browser versions or additional browser vendors. Any of these factors might introduce compatibility issues. It would be very costly, boring and ultimately unrealistic to manually test against all of these possible variations.This is where Browsershots enters the picture. This open source service (created by Johann C. Rocholl) generates screen shots of your web application running under your choice of over 40 web browsers that span 4 platforms.
I'm very pleased to have such a tool available for automating the leg work that goes into browser testing, especially for the less likely scenarios.
March 31, 2008
Design Pattern Reference
The Net Objectives Pattern Repository
Net Objectives has put together some well articulated verbiage detailing the nuances of over half a dozen design patterns. For myself, the inclusion of procedural analogs and non-software analogs (metaphors for each pattern in the real world) are especially helpful. Sample implementations, motivations for use, testing issues and consequences of use are also explored for each pattern.
October 05, 2007
Removing Boot Camp
When I first got my MacBook Pro I installed Apple's Boot Camp software so I could still run the odd Windows application. This proved handy, albeit tedious to have to reboot whenever switching operating systems. During the summer I installed a copy of Parallels and can now blissfully run Windows within OS X whenever necessary.Unfortunately, removing Boot Camp took a little leg work. I started by using the "Boot Camp Assistant" to restore the startup disk to a single volume. This seemed to work properly at first. But before long I noticed this change affected the startup time. Upon booting, a folder with a question mark would appear and spin its wheels for a moment prior to the gray Apple logo. Everything else worked fine.
Today I found a solution to this nagging issue in the Apple support forums. Simply reset the PRAM:
- Shut down computer.
- Turn on computer.
- Press and hold the Command+Option+P+R keys before the startup screen appears.
- Wait until the computer restarts and you hear the startup sound.
October 04, 2007
Commitment to Service Oriented Architecture
SOA, in many circles, is something of a holy grail in software development. After all, a group of applications that're fluent in XML to gracefully synchronize with a central message bus makes for an enticing proposal. Suddenly no single system is a lone island, but every application has to work together. Existing redundancy between systems can be eliminated, alleviating maintenance. If an application could be likened to a single-cell organism, then SOA enterprise architecture would represent a complex multi-celled creature.
But how do businesses get from point A to point B? It's unrealistic to pretend that the transition will happen all by itself. It's my opinion that if an enterprise decides to pursue an SOA architecture it will have to drive it home with a top-down mandate from leaders within the company. Anything less will equate to a lukewarm infinite loop of high expectations, varying degrees of commitment from developers and resulting projects that fail to consistently communicate with the message bus.
The first application to transition to a service may be the biggest challenge. It may consist of several identifiable resources each needing to be dissected into a smaller subset of unique services. This process will take time, burn money and require a business to be fully on board with the new architecture.
August 04, 2007
Mobile Web Forms in Visual Studio 2005 SP1
After a bit of searching I found out that Visual Studio 2005 SP1 removed this capability for web application projects (it was last present in Visual Studio 2003). Thankfully the Visual Studio Web Tools group posted the templates here as an optional download.