Life, Technology, and Meteorology

Author: mike (Page 7 of 26)

Signs that Apple is Becoming a Big Evil Corporation

Over the past few years it seems that Apple is slowly selling its soul. It’s a bit unsettling, as many people look to Apple as an example of a virtuous company. That’s how it started anyway, just two guys in a garage designing cool computers. Now it seems with every record quarter, new kick-ass product, and innovation made in media, Apple sells itself out. Before I continue down this road, let me make it perfectly clear that I still think Apple has it’s virtues. Apple products are top-notch, and I’m happy the Mac market share is expanding at the rate it is, simply because more Mac users means more potential Seasonality users. The Mac platform is a good place to be right now. So before you send me that hate mail, just remember that I’m telling it as I see it, and this is how I’m seeing it.

What does it mean to become a big, evil corporation? To me a big, evil corporation is one that is driven completely by profits, does not care what it sells, just that consumers buy it, and doesn’t care what it does to produce the products it sells. Actually, it pretty much is against everything that Apple stands for: free ideas, thinking different, and building tools that innovate to help you innovate. Imagine a bright, shiny, chrome shield of virtue; Apple’s coat of arms if you will. Here are a few things I’ve noticed keeping that shield from being shiny and new.

The iTMS

I spent some time thinking back to where it all started, and the best turning point I could think of was the introduction of the iTunes Music Store. I still remember the day this store opened. I remember downloading a fresh version of iTunes, and checking out the hip store that was so easy to shop at. 1-click shopping to purchase any of thousands of songs. Sure there was DRM, but there had to be or else none of the music companies would go for it. “Apple did good though! Only $0.99 a song, and you can play it on 5 devices, AND burn it to a CD!” DRM was certainly a bullet Apple had to bite, otherwise the iTMS would never exist as it does today. However, Apple as a corporation is about free thinking, selling products that you can use for endless innovation. DRM is most certainly against those ideals, being practically invented for the music and movie industries, which are the epitomes of big, evil business… Chink.

.Mac

Remember when .Mac came out and they weren’t charging for it? “Really, it was free?” Yep. Does it make sense for this service to be free today? Maybe not. There are certainly a lot of people who take advantage of .Mac, and someone has to pay for all that bandwidth and server hardware. It’s not really Apple’s responsibility to provide such a service for no cost to all Mac OS X users. So what’s my dig with .Mac? What I don’t like about it is how many features in Mac OS X and iLife especially are completely crippled for users who don’t subscribe. Why can’t I use any online-accessible directory as an export location for iWeb or iPhoto galleries? To add insult to injury, Apple really puts pressure on developers to make use of .Mac in their software applications. Really then, it’s developers who sell .Mac for Apple. Want to sync X, Y, and Z apps with each other? Sorry you can’t do that unless you have a .Mac account…

The fact of the matter is, I wouldn’t even mind paying for .Mac if it was competitive in the hosting industry. For $100/year, you’re getting a paltry amount of online disk space (this was made somewhat better recently), a couple of email accounts, and some web space with a small helping of bandwidth. Compare to Google, who gives away disk space, email, and shared documents for free. .Mac is just another hook Apple uses to get more recurring money from customers, instead of being a solid innovation in the online sharing community like it should be. Sounds big evil corporationy to me… Chink.

“Because of Accounting…”

It seems we are seeing these paid hardware unlocks from Apple much more frequently. First, last year with MacBook Pros and 802.11n, and now with the recent iPod touch update. It’s blamed on some accounting rules, but really, since when can a company not decide to give something away for free? Why can only products sold on a subscription basis be given free feature updates? Is Leopard a subscription-based product? In the case of the MacBook Pro, the network card was already there, but you had to pay an extra $2 to use it at that speed. Why? Why can’t the users who bought those machines just find out their laptops are even more awesome than before? $2 is a pain in the butt. Katrina has one of these laptops, and we just never paid: not because of the money or the principle of the thing (the latter of which is certainly a valid reason to avoid a product for us), but because it was just another line-item on our todo list that gets lost below all the other important stuff.

Now the big rage is this iPod touch update. 5 new apps for the iPod touch, only $20…what a deal!</sarcasm> Actually, it is a deal. Those 5 apps make the iPod touch twice as useful as it was before, useful enough that I bought one yesterday to replace my Dell PDA. Now I’m in the software industry, so I understand that paid updates are important. You can’t just give away free updates forever, because you have to pay for that continued development. Furthermore, when current iPod touch users purchased their devices, they paid for the current features, so it was worth it to them at the time. If the iPod touch didn’t fit your needs before, then why’d you buy it to begin with?

