tag:blogger.com,1999:blog-89064020184644012232024-03-05T01:02:29.137-08:00Wilson LeiWilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.comBlogger56125tag:blogger.com,1999:blog-8906402018464401223.post-12276707837183676112020-12-27T11:24:00.005-08:002020-12-27T13:33:21.517-08:00Bose TV Speaker vs Sonos Beam<div>I have been searching a <b><i>compact </i></b>soundbar for my living room. The Bose TV Speaker (2020 model) and Sonos Beam (2018 model) are my final contenders. </div><h2 style="text-align: left;">Size and Build</h2><div>Bose 23.5 w x 2.2 h x 4.1 d. Sonos 25.6 w x 2.6 h x 4.0 d. Height is an important factor here considering lots of TVs have very low bottom clearance. For example, LG OLED is only 1.5 inches. Build quality on both soundbars is solid. I personally like the Bose better because it has metal grills instead of cloth on Sonos.</div><h2 style="text-align: left;">Sound</h2><div>rtings.com's technical review is spot on. I'm not going to have an in-deep review here, but just to point out a few things I found that are important. </div><div>The sound profiles are very similar. Sonos has a little bit wider stage and able to fill the room with music better thanks to its extra side speakers. It's also more neutral sounding. Bose has a noticeable clearer dialogue. They both have a dialogue enhance feature, but I find the result is poor. For Bose, it makes the dialogue harsh and hurts my ears. For the bass, Sonos uses a passive radiator design while Bose uses a ported design. Both are quite good for a soundbar. Sonos has a TruePlay feature that can tune the sound to sound better in the room. I didn't find any improvement in my room. So don't think that can improve the sound dramatically. The last thing I want to point out is that both soundbars have poor instrument separation. Even though Sonos has a wider stage, all sound sources are diffused. Bose has a tiny little bit better separation. I would not recommend using these for serious music listening. </div><h2 style="text-align: left;">Connectivity</h2><div>Sonos supports HDMI, optical, and WiFi. It's also a smart speaker that you can use Google or Alexa assistant. If you want to expand Sonos to a 5.1 setup later, you can only choose Sonos products. </div><div>Bose supports HDMI, optical, 3.5mm aux, and Bluetooth. It also has a sub out which can be connected to any powered sub. </div><div>Sonos does not come with a remote, you need to use the Sonos app. However, it can be set up to use your tv remote to control the volume. Bose has a little remote to control all of its features. </div><h2 style="text-align: left;">Conclusion</h2><div>I chose Bose because it's $150 cheaper, better looking, sounds almost as good, much more versatile connectivity. I don't need smart home assistant integration.</div>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-68209224784033645502018-01-30T17:18:00.000-08:002018-01-30T17:52:23.641-08:00Userful xcodebuild command linesI setup Jenkins jobs to build iOS project for QA and release. Here are some useful xcodebuild commands that I use. Tested with XCode 9.<br />
<br />
Create a xcarchive file<br />
<pre class="brush: shell; toolbar: false;">xcodebuild -project ${APPNAME}.xcodeproj -scheme ${APPSCHEME} -configuration Release clean -archivePath "${WORKSPACE}/${APPNAME}.xcarchive" archive
</pre>
<br />
Create an IPA from xcarchive file with exportOptions.<br />
<pre class="brush: shell">xcodebuild -exportArchive -archivePath "${APPNAME}.xcarchive" -exportPath "${WORKSPACE}" -exportOptionsPlist exportOptions.plist -allowProvisioningUpdates
</pre>
<br />
If the above command doesn't create an IPA, try putting xcrun in front.
To generate an IPA with the correct certificate and provision profile, you must set them correctly in exportOptions.plist. See example below.<br />
<br />
Create an APP file for simulator<br />
<pre class="brush: shell">xcodebuild -project ${APPNAME}.xcodeproj -scheme ${APPSCHEME} -configuration Debug -sdk iphonesimulator clean build
</pre>
<br />
<br />
Sample exportOptions.plist<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>enterprise</string> //app-store, enterprise, ad-hoc or development
<key>signingCertificate</key>
<string>iPhone Distribution</string> //Certificate name
<key>teamID</key>
<string>T7L12345678</string> //The development program team identifier.
<key>uploadBitcode</key>
<false>
<key>uploadSymbols</key>
<false>
<key>provisioningProfiles</key>
<dict>
<key>com.sample</key>
<string>fe26f4e4-11d0-4054-898c-144a8se030a1</string> //Provision profile UUID
</dict>
</dict>
</plist>
</pre>
<br />
Update build version in Info.plist
<br />
<pre class="brush: shell">/usr/libexec/Plistbuddy -c "Set CFBundleVersion ${BUILD_NUMBER}" "${WORKSPACE}/${APPNAME}/Info.plist"
</pre>
Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-37360298320343364672018-01-24T12:26:00.001-08:002018-01-24T12:28:17.677-08:00KML Collection iOS AppI often create apps I need that are not available in the app store. This is one of them. I usually plan my travel trip using Google My Maps to store all the interesting places I want to go. I needed an app that can import KML map files exported by Google and show all the places. I also want an easy way for me to open the place in my favorite navigation app. So, I created KML Collection using swift.<br />
<br />
<a href="https://itunes.apple.com/mt/app/kml-collection-import-maps/id1337982582?mt=8">App Store link</a>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-69735822035557825152018-01-01T16:31:00.000-08:002018-01-24T17:18:38.796-08:00Update: Items for Diablo 3Happy New Year!<br />
My first personal app Items for Diablo 3 was released in September 23rd, 2013 when I was actively playing the game Diablo 3. It received lots of great reviews from players that encouraged me to keep making updates to Items for Diablo 3. From a simple off-line items viewer to hero profiles checker, to hero skills simulator, to rift rankings. I want to say thank you to the fans of the app.<br />
<br />
<a href="https://itunes.apple.com/us/app/items-for-diablo-3/id702071888?mt=8">App Store link</a> <br />
<br />
Here are a few reviews from the app store.<br />
<blockquote class="tr_bq">
Like it was made by Blizzard themselves<br />
I have been searching for awhile for an app that would provide the utility of the official WoW Armory app for Diablo. I've tried several and never been satisfied - until now! This app is absolutely fantastic. It provides everything I had been wanting - easy ability to view my characters, full skill calculator/browser, and a cleanly presented database of legendary and set items. The search for the database is quick and robust - it will even give you a list of all class-appropriate items by simply entering the class in the search box! For the Diablo enthusiast, I highly recommend this app. It is everything the Armory is for WoW - 10/10! by <u>darienspecter</u>
</blockquote>
<blockquote class="tr_bq">
Well written Diablo 3 app finally!! by <u>*Vladimir*</u>
</blockquote>
<blockquote class="tr_bq">
Very useful and better than any tool I've tried! by <u>Rg418</u>
</blockquote>
<blockquote class="tr_bq">
This app goes above and beyond all it's competitors. Just the fact that all the info in it is updated should be enough to put it head and shoulders above the other Diablo 3 companion apps but this app takes it to an even higher level. Excellent app and even though the ads weren't something I needed to pay to get rid of, I did just to pay tribute to the developer going above and beyond what he had to. It's a shame I can't do a better job articulating how good this app is because it deserves it after I've dealt with other subpar apps for months. by <u>Mawillar</u></blockquote>
<blockquote class="tr_bq">
No doubt you Gentlemen have done a fantastic job in the development of probably one the most comprehensive D3 information sites I have found. Kudos for a job well done. by <u>ElsagBailey</u></blockquote>
Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-62197458233121251052017-07-08T12:40:00.000-07:002018-01-24T17:15:12.882-08:00Skill Tree Lookup for ESO app: Taste of ReactNativeI heard about ReactNative when it first came out. After many years later, I finally decided to give it a try because it would be nice to release an app for both Android and iOS platform. I'm not an Android app engineer so this was my first app that is available on Google Play thanks to ReactNative. The app turned out nice and looks native, but the performance is not as good as native app build using Swift or Java especially on older devices.<br />
<br />
I was excited about the Android release because there are more Android phones out there. Result is that I made about the same Ad revenue from each platform.<br />
<br />
<a href="https://itunes.apple.com/mt/app/skill-tree-lookup-for-eso/id1255610711?mt=8">App Store link</a><br />
<a href="https://play.google.com/store/apps/details?id=com.wilsonlei.esoskills.android&hl=en">Google Play link</a>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-61842932849742030102017-04-27T17:12:00.000-07:002018-01-24T17:16:52.263-08:00My HTPC remote mouse: VMouseI have a HTPC set up in my living room that have TightVNC running so I can remote control it using my tablet or desktop. Sometimes, I just need to have an app that act like a mouse without the full remote desktop experience. I found many apps in the app store can do this but requires installation of its own server application on the HTPC. I don't like the idea of installing extra server that would take up more computer resource. Plus I trust TightVNC more. Since I already have TightVNC installed, I should be able to control the mouse via VNC protocol (<span class="st">RFB)</span>. This's why VMouse was born.<br />
<br />
<a href="https://itunes.apple.com/us/app/vmouse-vnc-remote-mouse/id1229905506?mt=8">App Store link</a>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-6188745676857089132017-03-08T11:15:00.001-08:002018-01-24T15:51:43.069-08:00Ridiculous Apple App Store rejectionMy <a href="https://itunes.apple.com/us/app/items-for-diablo-3/id702071888?mt=8">Items for Diablo 3</a> app has been in app store for years with 4.5 stars reviews from users got a rejection for a minor update. The reason was the following.<br />
<br />
"We noticed that your app only includes links, images, or content aggregated from the Internet with limited or no native iOS functionality. We understand that this content may be curated from the web specifically for your users, but since it does not sufficiently differ from a mobile web browsing experience, it is not appropriate for the App Store."<br />
<br />
Anyone that uses the app would know that the reviewer does not know what he is doing.Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-88426672941065303812016-10-05T16:28:00.000-07:002018-01-24T15:51:57.406-08:00Xcode 8 automatic code signing problem with JenkinsXcode 8 automatic code signing is great. However if you try to use Jenkins to automate your app build with a specific provision profile, you would want to use manual code signing. What I wanted to do was use automatic code signing during development and use manual code signing with Ad-Hoc provision with Jenkins.<br />
<br />
To switch from automatic to manual code signing, you need to change the following setting in the project file ([project name].xcodeproj/project.pbxproj).<br />
Change "ProvisioningStyle = Automatic" to "ProvisioningStyle = Manual"<br />
By default "ProvisioningStyle = Automatic" is not in the project.pbxproj. You just need to uncheck and check "Automatically manage signing" in app Target -> General in Xcode to add that setting.<br />
<br />
Now in Jekins, you want to add this shell script before you run the Xcode build command to change "ProvisioningStyle = Automatic" to "ProvisioningStyle = Manual"<br />
<br />
<pre class="brush: shell; toolbar: false;">sed -i '' 's/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/' [project name].xcodeproj/project.pbxproj
</pre>
<br />
You can then use xcodebuild argument "PROVISIONING_PROFILE=xxxx-xxxx-xxxx" to use the provision profile you want.Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-2950296452845435852016-03-25T14:40:00.004-07:002018-01-24T15:52:18.218-08:00Add tint to UIImageI have been working on a SDK that allows user to customize colors for images. In many cases, I need to add an image to a button with different color at run time. So using just tintColor is not going to work. The following method will mask an image with the color you define.<br />
<br />
<pre class="brush: c; toolbar: false;">- (UIImage *)maskWithColor:(UIColor *)color
{
CGImageRef maskImage = self.CGImage;
CGFloat width = self.size.width * self.scale;
CGFloat height = self.size.height * self.scale;
CGRect bounds = CGRectMake(0,0,width,height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, width, height, 8, 0, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
CGContextClipToMask(bitmapContext, bounds, maskImage);
CGContextSetFillColorWithColor(bitmapContext, color.CGColor);
CGContextFillRect(bitmapContext, bounds);
CGImageRef cImage = CGBitmapContextCreateImage(bitmapContext);
UIImage *coloredImage = [UIImage imageWithCGImage:cImage scale:self.scale orientation:self.imageOrientation];
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
CGImageRelease(cImage);
return coloredImage;
}
</pre>
Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-25676577449389377182015-01-20T16:26:00.002-08:002015-01-20T16:32:02.163-08:00Using xcodebuild To Export a .ipa From an ArchiveFound this helpful article.
<br />
<br />
source: http://www.thecave.com/2014/09/16/using-xcodebuild-to-export-a-ipa-from-an-archive/<br />
<br />
<h2>Clean project</h2>
<pre class="brush: shell; toolbar: false;">xcodebuild clean -project $projectname.xcodeproj -configuration Release -alltargets
</pre>
<h2>Create project archive</h2>
<pre class="brush: shell; toolbar: false;">xcodebuild archive -project $projectname.xcodeproj -scheme $schemename -archivePath $projectname.xcarchive
</pre>
<h2>Create IPA</h2>
<pre class="brush: shell; toolbar: false;">xcodebuild -exportArchive -archivePath $projectname.xcarchive -exportPath $projectname -exportFormat ipa -exportProvisioningProfile “Provisioning Profile Name”
</pre>
Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-70405297682238245852014-12-23T14:22:00.002-08:002015-07-22T11:17:39.196-07:00Weather for your business?A beautiful iPhone app before the year end. It is a business analytics app.
<br/>
In App Store: <a href="https://itunes.apple.com/us/app/weathr-lite/id980422041?ls=1&mt=8">https://itunes.apple.com/us/app/weathr-lite/id980422041?ls=1&mt=8</a>
<p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvt-rmHTTtnwLVUbW0pFLS5b2vk2AlxXotRJZVS9Nu6eo2BECA5JFwr9YDsD492uTmq2dRwEZTljx1-GhOX2rrmoYVzKELbXUaukQsBrVU0JygDkFdjCIFzX3fuP6O2aaX5l_AjzF2VNk/s1600/IMG_2832.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvt-rmHTTtnwLVUbW0pFLS5b2vk2AlxXotRJZVS9Nu6eo2BECA5JFwr9YDsD492uTmq2dRwEZTljx1-GhOX2rrmoYVzKELbXUaukQsBrVU0JygDkFdjCIFzX3fuP6O2aaX5l_AjzF2VNk/s400/IMG_2832.PNG" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic4yVqGGadK6bwAkSu7ch0ZrKh9r7oGb1sENeHRrABEYcSx9I4EQFcqi1fMTW_Ff4tp-nDVvpbAJekuPHK0K5zHlpoTUl96JSWBymHLZefHDmfgIBQQvCX46g8_1j3RA0TDGa4xbstXQ8/s1600/IMG_2833.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic4yVqGGadK6bwAkSu7ch0ZrKh9r7oGb1sENeHRrABEYcSx9I4EQFcqi1fMTW_Ff4tp-nDVvpbAJekuPHK0K5zHlpoTUl96JSWBymHLZefHDmfgIBQQvCX46g8_1j3RA0TDGa4xbstXQ8/s400/IMG_2833.PNG" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaH7pcEKNF6rve7ROQPY-Hy_5S3Fne_FTTVoseo5LeM3tzwtfMJrFhe3FpJtsR1xC1BDjUBq6nBpXE9mCg2mmVIuoLOYFpcA_QL2lVaosVyp-8nEQtr5zlndOzOi0vcJhPQl-ShPCe3gY/s1600/IMG_2834.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaH7pcEKNF6rve7ROQPY-Hy_5S3Fne_FTTVoseo5LeM3tzwtfMJrFhe3FpJtsR1xC1BDjUBq6nBpXE9mCg2mmVIuoLOYFpcA_QL2lVaosVyp-8nEQtr5zlndOzOi0vcJhPQl-ShPCe3gY/s400/IMG_2834.PNG" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipcFCeC9hIyv7A27R9pAfsTXmz2c_RZg26k5bJscI1Z-vfyPsdPORXquERnrM2iqFRqIxeozZd0RcDHf6F1aCe0bZndrGL_TQKWpAEnrDSkDe0fPRAHimgxTDnO149Uglb4ZfWU1jR8Hk/s1600/IMG_2835.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipcFCeC9hIyv7A27R9pAfsTXmz2c_RZg26k5bJscI1Z-vfyPsdPORXquERnrM2iqFRqIxeozZd0RcDHf6F1aCe0bZndrGL_TQKWpAEnrDSkDe0fPRAHimgxTDnO149Uglb4ZfWU1jR8Hk/s400/IMG_2835.PNG" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIYX4ojGt_OCMLORCtuVsTOmwtDFd2Uy9ARPfKjXk5eiLkdty43OPTTH87VpHfllsNhuZSwJ-1i0c-14kEGsR4j0F5UloR0fhNy-dXWREw9nNLQAQQuttJ6Vjdm24OAZemXigt-No5QpM/s1600/IMG_2836.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIYX4ojGt_OCMLORCtuVsTOmwtDFd2Uy9ARPfKjXk5eiLkdty43OPTTH87VpHfllsNhuZSwJ-1i0c-14kEGsR4j0F5UloR0fhNy-dXWREw9nNLQAQQuttJ6Vjdm24OAZemXigt-No5QpM/s400/IMG_2836.PNG" /></a></div>
</p>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-46639491222631201092014-10-01T17:56:00.002-07:002014-10-01T17:57:30.199-07:00Directory with extra funEmployee look up app with fun ideas.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQa3zbKxGEZXsc4hO6_6f0clqVEYyZr52q175-6bar1f1c7v65TRU03KRI8usvTDaRIZQ5g-z1XbssrG1Vrc0PWaQU0Rna5YXXEXmNC1OrTABeCmto3X-fjBORmxCGSOY5eIxDdFOJFVA/s1600/iOS+Simulator+Screen+Shot+Oct+1,+2014,+5.48.07+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQa3zbKxGEZXsc4hO6_6f0clqVEYyZr52q175-6bar1f1c7v65TRU03KRI8usvTDaRIZQ5g-z1XbssrG1Vrc0PWaQU0Rna5YXXEXmNC1OrTABeCmto3X-fjBORmxCGSOY5eIxDdFOJFVA/s1600/iOS+Simulator+Screen+Shot+Oct+1,+2014,+5.48.07+PM.png" height="400" width="225" /></a></div>
<br />Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-59871249311966708542014-09-24T17:44:00.001-07:002014-09-24T17:45:36.990-07:00VW Interactive Ad UnitBuilt the API services for an Ad unit that is personalized for each CBS fantasy football team.<br />
<ul>
<li>Each team plays 10 unique questions each week and earn points. </li>
<li>Leader board for each league. </li>
<li>History for last week's score. </li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipm_U3MG75MiPgz-cnSk9S3rqU3vi7szHsLFS97Bz6oZ_JohNsGdS_i_gxvWiZ4rUPVAABb-506oXE2DjjfqXMfVG1_HwmZKamNUCa8ajeMRyJM-D6GJ-QarZ2PbftFD_giiYatBnapOY/s1600/2014-09-11_1020.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipm_U3MG75MiPgz-cnSk9S3rqU3vi7szHsLFS97Bz6oZ_JohNsGdS_i_gxvWiZ4rUPVAABb-506oXE2DjjfqXMfVG1_HwmZKamNUCa8ajeMRyJM-D6GJ-QarZ2PbftFD_giiYatBnapOY/s400/2014-09-11_1020.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMgFTDCD2cAcluUQYeuJdzS8tRD8fqnZj5dGvwAAiR3Qz77O3HL_OxO4tqX_aEk_UjuUoVyqP5ZH-W0w9LDmC9TCoEtEfiAkfHaoTuP5NurmPc2V-zZALfy2Ikq5L89TIl5OF2AOLUKm0/s1600/2014-09-11_1021.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMgFTDCD2cAcluUQYeuJdzS8tRD8fqnZj5dGvwAAiR3Qz77O3HL_OxO4tqX_aEk_UjuUoVyqP5ZH-W0w9LDmC9TCoEtEfiAkfHaoTuP5NurmPc2V-zZALfy2Ikq5L89TIl5OF2AOLUKm0/s400/2014-09-11_1021.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2E3wz6gbkQZG5y6KagUSqBvYsLOmT7BjdtB0TJ7I0zvR6cald5gY9xDO2cV1Xgtcx0bx0DnJCD4zcfbF_M2bm2sqvmNsQ7yEegNgjKOxiDc45DMqJoK0eyuMco5Y0GZABifpJ1k8bdMw/s1600/2014-09-11_1022.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2E3wz6gbkQZG5y6KagUSqBvYsLOmT7BjdtB0TJ7I0zvR6cald5gY9xDO2cV1Xgtcx0bx0DnJCD4zcfbF_M2bm2sqvmNsQ7yEegNgjKOxiDc45DMqJoK0eyuMco5Y0GZABifpJ1k8bdMw/s400/2014-09-11_1022.png" /></a></div>
Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-66006526665550072782014-04-15T21:56:00.001-07:002014-04-16T10:04:03.363-07:00How to install ImageMagick with MAMP1. Install Homebrew <a href="http://brew.sh/" target="_blank">http://brew.sh/</a>
<pre class="brush: shell">
ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
</pre>
2. Install ImageMagick for the PHP version your MAMP is running.
<pre class="brush: shell">
brew search imagick
brew install php55-imagick
</pre>
After installation, the ImageMagick PHP extension is created in /usr/local/Cellar/php55-imagick/3.1.0RC2/imagick.so<br/>
3. Disable the DYLD_LIBRARY_PATH variable in Apache's environmental variables.
<pre class="brush: shell">
vi /Applications/MAMP/Library/bin/envvars
</pre>
Comment out the following line:
<pre class="brush: shell">
export DYLD_LIBRARY_PATH
</pre>
4. Update php.ini to include imagick.so<br/>
<pre class="brush: shell">
vi /Applications/MAMP/bin/php/php5.5.3/conf/php.ini
</pre>
Add the following line.
<pre class="brush: shell">
extension="/usr/local/Cellar/php55-imagick/3.1.0RC2/imagick.so";
</pre>
5. Restart MAMP<br/>
6. Check if imagick is included in phpinfo()Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-54196065076979060272014-03-03T10:33:00.003-08:002014-03-03T10:37:14.350-08:00A simple copying directory function<pre class="brush: php">
function recurseCopy($src, $dst, $excludeFileType=array()) {
$dir = opendir($src);
mkdir($dst, 0755, true);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
$this->recurseCopy($src . '/' . $file, $dst . '/' . $file, $excludeFileType);
}
else {
$filePathInfo = pathinfo($file);
$ext = '';
if(!empty($filePathInfo['extension'])){
$ext = $filePathInfo['extension'];
}
if(empty($ext) || !in_array($ext, $excludeFileType)){
copy($src . '/' . $file, $dst . '/' . $file);
}
}
}
}
closedir($dir);
}
</pre>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-23837154970085097322014-02-28T15:17:00.001-08:002014-02-28T15:21:14.818-08:00How to get WordPress posts permalinks using SQL(database) alone<pre class="brush: sql">
SELECT wpp.post_title, wpp.post_type, wpp.guid, wpp.post_date, CONCAT( wpo_su.option_value, REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( wpo.option_value, '%year%', DATE_FORMAT( wpp.post_date, '%Y' ) ) ,'%monthnum%', DATE_FORMAT( wpp.post_date, '%m' ) ) , '%day%', DATE_FORMAT( wpp.post_date, '%d' ) ) , '%postname%', wpp.post_name ) , '%category%', wpp.post_type ) ) AS permalink
FROM wp_posts wpp
INNER JOIN wp_options wpo ON wpo.option_name = 'permalink_structure'
INNER JOIN wp_options wpo_su ON wpo_su.option_name = 'siteurl'
WHERE (
wpp.post_type = 'post'
OR wpp.post_type = 'page'
)
AND wpp.post_status = 'publish'
</pre>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-21365436880197022872014-02-25T14:15:00.000-08:002014-02-25T14:29:29.129-08:00A Target campaign<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6mvgh4b6T9JCnu61wXj5toNm-93K3Jhs6ptC-hPMNNoCrpXegU_Qp5dJPhaN5HUnmsX-GZa7YX7UcJd3_beGre6y6434NebfkpMi-0NguVhYcqoD_0UQWG8_o025g5mLRo1-4RrBkPxE/s1600/Screen+Shot+2014-02-25+at+2.03.30+PM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6mvgh4b6T9JCnu61wXj5toNm-93K3Jhs6ptC-hPMNNoCrpXegU_Qp5dJPhaN5HUnmsX-GZa7YX7UcJd3_beGre6y6434NebfkpMi-0NguVhYcqoD_0UQWG8_o025g5mLRo1-4RrBkPxE/s400/Screen+Shot+2014-02-25+at+2.03.30+PM.png" /></a></div>
<br />
A micro site that allows user to get a free mp3 download after Facebook authentication. The site is written in PHP with MySQL database. <br />
Application features:<br />
<ul>
<li>Limits one download per user. </li>
<li>Integration with real-time music purchasing and download.</li>
<li>Location restriction by user IP address.</li>
<li>Integration with Email injection services.</li>
<li>Twitter, Instagram and Facebook user authentication process.</li>
<li>Works on both desktop and mobile web browsers.</li>
<li>Supports high volume of traffic.</li>
</ul>
<br />
<a href="http://moreshakira.target.com/" target="_blank">moreshakira.target.com</a>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-8871689109848750702013-11-18T17:23:00.001-08:002015-07-22T11:06:45.680-07:00How to get iDevice hardware model<pre class="brush: c">
size_t size = 100;
char *hw_machine = malloc(size);
int name[] = {CTL_HW,HW_MACHINE};
sysctl(name, 2, hw_machine, &size, NULL, 0);
NSString *hardware = [NSString stringWithUTF8String:hw_machine]; //e.g. iPhone4,1
free(hw_machine);
</pre>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-18915238493910925352013-11-06T15:58:00.002-08:002018-01-30T17:51:34.313-08:00How to resign an IPA with new bundle Id, certificate and entitlements<ol>
<li>Create an Entitlements.plist using Xcode</li>
<ol>
<li>Include the following keys values in the plist file. </li>
<ol>
<li>application-identifier (String) -> 3Q83MXXZGH.com.company.appname</li>
<li>get-task-allow (Boolean) -> NO</li>
</ol>
</ol>
<li>Put the Entitlements.plist in the same folder of the app.ipa file</li>
<li>Unpackage the app</li>
<ol>
<pre class="brush: shell; toolbar: false;">unzip app.ipa</pre>
</ol>
<li>Delete current code signature</li>
<ol>
<pre class="brush: shell; toolbar: false;">rm -rf Payload/MyApp.app/_CodeSignature/</pre>
</ol>
<li>Open Payload/MyApp.app/Info.plist in Xcode and update the bundle ID(CFBundleIdentifier)</li>
<li>Copy the new .mobileprovision file to Payload/MyApp.app/embedded.mobileprovision</li>
<li>Run the codesign command</li>
<ol>
<pre class="brush: shell; toolbar: false;">codesign -f -s "iPhone Distribution: Company Certificate" --resource-rules Payload/MyApp.app/ResourceRules.plist --entitlements Entitlements.plist Payload/MyApp.app</pre>
</ol>
<li>Repackage the app</li>
<ol>
<pre class="brush: shell; toolbar: false;">zip -qr app-resigned.ipa Payload/</pre>
</ol>
</ol>
Sample Entitlements.plist
<pre class="brush: xml; toolbar: false;">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>3Q83MXXZGH.com.company.appname</string>
<key>get-task-allow</key>
<false/>
</dict>
</plist>
</pre>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-84548624922277883592013-10-08T10:40:00.001-07:002015-07-22T11:07:09.561-07:00How to add parallax effect to your apps<pre class="brush: c">
UIInterpolatingMotionEffect *interpolationHorizontal = [[UIInterpolatingMotionEffect alloc]initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
interpolationHorizontal.minimumRelativeValue = @-10.0;
interpolationHorizontal.maximumRelativeValue = @10.0;
UIInterpolatingMotionEffect *interpolationVertical = [[UIInterpolatingMotionEffect alloc]initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
interpolationVertical.minimumRelativeValue = @-10.0;
interpolationVertical.maximumRelativeValue = @10.0;
UIMotionEffectGroup *interpolationGroup = [[UIMotionEffectGroup alloc]init];
interpolationGroup.motionEffects = [NSArray arrayWithObjects:interpolationHorizontal, interpolationVertical, nil];
if([aView respondsToSelector:@selector(addMotionEffect:)]){
[aView addMotionEffect:interpolationGroup];
}
</pre>Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-46191737826291471822013-09-10T16:06:00.000-07:002013-09-19T11:04:24.513-07:00Experiencing Sencha Touch: VW Dealer appSencha Touch, a high-performance HTML5 mobile application framework. We used Sencha to build an iPad application that allows Volkswagen field managers and dealers to show customers everything about VW cars.<br />
<div>
Application features:</div>
<div>
<ul>
<li>Work offline.</li>
<li>Update application data without reinstalling the app.</li>
<li>Support multiple events.</li>
<li>Capture customer information locally and upload to server later on.</li>
<li>Vehicle gallery and videos slide show.</li>
<li>Vehicle trim specs, color specs, technical specs, pricing.</li>
<li>Vehicle comparison. </li>
</ul>
<div>
Since this app needs to work with iPad 1st generation, memory management became very important. We spent good amount of time to tweak the app to have small memory footprint. </div>
</div>
<div>
<br /></div>
<div>
The app is being used at places with no wifi. When the application is installed, it downloads all data from a server and stored on the iPad using HTML5 local file system feature. App uses high quality gallery images, so using manifest method would exceed the browser storage limit.</div>
<div>
<br /></div>
<div>
The app itself has a version control built-in so every update is an incremental update instead of re-download all data again.</div>
<div>
<br /></div>
<div>
Customer data are stored on the app using Sencha store data model.<br />
<br />
2013 Sep updates: Redesign user interface!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; float: left; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWRXQRbPxqvWXjXiiXF0zUJH4zLGRYleGcEEICiONeLTiH33cp_WSfdgOhnVgRbIxNP9nvoubnVnzXhSS6ybBJcEEv6NaBke2LVyv7p9SKCKZqZ8lNonl1KEj2wWvjS7TAp8SNQOg0_Bs/s1600/vwevent-iPad-sh1.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWRXQRbPxqvWXjXiiXF0zUJH4zLGRYleGcEEICiONeLTiH33cp_WSfdgOhnVgRbIxNP9nvoubnVnzXhSS6ybBJcEEv6NaBke2LVyv7p9SKCKZqZ8lNonl1KEj2wWvjS7TAp8SNQOg0_Bs/s320/vwevent-iPad-sh1.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9IBAYxYfEatHrdUR1cd5TQEqh1BJQfEQDiqfEPT24T0mdgC2ofK3ZuflHnqqYXpz8thBcAcx3opb_7mhD3Fo6fPw_Z-H-fgE-E1xUmBW4VcrWCufB_EcUMi0KYftUvoxdPQrfsGrOHk/s1600/vwevent-iPad-sh2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9IBAYxYfEatHrdUR1cd5TQEqh1BJQfEQDiqfEPT24T0mdgC2ofK3ZuflHnqqYXpz8thBcAcx3opb_7mhD3Fo6fPw_Z-H-fgE-E1xUmBW4VcrWCufB_EcUMi0KYftUvoxdPQrfsGrOHk/s320/vwevent-iPad-sh2.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq_BEzuedPaf4rMgxiFJFGXUIY1OE9zEn2UOt92yyoOoX3ai6XSuwzu90jPGXKwI_eXmXC6WYWVbUugEJYlvyachHurbwGICIA65kjGp3qlWFuZDR52fPMI8_KU69VSVZ0kVmJ2lASCqA/s1600/vwevent-iPad-sh3.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq_BEzuedPaf4rMgxiFJFGXUIY1OE9zEn2UOt92yyoOoX3ai6XSuwzu90jPGXKwI_eXmXC6WYWVbUugEJYlvyachHurbwGICIA65kjGp3qlWFuZDR52fPMI8_KU69VSVZ0kVmJ2lASCqA/s320/vwevent-iPad-sh3.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjcHo7PTFxHYNatf-soNVD8sV-NceimDy0QDb2q0QORG6bOR40Vdj-7daSJhXQbXCM7XDlTSHyCl3keECPUS4zlctGfaGkU7vEhoh9FtKQD2pkshFm_rYipzneuu5ECGOOiYewFypRxFA/s1600/vwevent-iPad-sh4.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjcHo7PTFxHYNatf-soNVD8sV-NceimDy0QDb2q0QORG6bOR40Vdj-7daSJhXQbXCM7XDlTSHyCl3keECPUS4zlctGfaGkU7vEhoh9FtKQD2pkshFm_rYipzneuu5ECGOOiYewFypRxFA/s320/vwevent-iPad-sh4.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3y5ir_PsfnlPZ9DFAikbWQtk5IAl63Cxe46SSBTAM054LITfZICLMzLCWFqkbx4X-8Oe1hQTzqtABdzJE3RvIham4YjuaNXM_eFPy5c3G8dAaMB4c88z8hlQGLqFdYx332qyoxQ3O8B4/s1600/vwevent-iPad-sh5.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3y5ir_PsfnlPZ9DFAikbWQtk5IAl63Cxe46SSBTAM054LITfZICLMzLCWFqkbx4X-8Oe1hQTzqtABdzJE3RvIham4YjuaNXM_eFPy5c3G8dAaMB4c88z8hlQGLqFdYx332qyoxQ3O8B4/s320/vwevent-iPad-sh5.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyOQPRYUSsT0qYqwNN88hyTDc8iyhCqV37JSXWnJ_0JbBI2_h87Tcf7Fle1tSCraoFApb-0cYmLkM3anv4myrij1P2yXZLslnQXQYETuIFPAZ93rV7vYJL1zeCdDR3h8z9A2nwkta_nJI/s1600/vwevent-iPad-sh6.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyOQPRYUSsT0qYqwNN88hyTDc8iyhCqV37JSXWnJ_0JbBI2_h87Tcf7Fle1tSCraoFApb-0cYmLkM3anv4myrij1P2yXZLslnQXQYETuIFPAZ93rV7vYJL1zeCdDR3h8z9A2nwkta_nJI/s320/vwevent-iPad-sh6.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieDvhqZjgT3tTOa84xXH6txCBtIQ85FSKaG3lST0icdCADehqeTpPPffBPPYQOAGcH-1ZCEwDegZtC8AF21uDWfZ47ylg-l67cRVOuUgarszqi9uyvYsslwim9LyzPuERA8I04326r1-A/s1600/vwevent-iPad-sh7.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieDvhqZjgT3tTOa84xXH6txCBtIQ85FSKaG3lST0icdCADehqeTpPPffBPPYQOAGcH-1ZCEwDegZtC8AF21uDWfZ47ylg-l67cRVOuUgarszqi9uyvYsslwim9LyzPuERA8I04326r1-A/s320/vwevent-iPad-sh7.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxs0aRgwOrVNWVZmmDkt3lMRhsiyWuHBaqw3NgK83EyHEaTexmjQV-QtcPmEavqj13IMjF-tnNfdarpIgVLcGVq9M4MwUnP2yQArHYegPTLNbBct_3d8ORl2si6heatBzPHe3mVOazDhk/s1600/vwevent-iPad-sh8.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxs0aRgwOrVNWVZmmDkt3lMRhsiyWuHBaqw3NgK83EyHEaTexmjQV-QtcPmEavqj13IMjF-tnNfdarpIgVLcGVq9M4MwUnP2yQArHYegPTLNbBct_3d8ORl2si6heatBzPHe3mVOazDhk/s320/vwevent-iPad-sh8.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW9LPZU00CVMCbEWa2lMOpeYOLpQWyJO_VCZVhwteB08xeKBGELgKGTNy5eCKAisnZXzTC3yJ5o5ytX_wTGLzJNzYmujc-DsrY1z2xRDlVi01Og2Qn0yAFSlYMEjv-hCOH2JYU-bJWTok/s1600/vwevent-iPad-sh9.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW9LPZU00CVMCbEWa2lMOpeYOLpQWyJO_VCZVhwteB08xeKBGELgKGTNy5eCKAisnZXzTC3yJ5o5ytX_wTGLzJNzYmujc-DsrY1z2xRDlVi01Og2Qn0yAFSlYMEjv-hCOH2JYU-bJWTok/s320/vwevent-iPad-sh9.jpg" width="320" /></a></div>
<br />Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-70544729737460045262013-07-02T17:38:00.001-07:002013-10-22T20:09:30.776-07:00A little taste of SymfonyNeeded to work on a Target application that was built using <a href="http://symfony.com/" target="_blank">Symfony</a>. I am not convinced that I should leave <a href="http://ellislab.com/codeigniter" target="_blank">Codeigniter</a>.Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-6456569543796156102013-06-20T17:15:00.000-07:002013-09-19T11:05:35.666-07:00VW Merge & Purge campaignThis application uses Javascript framework backbone and several APIs built using PHP. I was working on the backend PHP with MySQL. The one major component is PHP GD image. All the Facebook feed images are generated with dynamic information using GD.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvpPZhY6MPPu4oe4q7JxeYxZJx2zfllFIO9BTEWJNJQeTLxdxtes0JqV6JTNNpgZmOxdzlmgn4sarM5sJ7-JZwvrnj1-AdDWEYVIN2ctgQSPfqVsh5JVSqdsyxr_EUOqSMKC5OmmwdcjE/s812/2013-07-02_1706.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvpPZhY6MPPu4oe4q7JxeYxZJx2zfllFIO9BTEWJNJQeTLxdxtes0JqV6JTNNpgZmOxdzlmgn4sarM5sJ7-JZwvrnj1-AdDWEYVIN2ctgQSPfqVsh5JVSqdsyxr_EUOqSMKC5OmmwdcjE/s320/2013-07-02_1706.png" width="306" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihyTlls8lrW6E8CUjxeOZCcW122ZLheXTsPLgcpqcCZNnqvN-78Kjl4fhOgegi4WbipQdOOkbieyAFR5MKO7aR5xB_fAVwXgEehMCcCuVuStDHRPxzTcHvZQWDkomqFFuBUaQOdfY4mjg/s812/2013-07-02_1707.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihyTlls8lrW6E8CUjxeOZCcW122ZLheXTsPLgcpqcCZNnqvN-78Kjl4fhOgegi4WbipQdOOkbieyAFR5MKO7aR5xB_fAVwXgEehMCcCuVuStDHRPxzTcHvZQWDkomqFFuBUaQOdfY4mjg/s320/2013-07-02_1707.png" width="307" /></a></div>
<br />Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-10062638403475520302013-06-03T17:03:00.000-07:002013-07-02T17:49:13.829-07:00iPhone app: real time video sharingAn native iPhone app prototype that steams camera video between two iPhones. Not very complex, but it took a good amount of research and learning. Major classes are NSOperation, AVFoundation and GameKit.<br />
<ul>
<li>Multi-threading is necessary to prevent UI lockup, so NSOperation is used. </li>
<li>AVFoundation
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer (CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
is the key element to capture video frames from camera. </li>
<li>GameKit peer-to-peer communication via Bluetooth is used to send and receive data between two devices. </li>
</ul>
Result was that I was able to reach about 4 frames per second. Did not get to try Game Center peer-to-peer via local WiFi. I believe that will increase the frame rate.Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0tag:blogger.com,1999:blog-8906402018464401223.post-72409630227302054322013-05-06T16:00:00.000-07:002013-07-02T16:45:53.464-07:00NodeJS and real time communication applicationIt is always fun to try out something new. This time I had time to create a prototype game that uses NodeJS server and PubNub API. Multiple players join the game to answer a movie trivial question. Whoever answer the question correctly first gets to control the movement of a real object remotely. Players that do not win can keep playing the game while the winner controls the real object. The server app keeps track of the winner, game status and the real object status. Making sure only one player has access to control the real object.Wilsonhttp://www.blogger.com/profile/13694540072265836032noreply@blogger.com0