Latest Browser Stats for November 2011

Overall Stats

I separated out mobile devices and tablets here, since to me they are vastly different devices and its a mistake to lump them. But I also grouped all different specific mobiles and tablets to make it more clear the trend.

You see our audience continues to be ahead of the overall curve from wider stats we see of the internet. Our audience is younger and more tech savvy and weighted heavily in the education system. For that reason, I think, we see a few things: faster adoption of mobile/tablets, accelerated downtrends of Internet Explorer, and higher use of Safari (more Mac usage than average, see our operating system stats below).

I am actually closely watching and very interested in the small (but somewhat growing) percentage of TV console users. Right now Wii is about 60% of that market, PlayStation 3 about 28%, Google TV about 10%, and then other makers like Samsung and other embedded TV OSes with tiny slices. Wii is based on a version of Opera and is really difficult to work with. Google TV’s Chrome version is pretty decent. Not sure about PlayStation 3… need to research that one. I think this space at some point will be really important as HTML 5 browsers on TVs get larger we will be able to create compelling new experiences targeted at the large screen.

Closer Look at Internet Explorer Users

Keep in mind these percentages above are of the 35% of our users on Internet Explorer. So when you see that 14% are using Version 7, that actually represents 5% of our total user base. So that’s pretty encouraging.

Interestingly Version 6 usage seems to be leveling out. I haven’t see a drop in its relative share for several months now. Basically, it seems like IE 6 users either can’t upgrade, don’t want to, or don’t know how.

The biggest trend here we are seeing is IE 8 and to a lesser degree IE 7 users moving toward IE 9. That is very encouraging…. especially IE 7 decreasing at a steady pace. Our policy is currently that we do not support IE 6 at all. If it works for them great, but we can’t test it and won’t attempt to debug issues with that browser. For IE 7 the policy is currently in flux… it is going from full support (which was policy at the start of the year) to now one of attempting to make the site functional to its users, but NOT attempting to make it visually similar. We are attempting a graceful degrade policy and considering really stripping down the experience via alternate stylesheets for IE 7 users. That is the current path. We will probably have to partially support the browser for another couple of years before it can be completely cut out.

Mobile Browsers

Interesting little chart to see… not surprising. Our audience seems to favor Apple products more than the national average, which shows Android and iOS much closer. But Android does continue to close the gap for our users as well. BlackBerry has continued to fall off the planet. Windows Phone hasn’t gotten any traction for us yet.

Desktop/Laptop Operating Systems

This is really not relevant for us as far as how we design the site. But it is none the less interesting to see how it breaks out. Again this shows how our users are more largely Apple fanboys. 🙂

Not visible on the chart, but we saw a few alternative OSes ringing in… UNIX, SunOS, a small spike lately for ChromeOS (“Chrome Books”), and other crazy ones like OS/2 and AIX!

Posted in Browsers, Technology, Web Trends | Leave a comment

Contributing to Open Source Community

We have done some more work in our quest to open source some of our projects…

MileSplit Open Source Projects Page

Posted in Open Source, Technology | Leave a comment

Open Source Project: Prereq

We at MileSplit are developing a lot of what I can foundational code right now. We’ve been rewriting a lot of what our base platform and framework is, slowly having this huge reusable object oriented base to build upon going forward. Sometimes it feels like we’re moving too slowly because of this, but in the end it will pay off.

Part of what we want to do with a portion of that foundation is make a concerted effort to open source some of these items.

Several months ago I did open source one small, but powerful little bit of code that we wrote… and that I personally love. It is called Prereq. It is, yes another script loader. It allows you to load scripts asynchronously, control the order of load, and have script to executes after certain pieces have loaded.

There are a lot of others out there like it (LabJS, HeadJS, YepNope, and plenty more), but there were none that really met my goals and only my goals:

Focused in its purpose: don’t get sucked into doing more than just loading scripts.
Event based
Simple syntax handing for dependencies and callbacks
Load all scripts right away (with some exceptions)
Be able to define the requirements in the external js file… for more modularization
Don’t get sucked into trying to support every old browser known to man. If they’re still using IE5 or Netscape they are used to sites not working.
Keep it as small as possible.

Here is the project in GitHub: https://github.com/milesplit/Prereq

Posted in JavaScript, Open Source, Technology, Uncategorized | Leave a comment