On the other hand, these 5 applications have been on the iPhone for quite some time. They aren’t really new developments (though there are some new features in each of the apps), and the touch only came out back in September. If someone just bought a product from you less than 6 months ago, you shouldn’t be sticking them with an upgrade fee. Apple screwed up by crippling the iPod touch from the start “to protect iPhone sales,” they should be biting the bullet. It’s just a collection of bits anyway, nothing physical that would actually cost Apple money to offer.

Admittedly, this brings up a tricky topic: upgrade fees. Now since I just bought an iPod touch, if Apple decides a year from now to release and charge for a big software update, how will I feel? Actually, that would be completely fine by me. In fact, I’d be happy if they were still upgrading the software on my device after a year. So where do you draw the line? Somewhere between 5 and 12 months I think. Seriously though, Apple here is releasing software version 1.1.3… This is a point release, what most of the industry would consider a bug-fix. To charge for a point release is absurd, so at the very least, the iPhone/iPod touch development team needs to get their version numbering in check.

Upgrade fees are a fact of life, but these few select examples rub me the wrong way. I’ll be the first in line to buy a new version of OS X every year, but even noting that Apple has to point the finger at “accounting” is kind of a clue the company is going evil. Chink.

iPhone nonSDK

Just over a year ago, Apple dropped the bombshell that it’s new iPod phone would be running a “stripped down version of OS X.” I couldn’t believe it… I thought OS X was just too big for an embedded device, and I’m glad I was proven wrong. That means developing for the iPhone wouldn’t be much different than developing for the Mac. Awesome. Until developers asked Apple how we could go about writing software for the iPhone. Their answer: web apps… Great.

Now to give Apple credit, an SDK is expected sometime next month, and I’m anxiously awaiting such an SDK, but they didn’t get it right from the start. The iPhone is an iPod, but it’s a lot more than that…it’s a mobile device, and developers expect to be able to write software for mobile devices. Actually, development of new software for mobile devices really drives the platforms forward. Not having this is a slap in the face, almost as big as DRM. I’m just hoping they get it right the second time around. It would be a shame if they place too many restrictions or force developers to get “approval” to write apps for the platform. The verdict is still out on this one, but it still strikes me as a big evil company lock-out. Chink (but you might be able to buff this one out).

Time Capsule

To wrap up my argument, I present the new Time Capsule announcement. If you’re unfamiliar, Time Capsule is basically a networked attached Mac hard drive, a NAS. Apple is marketing it as a Time Machine backup device, a hard drive any of the Macs on your network can use to backup files to. It’s certainly a product that Apple should produce, and it really seems like something they could do a nice job with. So what’s the problem?

For this one, you need a little bit of background. You see, when Time Machine was originally announced at WWDC 2006 (!), Apple claimed that backing up over a network would be supported. To me, this was it. I like running servers, and setting a Time Machine server sounded like a nice idea to me. Even better, last year the NAS market took off, and I ended up purchasing a 1TB NAS from Micronet, expecting to have no problem backing up over Samba, NFS, or whatever other network protocol Mac OS X supported (webdav?). Fast-forward to October 2007 when Leopard was released, and what do we get? You can backup over the network to a Mac running OS X Leopard Server, and that’s it.

So now you have all these NAS devices on the market, and none of them work with Time Machine, without the use of an unsupported hack. Supposedly, Time Machine requires backup to an HFS+ formatted device for it’s hard-link support. Well, my NAS is formatted ext3, which also supports hard-links. And why can’t Time Machine fall back to using a device without hard-link support and just take more disk space by writing more than one copy of the files? Or perhaps it would even be useful for users to have just a single backup copy of their files to a device that doesn’t fully support incremental backups with hard-links. It begs the question, was Time Machine built to truly bring backup to Mac OS X users at large, or was it designed into OS X to sell the upcoming Time Capsules? Chink.

Of the Coat of Arms

So our new Apple coat of arms is a little more battered than when it started. These are definitely areas that need improvement. Am I optimistic we’ll see these issues resolved? I try to be, but when the frequency of these events is increasing, it’s difficult to look at it with a positive note. Maybe it doesn’t matter… Apple still designs a lot of cool products, maybe that’s enough. This is true to some extent, as long as Apple continues to sell it’s products, it will continue to survive as a corporation, and we’ll still be Mac users. The drawback I think comes to customer loyalty. Apple is known as one of the strongest brands worldwide, simply because of their customer loyalty. Practices such as the above that step on their customers are sure to lessen their brand loyalty though. I won’t purchase or design products that use .Mac simply because I see it as a way Apple locks users into that service. I had no interest in purchasing the iPhone/iPod touch until it was announced I could write apps for it, and the verdict of whether that was a waste of my money is still out on that one. Steve Jobs noted 2007 as a great year in Apple history (indeed), and how much has happened in 2008 already. I sincerely hope I don’t have any more chinks to add to this list next January…

