Futureshock-ed http://blog.futureshock-ed.com Notes about technology and innovation posterous.com Sun, 29 Jan 2012 00:06:00 -0800 The evil of capitalism crushing the "common" folk and those that find it unfair. http://blog.futureshock-ed.com/the-evil-of-capitalism-crushing-the-common-fo http://blog.futureshock-ed.com/the-evil-of-capitalism-crushing-the-common-fo

When my migrant grandparents moved to Australia in the 1950s, they worked 7-day weeks, 12 hours per day, at least. My grandmother worked in a textile factory ran by a wealthy family of earlier migrants. My grandfather worked wherever there was work, often in the western outback for months at a time.

 

From the stories they told me, it wasn't fun. Noise, sweat, long hours, boredom from the repetive work. My grandmother did mention several tough, unfair and stingy (at least in the salary department) bosses. But, they were happy there was work, and they gladly took it. Overtime, they built up their savings and they didn't have to worry about all that, but they continued living a simple and self-sustainable life. They didn’t need much; some food on their table and a roof over their heads.


The world had just changed back then. It was the aftermath of the 2nd World War and of a civil war back home. Things were uncertain, but there was relative peace, relative safety, and plenty of work. In Australia, that is, because other parts of the world were either still devastated or dealing with other deadly and destructive wars and conflicts. The old country had yet to recover, and the United States and the Soviet Union dominated world politics. But my grandparents were simple people, they instinctively knew that given work and safety, every thing would  magically "work out". They didn’t expect much help, other than the aforementioned basics, from their bosses or their government or some other nebulous but powerful organisation. If they wanted a better life, it would have to be because of their hard work.


Fast forward to today, and we find ourselves amidst a tectonic change in the way that the world works. Europe is in crisis (really, nothing new here), regional wars raging, dictators waging their fists in rage, religious fundamentalism as powerful as back in the good old middle ages in many parts of the world, conspiracy theories “explaining” every new development in the economy or politics as the implementation of a plan by certain powerful elites (usual, bankers) to take over the world and turn humans into some sort of battery, and, gasp, the emergence of China and the Far East as the new economic center of gravity.


This essay was triggered by a discussion with a few friends about the apparent unfairness of the migration of manufacturing work to the East, and especially to China, which was itself triggered by this NY Times article. In this discussion, all of the above points were raised as if they are facts perfectly connected with each other. It all accumulates to this: it is in the interest of multinational organisations to reduce our standard of living, and we are powerless to do anything about it.


It started when a friend, disturbed by the ruthlessness of a certain multinational company, complained:


How do you reconcile the fact that workers making iphones for $17 per day, sleeping in the factory, a company that makes 75b profit saying that it has no responsibility to employ people in the US because of inflexible practices!


At first look, this really does seem unfair. Getting $17 per day for my work would not be enough for my train ticket to work. A rich company could certainly pay its workforce a little bit more. And the same company should certainly do more of its business in a particular country of the world as an indication of its loyalty and patriotism.


But on second examination, there are so many wrong assumptions in this statement that are so easy to overlook when you emotionally glance at it and not make the effort to look at the facts. For example, when I lived in Hong Kong for a short period of time back in 2006, sharing a dormitory room with two Chinese students, I would spent around $5 per day on three meals at the university canteen, and around $1 on the room. And Hong Kong is expensive compared to places like Schenzen where most of this company's products are made. It seems like $17 per day is good money for an unskilled 18yo worker from a village in central China. I doubt my grandparents were getting much more than that working in Australia as unskilled workers in the 1950s.


Then, the fact that a company is filthy rich, does not require this company to pay more unless it really has to. Securing plenty of unskilled labour in China does not seem to be a problem, therefore such labour can be secured for a very small price. Simple economics show that prices of any commodity, including labour, find an equilibrium with depends on the ratio of demand vs supply. This does not include the amount of cash in the buyer’s bank account.


Finally, it is common sense that organisations, just like people, will try to maximise their potential even if that means leaving the shores of their home country. My ancestors did that many times by migrating in 5 different countries around the world. And all of them are still deeply patriotic about their home country. Prosperity and patriotism does not seem to mutually exclude each other when it comes to people making important personal decisions; why should large organisations, which by definition are multinational due to the composition of their workforce, be any different?


In any case, the friend’s argument seemed to be mainly targeting the unfairness of the corporation against “exploited workers”. A little bit like my grandparents sixty years ago. But look at what happened to my grandparents after they gratefully took that money, put their head down, and worked to their limits: many of their descendants are now living in an affluent society expecting to be paid handsomely for working as little as possible so they can live a comfortable and secure life, free of worries about what tomorrow brings.  These decedents are also fortunate enough to be able to show signs of sympathy for others who, like their grandparents, are today working in similar (a relative term since no Shenzen equivalent has ever existed in Australia) conditions to build their own future so that their own descendants can one day live the lives we live.


It is also easily forgotten that it is because of people like my grandparents that the average modern latte-sipping 40-year old expects that their employer is obliged to pay them to drink lattes and engage in philosophical discussions about fair and unfair trade practices or evil and good enterprises, pay their mortgages and get their kids through private schools. My grandparents, with all their hard work, created generations of people that expect that things will always be as they used to be, safe, wealthy, easy.


But my friend countered:


What goes around comes around, lets see what you do when wage deflation hits your front door....while the people asking you to cut eat more than ever!


A common defence of people without strong arguments to support their position is the claim that enough time, their position will be justified. They believe that 15,000 years of "civilised" human history and society haven't got anything to teach us about modern affairs, and that this present argument of the evil of capitalism and unfairness of the changing global economic dynamics cannot be analysed or settled with the data available now. Loosing our hard earned privileges due to others working longer and harder is so unfair. They are masking their own fear of loss of the quality of life given to them by their ancestors by pretending to worry about the quality of life of those workers in far away places who aspire to a better life.


The fact is that when you knock on other people's doors for a wage, you have to get what you are given; if you don’t like it and you have the options or the conviction you can refuse the terms and move on. Rules and laws that protect workers work well when everything is going well, but as soon as a society comes under strain, these rule break down. They have to break down because they are not sustainable, they are not natural; they are designed and imposed to work under certain conditions, like all laws are. Change those conditions, and the rules under which a society operates have to change.


If you want to eat like never before, as the bosses of multinationals or large business apparently do, go build your own Apple (if you dare to do it).


Of course, most people would never do what Googler #13 (Steve Schimmel) did, because that would be not cool, or safe, or comfortable, or even possible (“they” will not allow it) to do. Working like Alex Payne (Twitter)? Or learning something new (Tracy Osborne)? No! The world may be changing but hard-earned habits don't. For most, the best thing to do is to stay put and complain about it instead on steaming ahead as the times demand. Staying put is so much easier that, say, innovating your way out of a tectonic change in world order! For respectable latte-sippers everywhere, complaining is so much more dignified, in case a wealthy benefactor or an enlightened government hears their plea. For some that can, complaining of the changes in the world order manifest also by extremes such as striking, which involves unilaterally cutting down services by abusing a position of power, blocking economic activities for others, demanding that the evil capitalists and/or the rest of the society looks after them, all while they sip cafe-lattes and watching the cricket.


We have to understand that the people that pay our wages don't have an obligation to look after our well being unless it makes economical sense. Reality does hurt. We have to take responsibility for our own path in life just like my grandparents did sixty years ago... Like the Schimmels, Paynes and Osbornes do today.


The world is changing and is, as always, full of opportunities for those that are brave (and crazy) enough to chase them.


For the rest of us, we can complain about the unfairness of it all.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Thu, 19 Jan 2012 03:43:40 -0800 Testing http://blog.futureshock-ed.com/testing http://blog.futureshock-ed.com/testing Spent two full days writing tests to automatically stress model and controller code in my Rails app. I suddenly feel peaceful!

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Wed, 24 Aug 2011 20:49:00 -0700 Steve Jobs resigns http://blog.futureshock-ed.com/steve-jobs-resigns http://blog.futureshock-ed.com/steve-jobs-resigns

Although I knew that Steve Jobs would have to step down soon after he announced taking medical leave earlier this year, it is still sad to hear he has now decided to resign the post of Apple CEO.

Rarely can individuals be both as visionary and successful in achieving their vision as Steve Jobs has been.

Any flaws of his character, of which many people seem to know so much, only underline his humanity.

Steve, thank you for sharing the vision of what computing can be with us through the market.

You have inspired many more than you have angered (jealousy is a human flaw after all), and thanks to that sharing I am sure many more good things will follow from Apple and others.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Tue, 24 May 2011 17:54:00 -0700 Happy 2011 Geek Pride Day! http://blog.futureshock-ed.com/happy-2011-geek-pride-day http://blog.futureshock-ed.com/happy-2011-geek-pride-day

In this 2011 Geek Day, I take price in copying and pasting the Geek Manifesto from Wikipedia. Happy Geek Pride Day to all my fellow geeks!