One of our own gets married

Beach Wedding

Last week Todd Grasley, a multimedia producer at MileSplit, married his bride Stacy and now the two are off on their honeymoon on a Mediterranean Cruise.

Here are some photos from the wedding and reception. For those of you not from Florida, the beach wedding may seem amazing… for us, it’s typical. Yes, we live in paradise. And, yes, Jimmy Buffet music was playing in the background pretty much the whole time.

It was a great time meeting new friends and members of our co-worker’s family. One thing that I did learn, which should have been obvious from the pathetic attempt at karaoke I saw on in NYC after New Balance Indoors, is that Todd is perhaps the only person on the planet who dances worse than me. I didn’t think that was possible! After the entire song completed, I still don’t think he got the letters to YMCA right once.

Congrats Todd and Stacy! Safe travels and come home soon!

Posted in MileSplit Corporate Culture | Leave a comment

ArmoryTrack to Regain Independent Status in August

Press release we are sending out this morning.

—–

FOR IMMEDIATE RELEASE

ArmoryTrack to Regain Independent Status in August

JUNE 18, 2011 – NEW YORK CITY, NY

Four years ago, ArmoryTrack.com (a division of the Armory Foundation) joined MileSplit as the network’s New York affiliate site. That chapter in the site’s history will come to a close in August when ArmoryTrack will once again operate as an independent publication.

Dr. Norbert Sander, president of the Armory Foundation, says the affiliation has been a positive one for their organization and the decision to leave was not an easy one.

“The Armory Foundation has been proud to partner with and (has greatly benefited) from our four year collaboration with MileSplit. The addition of invaluable technology by MileSplit has created a wonderful service to our thousands of young runners and field athletes from throughout New York State,” said Sander.

Despite the successful relationship, which has given rise to unprecedented levels of coverage and soaring traffic for both the ArmoryTrack affiliate and the MileSplit Network as a whole, Sander says that the organization needs to refocus its efforts.

The core purpose of the site has always been to bring awareness to the many meets, programs, and outreach efforts going on at the Armory, a New York City landmark that Sander helped salvage from disrepair in the early ‘90s. The practicing doctor and former New York City Marathon winner stated further the decision centered on their “regional impact and need to continue development and coverage of the many programs specific to the Armory.”

MileSplit founder and CEO, Jason Byrne, admitted he was disappointed when he found out that the Armory Foundation would not be renewing its contract; however, believes in the end it may be what’s best for both groups.

“We have really enjoyed being affiliated with such a stellar group and have forged some really great friendships as well,” Byrne explained, “the Armory has been a tremendous success story and a pillar in our sport and it’s been great to work with them. However, I fully understand their need to reemphasize their focus on their immediate goals and the mission of the venue and the Foundation more directly.”

Byrne though insists that MileSplit’s coverage of the state of New York is anything but over. “Absolutely not, we will be re-branding our New York portal and looking for a new team to maintain our presence in the Empire State. I think it’s an opportunity for us, for the Armory, for an aspiring new webmaster, and for the state of New York.”

While ArmoryTrack will no longer be a direct member of MileSplit, both groups unequivocally state that the working relationship will continue to thrive. “We are already talking about ways we can continue to partner (with them)”, says Byrne, “and we stand with them in their goals of promoting and growing the sport.” Sander concurs and says the Armory Foundation “will continue to work closely with MileSplit to enhance their mission of great dedication to their viewers… our profound thanks to Milesplit… for their professionalism and creativity. We will all continue to work together in service of this great sport.”

Anyone interested in potentially being the new editor(s) of MileSplit’s re-branded New York affiliate is encouraged to contact MileSplit COO Don Rich by emailing inquiries to jobs@milesplit.com for more details. Ideal candidates are experienced with (or eager to learn) media in its various forms (written, video, photos), bring an entrepreneurial spirit, can work a flexible schedule, and—according to Byrne’s description–are “multi-tasking, stat-junky, social networking ninjas with a passion for track & field (especially on the high school level)”.

# # #

ABOUT ARMORY FOUNDATION

The Armory Foundation, a NYC not-for-profit and home to the premier indoor track and field center in America, is committed to serving youth by promoting excellence and fitness through a broad range of athletic, educational and community programs.