Indie Marketing @ Macworld

Macworld Expo San Francisco is one of the largest, if not the largest, Mac user event of the year. For an indie Mac developer, if there is one conference (other than WWDC) that should be attended, this is it. So why haven’t I attended in previous years? I asked myself that same question last year after hearing about all the indie get-togethers and bar nights.

The Good Ol’ Days

The last time I attended Macworld Expo was back in 2001, just after I graduated from UCSB and before starting a job in Tucson, AZ. A lot has changed in my career in these past 7 years. For one, 7 years ago I hadn’t yet developed any software for the Mac platform. Though I was an avid Mac user, at that time I was programming mostly for Unix, and occasionally on Windows (against my will).

But that was years ago…I started programming for Mac OS X in 2002, so the question remains, why haven’t I been attending Macworld? I think it may have something to do with the conditions of which I have attended Macworld in the past. You see, the first year I attended Macworld Expo was back in 1990. The Mac IIfx was the big new machine at the time, and with the costs of such a machine nearing $10,000, only a few companies had that kind of hardware at their booth. Mac IIcx and IIci’s were more common, as was the Mac Portable—which was new at the time. I attended Macworld every year after that until 1997, when it didn’t make sense to take time off from classes at UCSB to do so. To me, attending the expo was a fun event; almost like going to an amusement park. Yeah…I was most definitely a Mac geek.

Perspective

The thing is, I never saw Macworld as a business event…it was strictly for fun. And now that I’m living in Michigan, it didn’t make sense to spend the money to attend a “fun” event. It wasn’t until I started talking to other developers who had attended the conference that I realized just how much I was missing by not attending.

Will I have a booth? No. How about one of those ADC developer kiosks? Nope. Why not? Well, this year I just want to re-learn the ropes of the conference. Paul Kafasis has written a nice series of articles on exhibiting at Macworld, but it’s been such a long time, I really want to get a recent perspective on what the conference is like before plunking down $10k to become an exhibitor. So this year, Gaucho Software will be at Macworld as a Quasi-Exhibitor.

What does this mean? Well, it means that I’ll have a lot of similar materials as a company exhibiting would, except for the actual 10×10 foot real-estate on the show floor. First, I designed a different Seasonality t-shirt for each day on the show floor and had Zazzle print them up. Second, I designed a flyer and ordered 1000 copies from SharpDots. Finally, I put in an order through PensXpress for 200 Seasonality pens to give away at the show. Let me elaborate a bit to explain my reasoning for each of these…

1. T-Shirts

I started designing and ordering the first Gaucho Software T-Shirts about 18 months ago for WWDC 2006. Thanks to outfits like Zazzle and CafePress, it’s now easy to print a custom design on a t-shirt of pretty much any color and style. At the time, I just threw the words Gaucho Software across the front and a big logo across the back. It was beneficial to wear at developer conferences like WWDC and C4, because it would give people a better idea of who I was before actually meeting them. Did it increase sales? No…but that’s okay, it was cool to have the shirts all the same.

For WWDC 2007, I designed a t-shirt highlighting Seasonality and I wore it on a day when there was an event at the SF Apple Store in the evening. Surprisingly enough, I found a nice little spike in sales during the day or two after wearing that shirt. Hey, if that one t-shirt helped sales, wearing a different Seasonality shirt each day of Macworld should help too…

2. Flyers

The decision to design a flyer to hand out at the show was easy, but going through the details of actually designing it was much more difficult. First, I had to choose a size. I decided to go with a half-sheet, or 8.5×5.5 inches. I chose this size because I didn’t want the flyer to get lost in the shuffle. I remember getting tens, even hundreds, of flyers every day I attended in previous years. A full page flyer would require a lot of content, and would be more difficult to hand out to people. Going with a size that is as wide as normal page but not as tall, will keep it from getting lost, but still make it easier to hand out.

The design was a bit tricky. I’m used to designing interfaces on-screen using the RGB colorspace. Designing for print is different. First, you have to deal with color limitation in the CMYK colorspace. Seasonality uses a lot of blues…which CMYK wreaked havoc upon. I had to choose a screenshot carefully to make sure it still looked good. Next, I had to deal with the print design being a fixed entity. Application (and to some extent, web) interfaces are dynamic. I needed to find a good way to portray information in a non-changing medium. Finally, I needed to make sure all the necessary information was on the flyer somewhere. I was pretty close to printing a design without any kind of URL to note where to purchase Seasonality. Incredible, yes… That would have made the flyers next to useless. I spent hours designing the flyer, and it took a second viewer only a few minutes to notice the lack of any kind of link. Moral of the story is, have someone check your work before shipping it off to print.

