Saturday, January 29. 2011
LAN Party
Digital Engine Software is proud to host our fourth LAN party of
the year on February 5th from 1:00 p.m. to 10:00 p.m. at the Bozeman Public Library. We'll be playing some StarCraft 2, UT 2004, Quake 3, Team
Fortress 2, Counter-Strike: Source, Left4Dead 2 and anything else that
happens to strike our fancy. Drinks and snacks will be provided and
we'll take pizza orders come dinner time. Admission is free and everyone
is welcome.
For more information visit:
Our website: http://www.digitalenginesoftware.com/lan/
Our Facebook group: http://www.facebook.com/#!/group.php?gid=102202183163875
Or e-mail: marcher@digitalenginesoftware.com
Tuesday, November 23. 2010
Indexes on Linked Tables/Views in Access
Access has 2 distinct notions of an index on a linked table/view. The first is a "true" index, which resides in the linked database and is not used/modified directly by Jet/Access. These "true" indexes can be used by the database engine for executing query plans and are enforced during data modification (e.g. for uniqueness). The second is a "pseudo-index" which is "a dynamic cross-reference" that Jet/Access creates/maintains to facilitate data modification on linked tables/views which lack a unique index in the linked database. Constraints in pseudo-indexes can not be enforced outside of Access (and I am unsure if they are even enforced within Access) and are not used during query execution on the linked database (of course, although I have no knowledge of how they are used within Access...).
How to add indexes to linked tables/views
Create the indexes in the linked database (e.g. SQL Server) and refresh the table/view link (using Linked Table Manager or programmatically with TableDef.RefreshLink).
How to add pseudo-indexes to linked tables/views
When a link to a table/view without an index is created, Access prompts the user with a "Select Unique Record Identifier" dialog box (which is also triggered from code using DoCmd.TransferDatabase
to create the link). Simply select the fields to be included in the index. Note that when creating the table using DAO/ADOX methods, this dialog is not presented and the pseudo-index is not created. Also, attempting to add an index to a linked table using DAO/ADOX results in an error (similarly to attempting to add an index through the table designer). To create the pseudo-index programmatically use Database.Execute
to run a CREATE INDEX
statement on the linked table/view. Jet will decide that the index must be a pseudo-index and create one.
Why pseudo-indexes?
There are several situations where an index in the linked database is not desirable. Particularly on updateable views where the underlying table(s) are updated frequently. Creating an indexed view has the side effect of materializing the table on disk, which requires every update to the underlying tables to involve multiple writes to disk as both the original table and the indexed view are updated. Yet, without a pseudo-index, the view would not be updateable from Access. So in these situations a pseudo-index is required.
Caveats
Unfortunately, pseudo-indexes are not preserved when the linked table connection is updated. So for any scripts which modify the connection (e.g. to re-point a table to a different server) must recreate the indexes after refreshing the link. The following code is a general outline for what is required (note that index direction is not currently preserved). The code should be run on the index before the connection is updated, then the returned SQL run after the connection is changed and the link is refreshed:
function indexToSQL(index, tableName) {
var e, query;
query = new Array();
query.push("CREATE ");
if (index.Unique) {
query.push("UNIQUE ");
}
query.push("INDEX ");
query.push(index.Name);
query.push(" ON ");
query.push(tableName);
query.push(" (");
for (e = new Enumerator(index.Fields); !e.atEnd(); e.moveNext()) {
query.push(e.item().Name);
query.push(", ");
}
query.pop();
query.push(") ");
if (index.IgnoreNulls || index.Primary || index.Required) {
query.push("WITH ");
if (index.IgnoreNulls) {
query.push("IGNORE NULL ");
}
if (index.Primary) {
query.push("PRIMARY ");
}
if (index.Required) {
query.push("DISALLOW NULL ");
}
}
return query.join("");
}
Tuesday, November 16. 2010
Failed to map the path '/' After Installing IIS
Over the past weekend I installed SQL Server 2005 Express Reporting Services according to the directions in KB934164 on my Windows 7 machine (which did not go particularly smoothly due to problems with the default Application Pool Identity that caused some Reporting Services Configuration steps to fail... but that is another story). Returning to developing ASP.NET in VS2010 I found that most pages of the site I am working on would no longer load in the ASP.NET Development Server for debugging. The failing pages produced the following error message:
The error could easily be reproduced by calling System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath)
.
After a bit of searching, I found several discussions of the problem (or very similar problems) and all of the posts that contained a solution involved running Visual Studio as Administrator (e.g. Gabe Sumner on Sitefinity or Miha Markič on Righthand Blogs). I found this solution unacceptable (for a number of reasons) and decided to dig deeper.
After much tracing and browsing around in .NET Reflector, I determined that System.Web.Configuration.ProcessHostConfigUtils
makes calls to several external functions in System.Web.Hosting.UnsafeIISMethods
which were failing. Although these calls failed, the code in ProcessHostConfigUtils
ignores the failures up until it throws the nearly useless message quoted above (rather than using the failure message from the UnsafeIISMethods
methods). Using reflection, I invoked the external methods directly, then converted the HRESULT to an exception using System.Runtime.InteropServices.Marshal.GetExceptionForHR
and received the following error message:
Finally! Something useful. So I granted my user account read permission on C:\Windows\System32\inetsrv\config and the problem was solved (note that I don't have any sensitive information in this directory which would need to remain private, so I don't have a problem with extra read-only access).
It seems very odd that this file would be loaded at all, given that IIS is not configured with the "shared configuration" feature that uses redirection.config (in fact it has the default configuration in every way). It also seems strange that the code would need to consult the global IIS configuration, although this could be due to any number of reasons (legitimate or due to code which makes incorrect assumptions about IIS and the ASP.NET Development Server co-existing on a machine). However, since all of the code necessary to reproduce the problem is outside of my control, there isn't much more I can do. Enjoy the workaround.
Friday, November 12. 2010
Access Data Pages in Access 2002/2003 on Windows Vista/7
For anyone who has tried creating a blank Access Data Page in Access 2003 (or Access 2002 aka Access XP) on Windows Vista or 7, you will have seen the following message:
Wednesday, November 10. 2010
Access 2003 Not Compatible with Access Runtime 2010
Just a quick warning: Don't install Access Runtime 2010 on any computer where you are still using Access 2003 (this may apply to other version combinations as well). I recently installed the latest version of SQL Server Migration Assistant for Access, which requires the Microsoft Access 2010 Runtime. After installing the runtime, creating an event procedure would cause Access 2003 to crash. With a bit more testing, I found that the Visual Basic Editor was automatically creating a reference to the "Microsoft Access 14.0 Object Library" (that came with the 2010 Runtime) instead of the "Microsoft Access 11.0 Object Library" (that came with Access 2003) and it would not allow me to change this library. After removing the 2010 runtime, all is back to normal.
Wednesday, November 3. 2010
SotC November Style.
Another super exciting month for us here at Digital Engine Software. Ok, maybe not super exciting but marginally above average! Let’s see…beginning of the month we had our third LAN party of the year. It was a lot of fun, I got to play grownup Lego’s quite a bit (Minecraft) and Peter laughed all the way to the bank whooping it up on LoL (League of Legends). We also attended the Tech Ranch networking party at the 317 Pub. Having been to a whole two networking events with the Tech Ranch I can authoritatively state that they are all awesome. You get to meet some really interesting people, talk about some cool stuff and usually there is free food/drink. Which brings me to my starving entrepreneur tip of the day: There are a surprisingly large number of events in this town that just give away food. A lot of the time it is even good food (even assuming you haven’t eaten Ramen for the last 12 meals). Attend these events. You will meet some people (sometimes cool) and you may be able to sneak out some food. Mix your stolen food with Ramen the next day and you can eat like a king! I call it Fancy Ramen ™.
As far as actual work goes just some more of the same. I have been finalizing some of the web projects I have been working on and trying to develop a solid marketing plan for whenever Peter thinks of his name for the Git GUI project. Peter, ironically, has been working on the Git GUI project and Kevin has been working on his office management software along with a nearly fully-functional demo for a secret project we’ll hopefully be able to discuss sometime soon. Kevin has also submitted his patch to the Duplicity project to be merged with the main development branch so theoretically Duplicity will have a Window’s port (and a lot of bug fixes) available soon. A social media users group is in the works at the Tech Ranch. The first meeting should take place before the end of the year. Keep an eye on our blog or the Tech Ranch calendar for the official date. More next month!
Wednesday, October 20. 2010
The Curious Case of OBJC_DISABLE_GC in OCUnit tests
When I first started writing unit tests using the OCUnit testing framework, my unit tests were failing when I ran them, but when I set break points to debug them they started passing. It turned out, after much swearing and frustration, that there were errors being spewed to the standard error file handle. This error looked a little something like this:
GC: forcing GC OFF because OBJC_DISABLE_GC is set
Normally this wouldn't be a big deal, and my application at it core relies on reading messages from both standard out and standard error as part of communicating with an NSTask object. I'm using RegexKit in order to parse the output into a meaningful set of data, and that's where the problem manifests itself. Since this error is coming from the unit testing harness and my regex's are not expecting this error message in the standard error file handle, this led to failed unit tests.
Naturally, I immediately started googling for the answer, and read posts every from CocoaBuilder to StackOverflow, and everyone suggested to change the Garbage Collection behavior from Unsupported to either Supported or Required. Easy enough, and so I did, in these steps:
- Double click on the project at the top of the project browser
- Find the garbage collection setting
- Change the value to either supported or required (supported in my case, as I'm actually using the retain count method)
Done and done...or so I thought. I ran my unit test again, and I continued to get the same error message. I switched the garbage collection setting to the other value (required in my case) and still I continued to get the error message.
So, I went back on the hunt for the answer and the same answer came up again and again, "Switch your garbage collection setting", which was not solving my problem. In the end, I did end up solving my problem and the answer is indeed "switch your garbage collection setting" but one thing no one told me, and I'm here to tell everyone having the same problem as I was having, is exactly WHICH garbage collection setting to change.
The secret it turns out is that the Unit Test Bundle has its own garbage collection setting, and its not inherited from the project level setting.
So, instead of double click on the project, double click HERE:
and change that garbage collection setting to either Supported or Required, per normal:
The instant I changed the unit test bundle's setting, the errors in standard out that I'm not expecting are gone.
Sunday, October 17. 2010
CSS3 Flexible Boxes Don't Always Work
While working on a web page for a web-based intranet application, I ran into the problem of vertically sizing an HTML element such that it fills the remaining vertical space within its parent (given an unknown amount of space already filled by its preceding siblings). Although may sound like a simple problem, I have yet to find a CSS-only solution. There is a very useful (although now a bit dated) discussion of the problem on Patrick van Bergen's Blog, although the Internet Explorer portion of his solution can not be used in IE8 Strict Mode due to the removal of dynamic properties. However, this post lead me to discover the CSS3 Flexible Box Layout Module.
The purpose of this post is not to describe the flexible box layout module or how to use it, for that there are many excellent resources such as The CSS 3 Flexible Box Model on Mozilla Hacks and Introducing the Flexible Box Layout module on CSS3.info, the point of this post is to highlight one important caveat of flexible boxes in Firefox: They don't work when positioned absolutely. This fact isn't mentioned in the documentation that I have come across (or, if it is, I have managed to overlook it multiple times) and I am unsure if it is a bug or intended behavior. In either case, it can be very confusing for developers who are new to flexible boxes and unsure what to expect. For a quick example of the problem, consider the following code:
<div style="border: 2px solid green; display: -moz-box; height: 5em; -moz-box-orient: vertical">
<div style="background-color: red">Child 1</div>
<div style="background-color: blue; -moz-box-flex: 1">Child 2</div>
</div>
This produces the following output (best viewed in a Gecko-based browser):
Yet if we make the container absolutely positioned (and place in a relatively positioned container so it appears below this text) we get the following:
Keep this in mind if you are working with flexible boxes.
Friday, October 15. 2010
The proper care and feeding of NSWindow objects display as a sheet
The Too Long, Didn't Read version:
Displaying a NSWindow, one that's lazily loaded from its own nib file, as a sheet doesn't have a any method for notifying observers that its about to be displayed, and therefore its difficult to reset the sheet UI on the second and later displays. Therefore, use this NSWindow subclass as your controller to re-set the UI right before the window will display as a sheet.
---
The long version wherein I lead the reader, step by step, through the problem and the solution to lazily-loaded, re-usable NSWindow objects displayed as a sheet:
In many examples of using custom NSWindow object displays as a sheet in a Cocoa application, found both on the web and in print, the author has placed the NSWindow object that will be used as a sheet inside in the .nib file of the window that the sheet will be attached to. This works fine if the sheet is guaranteed to be displayed to the user. On the other hand if you can't guarantee that the user will see the sheet, as you frequently cannot with a sheet, including the sheet in the nib file violates the guideline of "For a window or menu that is used only occasionally, store it in a separate nib file. By storing it in a separate nib file, you load the resource into memory only if it is actually used."
As a tangential discussion before diving into the main point, everytime you load a resource from a nib file all objects contained within the file, with the exception of the 'File's Owner', 'First Responder' and 'Application' objects since these are proxy objects, are unarchived and have their connections (both IBAction and IBOutlets) set up. Therefore, even if you don't use a particular resource contained with in the nib, such as in the case where the sheet is never presented to the user, the program has wasted both computation time and memory loading all the unused objects anyway. The more you can get away with not loading from your nib files, the faster your program will launch and the more memory efficient it will be while running. As such, the best way to handle NSWindow objects that may not be displayed to the user is to move them into their own nib file and only load them from the nib file when, and if, they need to be displayed to the user. For a more complete run down of the ins and outs of nib files please read through Apple's Resource Programming Guide.
So, in the case of a custom sheet, since we don't want to waste processing time and system memory until we need it, the best way to handle this is as follows. I'm purposefully omitting the corresponding .h files for this example since they're rather trivial. The only important part is that both MainWindowController and SheetController are both subclasses of NSWindowController:
MainWindowController.mSheetController* sheetController = [[SheetController alloc] init];
[NSApp beginSheet:[sheetController window]
modalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:sheetController];
}
- (void)sheetDidEnd:(NSAlert*)alert returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo {
// do something with the user input to the sheet here
SheetController* sheetController = contextInfo;
[sheetController release];
}
self = [super initWithWindowNibName:@"someSheet"];
return self;
}
- (IBAction)dimissSheet:(id)sender {
[NSApp endSheet:[self window] returnCode:NSOKButton];
[[self window] orderOut:self];
}
This is just sample code, with just enough to show how displaying a sheet would work. Obviously it will work, but there's a subtle error in here that's easy to miss for new programmers. Everytime [[SheetController alloc] init]
is called in the main window controller, the contents of the nib containing the sheet is opened, unpacked, and hydrated. Even though we're properly lazily loading the objects in the nib file, we've committed another error. We're now incurring the nib loading everytime the sheet displays. It would be better if we could unpack this information from the nib only once, and reuse the sheet NSWindow object every time and therefore we only incur the cost of instantiation the first time a user needs the sheet.
Easy enough, in theory (you'll see why this turns out to be harder than it looks in a second), and with that change it looks something like this:
MainWindowController.h MainWindowController.mif (sheetController == nil) {
sheetController = [[SheetController alloc] init];
}
[NSApp beginSheet:[sheetController window]
modalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:sheetController];
}
- (void)sheetDidEnd:(NSAlert*)alert returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo {
// do something with the user input to the sheet here
}
self = [super initWithWindowNibName:@"someSheet"];
return self;
}
- (IBAction)dimissSheet:(id)sender {
[NSApp endSheet:[self window] returnCode:NSOKButton];
[[self window] orderOut:self];
}
Now, we're creating the sheet a single time, which fixes the problem of loading the resources from the nib every time you display the sheet, but introduces a new problem (one that's hard to see from the example code without running a full application that implements this code). The problem is that because we're using the exact same NSWindow object over and over, if the sheet contains UI elements that the user can change (NSTextField, NSSlider, NSPopupButton, etc.) then those UI elements will be displayed as the user left them from the first time they interacted with the sheet. Sometimes this is the desired behavior, but in the event that its not, you have a problem.
Normally in the case where you want to re-use a window over and over and want to reset its UI every time its presented to the user, you can override the - (IBAction)showWindow:(id)sender
method in the NSWindowController. Unfortunately for a NSWindow displayed as a sheet, the showWindow:
method is not invoked by [NSApp beginSheet:...]
and therefore your NSWindowController subclass isn't notified that the window is about to be displayed. This lack of notification just prior to the window showing on screen as a sheet is the heart of the problem. As a quick rundown of the methods you might think work but don't:
- When the sheet is loaded, it invokes
windowDidLoad:
on its controller, but this only happens the first time its loaded from the nib and is never invoked again (since we're re-using the sheet and only loading it from the nib a single time), so it can't be used to reset the UI for the second display of the sheet. - The NSWindow that will have a sheet attached to it notifies its delegate that its about to display a sheet through the
willDisplaySheet:(NSNotification*)
method, but the notification contains a nil userInfo dictionary so it doesn't contain a pointer to the sheet its about to display - You might think that when a window's delegate receives a
willDisplaySheet:
notification the delegate could invoke theattachedSheet
method on the window that's about to display a sheet. Unfortunately, the NSWindow'sattachedSheet
method returnsnil
at this point since the sheet isn't yet attached. - You could override
[controller window]
method on the NSWindowController for the sheet in order to reset the UI before returning the window object. This partially works since you'll reset the UI as part of the[NSApp beginSheet:[sheetController window] ...]
invocation, but it also means you lose access to what the user did on the other side since dismissing the sheet through[NSApp endSheet:[self window] ...]
also resets the UI.
Since the last bullet point is half usable, it turns out that with the right tweaks, we can avoid restting the UI while dismissing the sheet. I now present the DESSheetController, which you can use in your own Xcode project to fix this issue:
DESSheetController.h// DESSheetController.m
//
// Created by Peter Nix (pnix@digitalenginesoftware.com)
//
#import <Cocoa/Cocoa.h>
/*!
@class DESSheetController
@abstract An abstract super class to use instead of NSWindowController to
assist in using sheets.
@discussion Using an NSWindow controller loaded from its own nib as a sheet
(a distinct nib from the window its going to attach to) doesn't have a good
notification to its NSWindowController or delegate that its about to display.
Therefore, it is very difficult to reset the UI to a default state when re-displaying
the sheet to the user. This class provides the necessary overrides and callbacks
to help reset the UI to a default state when reusing the same NSWindow
object as a sheet.
@updated 2010-10-13
*/
@interface DESSheetController : NSWindowController {
}
/*!
@abstract dismissSheet: provides a way of dismissing the sheet without losing
the information contained in the UI elements the user can interact with.
@discussion Based on the override of the window method (see the implementation
file) if you call [self window] as part of the call to dismiss the sheet, you will
reset the UI on the sheet before you query for this information in your modal
delegate's selector callback. Therefore, the contract for overriding this class
for a custom sheet controller is call this method when dismissing the sheet
in order to preserve the UI state.
@param returnCode the integer indicating the status that the sheet ended with.
This parameter will be passed onto NSApp when sending the sheet out and in
turn gets passed to the modal delegate's callback selector.
*/
- (void)dismissSheet:(NSInteger)returnCode;
/*!
@abstract This is the method that needs to be overriden in your custom subclass
in order to reset the UI when redisplaying the sheet.
@discussion This method is invoked in the middle of returning the window from
your controller to the NSApp instance to begin a sheet. Therefore this method
is invoked at (literally) the last possible moment, meaning that all the UI for
the sheet has been properly hydrated from the nib, and is just about to be
displayed as a sheet. This method is empty in this class, and is designed to be
overridden by a custom subclass in order to perform any UI clean up in order
to get the sheet into a reset/clean state for display to the user.
*/
- (void)hydrateView;
@end
@implementation DESSheetController
#pragma mark inherited methods
- (NSWindow*)window {
NSWindow* window = [super window];
[self hydrateView];
return window;
}
#pragma mark private methods
- (void)hydrateView {
// do nothing by design, overridden by sub-classes
}
- (void)dismissSheet:(NSInteger)returnCode {
// note the use of super instead of self in order to bypass the sheet reset code
// via the hydrateView method
[NSApp endSheet:[super window] returnCode:returnCode];
[[super window] orderOut:self];
}
@end
So, now for a bit of explanation. The point is to use this class as your sheet controller's superclass instead of NSWindowController. By subclassing DESSheetController, all you have to do is implement -(void)hydrateView
within your subclass and use that method to re-initialize the UI everytime the sheet is displayed. On the outgoing side, the contract is to invoke the - (void)dismissSheet:(NSInteger)returnCode
method instead of invoking [NSApp endSheet:]
directly in your subclass. The dismissSheet:
method calls [super window]
instead of [self window]
and therefore avoids resetting the UI before the modal delegate can query the sheet for information.
Now, you can safely re-use a single NSWindow as a custom sheet for user interaction over and over again, and still stick to lazy initialization and avoid multiple nib loading.
Monday, October 4. 2010
State of the Company October Edition
September is gone already, that was crazy fast. Digital Engine Software has been busy but nothing too much has changed since last month. Kevin has been teetering on the edge of insanity as he works on trying to automate some interactions with the state websites. I’m tempted to try and push him over because I’ve never seen a ginger angry before but as it is I will most likely be the first against the wall when the Kevin revolution comes so I’m not going to push my luck.
In other news we were asked to do an evaluation of some inventory management software. Peter took charge of that and it turns out, unfortunately, that there is only one semi-decent piece of open source inventory management software (OpenBravo in case anyone is curious). OpenBravo is even a corporate sponsored half open source half premium product that has received almost $20M in venture funding. As we were evaluating off-the-shelf software options we also ran the numbers on our own development. Once you begin digging into the nitty gritty of the software features you begin to realize how incredibly immense these programs are. Our conservative estimate for development time was nearly 3,000 hours. There are admittedly some very complex and gigantic open source projects but inventory management doesn’t have nearly the sexy cachet of say a new encryption algorithm implementation. Ultimately we discovered that this is definitely an area that is better served by closed source proprietary solutions. Peter is also still hard at work on his GIT GUI project. I’m pushing him to get it done by December 7th because it’s possible that he may become a permanent resident of the World of Warcraft once Cataclysm comes out.
As I blogged earlier I spent most of September preparing for and actually doing the Orbit seminars. So much fun! We have another LAN party coming up this Saturday (October 9th) at the library. Our reserved seat charity this time around is the Human Resource Development Council – donate and help keep people warm and fed this winter. I’ve also been attending some Young Professionals Group meetings. These are really cool get-togethers put on once a month by the Chamber of Commerce (you don’t have to be a member of the Chamber to join YPG) where younger individuals (<35or so) meet to network, learn stuff, volunteer and have fun. Last month we had three business people from the community come in and answer our questions and I’ve heard that this month is Vegas night. There are four sub-committees within YPG that you can join: Community service, education, social and mentoring and the groups alternate hosting the meeting or activity each month. If you’re a younger professional and you enjoy groups you should totally join (bonus points if you’re not a financial adviser or a chiropractor).
Monday, September 27. 2010
Orbit Presentations
Last week Gary Bloomer from the Tech Ranch, Shelby Nordhagen of NetNewMarketing and I made a trip up to Bigfork and Frenchtown to give our presentations on e-marketing. It was so much fun! The audience members were awesome! They were really engaged and often contributed as much or more than Shelby and I did. I should warn, however, that these seminars are pretty basic. We have a lot of great information but anyone involved in the industry will likely know 95% of the stuff we cover. However, if anyone reading this blog is interested in an introductory course on how to set up a WordPress site, search engine optimization, Google Analytics, AdWords, social networking or e-mail marketing should plan to attend one of our future seminars! They’re a lot of fun, you can make fun of Gary and he can’t do a thing about it plus lunch is included. Keep an eye on this blog or the official Orbit Montana site for dates and places starting again in the beginning of 2011.
GoDaddy is the Devil
I just finished working on a couple of projects that used GoDaddy as their hosting provider. Please note the past tense. GoDaddy is the most worthless hosting provider ever. Not that their actual service is bad once the site is up, they appear to have plenty of hardware and bandwidth, but the getting the site up part is where they fall on their stupid faces. Instead of using the industry standard cPanel GoDaddy decided to roll their own administration panel and incorporate it into their website. I’m not against people trying their own thing, variety is the spice of life as it were, but reinventing the wheel by adding 18 different advertisements and making it oval is a pretty stupid idea.
So let’s assume you have navigated the GoDaddy crap maze and found the area that allows you to create an ftp account. Hooray! You think you’ve won, but in fact GoDaddy has spat in your cereal and definitely not for the last time. For some reason the completely automatable task of ftp account creation takes 30 minutes. Why should something simple like FTP account creation take longer than say 5 seconds? My guess is that the IT guys have been tasked with figuring out how to make bowel movements a sellable add-on and are too busy to work on trivial things like FTP account creation.
Thank goodness, FTP is finally set up, we have a bowel movement added to our shopping cart and we can start making our website. Oh noz! We forgot about the database we need to keep track of the number of kittens I kill while waiting for FTP accounts to setup. But really, how difficult could it be to setup a database? Assuming you can find the link to the database setup page you are required to create another user name and password pair for logging in to the database setup. Once that’s done you can count on another 30 minutes to create the database and users. Cheers GD!
Database is setup, we have FTP access, and finally we are able to get our site up and running! Hahaha, nope. GoDaddy doesn’t have access to some common PHP packages like Archive_Tar or the PHP FTP commands (those are the two that I know of for sure, I’m guessing there are probably lots of others). Of course the fact that these packages are missing isn’t documented anywhere on their website so you get a silent fail and you have no idea why. Not to mention that you can’t create folders outside of the web root, or change the web root location at all for that matter. GoDaddy is a gigantic sore on the internet’s butt. However, I did spend tons of time on their phone support line and never had a bad experience, so kudos on your support GoDaddy otherwise kindly go away.
Friday, September 3. 2010
State of Company
August is officially over (according to Julius Caesar) so time again for another State of the Company. The big news this month is that we have expanded! An incredible office opened up on the third floor and since things were getting a little cramped up in the tower we decided to get it. Half of the new office is for Peter and half has been converted into an employee lounge of sorts. It's pretty swanky. Unfortunately I keep forgetting to bring my camera into the office so no pictures yet but as soon as I remember I'll update this post.
For any budding entrepreneurs out there considering whether to get an office or work out of a garage, definitely get the office. Yep it's a little extra money a month (when we were first looking prices ranged from ~$275-$600 per month for single offices) but the ability to go somewhere outside of your house and focus on your work is priceless.
On the work front Kevin is still working diligently on his office management project. In fact, due to a shortage of decent backup programs Kevin spent part of August porting Duplicity from Linux to Windows! Woohoo Kevin! While we are waiting on some items to be sorted out with the heat mapping project Peter has been working on a GUI for Git which sounds like it is coming along nicely although I haven't seen it yet so it could be a lie just like the cake. Finally I have been finishing up the real estate search plug-in for Joomanager, making modifications to the Huffing For Stuffing site and working on my Orbit presentation. We are going to have a ton of great information at our Orbit presentations (the first two will be in Big Fork on the 22nd and Frenchtown on the 23rd) so come by if you can make it. Also the next LAN party will be on Saturday October 9th at the Library. See you next month!
Wednesday, August 25. 2010
Xcode and 'Fix and Continue'
A quick pro tip:
Coming from the Java world and the eclipse IDE, I fell in love with the 'Drop to Frame' feature and the ability to change code on the fly while debugging. In Xcode, you can get half way there with the 'Fix' command (under the Run menu, enabled only while paused while debugging). The frustrating thing is that in the most recent version of Xcode (v3.2.3) this command is constantly disabled.
If you read the Apple's "Xcode Debugging Guide" (http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeDebugging/230-Modifying_Running_Code/modifying_running_code.html) and follow its guidelines about how to set up your environment to enable the menu item, it'll most likely stay disabled. The thing that the guide doesn't mention, and therefore is probably a bug and one that hopefully gets patched in Xcode 4, is that your build architecture must be 32-bit only. Since the default architecture is 32/64 bit universal, the fix command is unavailable by default until you change it.