The Armory Foundation’s primary emphasis is reaching and motivating the youth of all five boroughs by offering them competitive track and field activities and broadening their horizons with computer classes, college preparation programs and a variety of cultural and school-coordinated educational activities.

The Armory Foundation promotes excellence, fitness and community by hosting over 100 track events each year, maintaining the National Track and Field Hall of Fame, operating the largest after school activity center in New York and offering a variety of community support programs in its world class facility.

Contact:
http://armoryfoundation.org/
Rita Finkel, rita@armorytrack.com, (212) 923-1803 x32 (office)

ABOUT MILESPLIT, INC.

MileSplit is the premier network for high school track & field and cross country. We believe that the heart of the sport is on a local, grassroots level. By facilitating the publishing and business process for our state affiliates, we are able to provide in depth state-by-state coverage of the sport. At the same time, these state portals feed content into a national database allowing us to provide an unprecedented depth of coverage on the national level.

Designed around powerful proprietary database software that unites all of the important aspects of covering the sport–results, rankings, articles, videos, photos, statistics, etc.–MileSplit is the only online publisher in the sport with the tools to provide a high level of timely and comprehensive nationwide coverage.

MileSplit, Inc. is a privately held Florida corporation. Its corporate offices are located in the Sanlando Center in Longwood, Florida (just north of Orlando) and overlook the Seminole Wekiva Trail.

Contact:
http://www.milesplit.com/help/about/contact
Jason Byrne, jbyrne@milespilt.com, (877) 833-7223 x601 (office), (321) 385-7223 (mobile)

Posted in Business, Press Release | Leave a comment

Traffic Trends, May 2011: Mobile Surges 40%, IE Continues to Fade

In our last traffic trends update in March, we saw Internet Explorer drop below 50% of our traffic share for the first time in history and we saw mobile continue its rise. Since then we’ve seen both trends accelerate. Just under 46% of our traffic now originates from the inferior Microsoft browser–with IE 9 adoption starting to get a little hold, while IE 6 dies a slow painful death (finally!). Meanwhile, mobile and tablet traffic has continued to rise and soared 40% in just the two months from March to May! For the first time portable devices are contributing more than 10% of our traffic.

To a smaller degree Firefox has picked up some ground on both the Windows and Mac platforms, as has Chrome. Windows overall has given up a single percentage point to Mac. Android has darn near caught up with iPhone on the mobile statistics–though if you throw in iPod Touch users it’s still lagging by quite a bit. We have not seen TV/Consoles gain any ground between Wii, PlayStation 3, or Google TV. On the tablet scene, the iPad numbers continue on a steep incline with a 30% increase in two months while Android tablets such as the Xoom have yet to really even make a blip on the radar screen, with the tablet version of Android (3.x) representing less than 1% of Android visits.

Posted in Browsers, Mobile, Technology, TV, Web Trends | Leave a comment

Conversion Calculator Available in the Android Market

Our first mobile app (of many to come) is now available for sale in the Android Marketplace for $2.99 and will be coming to the Apple App Store as soon as possible (once we clear Apple’s lengthy approval process).

This is a really handy little app to convert between similar distances to see equivalent times, some simple pacing information on the K and Miles, and for field events converts english to metric and metric to english for you.

It’s actually just kind of fun to play with also. The app is intuitive in that it guesses what you want. And also everything updates live meaning you can get the info faster, play around more, and don’t have to hit a button every time you want to convert.

I think it will be very useful for fans, athletes, and coaches… and not just because I wrote it. We will be looking to release a whole line of apps this summer.

Check it out in the Android Market…

Posted in Mobile, Press Release, Site Updates, Technology | Leave a comment

Simple Time Broadcast Server with Node.JS

Server on the right, two clients on the left.

I think Node.JS is really going to re-invent the way the web works. It’s not the end-all be-all by any means, but it has such great possibilities to leverage JavaScript on the server side and create very responsive web applications. At very least I think its core concepts are going to be the new design of next generation web programming.

Most developers have at least some experience with JavaScript… whether they are server-side, client-side, backend… shoot even designers! Most everyone has used JavaScript at some point. As I see it though most developers will have the following two problems with Node…

1) Most people who think they know JavaScript are actually really really terrible at it. Most learned the basic stuff of how to manipulate something on a page, but never learned it correctly. It is such a flexible language that it can let you get away with it. But people like John Resig have totally re-invented the language and shown us how to make it really elegant and object-oriented.