3. Pens

The pens I ordered was a last-minute idea that I think will be pretty cool. Macworld exhibitors usually give away some kind of trinket, and I thought it would be cool to do the same. Most trinkets aren’t often used after the conference ends, and I didn’t want to give someone a trinket they would just end up throwing out afterwards. A pen will hopefully remain useful for most attendees after the conference ends.

Another thing I didn’t want to do was skimp out, so I decided to go for a metal casing instead of plastic. Of course, some plastic pens are very nice, but you can’t tell that by looking at a picture on a website. I figured with a metal pen, it would at least have a decent weight and feel to it. At the same time, I didn’t want a pen that was too expensive either. There’s no way I would get enough sales to cover the costs of handing out pens at $10+ a piece. I ended up finding a nice metallic pen with laser engraving for $1 each at PensXpress. Their turn-around time was pretty quick, and I’m pleased with the results.

4. Profit?

After all this work, I’m not exactly sure what to expect at this point. Obviously, I hope I make enough in sales to pay for all of these materials and my trip costs, but it’s not so much the money I’m looking for here. What I would really like is increased mind-share. Thus far, all of my marketing has been directed towards Mac users who frequent news and download websites. There are certainly a lot of users who fit into this category, but what about users who don’t spend their free time online? I’m hoping to meet a lot of these other users at Macworld, and hopefully it will give me a chance to widen Seasonality’s audience.

If you’re planning to attend Macworld, be sure to look for the guy in the Seasonality shirt and stop to say hello… 🙂

MacSanta Brings Seasonality and Dash Monitors to You!

MacSanta has been bringing popular Mac software from indie developers to your stocking this year, and Gaucho Software is joining in on the fun.  Save 20% when you purchase Seasonality or Dash Monitors today, just in time to watch that big storm slamming the Eastern U.S. with rain and snow… 🙂

Since many of you are offline during the weekend, enjoy the same 20% discount tomorrow too!  Just use coupon code MACSANTA07 when checking out from the Gaucho Software Store.  After that, you can save 10% through December 31st by using the coupon code MACSANTA07TEN.

Happy Holidays!

Inside DynDNS Updater 2.0

I’m thrilled to link to a major update of DynDNS’s Mac client, DynDNS Updater 2.0. I’ve been working on the DynDNS Updater for quite some time, and this release is a complete re-write that has a lot of new functionality. Looking at 1.x and 2.0, you would never know the projects were related; there are far too many changes to even list. To try and summarize, DynDNS Updater 2.0 is built from the ground up to give a completely modern Mac experience to people who use the services provided by DynDNS. The updater now has auto Sparkle updating built-in, Growl integration, a custom Dashboard Widget, and an interface that looks right at home on both Tiger and Leopard. Core technologies like OpenSSL, libcurl, and pthreads are used on the back-end.

In case you aren’t familiar with DynDNS as a company, their products solve the problem of managing DNS for just about every type of user, from individuals to large companies. I believe Dynamic DNS is the project that is most well-known (at least that is how I heard of them years ago), giving users with dynamic IPs a method of having a static name point to their computer. The DynDNS Updater’s primary function is to watch out for IP address changes on your Mac, and let the DynDNS servers know when there is a change. The updater is broken up into two separate executables, one is a Cocoa application where you configure your accounts and hosts. The other executable is a background daemon running 24/7 that performs all the grunt work.

I started working on version 2.0 last year. Jeremy Hitchcock and the rest of the DynDNS crew had some nice feature ideas for the next version, and I mocked up a design that would implement some of these features. I was pretty excited about the project and started working on what was to be a fairly advanced update. Fast forward to around March or April of this year when the first beta was being wrapped up. This beta had the foundation of a solid background daemon where I tried to stick to the basic POSIX libraries, so it could run on multiple platforms. At one point, I was regularly compiling it on Linux and it was working well (I haven’t tried this for quite some time since then). The daemon was completely threaded, and supported multiple network connections. Unfortunately, while the code design was solid and the product had a lot of nice new features, the UI was horribly difficult to use and the interface to configure these complex setups was not pretty. The mock-ups looked nice, but actually using it is where we ran into problems. Seemingly simple operations took multiple steps, because a lot of advanced options had to be taken into account.