(Republished without permission from http://en.wikipedia.org/wiki/Geek_Pride_Day)

Rights:

  1. The right to be even geekier.
  2. The right to not leave your house.
  3. The right to not like football or any other sport.
  4. The right to associate with other nerds.
  5. The right to have few friends (or none at all).
  6. The right to have as many geeky friends as you want.
  7. The right to be out of style.
  8. The right to be overweight and near-sighted.
  9. The right to show off your geekiness.
  10. The right to take over the world.

Responsibilities:

  1. Be a geek, no matter what.
  2. Try to be nerdier than anyone else.
  3. If there is a discussion about something geeky, you must give your opinion.
  4. To save and protect all geeky material.
  5. Do everything you can to show off geeky stuff as a "museum of geekiness."
  6. Don't be a generalized geek. You must specialize in something.
  7. Attend every nerdy movie on opening night and buy every geeky book before anyone else.
  8. Wait in line on every opening night. If you can go in costume or at least with a related T-shirt, all the better.
  9. Don’t waste your time on anything not related to geekdom.
  10. Try to take over the world!

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Sat, 26 Mar 2011 19:21:00 -0700 Xcode ad-hock provisioning certificate pains. http://blog.futureshock-ed.com/xcode-ad-hock-provisioning-certificate-pains http://blog.futureshock-ed.com/xcode-ad-hock-provisioning-certificate-pains

In a previous article, http://blog.futureshock-ed.com/2011/01/ios-ad-hock-app-distribution-for-beta...., I documented how I managed to produce a testing version iOS app that I needed to distribute to testers. To do this, I needed to create a ad-hock provisioning certificate on Apple's Developer's Provisioning Portal.

While the method I described worked back then, and I thought I had a decent undersrtanding of the certificate creation and application signing process, when I tried to repeat it last week, it all fell apart. 

I tried Xcode 3, Xcode 4, deleting and creating all certificates, editing the Xcode project configuration by text editor, and repeating everything hundeds of times over two days, the bloody thing didn't want to work. I kept getting errors like:

  • Code Sign error: Provisioning profile  can't be found
  • Code Sign error: Provisioning profile '2B29F6DB-B03A-4882-A405-40BB6A2377EC' can't be found
  • XCode could not find a valid private-key/certificate pair for this profile in your keychain.
  • profile doesn’t match Application Identifier xyz

and many others. 

I finally started suspecting that I was innocent of incompetence, and that there was something NOT FUNNY going on with Apple's signing process, especiall the part where in Xcode, you Build and Archive the app, then in the Organizer you Share the archived app by choosing the appropriate code-signing identity.

I decided to find out whether this process really worked. 

Reading the documentation (http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iphone_... discovered that there is a utility that inspects a built application and reports a few interesting statistics and settings, including the certificate used to sign the app.

This utility is called 'codesign'. I tried running it first against the .ipa file that the Organizer creates, but failed. The documentation only had examples with .app files, those produced by the Xcode build process. So I decided to just build the app in Xcode, then browsed to the build directory, and applied the tool to the new .app file. This is what I got:

$ codesign -dvv myApp.app

Executable=/Users/me/programming/iPhone/myApp/build/Beta-iphoneos/myApp.app/myApp

Identifier= myApp.

Format=bundle with Mach-O universal (armv6 armv7)

CodeDirectory v=20100 size=1900 flags=0x0(none) hashes=87+5 location=embedded

Signature size=4337

Authority=iPhone Distribution: Awesome Enterprises Pty Ltd

Authority=Apple Worldwide Developer Relations Certification Authority

Authority=Apple Root CA

Signed Time=26/03/2011 6:24:21 PM

Info.plist entries=24

Sealed Resources rules=3 files=71

Internal requirements count=1 size=144

That was interesting. The distribution certificate was correct, as specified in my testing profile. This file *should* work if I tried to install it on an iOS device with this certificate installed, as long as the device's UUID was valid for this certificate. With no time wasted, I just drag-droped the .app file onto iTunes; my testing iPod Touch with the correct certificate installed was already connected. Clicked Synced, waited for a few seconds, an there you go, app installed, no worries!

It seems that the Organizer was messing around with the certificates. I don't know exactly how, I might investigate further if time permits, but what was happening just did not make sense for a systemt that one would expect would be throroughly debbuged and working as expected. It seems like this isn't.

So lesson learned: only sign apps in Xcode, forget about archiving in Organizer. Note that the Share Archived Application in the Designer has the option 'Don't Resign". This might produce a properly working archive if in fact it doesn't touch the signing that Xcode did prior to archiving. But with what I have learned about the reliability of all this, I will be staying away from archiving via the Organizer.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Thu, 03 Mar 2011 18:54:00 -0800 HTTP status code symbols for Rails http://blog.futureshock-ed.com/http-status-code-symbols-for-rails http://blog.futureshock-ed.com/http-status-code-symbols-for-rails

Thanks to Cody Fauser for this list of HTTP responce codes and their Ruby on Rails symbol mappings. This table is sure to save me a lot of time when I need one of these.

 

Status CodeStatus MessageSymbol
1xx Informational
100 Continue :continue
101 Switching Protocols :switching_protocols
102 Processing :processing
 
2xx Success
200 OK :ok
201 Created :created
202 Accepted :accepted
203 Non-Authoritative Information :non_authoritative_information
204 No Content :no_content
205 Reset Content :reset_content
206 Partial Content :partial_content
207 Multi-Status :multi_status
226 IM Used :im_used
 
3xx Redirection
300 Multiple Choices :multiple_choices
301 Moved Permanently :moved_permanently
302 Found :found
303 See Other :see_other
304 Not Modified :not_modified
305 Use Proxy :use_proxy
307 Temporary Redirect :temporary_redirect
 
4xx Client Error
400 Bad Request :bad_request
401 Unauthorized :unauthorized
402 Payment Required :payment_required
403 Forbidden :forbidden
404 Not Found :not_found
405 Method Not Allowed :method_not_allowed
406 Not Acceptable :not_acceptable
407 Proxy Authentication Required :proxy_authentication_required
408 Request Timeout :request_timeout
409 Conflict :conflict
410 Gone :gone
411 Length Required :length_required
412 Precondition Failed :precondition_failed
413 Request Entity Too Large :request_entity_too_large
414 Request-URI Too Long :request_uri_too_long
415 Unsupported Media Type :unsupported_media_type
416 Requested Range Not Satisfiable :requested_range_not_satisfiable
417 Expectation Failed :expectation_failed
422 Unprocessable Entity :unprocessable_entity
423 Locked :locked
424 Failed Dependency :failed_dependency
426 Upgrade Required :upgrade_required
 
5xx Server Error
500 Internal Server Error :internal_server_error
501 Not Implemented :not_implemented
502 Bad Gateway :bad_gateway
503 Service Unavailable :service_unavailable
504 Gateway Timeout :gateway_timeout
505 HTTP Version Not Supported :http_version_not_supported
507 Insufficient Storage :insufficient_storage
510 Not Extended :not_extended

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Sun, 20 Feb 2011 19:56:00 -0800 strftime for date/time formating in Ruby - parameters http://blog.futureshock-ed.com/str http://blog.futureshock-ed.com/str

In Ruby, I often need to format time and date strings to make them look decent. I use strftime, which aparently is used in other languages, like PHP.

In Ruby, you would do something like this:

puts (inspection.date + HOURS_FROM_UTC.hours).strftime('%e-%b-%Y, %H:%M')

The formatting parameters (starting with the percentage sign) are many and not to intuitive to remember. 

I found one post with a list of most of them here, but I also include them here for quick reference:

%a - abbreviated weekday name according to the current locale
%A - full weekday name according to the current locale
%b - abbreviated month name according to the current locale
%B - full month name according to the current locale
%c - preferred date and time representation for the current locale
%C - century number (the year divided by 100 and truncated to an integer,
   range 00 to 99)
%d - day of the month as a decimal number (range 01 to 31)
%D - same as %m/%d/%y
%e - day of the month as a decimal number, a single digit is preceded by
   a space (range ' 1' to '31')
%g - like %G, but without the century.
%G - The 4-digit year corresponding to the ISO week number (see %V).
   This has the same format and value as %Y, except that if the ISO week
   number to the previous or next year, that year is used instead.
%h - same as %b
%H - hour as a decimal number using a 24-hour clock (range 00 to 23)
%I - hour as a decimal number using a 12-hour clock (range 01 to 12)
%j - day of the year as a decimal number (range 001 to 366)
%m - month as a decimal number (range 01 to 12)
%M - minute as a decimal number
%n - newline character
%p - either `am' or `pm' according to the given time value, or the
   corresponding strings for the current locale
%r - time in a.m. and p.m. notation
%R - time in 24 hour notation
%S - second as a decimal number
%t - tab character
%T - current time, equal to %H:%M:%S
%u - weekday as a decimal number [1,7], with 1 representing Monday
%U - week number of the current year as a decimal number, starting with
   the first Sunday as the first day of the first week
%V - The ISO 8601:1988 week number of the current year as a decimal
   number, range 01 to 53, where week 1 is the first week that has at
   least 4 days in the current year, and with Monday as the first day
   of the week. (Use %G or %g for the year component that corresponds
    to the week number for the specified timestamp.)
%W - week number of the current year as a decimal number, starting with
   the first Monday as the first day of the first week
%w - day of the week as a decimal, Sunday being 0
%x - preferred date representation for the current locale
   without the time
%X - preferred time representation for the current locale
   without the date
%y - year as a decimal number without a century (range 00 to 99)
%Y - year as a decimal number including the century
%Z or %z - time zone or name or abbreviation
%% - a literal `%' character

 

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Wed, 09 Feb 2011 19:52:00 -0800 iPhone - Beware of case sensitivity when enabling data model versioning http://blog.futureshock-ed.com/iphone-beware-of-case-sensitivity-when-enabli http://blog.futureshock-ed.com/iphone-beware-of-case-sensitivity-when-enabli

In an app I'm building, I decided it was about time to start thinking about data model versioning as a way to protect user data from database schema changes. Without versioning, every time I updated the app's schema, the user's data would have to be wiped out. Not good.

Any way, I consulted various sources on how to do this, including my beloved More iPhone 3 Development and Apple's Introduction to Core Data Model Versioning and Data Migration Programming Guide.

I made the minor changes to my code in the persistentStoreCoordinator and managedObjectModel, and tested in the Simulator. Great, nothing was broken, the changes worked just as advertised.
I continued coding, and a few hours later decided it was time to test on the device.
Bummer, I got this error message:

2011-02-10 14:23:12.470 myApp[9241:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter' 
*** Call stack at first throw: 

0 CoreFoundation 0x33ac0987 __exceptionPreprocess + 114 
1 libobjc.A.dylib 0x3347b49d objc_exception_throw + 24 
2 CoreFoundation 0x33ac07c9 +[NSException raise:format:arguments:] + 68 
3 CoreFoundation 0x33ac0803 +[NSException raise:format:] + 34 
4 Foundation 0x3362b54f -[NSURL(NSURL) initFileURLWithPath:] + 70 
5 Foundation 0x33650157 +[NSURL(NSURL) fileURLWithPath:] + 30 
6 myApp 0x00003537 -[myAppAppDelegate managedObjectModel] + 138 
7 myApp 0x000036fb -[myAppAppDelegate persistentStoreCoordinator] + 302

8 myApp 0x00003407 -[myApp AppDelegate managedObjectContext] + 62 

9 myApp 0x0000302f -[iNspectorAppDelegate application:didFinishLaunchingWithOptions:] + 78 
10 UIKit 0x3209ebc5 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 772 
11 UIKit 0x3209a259 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 272 
12 UIKit 0x3206648b -[UIApplication handleEvent:withNewEvent:] + 1114 
13 UIKit 0x32065ec9 -[UIApplication sendEvent:] + 44 
14 UIKit 0x32065907 _UIApplicationHandleEvent + 5090 
15 GraphicsServices 0x33b0ef03 PurpleEventCallback + 666 
16 CoreFoundation 0x33a556ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26 
17 CoreFoundation 0x33a556c3 __CFRunLoopDoSource1 + 166 
18 CoreFoundation 0x33a47f7d __CFRunLoopRun + 520 
19 CoreFoundation 0x33a47c87 CFRunLoopRunSpecific + 230 
20 CoreFoundation 0x33a47b8f CFRunLoopRunInMode + 58 
21 UIKit 0x32099309 -[UIApplication _run] + 380 
22 UIKit 0x32096e93 UIApplicationMain + 670 
23 myApp 0x00002fb3 main + 70 
24 myApp 0x00002f68 start + 40 

Tried again in the simulator, it worked.
Looking at the error trace, something was happening in the managedObjectModel function, and the error message in the first line indicated that the NSURL string was nil. The offending block of code was this:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Datamodel" ofType:@"momd"];
NSLog(@"path: %@", path);
NSURL *momURL = [NSURL fileURLWithPath:path];

I added the NSLog line to print out the contents of the `path` variable, and discovered that it was not nil when running in the simulator, but nil when running on the device.

I went to have a look at the application assets in

/Users/peter/Library/Application Support/iPhone Simulator/4.2/Applications/F2854B27-4750-4DC8-8CB6-A22B036F5DC9\myApp.app

by right-clicking and selecting "Show Package Contents", and noticed that the data model versioning directory was named `DataModel.momd`.
However in my code, the path variable was `Datamodel` (loading a resource of type `momd`), whereas the directory containing the model versions was `DataModel`.
Yeap, this was another case of the simulator and the device behaving differently, this time in how they handle file name cases.

Once I changed my code to
NSString *path = [[NSBundle mainBundle] pathForResource:@"DataModel" ofType:@"momd"];

and ran on the device, it worked.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Mon, 24 Jan 2011 23:35:00 -0800 iOS: ad-hock app distribution for beta testing http://blog.futureshock-ed.com/2011/01/ios-ad-hock-app-distribution-for-beta.html http://blog.futureshock-ed.com/2011/01/ios-ad-hock-app-distribution-for-beta.html

I needed to distribute two copies of a new app I'm building to beta testers, and a process Ithough should only take 30 minutes or so, took me half a day.

Apple's iOS Provisional Portal has these instructions (https://developer.apple.com/ios/manage/distribution/distribution.action):


1. Create and Download an iOS Distribution Certificate
2. Create and Download an Ad Hoc Distribution Provisioning Profile
3. Build your application with Xcode
4. Share your application file and the Ad Hoc Distribution Provisioning Profile with the owner of each device
5. Recipients of the application will need to drag the application file and Ad Hoc Distribution Provisioning Profile into iTunes, then sync their iPhone, iPad or iPod touch to iTunes to install
Well, that didn't work. Although I was able to produce a built, create a zip archive of the .app file, install it on the beta tester's iTunes (along side the provisional certificate), after syncing the phone I was getting error messages about either the app not being signed, or the entitlements being incorrect.

After lots of reading, trial and error, I managed to get a configuration that worked, documented here. Thanks to the many authors who helped out, including:


How to create an Ad-hock distribution
Media_http4bpblogspot_malci

I will start from the end of the process so that you know what you should be aiming for. A bit of an anti-climax, I know, but I find it useful to know what my target is.

xCode 3.2.5 has got a very nice distribution feature, accessible via the Build menu.

Once the project is configured properly for this feature to work, Build and Archive will create an .ipa archive that can be opened by iTunes on Windows or Mac. The file can be found in the Organizer. The Organizer can even help you email it to your beta testers, save it to disk, or distribute to an enterprise (that sounds cool, but don't know exactly what it does). Before this feature was put in xCode, people had to do everything manually, and some even wrote their own scripts trying to automate the process.
Media_http2bpblogspot_cqent

For Build and Archive to work, you must build using on the device, not the simulator. If your selected target is the simulator, the Build and Archive option will be disabled. Yep, this cost me an hour.

Steps for getting your ad-hock distribution

1. You can have up to 100 ad hock deployments of your app. For each one, you need the UUID of the beta tester's iphone or ipod touch. This can be found by connecting the device to itunes and accessing its property page. See here for details. Then proceed to the iOS Provisioning Portal, click on "Devices", "Manage", and "Add devices". Fill the blanks with the information you have.

2. You will need a distribution provisioning profile. This can be obtained by going to the iOS Provisioning Portal, click on Provisioning, and then on the Distribution tab. Click on "Create new profile", then fill in the blanks ensuring that Distribution Method is set to "Ad Hock". Submit, refresh a couple of times until you see the Download link, then download the certificate and put is aside for now.

3. Start xCode and open your project. Click on the Resources folder, and with it selected, click on File, New File. Under Code Signing, select Entitlements, and click Next.

4. Name the file "Entitlements.plist", and click "Finish".

5. Find the Entitlements.plist file in Resources, and open it. Add a new row so that the file now has these contents (make sure "Can be debugged" is not checked":

Media_http2bpblogspot_tclgo
6. Go to "Project", "Edit project settings" and scroll down to the code signing section. You need to edit the Code Signing Entitlements with the name of the file you created in step 5, and the Code Signing Identity rows with your valid developer certificate.

Ad-hock-1


7. You are now ready to create the distribution file. Click on Build, Build and Archive. The file is created and the Organizer pops-up. Click on the file to select it, then click on Share. Select the correct distribution identity from the drop-down, and then Save to Disk (or E-mail if you prefer).

8. Attach the .ipa file you created in step 7, along with the distribution provisioning profile from step 2 in an email, USB drive, network drive, or any other distribution method you like, and sent it to your beta tester.

9. With their device connected to iTunes, your beta tester needs to drag-drop the provisioning profile on the iTunes library. Then, double-click on the .ipa file. Once the app is installed on iTunes, it's icon will be visible in the apps library. He can now sync the device to get the app installed.

This worked for me and have done a few deployments without problems. Let me know how it worked for you, or if you came across problems.

UPDATE: Checkout a related post if you are still having trouble with getting your ad-hock distribution to work: http://blog.futureshock-ed.com/xcode-ad-hock-provisioning-certificate-pains

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Wed, 14 Jul 2010 02:13:00 -0700 Mongomapper with Rails 3 http://blog.futureshock-ed.com/2010/07/mongomapper-with-rails-3.html http://blog.futureshock-ed.com/2010/07/mongomapper-with-rails-3.html These are some notes I have taken while creating my first Rails 3 application with MongoDB/Mongomapper as the back end.

After installing RVM, Ruby 1.9.2dev, and Rails 3.0.0.beta4, I followed the instructions here to update a bunch of files (assuming you are running MongoDB locally):

config/initializers/mongo.rb

MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
MongoMapper.database = "#myapp-#{Rails.env}"

if defined?(PhusionPassenger)
PhusionPassenger.on_event(:starting_worker_process) do |forked|
MongoMapper.connection.connect_to_master if forked
end
end

Gemfile:

source 'http://rubygems.org'

gem 'rails', '3.0.0.beta4'

gem 'mongo_mapper'
gem 'rails3-generators'

config/application.rb
(only first 8 lines shown, not change to the rest of the file)

require File.expand_path('../boot', __FILE__)

#require "rails/all"

require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"

Then, I went on to create a model, and to do that I used kristianmandrup's rails3-generators gem:

sudo gem install rails3-generators
rails generate model Book --skip-migration --orm=mongomapper

Edit this model to contain at least one MongoDB key:
class Book
include MongoMapper::Document

key :title, String
key :author, String

timestamps!

# Validations :::::::::::::::::::::::::::::::::::::::::::::::::::::
# validates_presence_of :attribute

# Assocations :::::::::::::::::::::::::::::::::::::::::::::::::::::
# belongs_to :model
# many :model
# one :model

# Callbacks :::::::::::::::::::::::::::::::::::::::::::::::::::::::
# before_create :your_model_method
# after_create :your_model_method
# before_update :your_model_method

end


We'll need a controller to access the Book model:
rails generate controller Book

This creates an empty controller file. Edit book_controller.rb to look like this:

class BookController < ApplicationController
def index
@books = Book.all
end
end

Create a view for this controller and action in app/views/book/index.erb:

<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<h1>Books</h1>
<% @books.each do |book| %>
<div class="entry">
<h3><%= book.title %></h3>
</div>
<% end %>

Add the Book routes in the routes.rb file:

Inspector::Application.routes.draw do |map|
resources :books
end

Start the server to see if the application works so far:
rails server

Navigate your browser to http://localhost:3000/books/index. If you get a blank page with "Books" only displayed, then you are doing well, no worries. There are no errors, but also there are no records to display. The easiest/quickest way to add some books at this point is to use the console. Type "rails console", and add a couple of books:

book1 = Book.create(:title => "title 1", :author => "author 1")
=> true
book2 = Book.create(:title => "title 2", :author => "author 2")
=> true

Finally, make sure the rails server is running, and try to access http://localhost:3000/books. If all went well, the two entries we just made will be listed.

PS. Good resources on this subject:
http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails
http://blog.bitzesty.com/mongodb-with-mongomapper-and-ruby-on-rails

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Sat, 12 Jun 2010 23:03:00 -0700 MacRuby and CoreData reading and writing http://blog.futureshock-ed.com/2010/06/macruby-and-coredata-reading-and.html http://blog.futureshock-ed.com/2010/06/macruby-and-coredata-reading-and.html I am working on an iPhone project that uses CoreData. We need to pre-populate the database with a large dataset, for which the data is available on a number of CSV file.

I decided to use MacRuby 0.6 to build a tool to get the data out of the CVSs and into the CoreData's sqlite3 database. Although MacRuby (an implementation of Ruby 1.9 for Mac OS X) has really good APIs for CSV manipulation (a reason I decided to use MacRuby instead of Cocoa/Objective-C), the documentation on how to use CoreData with MacRuby was very thin, to say the least. But I did find some example code that got me started.

The full code is available on Github. But here's a couple of things I learned along the way.
  • Once you have a data model created on XCode, you need to compile it into a ".mom" file so that the Persistent Store Coordinator can be instantiated with it. This can be done with momc tool that comes with XCode available in /Developer/usr/bin (see gist example).
  • The relationship property names are used when you want to retrieve records, and the attribute property names for saving data.
  • In a one-many relationship, the object returned is an Array, through which you can iterate in Ruby with the "each" iterator.
  • In a one-one relationship, just use the entity name and its attribute property name.
This is the entity relationship diagram I used in the Github example:

Media_http1bpblogspot_rmhbr

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Fri, 26 Mar 2010 11:31:00 -0700 David Heinemeier Hansson at Startup School 08 http://blog.futureshock-ed.com/2010/03/david-heinemeier-hansson-at-startup.html http://blog.futureshock-ed.com/2010/03/david-heinemeier-hansson-at-startup.html This is a really insightful talk by "DHH", creator of Ruby on Rails on creating a great startup company and keeping it focused on what matters. Some of the ideas he talked about remind me of the "7 day weekend" by Ricardo Semler.

&amp;lt;div&amp;gt;&amp;lt;a href='http://www.omnisio.com'&amp;gt;Share and annotate your videos&amp;lt;/a&amp;gt; with Omnisio!&amp;lt;/div&amp;gt;
Media_httpcdngigyacom_pbgzj

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Mon, 15 Mar 2010 20:41:00 -0700 New concept laptop design: rollable laptop http://blog.futureshock-ed.com/2010/03/new-concept-laptop-design-rollable.html http://blog.futureshock-ed.com/2010/03/new-concept-laptop-design-rollable.html Check this out, a laptop design where the computer rolls into a tube, based on flexible organic LED technology (OLED). The whole top surface of this computer is the screen, and a keyboard or tap controls appear when needed.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Mon, 08 Mar 2010 23:09:00 -0800 Microsoft Courier, an imressive digital journal device http://blog.futureshock-ed.com/2010/03/microsoft-courier-imressive-digital.html http://blog.futureshock-ed.com/2010/03/microsoft-courier-imressive-digital.html Microsoft has demonstrated a very impressive digital journal device called "Courier". Its a dual-screen device that when closed is of the size of a 5x7 photo, and very thin. It supports finger gestures, like the iPad, but also includes a stylus for writing and sketching. I saw the demo video produced by Engadget, and I was very impressed. It should be released later (towards the end) of this year; I can't wait to see how it compares with the Apple iPad.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Fri, 26 Feb 2010 04:06:00 -0800 How did it all start? http://blog.futureshock-ed.com/2010/02/how-did-it-all-start.html http://blog.futureshock-ed.com/2010/02/how-did-it-all-start.html I came across this cartoon while surfing. I don't know its original location, but was too good to not include here.
Media_http1bpblogspot_jiddg

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Thu, 18 Feb 2010 05:05:00 -0800 The future of magazines? http://blog.futureshock-ed.com/2010/02/future-of-magazines.html http://blog.futureshock-ed.com/2010/02/future-of-magazines.html Some have looked at tablet computers as the ideal format for the magazine of the future. Wired has done some custom design of puting its content on tablet computers. The result is really interesting. Check it out:

http://link.brightcove.com/services/player/bcpid56328629001?bclid=10175001001...

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Sat, 30 Jan 2010 10:49:00 -0800 Don't loose your Targus receiver http://blog.futureshock-ed.com/2010/01/dont-loose-your-targus-received.html http://blog.futureshock-ed.com/2010/01/dont-loose-your-targus-received.html
Media_httpwwwtargusco_zfiqi

I almost lost my excellent Targus AMP09EU pointer receiver last week, and it got me thinking what would I do if I had actually lost it.

I could buy a new one, but at around AU$80, I thought there might be a better solution. Perhaps buying a receiver as a spare part?

I contacted Targus and learned that each receiver and pointer device are coded to only work in single pairs. Even if I could buy a spare receiver it would be useless because there is no way to pair them to work together.

So buyer beware, if you loose the $10 receiver, your $80 device will be useless.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Tue, 29 Dec 2009 09:09:00 -0800 Creating an NFS share on Ubuntu to allow access from Mac OS X http://blog.futureshock-ed.com/2009/12/creating-nfs-share-on-ubuntu-to-allow.html http://blog.futureshock-ed.com/2009/12/creating-nfs-share-on-ubuntu-to-allow.html I have a few Ubuntu servers and find it useful to have easy file access from my Mac workstation. To make this possible, I have setup my Ubuntu servers as NFS server, and the Mac as NFS client. This is how I did it:

At the Ubuntu side

Install the NFS server support:

sudo apt-get install nfs-kernel-server nfs-common portmap

Then, edit the exports file that controls the file systems (or simply the directories) that can be exported to clients.

sudo vi /etc/exports

I want to make all exports available to all client on my network, so here's my exports file:

# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/home/peter 192.168.110.0/24(rw,insecure)

The directive "insecure" is there to allow for correct (RW) connectivity with the Mac OS X client. You may also need to tweak the file/folder permissions on the NFS server to allow for the desired level of access on the client. This is because the client user who is connected to the NFS server does not map accurately.

Then, restart the NFS service:
sudo /etc/init.d/nfs-kernel-server restart
If you get something like this, everything is well:

* Stopping NFS kernel daemon
...done.
* Unexporting directories for NFS kernel daemon...
...done.
* Exporting directories for NFS kernel daemon...
exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "192.168.110.0/24:/home/peter".
Assuming default behaviour ('no_subtree_check').
NOTE: this default has changed since nfs-utils version 1.0.x

...done.
* Starting NFS kernel daemon
...done.

At the Mac side

In Finder, click Go --> Connect to Server, and in the server address field type:

Media_http4bpblogspot_bbvpm
nfs://192.168.110.114/home/peter/

It should take less than a second to connect, and the NFS drive will appear in the list of shares in a Finder window.

Media_http1bpblogspot_byfub

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Tue, 29 Dec 2009 04:36:00 -0800 VMWare: network lost in Ubuntu VM after moving or copying http://blog.futureshock-ed.com/2009/12/vmware-network-lost-in-ubuntu-vm-after.html http://blog.futureshock-ed.com/2009/12/vmware-network-lost-in-ubuntu-vm-after.html I came across an unusual problem with one of my Ubuntu virtual machine after copying it, which cause the network to stop working and my eth0 adaptor to disappear.

The problem was caused by VMWare creating a new MAC address for the new (copied) VM, and a mismatch between this new MAC address and the address recorded in the Ubuntu /etc/udev/rules.d/70-persistent-net.rules file.

It took me a while to figure out how to fix it (well, it was quick after I discovered which file to edit): edit 70-persistent-net.rules so that the MAC address for eth0 matches that given by VMware:

VMware Fusion

Media_http2bpblogspot_ndcie

70-persistent-net.rules
Media_http1bpblogspot_edabf

Edit the file so that the MAC address in the ATTR{address} field matches what VMWare allocates to this adaptor, and restart the virtual machine.

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked
Sat, 26 Dec 2009 08:48:00 -0800 Buidling a new Ruby 1.9 development stack on Ubuntu http://blog.futureshock-ed.com/2009/12/buidling-new-ruby-19-development-stack.html http://blog.futureshock-ed.com/2009/12/buidling-new-ruby-19-development-stack.html I have written these notes as a record of my last Ruby development machine, build on top of Ubuntu 9.10 server. I use Ruby 1.9 exclusively, with no Rails, just pure Ruby.

Start by downloading the latest Ubuntu server image. I use the 64 bit version.

Start up your virtual machine manager (I use VMWare Fusion), and create a new machine with 5-6GBytes of disk space. I am not too worried about partitioning since this will not be a production machine. I don't need too much space since development of pure Ruby apps is not too space consuming. I also like the ability to quickly copy the VM from one computer to another, and creating lots of backup snapshots for not too much extra space.

Once the new VM is ready, boot into it and log one. First update the OS before adding the development stack.

Update the apt-get sources:

sudo apt-get update

Then the OS:

sudo apt-get dist-upgrade.

Now get the development tools and libraries:

sudo apt-get install build-essential

You will also need:

* The Zlib development headers:

sudo apt-get install zlib1g
sudo apt-get install zlib1g-dev

* The OpenSSL development headers:

sudo apt-get install libssl-dev

* The GNU Readline development headers:

sudo apt-get install libreadline5-dev

Now you are ready for Ruby itself. Get the source and expand the package:

wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p376.tar.gz
tar -xvzf ruby-1.9.1-p376.tar.gz

Enter the Ruby source code directory and configure, make, make install:

cd ruby-1.9.1-p376
./configure --prefix=/opt/ruby1.9 --program-suffix=1.9
sudo make
sudo make install

Add symlinks to access the Ruby binaries. Symlinks also make it easy to manage multiple versions of Ruby running on the same machine:

sudo ln -sf /opt/ruby1.9/bin/ruby1.9 /usr/local/bin/ruby
sudo ln -sf /opt/ruby1.9/bin/erb1.9 /usr/local/bin/erb
sudo ln -sf /opt/ruby1.9/bin/irb1.9 /usr/local/bin/irb
sudo ln -sf /opt/ruby1.9/bin/rdoc1.9 /usr/local/bin/rdoc
sudo ln -sf /opt/ruby1.9/bin/ri1.9 /usr/local/bin/ri
sudo ln -sf /opt/ruby1.9/bin/testrb1.9 /usr/local/bin/testrb
sudo ln -sf /opt/ruby1.9/bin/gem1.9 /usr/local/bin/gem

Almost done, just update Ruby gems, and your Ruby stack is ready, albeit at bare minimum level of functionality:

sudo gem update --system

Additional resources:

You will most likely need support for Git, and sqlite3 (at least for prototyping).

For Git, install the essentials, then get the source, enter its directory, configure, make it, and install it:

sudo apt-get build-dep git-core git-doc
wget http://kernel.org/pub/software/scm/git/git-1.6.6.tar.gz
tar -xvzf git-1.6.6.tar.gz
cd git-1.6.6
./configure
make prefix=/usr/local all doc
sudo make install install-doc

For Sqlite3, you will need the binary and the development sources:

sudo apt-get install sqlite3
sudo apt-get install libsqlite3-0 libsqlite3-dev

And finally get the Ruby gem:

sudo gem install sqlite3-ruby

Happy Ruby coding!

Permalink | Leave a comment  »

]]>
http://posterous.com/images/profile/missing-user-75.png http://posterous.com/users/he6mkpUf5kmuu futureshocked futureshocked futureshocked