2) Node is so totally different from any other server-side language that most have dealt with. All common server-side languages (and frankly how most people write client-side JavaScript also) is synchronous… meaning everything moves in a straight line. Node is event-based and asynchronous. So it is jumping all over the place, waiting for one event to complete while it does something else, then jumping back to complete the other thing. On the server side, it makes use of callbacks much like you would AJAX on the client side.

So anyway… it makes so much sense and yet it is such a hard concept to grasp because it’s the opposite of how we’ve been trained in server-side programming since the dawn of the WWW.

Back to the main point of the article! To give you an example of the latest Node experiment…

I wanted to write a simple TCP server that allowed clients to connect to it and subscribe to messages that it published. So it maintains a continuous connection and the server pushes out updates to its clients (which I am calling subscribers). The easiest thing was just to make a time server that pushed the current system time out every two seconds. But the messages could be pushed out in any interval or most likely in a real world case not at a set interval but when a certain event occurred or a command was sent to the server.

Here is the main root/index of the server:


// get our custom broadcast server module
var my = require('./broadcast_server');
// Instantiate the server, passing the port to listen on
var server = new my.BroadcastServer(7000);
// Send time every 2 seconds
setInterval(function() {
var now = new Date();
server.broadcastMessage(now.toTimeString());
}, 2000);

So as you see, it includes my custom module (broadcast_server.js) with the require function. It then instantiates a new instance of that BroadcastServer object, and then it just starts a timer so that every two seconds it will call the broadcastMessage method of that server object to push the current time to all of the subscribers.

Now here is the broadcast_server.js module that does all of the hard work…


// Get net module
var net = require('net');
// Remove from array
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
// Our server class
exports.BroadcastServer = function(port) {
var Me = this;
// Private variables
var subscribers = [];
var server;
// Private: initialization method
var init = function() {
server = net.createServer(onNewSubscriber);
server.listen(port);
console.log("\nListening on port " + port + "\n\n");
return Me;
};
// Private: called when new client connects
var onNewSubscriber = function(stream) {
// Initialize stream
stream.setTimeout(0);
stream.setEncoding('utf8');
// When subscriber connects
stream.on('connect', function() {
subscribers.push(stream);
stream.write("~~~~~~~~ WELCOME TO THE TIME SERVER ~~~~~~\n");
stream.write('You are subscriber #' + subscribers.length + "\n");
stream.write("\n\n");
console.log('New subscriber: ' + subscribers.length + " total.\n")
});
// When subscriber disconnects
stream.on('end', function() {
subscribers.remove(stream);
stream.end();
console.log('Subscriber left: ' + subscribers.length + " total.\n");
});
};
// Public: method to push message to all clients
Me.broadcastMessage = function(msg) {
subscribers.forEach(function(s) {
s.write(msg + "\n");
});
};
// initialize and return self
return init();
};

I won’t go line by line, but basically we are defining a class called BroadcastServer and we pass in an argument telling it what port to listen on. The init method instantiates that server and tells it to listen on that port. The onNewSubscriber method handles create that new connection, saves it to our subscribers array, sends it an initial welcome message, and handles removing them as a subscriber when that connection is terminated. Notice those two methods are private. Finally, we have our only public method which is broadcastMessage. It just accepts the message argument and handles distributing that message to all of the connected subscribers.

You may wonder what the whole “exports” deal is about. When creating a module like this, Node does not let you put things into the general global object… which is a very good thing! It forces us to do better programming with namespacing! So we specifically tell it what we want to expose to the main thread. Back on our initial js file where we included this module, we defined that it would go into the my namespace.

If you have any questions about this example, please let me know.

Posted in Node.JS, Technology | 2 Comments

Experimenting with Node.JS

We are always trying to stay on top of the latest. And one of the hottest buzz words in super-geeky circles has been Node.JS. The thought of using the same programming language on both the server-side and client-side is highly appealing. And coupled with some of the stuff Appcelerator is doing to bring Javascript to native mobile app and desktop app development quite frankly is drool worthy!

Being already familiar with Javascript and specifically the AJAX variety, Node perhaps wasn’t as hard for me to grasp on to as it would be others. You have to break out of your normal programming mindset where things happen in a linear fashion. Node is event-based and asynchronous. That means multiple things are happening at once and you have to use callbacks to process them. It really is a completely COMPLETELY different way to program. But it’s a good way in my opinion.