Enter FJ de Kermadec and his team at Webstellung. They suggested bringing the project back to basics–thinking more about the typical use case and not all the features we could give to power users in unique situations. Webstellung put together some very impressive UI design mock-ups to get things started. Jeremy gave the go-ahead, and it was back to the drawing board as I began coding up the fresh interface. Fortunately, since the daemon code was designed with flexibility in mind, it could be re-used by dropping the new interface on top of it. The initial UI creation went pretty quickly, and within a few months a new application was born. The first beta was ready just before WWDC this year. As soon as I started using this UI, I knew it was a keeper. There were a few adjustments that had to be made, but overall the interface is very intuitive. After the functionality was mostly complete, it was time to focus on the interface polish. We went through several iterations of the software, catching small changes here and there that all added up to a nice shiny app.

If you’re currently using DynDNS Updater 1.2, definitely upgrade to version 2.0. And if you aren’t, download the app anyway and check it out. Dynamic DNS accounts are free for up to 5 hosts, and it’s pretty easy to set everything up.

Populated Places

When developing weather software, one of the most important pieces of data you will work with is a location list. A weather application is useless if the user can’t find a city and download weather data for it. There are several different methods users might want to be able to search for a weather location. The methods Seasonality supports include zip codes (U.S. only, for now), city, state, country, and ICAO. Actually, ICAO was just a convenience method I added, so when a user double-clicks on an ICAO weather station in the satellite imagery, the add location dialog box will pop up with a listing of locations that use that ICAO.

So where do you find a good location listing online? The best resource I’ve found is the GeoNames database. They have slightly over 80,000 cities, each having a population over 1,000 people in a simple CSV file you can download from their website. Each city has a state (if applicable), a country, latitude/longitude, elevation, population, time zone, and some other fields as well. Our basic needs are only the city name and it’s latitude/longitude, but some of these other fields come in handy when trying to calculate the local time, deciding which cities to mark on the map (higher population cities should take precedence), etc.

It’s not much use to have this location data unless you can correlate it with your weather data sources. You’ll definitely need a relational database to keep track of everything. I prefer PostgreSQL for my master location database. There are several aspects of data correlation that you’ll need to think about here. Everything from matching every location with the closest weather station ICAO, to getting zip code listings and matching each one with an appropriate city. It’s a lot of work (you’ll learn a lot of SQL along the way) but eventually you’ll have a giant web of location data that you can pull from.

Now that you have this master location database, you’ll want to trim it down to something you can actually ship with your application. For example, Seasonality’s master location database is over 4.5GB in size, which would obviously be too large to include in an application archive. A small download size is desirable, so only include the data you absolutely need. Also, PostgreSQL is a bit of overkill to be running in the background for a database this size, so convert your dataset to something different, like SQLite. Selecting a subset of data and converting it from PostgreSQL to SQLite all takes place in a custom script I wrote, so each time I update a location (and trust me, with so many locations there will be errors and corrections) all I need to do is re-run the export script and I have a fresh location database to include in the next version of Seasonality.

MicroNet G-Force MegaDisk NAS Review

If you have been following my Twitter feed, you know that I just ordered a 1TB NAS last week for the office network here. I wanted some no-fuss storage sitting on the network so I could backup my data and store some archive information there instead of burning everything to DVD. (In reality, I’ll still probably burn archive data to DVD just to have a backup.)

Earlier this month, MicroNet released the G-Force MegaDisk NAS (MDN1000). The features were good and the price was right so I bought one. It finally arrived today and I’ve been spending some time getting to know the system and performing some benchmarks.

When opening the box, the first thing that surprised me was the size of the device. It’s really not much bigger than 2 3.5″ hard drives stacked on top of each other. The case is pretty sturdy, made out of aluminum, but the stand is a joke. Basically, two metal pieces came with rubber pads on them. You’re supposed to put a metal piece on each side to support the case. It’s not very sturdy, and a pain to setup like this, so I doubt I’ll use them.

I had a few problems reaching the device on my network when I plugged it in. I had to cycle the power a couple of times before I was finally able to pick it up on the network and login to the web interface. I’m guessing future firmware updates will make the setup process easier. It’s running Linux, which is nice. The firmware version is 2.6.1, so I’m guessing that means the kernel is version 2.6 (nmap identifies it as kernel 2.6.11 – 2.6.15). Hopefully it’s only a matter of time before someone’s hacked it with ssh access. MicroNet’s website claims there is an embedded dual-core processor on board, which again sounds pretty cool. The OS requires just under 61MB of space on one of the hard drives. There are two 500GB drives in this unit. Both are Hitachi (HDT725050VLA360) models, which are SATA2 drives that run at 7200 RPM with 16MB of cache. From the web interface, it looks like the disks are mounted at /dev/hdc and /dev/hdd.

Disk management is pretty straightforward. You can select a format for each disk (ext2, ext3, fat32), and there is an option to encrypt the content on the disk. The drives are monitored via the SMART interface, and you can view the reports in detail via the web. By default, the drives come in a striped RAID format, but I was able to remove the RAID and access each disk separately (contrary to the documentation’s claims). Unfortunately, for some reason I was unable to access the second disk over NFS. It looks like you might be able to mess with the web configuration page to get around this limitation though.

