Pages

Saturday, May 18, 2013

Quick Tip: Set socket.io log level in zappajs

I've been working on a zappajs based website that has a socket.io connection to the browser. By default socket.io likes to output a lot of debug text. I got tired of seeing it all and wanted to turn it off. Thankfully, it's easy.

At the top level of your zappajs instance definition, right alongside where you define your @use statements, define routes/templates, and so on, you can call into the @io object, which is a reference into the socket.io server-side instance. You just put:

@io.set 'log level', 1

-- or if you like closer to "regular" javascript syntax you can do: --

@io.set('log level', 1)

Log level 1 is the least chatty of them all. You can see the different levels to choose the one you want here.

Friday, March 8, 2013

"do" stuff in Coffeescript

I can't deny that I have an attraction to coffeescript. I can't even fully explain it. I think it might be the super-tight syntax, ability to not have to depend on parenthesis or curly brackets, and zippy server-side templating engines like CoffeeKup or Eco. Of course there are pros and cons to coffeescript (I'll abbreviate to CS), and I definitely don't use it in all cases. The point of this post isn't to love or hate on CS; I'll leave that to others more qualified than myself.

As I've been learning CS there are a couple of things I normally do in javascript that I couldn't quite figure out how to do:
  • The right way to call a function with no arguments
  • Immediately execute anonymous functionality, like in a switch statement
It turns out that they both hinge on using the same keyword: "do."

No-Argument Functions
CS is very sparse in its use of parenthesis; calling functions with arguments makes clear sense, but it's not immediately clear how functions without arguments get called. Check out the two lines of code:

The second line of code seems logical, but we can't forget this is still javascript. The processData function is an object after all, so that line of code merely assigns processData to returnData. Adding parenthesis works - that is, processData() - but I figured there was a more "coffeescript-y" way to do it. Enter "do:"

There is the CS way to do things! Calls the function perfectly. "do" Helps us elsewhere too:

Immediately Call Anonymous Functionality:
In a similar fashion, there are times when an anonymous function is immediately called, as opposed to in a callback fashion. I'll just show the code:

Again, "do" is the secret weapon here. When supplying callback function to CS, you can just specify inline without "do." But in the case of the switch statement it needs to called immediately, hence the keyword.

Those are the two cases that I was able to find, but perhaps there are more ways "do" is used in CS. Did I miss anything?

Tuesday, January 15, 2013

How to: Receive NFC data in an Adobe AIR Android app

Getting NFC data into an Adobe AIR for Android application is much easier than it might seem. At least, it's a lot easier than I thought it would be.

I'm currently working on an app that has just such a need. Specifically, users will run the AIR app and then swipe their device over a physical display that has some NFC tag hotspots. The app needs to receive the NFC data from each tag and react in a specific fashion. I didn't know much about NFC data when I began working on this current app, and since AIR doesn't have official support for NFC I figured I would need a native extension to properly handle things.

It turns out it is *much* simpler than needing to implement any sort of native functionality. All you have to do is add the proper intent handling to the "manifestAdditions" portion of the AIR application xml. I'll put a sample xml block here, and then explain it:


The key to making everything work is in effect "extending" the <application> node - which prior to discovering this I didn't know was possible. By adding the appropriate NFC intent filter information - the "default" way you handle NFC data in Android - the AIR application is handed the day the same way any other Android application would be.

In the xml sample above, I have  my AIR app responding to a URI. I've got placeholders for the scheme and host attribute values. Most commonly these will represent a web URL; in that case scheme would be "http" and host would be the domain - "yourdomain.com". But if you want to use proprietary data, you can do that too. Scheme and host can be anything. Scheme could be "my" and host could be "uri.value" which would represent "my://uri.value." It doesn't really matter, the data will make it to the AIR app. This is just one way of targeting NFC data into an app - there are a number of different ways to use intent filters in Android to target varied NFC data types. Virtually all of them should work as manifest extensions for an AIR app. The Android documentation has information about targeting NFC data here.

Extending the manifest only gets us so far; it doesn't tell us how the data gets into the AIR application. Thankfully, Adobe has facilitated that too. Anytime the app responds to intent filter data, an InvokeEvent.INVOKE event gets fired. Check out the below class:

To be clear, the invoke event will in fact be fired when the app starts up, but will *also* be fired whenever the NFC intent data qualifies and is passed to the app. This means that the app will be handed any and all relevant NFC data and can respond by reading the events.arguments data.

This also has the added effect of launching your AIR application whenever the relevant NFC data is swiped. That's actually what Android generally means to have happen with NFC data - the user swipes their device and the relevant specific application is opened. This will in fact do that. But as this post discusses, it will also pass in the NFC data while the application is running.

If you aren't wanting the app to be launched on NFC data but instead *only* respond to the NFC data while the application is open, that requires more complexity. It does, in fact require a native extension interacting with something called the "Foreground Dispatch". A very intelligent person has actually cracked the code and has made, well, the source code available for free! You can see it here:

http://code.google.com/p/ane-lab/source/browse/#svn%2Ftrunk%2Fmobile%2Fandroid%2Fjava%2Fnfc-foreground-dispatch

I hope this helps!

Monday, December 10, 2012

Boxresizer FTW!

You may have noticed that I recently added a set of social icons to the sidebar of the ol' blog here. Don't they just look pretty there in the page? Yeah, I thought so too.

I created the icons at a resolution of 128px by 128px, just to have some extra image to work with; I figured I may end up using the icons in varied contexts. I also knew I'd be scaling-down the icons when I embedded them in the blog page layout.

I assumed that these days pretty much all modern browsers take care of smoothing out scaled images just fine, but turns out I was wrong. It's better than it used to be, but it still doesn't compare to a resample that you'd expect. I embedded the images in the page, manually setting their dimensions, and I was seeing enough jaggies to bug me.

I didn't want to have to create new, resized versions of the icons every place I used them, so I started looking for a website that would do real-time, url-based image scaling. I knew there were sites/services like that out there, but when I started my hunt they were actually harder to find than I expected.

Thankfully, I eventually stumbled upon Boxresizer. It was exactly what I was looking for: you call a particular URL including your source image, resulting size, and boom, they output a nice, smoothly scaled version of the image!
Boxresizer makes Octocat happy...
...because it makes him super sneaky small ninja Octocat!

If you want to see sample URLs of how Boxresizer works, just hit up their site or copy the image location of Octocat here or the other images in the sidebar. Both Firefox and Chrome have an option to copy the URL when you right-click on an image.

PROTIP: Don't forget, though, that when you're passing your image URLs to the Boxresizer URL, it needs to be URL encoded. You can't just pass the image path as is. Thankfully, there are tons of online tools to URL encode a string, like this one.

Sunday, November 25, 2012

RenderMode = direct required for camera in Adobe Air Android

I'll go over this one in reverse order to get the most relevant information in front of ya'll's eyeballs as fast as possible. (Oh yes I did just use a double contraction there.)

The Solution

When you want to get a raw, realtime image feed from the device camera in an Adobe AIR application on Android, you have to set the "renderMode" property in the app xml file to "direct" in order for it to work *at all*.

The Problem

If you don't set the renderMode property as such, when you are displaying the live camera image in your AIR app, you'll see something like this:
The gobbledeegook here has nothing to do with a turkey.


Just to be clear, I'm talking about the <renderMode>{someValue}</renderMode> node, which is a child of the <initialWindow> node in the AIR app xml file. To get things to work, "{someValue}" needs to be "direct."

As far as I can tell, I've come across this oh-so interesting behavior within a perfectly normal AIR application that I am running/developing/testing on my Android phone. These are the details on my app:
  • A Flex mobile app, running with installed AIR 3.5.
  • All UI layouts are in mxml.
  • In the code, the Camera/Video object instances are ending up added as a child to a <mx:UIComponent />.
  • My development device is a Galaxy S2 running Android 4.0.
Like I say, nothing too exotic going on there; seems like things should just work. I obviously had to go hunting when I first encountered this issue, but unfortunately I can't remember where I stumbled upon the idea to mess with the renderMode property. I'm aware it's possible this is specific to my device, version, etc. of Android.

But, Hopefully this will help someone out there!

Sunday, November 11, 2012

Gettin' wifi to work on my Raspberry Pi

Lately I've been geeking out with my Rapsberry Pi, which I've had for about a month now. I've now got all the accessories that I think I'm gonna need for it. Check out the setup:

Good fun for all nerds in the land
My most recent addition was a wifi dongle. I got a dongle with the Ralink 5370 chipset in it, which seems to be pretty popular in Raspberry Pi land. This is the adapter I got and the site where I purchased:

Ralink 5730 Dongle on DX.com

(Word to the wise though, it took 3 weeks for my order to get to me. Shipping costs were free, but that was a tough wait. You might want to pay to speed shipping up or find another dongle from another site.)

I didn't know what it would be like to get the dongle working, but as it turns out, it's very easy. Here's some notes on my experiences:
  • As it turns out, if you've burned your Pi distro image anytime probably within the last 6 months or sooner, you've got more or less what you need to get the Ralink and probably many other chipsets working.
  • This post had the info I needed to get things working:
    http://raspberry-pi-notes.blogspot.com.au/2012/05/rt5370-cheap-micro-usb-wireless-dongle.html
  • In short, you can remove anything related to "wlan0" and just put in what is in step 8 of that post. 
  • But! know what type of encryption you have on your wifi router. After logging in to my router I found out it was WPA-PSK, and the lines related to "wireless-*****" were not relevant. Al posted the way to modify the interfaces file - remove the "wireless-*****" lines and instead put:

    wpa-ssid <yourssid>
    wpa-psk <yourkey>

    Which means that only 4 lines are required in the interfaces file to get the dongle working.
  • I use a Logitech wireless keyboard when I'm directly working on the Pi; you can sort of see its little dongle in the bottom USB port in my picture. Interestingly, when I had both the wifi dongle and keyboard dongle in the standard Pi USB ports, the keyboard wouldn't work. I'm thinking the wifi radio signal was drowning out the keyboard signal. Moving the wifi dongle over to the small hub I've got made things work.
And with that, my Pi is now happily connecting to the internet, at least when in terminal mode. I can ssh to it and everything. Best of luck as you attempt to get wifi working on your Pi!