The other interesting thing about Node is that node BECOMES your web server. You are actually writing the web server! It’s not Apache or Lighttpd or Nginx hitting node… it is your users directly calling node and node handling the request. In my opinion this is another plus because web servers (especially Apache) come with extra baggage. This is straight to the point and you control it end to end. No unnecessary libraries or modules. You decide.

We may look at eventually migrating some of all of our server-end stuff at MileSplit to Node. Time will tell. So here is my first attempt to use it. Pretty please to go from zero node experiences to this in just a night. I invested about four hours into this tonight and developed a web server and web site called “What they sayin bout…”, which is basically just a service to search Facebook status posts. It serves up 404s if you call anything but the root, it serves and index page with a search for, and then of course after you search it shows you the latest status messages that included your search term.

And finally here’s my code… maybe it will help someone…

// Required
var http = require('http'),
sys = require('sys'),
url = require('url'),
path = require('path'),
events = require('events'),
fs = require('fs');

// Settings
var ipAddress = '127.0.0.1';
var port = 8080;

// Facebook client
var fb_client = function() {
var client = http.createClient(80, 'graph.facebook.com');
var me = this;
this.get = function(term) {
console.log('connecting to facebook...');
var request = client.request('GET', 'search?type=post&q=' + term, { 'host':'graph.facebook.com' });
request.on('response', function(res) {
var json = '';
res.on('data', function(data) {
if (data) {
json += data;
}
});
res.on('end', function() {
console.log('data complete.');
if (json) {
var data = JSON.parse(json);
//console.log(data);
me.emitter.emit('results', data);
}
});
});
request.end();
return me;
};
this.emitter = new events.EventEmitter();
return me;
};
var fb_request = function(response, q) {
var client = new fb_client();
response.write(
'<html><head><title>What they sayin bout.. ' + q + '</title>' +
'<style>li p { display: block; padding: 0; font-size: 13px; margin-left: 60px; margin-top: 0; margin-bottom: 0; }' +
' li { margin: 0; padding: 5; list-style: none; }' +
' li:nth-child(odd) { background: #d0d0d0 } li:nth-child(even) { background: #efefef }' +
' li b { }' +
' ul { list-style: none; margin: 0; padding: 0; }' +
'</style></head><body>' +
'<h1>What they sayin bout...' + q + '</h1>' +
'<form method="get">' +
'<p><input type="search" name="q" value="' + q + '"><button type="submit">Search</button></p>' +
'</form>'
);
client.get(q).emitter.on('results', function(json) {
var len = json.data.length;
if (len > 0) {
response.write('<p>' + len + ' results found.</p>');
response.write('<ul>');
for (var i=0; i < len; i++) {
var post = json.data[i];
var dt = new Date(post.created_time);
var hours = (dt.getHours() > 12) ? dt.getHours() - 12 : dt.getHours();
var min = (dt.getMinutes() < 10) ? '0' + dt.getMinutes() : dt.getMinutes();
response.write(
'<li style="clear: left">' +
'<img src="http://graph.facebook.com/' + post.from.id + '/picture" align="left" />' +
'<p><b><a href="http://www.facebook.com/profile.php?id=' + post.from.id + '">' + post.from.name + '</a></b></p>'
);
if (post.type === 'status') {
response.write('<p>' + post.message + '</p>');
} else if (post.type === 'link') {
response.write('<p><a href="' + post.link + '">' + post.link + '</a></p>');
} else {
response.write('<p>' + post.message + '</p>');
}
response.write('<p><small>At ' + hours + ':' + min);
try {
response.write(' via ' + post.application.name);
} catch (e) {
// Ignore
}
response.write('.');
if (typeof post.likes != 'undefined') {
response.write(' ' + post.likes.count + ' likes.');
}
response.write(
'</small></p>' +
'</li>'
);
}
response.write('</ul>');
} else {
response.write('<p>No results found.</p>');
}
response.write('</body></html>');
response.end();
});
};