Moving on to the RAID configuration, you can choose between RAID 0, RAID 1, and Linear (JBOD). Ext2 and ext3 are your filesystem options. Building a RAID 1 took a very long time (~ 4 hours), which I’m guessing is because the disks require a full sync of all 500GB of data when initializing such a partition.

So let’s bust out the benchmarks! I benchmarked by performing 2 different copies. One copy was a single 400.7MB file (LARGE FILE), and the other was a directory with 4,222 files totally 68.7MB (SMALL FILES). All tests were performed over a gigabit Ethernet network from my 2.5Ghz G5 desktop machine. Transfers were done via the Terminal with the time command, to remove any human-error from the equation.

A note about testing Samba with SMALL FILES: I started running a write test and let it go for around 8 minutes. At that point, it was still only done copying around a quarter of the files, and the transfer rate averaged less than 20KB/sec. This was absurdly slow, so I didn’t bother waiting for the full test to go through. It’s difficult to say if this is a limitation of the NAS, Samba, Mac OS X or all of the above.

Striped RAID (Standard) NFS Samba
Write LARGE FILE 1:13 (5,544 KB/sec) 0:42 (9,542 KB/sec)
Read LARGE FILE 0:42 (9,769 KB/sec) 0:35 (11,723 KB/sec)
Write SMALL FILES 3:46 (310 KB/sec) DNF
Read SMALL FILES 0:39 (1,759 KB/sec) DNF
Mirrored RAID NFS Samba
Write LARGE FILE 1:17 (5,328 KB/sec) 0:47 (8,730 KB/sec)
Read LARGE FILE 0:40 (10,257 KB/sec) 0:41 (10,007 KB/sec)
Write SMALL FILES 3:44 (314 KB/sec) DNF
Read SMALL FILES 0:43 (1,636 KB/sec) DNF
Separate Disks NFS Samba
Write LARGE FILE 1:13 (5,620 KB/sec) 0:43 (9,542 KB/sec)
Read LARGE FILE 0:46 (8,919 KB/sec) 0:35 (11,723 KB/sec)
Write SMALL FILES 3:11 (368 KB/sec) DNF
Read SMALL FILES 0:42 (1,675 KB/sec) DNF

All of these were using standard mounting, either through the Finder’s browse window, or mount -t nfs with no options on the console. I decided to try tweaking the NFS parameters to see if I could squeeze any more speed out of it. The following results are all using a striped RAID configuration…

  no options wsize=16384
rsize=16384
wsize=16384
rsize=16384
noatime
intr
Write LARGE FILE 1:13
(5,544 KB/sec)
1:00
(6,838 KB/sec)
0:59
(6,954 KB/sec)
Read LARGE FILE 0:42
(9,769 KB/sec)
0:32
(12,822 KB/sec)
0:32
(12,822 KB/sec)
Write SMALL FILES 3:46
(311 KB/sec)
3:47
(310 KB/sec)
3:09
(372 KB/sec)
Read SMALL FILES 0:39
(1,759 KB/sec)
0:42
(1,675 KB/sec)
0:40
(1,758 KB/sec)

In summary, while this NAS isn’t necessarily the fastest out there, it’s certainly fast enough, especially after some tweaking. A RAID configuration doesn’t necessarily improve performance on this device. All of the transfer rates were about the same, regardless of format. You’ll notice slightly slower speeds for a RAID 1, but the difference is minimal. Before tweaking, Samba had a clear lead in transfer rates on large files, but it was completely unusable with smaller files. After modifying the NFS mount parameters, it seems to give the best of both worlds.

Update: I researched the Samba performance (or lack thereof) and found that it is not the fault of the NAS. Using a Windows XP box, writing small files went at a reasonable pace (around the same as using NFS above). Then, testing from my MacBook Pro with an OS that shall not be named, performance was similar to the Windows XP machine. I’m going to attribute this to a bug in the Samba code between version 3.0.10 on the G5 and 3.0.25 on the MacBook Pro.

Software Announcements

Some very cool apps were released/upgraded recently. Just wanted to send out some props here.

First, Daniel Jalkut has been working on MarsEdit 2.0 for quite some time, and I have to say the results are spectacular. The blog post window has been much improved, and now includes the ability to add new blog categories without going to my WordPress admin interface. This feature alone is worth the upgrade price. Overall, the app seems a lot slicker, and blends into Tiger very nicely.

Next is Gus Mueller’s newest application, Acorn. I was fortunate enough to be shown a demo of a beta version back at C4 last month. This really is a good alternative to Photoshop Elements. It’s easy to use, has a very clean interface, and has some advanced features like Layers and Core Image filters. Definitely give Acorn a look-see, and take advantage of the introductory pricing offered.

Using Compressed Textures in OpenGL

I’m not sure if it’s just me, but for some reason OpenGL coding involves a lot of trial and error before getting a feature such as lighting, blending, or texture mapping to work correctly. The past few days I have been working on adding texture compression to my OpenGL map test project. Ultimately, this code will be merged with the rest of the Seasonality source tree, and it’s going to look pretty cool.

Most OpenGL developers will use regular images and possibly compress them when loading them as a texture on the GPU. This is fairly straightforward, and just involves changing one line of code when loading the texture. Note that this is a huge gain when it comes to graphics memory savings, as I was using about 128MB of VRAM when texture compression was disabled and only around 30MB with compression enabled. I wanted to accomplish something a bit more difficult though. I’m going to be using several thousand textures, so I would like to have OpenGL compress them the first time Seasonality is launched, and then save the compressed images back to disk so concurrent launches will not require the re-compression of the imagery.

The problem I ran into was not enough developers are using this technique to speed up their application, so sample code was scarce. I found some in a book I bought awhile back called “More OpenGL Game Programming,” but the code was written for Windows, and it didn’t work on Mac OS X. So I dove deep into the OpenGL API reference and hacked my way through it. The resulting code is a simplification of the method I’m using. It should integrate with your OpenGL application, but I can’t guaranty this completely because it is excerpted from my project. If you’re having a problem integrating it though, post a comment or send me an email.

First, we have some code that will check for a compressed texture file on disk. If the compressed file doesn’t exist, then we are being launched for the first time and should create a compressed texture file.

- (bool) setupGLImageName:(NSString *)imageName
         toTextureNumber:(unsigned int)textureNumber
{
   GLint width, height, size;
   GLenum compressedFormat;
   GLubyte *pData = NULL;

   // Attempt to load the compressed texture data.
   if (pData = LoadCompressedImage("/path/to/compressed/image", &width, &height,
       &compressedFormat, &size))
   {
      // Compressed texture was found, image bytes are in pData.
      // Bind to this texture number.
      glBindTexture(GL_TEXTURE_2D, textureNumber);

      // Define how to scale the texture.
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

      // Create the texture from the compressed bytes.
      glCompressedTexImage2D(GL_TEXTURE_2D, 0, compressedFormat,
                             width, height, 0, size, pData);


      // Define your texture edge handling, here I'm clamping.
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      // Free the buffer (allocated in LoadCompressedImage)
      free(pData);
      return YES;
   }
   else {
      // A compressed texture doesn't exist yet, run the standard texture code.
      NSImage *baseImage = [NSImage imageNamed:imageName];
      return [self setupGLImage:baseImage toTextureNumber:textureNumber];
   }
}

Next is the code to load a standard texture. Here we get the bitmap image rep and compress the texture to the GPU. Next we’ll grab the compressed texture and write it to disk.

- (bool) setupGLImage:(NSImage *)image
         toTextureNumber:(unsigned int)textureNumber
{
   NSData *imageData = [image TIFFRepresentation];
   NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:imageData];
   // Add your own error checking here.

   NSSize size = [rep size];
   // Again, more error checking.  Here we aren't using
   // MIPMAPs, so make sure your dimensions are a power of 2.

   int bpp = [rep bitsPerPixel];

   // Bind to the texture number.
   glBindTexture(GL_TEXTURE_2D, textureNumber);
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   // Define how to scale the texture.
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   // Figure out what our image format is (alpha?)
   GLenum format, internalFormat;
   if (bpp == 24) {
      format = GL_RGB;
      internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
   }
   else if (bpp == 32) {
      format = GL_RGBA;
      internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
   }

   // Read in and compress the texture.
   glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
                size.width, size.height, 0,
                format, GL_UNSIGNED_BYTE, [rep bitmapData]);

   // If our compressed size is reasonable, write the compressed image to disk.
   GLint compressedSize;
   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
                            GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
                            &compressedSize);
   if ((compressedSize > 0) && (compressedSize < 100000000)) {
      // Allocate a buffer to read back the compressed texture.
      GLubyte *compressedBytes = malloc(sizeof(GLubyte) * compressedSize);

      // Read back the compressed texture.
      glGetCompressedTexImage(GL_TEXTURE_2D, 0, compressedBytes);

      // Save the texture to a file.
      SaveCompressedImage("/path/to/compressed/image", size.width, size.height,
                          internalFormat, compressedSize, compressedBytes);

      // Free our buffer.
      free(compressedBytes);
   }

   // Define your texture edge handling, again here I'm clamping.
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

   // Release the bitmap image rep.
   [rep release];

   return YES;
}