// Handle requests
var handleRequest = function(request, response) {
var uri = url.parse(request.url, true);
if (uri.pathname === '/') {
response.writeHead(200, {
'content-type': 'text/html'
});
if (uri.query.q) {
console.log('search for ' + uri.query.q);
fb_request(response, uri.query.q);
} else {
console.log('serve index page');
response.write(
'<html><head><title>What they sayin bout...</title></head><body>' +
'<h1>What they sayin bout...</h1><form method="get">' +
'<p><input type="search" name="q" ><button type="submit">Search</button></p>' +
'</form></body></html>'
);
response.end();
}
} else {
console.log('404: ' + uri.pathname)
response.writeHead(404, {
'content-type': 'text/html'
});
response.write(
'<html><head><title>What you lookin fo...</title></head><body>' +
'<h1>404 fool...</h1>' +
'<p>We got no page like dat. Keep on walkin...</p>' +
'</body></html>'
);
response.end();
}

};

http.createServer(handleRequest).listen(port, ipAddress);

console.log('Server running at http://' + ipAddress + ':' + port);

Posted in Node.JS, Technology | 1 Comment

Mobile Development with Appcelerator

Appcelerator iconIn part of the next phase of our development of RaceTab, I have started developing the mobile companion apps to go with it. My first instinct was to skip the App Store route and just go pure browser-based HTML5. With both major platforms having their browsers based on WebKit and with all of the HTML5 buzz momentum, it seems like the natural thing to do.

I held on to that belief that the future of mobile apps lies in the mobile web rather than the app store. Still I feel very strongly that HTML5 is pointing the way toward the future and developing in the browser for many cases is prudent… especially perhaps in the future. But at this time there are a lot of limitations that the browser brings and mobile web browsers–especially Webkit–have not evolved quickly enough. Browser-based apps in my testing are less responsive than native apps. Additionally they are limited as far as what features of the device they can access. And it can be quite hack-ish to get things working consistently and fluidly on all devices and without being able to implement native UI controls.

I looked at the possibility of developing in Adobe Flash/Flex for a while. But I hated the idea of having to rely on a third party runtime and framework that would have to be installed (at least on Android). This gave me performance concerns as well–besides the fact that it just wouldn’t act native.

I looked at PhoneGap and some other things…. but finally settled on Appcelerator.

In all honesty, I have a love-hate relationship with Titanium Appcelerator right now. I think it’s great… when it works right. Unfortunately, the documentation is terribly inconsistent, incomplete, and sometimes inaccurate. It is also lacking in hardly any examples. I have found the best route is just to go straight to the KitchenSink example app and only go to the API Reference or Q&A section as a secondary information source, as the technology is moving so quickly both are out-dated by the time you read them.

My other beef with Appcelerator is that, since it was written for iOS first, the Android implementation is somewhat limited. You have to work around what features are available on that platform.

Now with the negatives out of the way, there are a lot of reasons to love Appcelerator…

1) Cross-Platform… though I’m going to need to buy a Mac to finish the development and deployment to compile for iOS and the Apple App Store, it is possible with the same codebase to deploy to both (and soon Blackberry and Windows Phone 7 supposedly)

2) It is native… they implement the native code and controls so that it looks authentic. Actually because it IS authentic! Cool!

3) JavaScript-based! This seems to be a trend and I long for the day that we have Javascript in the browser, Node.JS running on the server, and JS in our mobile development! If you are good at JavaScript (which everyone THINKS they are, but few people actually are) you can write modularized, namespaced, extensible, and object-oriented JS code. If you do then you will find that some of the same code that you write for mobile will be able to be used in the browser (and only the server if we implement Node)… and vice versa. This is freaking awesome!!

4) Lots of potential. This is open source with a professional edge. If they get their stuff together and give us some compelling reasons then we will definitely subscribe to their professional version. They also just acquired Aptana, the makers of a very popular IDE. Really I think they have some good momentum, funding… and hopefully they follow through. If so we could be looking at a really amazing company that could be a huge player in development of the future. They also have desktop development through their platform…. mobile, browser, desktop, server… all the same platform? Wow! It could happen.

More on Appcelerator…

So what now?

I’m building out the first app and along with it I’m building a pseudo-MVC framework that I will build all of the future apps off of as well. I may release the source of the framework, who knows! I am going to to try to get this in the Android Market as soon as possible and then will have to get my hands on a Mac to deploy it to the App Store.

Let me know your thoughts.

Posted in Mobile, Technology | 2 Comments