Finally we have a few functions to write the file to disk and read it from the disk. These functions were pulled almost verbatim from the OpenGL book. In the first code block above we called LoadCompressedImage to read the texture data from the disk. In the second code block, we called SaveCompressedImage to save the texture to disk. Nothing really special is going on here. We write some parameters to the head of the file, so when we go to read it back in we have the details. Bytes 0-3 of the file are the image width, 4-7 is the image height, 8-11 is the format (GL_COMPRESSED_RGB_S3TC_DXT1_EXT or GL_COMPRESSED_RGBA_S3TC_DXT5_EXT), 12-15 is the size of the image data in bytes, and bytes 16+ are the image data.

void SaveCompressedImage(const char *path, GLint width, GLint height,
                         GLenum compressedFormat, GLint size, GLubyte *pData)
{
   FILE *pFile = fopen(path, "wb");
   if (!pFile)
      return;

GLuint info[4];

info[0] = width;
info[1] = height;
info[2] = compressedFormat;
info[3] = size;

fwrite(info, 4, 4, pFile);
fwrite(pData, size, 1, pFile);
fclose(pFile);
}

GLubyte * LoadCompressedImage(const char *path, GLint *width, GLint *height,
GLenum *compressedFormat, GLint *size)
{
FILE *pFile = fopen(path, “rb”);
if (!pFile)
return 0;
GLuint info[4];

fread(info, 4, 4, pFile);
*width = info[0];
*height = info[1];
*compressedFormat = info[2];
*size = info[3];

GLubyte *pData = malloc(*size);
fread(pData, *size, 1, pFile);
fclose(pFile);
return pData;
// Free pData when done…
}

Hopefully this will save someone development time in the future. If you catch any errors, let me know.

Precipitation Intensity

Today I revisited the code on the Seasonality forecast server that decides on precipitation intensity. I.E., how much rain does it take to have a drizzle, light rain, moderate rain, or heavy rain? This is forecasted in 12 hour blocks, and I take the sum of precipitation over that time frame to get a total precipitation for that block of time.

Previously the intensity chart looked something like this:

  • 0 – 3mm: Drizzle
  • 4 – 7mm: Light Rain
  • 8 – 25mm: Moderate Rain
  • > 25mm: Heavy Rain

What I found was the GFS model output would often place a millimeter or two of precipitation at random locations and this would trigger a “drizzle” forecast far too often. I decided that I needed to revisit the precipitation intensity chart.

I ended up finding this page at the MetOffice (United Kingdom). They have about twice as many intensity categories, from Very slight to Downpour, so I tried to adapt them to my intensity names (which match those of the NDFD forecasts put out by the U.S. National Weather Service). I ended up using these values:

  • 3 – 6mm: Drizzle
  • 7 – 12mm: Light Rain
  • 13 – 25mm: Moderate Rain
  • > 25mm: Heavy Rain

We’ll try these out for awhile to see how accurate they are. If you’re a Seasonality user, these changes were made all on the forecast server, so no software update is necessary.

A Weather Developer's Journey Begins!

A few months ago an idea came to me for a new domain name I should pick up. I wasn’t sure what I was going to do with the domain yet, or if I would even use it at all, but I wanted to jump on it because it was available. It struck me as a good name, and I was a bit surprised that it was still available.

Zoom forward to a couple of weeks ago, when a different idea for a new website came to mind. Oftentimes I post detailed entries here specifically about the weather or very weather-tech related articles when I run into issues while developing Seasonality. The thing is, I’m not sure my typical reader is interested in these postings, and occasionally I will refrain from posting about weather-related issues simply because I don’t think it would fit well in the *Coder blog.

But wait a second…I bought that domain awhile back, maybe that would work. Actually, it ended up being perfect for my new site idea. So I started working on it off and on. I’ve been happily using WordPress to host this blog for quite some time, so I decided to use the same platform for the new site. I set things up, customized a theme, and wrote a posting or two. I think now it is finally ready to be revealed, and I wanted to share. The domain is weatherdeveloper.com, and the site is called “A Weather Developer’s Journey.” With the full-time development of Seasonality 2 coming soon here, I thought it would be a perfect time to start a site like this, as I’ll be spending a lot of time trying to overcome issues with data hosting, manipulation, and weather visualization.

If you’re at all interested in checking it out, please do so (Website, RSS Feed). I’ll most likely post links from here to the first few articles on the new site, just to get the ball rolling. The first article talks about finding and putting to use 90 meter elevation data.

« Older posts Newer posts »

© 2026 *Coder Blog

Theme by Anders NorenUp ↑