<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>This Is Not a Blog</title><link href="http://www.peterhansen.ca/blog" rel="alternate"></link><link href="http://www.peterhansen.ca/blog/feeds/all.atom.xml" rel="self"></link><id>http://www.peterhansen.ca/blog</id><updated>2011-11-29T18:12:00Z</updated><entry><title>BBX Python: Self-contained Demo App</title><link href="http://www.peterhansen.ca/blog/bbx-python-self-contained-demo-app.html" rel="alternate"></link><updated>2011-11-29T18:12:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-29:/blog/bbx-python-self-contained-demo-app.html/</id><summary type="html">&lt;p&gt;Earlier today I wrote about how it turns out that the Tablet OS (&lt;em&gt;2.0.0 beta or later&lt;/em&gt;) actually recognizes
Python as a &lt;a class="reference external" href="http://peterhansen.ca/blog/bbx-python-direct-entry-point.html"&gt;direct &amp;quot;entry point&amp;quot;&lt;/a&gt;
for apps, as it does for apps built using AIR or the Native SDK
(WebWorks apps use the AIR entry point at this time).&lt;/p&gt;
&lt;p&gt;With the original crude launcher, we'd developed a small set of
experiments and demonstration scripts, which you had to copy
over the network to &amp;quot;documents/scripts&amp;quot;, with the
&lt;tt class="docutils literal"&gt;bbxrun.py&lt;/tt&gt; file sitting above to let you select which one to run.&lt;/p&gt;
&lt;p&gt;I've taken the whole mess and packaged it up using
the new approach, with a signed .bar file up so you can
try it out for yourself if you'd like.  (Download link is at the end of this post.)&lt;/p&gt;
&lt;p&gt;Some of the demo scripts are purely experimental or proofs-of-concept,
without even a visible UI (except a blank screen) while they run.
Some do something visible in the UI or interact in other ways.
Following is a brief description of each.&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="19%" /&gt;
&lt;col width="81%" /&gt;
&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;deviceinfo.py&lt;/td&gt;
&lt;td&gt;Dispay a dialog with &amp;quot;device information&amp;quot; such as PIN and serial number.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;display_info.py&lt;/td&gt;
&lt;td&gt;Dump information about attached displays (LCD and HDMI) to log file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;event_test.py&lt;/td&gt;
&lt;td&gt;For 6s get screen, navigator, and virtual KB events, output to log file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;geotrace.py&lt;/td&gt;
&lt;td&gt;For 60s get GPS updates and output to log file, with satellite count.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;image_test.py&lt;/td&gt;
&lt;td&gt;For 3.5s blast small bitmap scaled to 1/4 size to screen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;notifications.py&lt;/td&gt;
&lt;td&gt;Generate several notifications in different styles, one being interactive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;os_info.py&lt;/td&gt;
&lt;td&gt;Write data from Python &amp;quot;os&amp;quot; package to log file (e.g. PID, current directory).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;play_sound.py&lt;/td&gt;
&lt;td&gt;Play a brief WAV file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;psychedelic.py&lt;/td&gt;
&lt;td&gt;For 5s randomly flash the screen different colours 25 times per second.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;python_info.py&lt;/td&gt;
&lt;td&gt;Write data from Python &amp;quot;system&amp;quot; package to log file (e.g. version, path).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The log file the demo app writes to is the usual in-sandbox file (under &lt;tt class="docutils literal"&gt;logs/log&lt;/tt&gt;)
but once you exit the app &lt;strong&gt;using the Cancel button&lt;/strong&gt; it copies it to
&lt;tt class="docutils literal"&gt;documents/ca.microcode.bbxpython.demo.log&lt;/tt&gt; so you can view it on your computer.
(It should be possible to respond to the &lt;tt class="docutils literal"&gt;NAVIGATOR_EXIT&lt;/tt&gt; event by doing the same
thing in a later update.)&lt;/p&gt;
&lt;p&gt;I should be able to include the
&lt;a class="reference external" href="http://peterhansen.ca/blog/bbx-python-freetype2-fonts.html"&gt;font_test.py&lt;/a&gt; demo
in a few days after I get a chance to refactor and optimize it a bit.&lt;/p&gt;
&lt;p&gt;The demo app is available in the &lt;a class="reference external" href="http://microcode.ca/bbx-python/downloads/"&gt;downloads folder as bbxpython-demo-x.x.x.x.bar&lt;/a&gt; with whatever version it happens
to be at when you download it.&lt;/p&gt;
&lt;p&gt;Source code code is in the &lt;a class="reference external" href="http://hg.microcode.ca/bbx-python/src/tip/demo"&gt;bbx-python bitbucket&lt;/a&gt;
repository, or you could just look in the .bar file since this version doesn't use
compiled bytecode, but .py source files.&lt;/p&gt;
&lt;p&gt;Future updates won't result in this page changing... I'll start including in-app
documentation and/or a separate page in the wiki where it can more easily be
maintained.&lt;/p&gt;
&lt;p&gt;As usual, follow the news on Twitter using hash tag
&lt;a class="reference external" href="http://twitter.com/#!/search/%23bbx-python"&gt;#bbx-python&lt;/a&gt; or follow me at
&lt;a class="reference external" href="http://twitter.com/#!/peter9477"&gt;&amp;#64;peter9477&lt;/a&gt;.&lt;/p&gt;
</summary></entry><entry><title>BBX Python: Direct Entry Point!</title><link href="http://www.peterhansen.ca/blog/bbx-python-direct-entry-point.html" rel="alternate"></link><updated>2011-11-29T12:06:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-29:/blog/bbx-python-direct-entry-point.html/</id><summary type="html">&lt;p&gt;Okay, this is just too cool not to mention right away!&lt;/p&gt;
&lt;p&gt;Jeff Kehres from RIM has been following the progress on and off, and
pointed out today the existence of the &lt;em&gt;blackberry-pythonpackager&lt;/em&gt;
that's already included in the NDK tools.&lt;/p&gt;
&lt;p&gt;I therefore herewith present the classic tiny &amp;quot;hello, world&amp;quot; app
for the PlayBook, written in Python and with output going only to the
&lt;tt class="docutils literal"&gt;appdata/logs/log&lt;/tt&gt; file (to which stdout is redirected by default).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;hello, world&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Okay, and let's make a nice icon for it (and by &amp;quot;nice&amp;quot;, I mean only
&amp;quot;really small file size&amp;quot;):&lt;/p&gt;
&lt;img alt="static/files/bbxpy_tiny_icon.png" src="static/files/bbxpy_tiny_icon.png" /&gt;
&lt;p&gt;Now we need a bar-descriptor.xml file.  I'll include one stripped of comments
and whatever else I can find that's optional.  Note the line with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;entry=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="pre"&gt;type=&amp;quot;Qnx/Python&amp;quot;&lt;/span&gt;&lt;/tt&gt; as that right there is the magic
key to the kingdom.
Also you do need the &lt;tt class="docutils literal"&gt;run_native&lt;/tt&gt; action (including the
system=&amp;quot;true&amp;quot; part if you'll ever sign the app for distribution):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;
&amp;lt;qnx xmlns=&amp;quot;http://www.qnx.com/schemas/application/1.0&amp;quot;&amp;gt;
    &amp;lt;id&amp;gt;ca.microcode.bbxpython.m2&amp;lt;/id&amp;gt;
    &amp;lt;name&amp;gt;BBXPyTiny&amp;lt;/name&amp;gt;
    &amp;lt;versionNumber&amp;gt;0.0.1&amp;lt;/versionNumber&amp;gt;
    &amp;lt;description&amp;gt;BBX-Python Tiny App&amp;lt;/description&amp;gt;
    &amp;lt;author&amp;gt;Your Name Here&amp;lt;/author&amp;gt;
    &amp;lt;authorId&amp;gt;gYAUseYour_OwnIdvPY&amp;lt;/authorId&amp;gt;
    &amp;lt;initialWindow&amp;gt;
    &amp;lt;systemChrome&amp;gt;none&amp;lt;/systemChrome&amp;gt;
    &amp;lt;transparent&amp;gt;false&amp;lt;/transparent&amp;gt;
    &amp;lt;/initialWindow&amp;gt;
    &amp;lt;icon&amp;gt;&amp;lt;image&amp;gt;icon.png&amp;lt;/image&amp;gt;&amp;lt;/icon&amp;gt;
    &amp;lt;asset path=&amp;quot;icon.png&amp;quot;&amp;gt;icon.png&amp;lt;/asset&amp;gt;
    &amp;lt;asset path=&amp;quot;main.py&amp;quot; entry=&amp;quot;true&amp;quot; type=&amp;quot;Qnx/Python&amp;quot;&amp;gt;main.py&amp;lt;/asset&amp;gt;
    &amp;lt;action system=&amp;quot;true&amp;quot;&amp;gt;run_native&amp;lt;/action&amp;gt;
&amp;lt;/qnx&amp;gt;
&lt;/pre&gt;
&lt;p&gt;We need to build and deploy it:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
c:\dev\bbxpy\tiny&amp;gt; bbndk-env.bat
...
c:\dev\bbxpy\tiny&amp;gt; blackberry-pythonpackager -devMode test.bar bar-descriptor.xml
Info: Package created: test.bar

c:\dev\bbxpy\tiny&amp;gt; blackberry-deploy -installApp -package test.bar -device PBIP -password PBPASS
Info: Sending request: Install
Info: Action: Install
Info: File size: 2414
Info: Installing ...
Info: Processing 2414 bytes
actual_dname::ca.microcode.bbxpython.m2.testDev_bxpython_m2f3b6aa2c
actual_id::testDev_bxpython_m2f3b6aa2c
actual_version::0.0.1.0
result::success
&lt;/pre&gt;
&lt;p&gt;Note the file size... it's always nice when you don't need a lot of setup and
boilerplate code in the way.  Of course, it doesn't actually do much, but we
can bloat it up a bit later.&lt;/p&gt;
&lt;p&gt;That worked because I had a debug token (from which I got my authorId info for the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;bar-descriptor.xml&lt;/span&gt;&lt;/tt&gt; file above) already installed on my tablet.  The alternative
would be not to use &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt; during packaging, but use your code signing key
instead, with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-sign&lt;/span&gt;&lt;/tt&gt; option and info about your keystore and password.&lt;/p&gt;
&lt;p&gt;Here it is installed and ready to run, as the last icon in the list:&lt;/p&gt;
&lt;img alt="static/files/bbxpy_tiny_ss.jpg" class="pbscreenshot" src="static/files/bbxpy_tiny_ss.jpg" /&gt;
&lt;p&gt;Run it, and you briefly get an all-white screen and then it exits.&lt;/p&gt;
&lt;p&gt;Let's log in via SSH using PuTTY and see the aftermath:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Using username &amp;quot;devuser&amp;quot;.
Authenticating with public key ...
$ cd /accounts/1000/appdata/ca.microcode.bbxpython.m2.testDev_bxpython_m2f3b6aa2c
$ cd logs
$ cat devmode_exitcode.txt
0
$ cat log
hello, world
&lt;/pre&gt;
&lt;p&gt;And what's the installed app code folder look like?&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls -l /apps/ca.microcode.bbxpython.m2.testDev_bxpython_m2f3b6aa2c/
total 16
drwxrwx---   2 apps      dev1           4096 Nov 29 12:28 META-INF
drwxrwx---   2 apps      dev1           4096 Nov 29 12:28 python
$ ls -l /apps/ca.microcode.bbxpython.m2.testDev_bxpython_m2f3b6aa2c/python
total 5
-rw-rw----   1 apps      dev1            710 Nov 29 12:28 bar-descriptor.xml
-rw-rw----   1 apps      dev1            796 Nov 29 12:28 icon.png
-rw-rw----   1 apps      dev1             22 Nov 29 12:28 main.py
&lt;/pre&gt;
&lt;p&gt;So that pretty much eliminates the need for the native stub launcher code
that &lt;a class="reference external" href="http://peterhansen.ca/blog-staging/bbx-python-proof-of-concept.html"&gt;started this whole thing off&lt;/a&gt;
for me.  Hasta la vista, baby.
It's over for us: I've found someone younger... and 25K thinner.&lt;/p&gt;
&lt;p&gt;Thanks for sharing that tip, Jeff!  I'm happy not to spend time on
improving the build tools for now, and this cuts out one more bit of
complexity.  Python should always look this clean and simple!&lt;/p&gt;
&lt;p&gt;One note to any rookies: Python actually compiles to bytecode, which
is stored in .pyc files. It's unlikely you'd want to include your
entire app in source form (.py files), so for any real app you'll
among other things want to compile the .py files to .pyc at packaging
time and include those instead of a mass of .py files.  The package
will be smaller and startup time will be shortened a bit as the
runtime won't be compiling your code each time the app launches.
I'll go into more detail on this whole area in later posts.&lt;/p&gt;
</summary></entry><entry><title>BBX Python: FreeType2 Fonts</title><link href="http://www.peterhansen.ca/blog/bbx-python-freetype2-fonts.html" rel="alternate"></link><updated>2011-11-27T00:05:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-27:/blog/bbx-python-freetype2-fonts.html/</id><summary type="html">&lt;p&gt;This is definitely not ready for serious use, but I thought I'd share
a screenshot with the first text rendering support for
&lt;a class="reference external" href="http://microcode.ca/bbx-python/"&gt;BBX-Python&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="static/files/bbxpython_text.jpg" class="pbscreenshot" src="static/files/bbxpython_text.jpg" /&gt;
&lt;p&gt;The code's too crude to commit yet, and it's ridiculously sluggish
at the moment, since I'm using FreeType to render each character
and then -- in Python! -- copying over each pixel into a libscreen
pixmap buffer which is then blitted onto the screen.  One character
at a time.&lt;/p&gt;
&lt;p&gt;But hey!  I've got some text output!&lt;/p&gt;
&lt;p&gt;Here's the top-level code which generated that screen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill_screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x337733&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;xpos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="n"&gt;draw_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;shared/documents/scripts/logo.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xff5511&lt;/span&gt;
&lt;span class="n"&gt;fontsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;
&lt;span class="n"&gt;leading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
&lt;span class="n"&gt;ypos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;BBX-Python!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;The time is &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;Python &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;Visit http://microcode.ca/bbx-python/ to learn more.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;draw_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ypos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ypos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;leading&lt;/span&gt;
    &lt;span class="n"&gt;fontsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xffffff&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary></entry><entry><title>BBX Python: Quick Update #1</title><link href="http://www.peterhansen.ca/blog/bbx-python-quick-update-1.html" rel="alternate"></link><updated>2011-11-24T23:31:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-24:/blog/bbx-python-quick-update-1.html/</id><summary type="html">&lt;p&gt;Here are a few quick notes on what's happened with
&lt;a class="reference external" href="http://microcode.ca/bbx-python/"&gt;BBX-Python&lt;/a&gt; since the last update.&lt;/p&gt;
&lt;div class="section" id="core-launcher"&gt;
&lt;h2&gt;Core: Launcher&lt;/h2&gt;
&lt;p&gt;I stripped almost everything out of the launcher, leaving it as just
the bare bones required to initialize the Python interpreter
and run the main script.&lt;/p&gt;
&lt;p&gt;That meant taking out all the OpenGL code, along with everything to
do with screen contexts, event handling, and other BPS stuff.&lt;/p&gt;
&lt;p&gt;This brought it down to under 24K for the native code portion of
the launcher, but had the unfortunate side effect of triggering
the OS app police, which terminates any app which doesn't &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Native-SDK-for-BlackBerry-Tablet/Minimalist-app-is-getting-terminated-after-30s-why/td-p/1428935"&gt;post
a window update within 30s of launching&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="user-interface"&gt;
&lt;h2&gt;User Interface&lt;/h2&gt;
&lt;p&gt;I looked into using &lt;a class="reference external" href="http://pyopengl.sourceforge.net/"&gt;PyOpenGL&lt;/a&gt; but
it appears we have only &lt;a class="reference external" href="http://en.wikipedia.org/wiki/OpenGL_ES"&gt;OpenGL ES&lt;/a&gt;
on the PlayBook, and the author of PyOpenGL (&lt;a class="reference external" href="http://blog.vrplumber.com/"&gt;Mike Fletcher&lt;/a&gt;)
tells me that
it's likely non-trivial to modify/port PyOpenGL to work with it.  The two
are apparently quite similar, but have enough differences that it could be
quite a pain.  I'll leave this on the back-burner until later, or until I
learn more.&lt;/p&gt;
&lt;p&gt;In the interim, we've got the QNX Dialog support, and full Notifications
support. The dialog demo code is doing system modal dialogs, which is a pain,
but I wouldn't expect it's hard to make that non-modal at which point it
should prove to be quite usable.&lt;/p&gt;
&lt;p&gt;I've also integrated the &lt;a class="reference external" href="https://github.com/blackberry/NDK-Samples/blob/master/ScreenTemplate/main.c"&gt;minimal app requirements&lt;/a&gt;
into &lt;tt class="docutils literal"&gt;bbxrun.py&lt;/tt&gt;,
so that it no longer times out after 30s and gets turfed by the OS.&lt;/p&gt;
&lt;p&gt;It shouldn't be a huge amount of work to get some basic bitmap stuff
going with the img/img.h functions, so that's high on the list of todos.
With some third-party bitmap library (PIL?), either pure Python or ported
to QNX, we could probably do some decent basic UIs using just bitmaps.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="libraries"&gt;
&lt;h2&gt;Libraries&lt;/h2&gt;
&lt;p&gt;I've added some &lt;a class="reference external" href="http://docs.python.org/py3k/library/ctypes.html"&gt;ctypes&lt;/a&gt;
wrapper modules for much of &lt;a class="reference external" href="https://bdsc.webapps.blackberry.com/native/reference/com.qnx.doc.bps.lib_ref/com.qnx.doc.bps.lib_ref/topic/about_bps_8h.html"&gt;bps/bps.h&lt;/a&gt;
(and siblings) and all of &lt;a class="reference external" href="https://bdsc.webapps.blackberry.com/native/reference/com.qnx.doc.screen.lib_ref/topic/cscreen_api_components.html"&gt;screen/screen.h&lt;/a&gt;.
This allowed doing the &amp;quot;minimal app requirements&amp;quot; above: create screen
context, window, buffer, post one update to window.&lt;/p&gt;
&lt;p&gt;There's code integrated into the latest &lt;tt class="docutils literal"&gt;bbxrun.py&lt;/tt&gt; to set this up,
and simplistic demo code in &lt;tt class="docutils literal"&gt;psychedelic.py&lt;/tt&gt; to rapidly flash the screen
different colours.&lt;/p&gt;
&lt;p&gt;The bps and screen modules also allow event handling, so I threw in an
&lt;tt class="docutils literal"&gt;event_test.py&lt;/tt&gt; quickly, just to verify it will work.  No real problems
with that, but it will need an Event class and subclasses added to wrap
all these events.  No idea how people actually write apps using the
low-level C stuff this is all built on... or maybe nobody really does.
Anyway, the Python version will be &lt;em&gt;much&lt;/em&gt; easier on the eyes, brain, and
fingers.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="next-priorities"&gt;
&lt;h2&gt;Next Priorities&lt;/h2&gt;
&lt;p&gt;I think I'll probably attack the following things next, in order:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Basic bitmap support through &lt;tt class="docutils literal"&gt;img/img.h&lt;/tt&gt;, at least part of it. Goal
will be to display at least full-screen bitmaps, preferably including
smaller bitmaps at arbitrary positions. Could go pretty far with just that.&lt;/li&gt;
&lt;li&gt;Event class and a core App class that can provide the basic event-handling
loop, and allow the rest of the app to be written as event-driven code
in conventional fashion.  This stuff is mostly tedious but straightforward.
I'll need to add some more ctypes wrappers; for now I'm doing that manually
but in the long run it will be better handled with some automated conversion
of the header files.  The &lt;a class="reference external" href="http://pypi.python.org/pypi/ctypeslib/"&gt;ctypeslib&lt;/a&gt;
can do that, though it's alpha-stage code and my first attempts at using
it failed for various and sundry reasons, when tried on QNX, Windows, or Linux.
I've done this before for other projects, and it's not terribly hard;
it should be even easier in this case because the QNX header files are
quite consistent and clean.&lt;/li&gt;
&lt;li&gt;With those two things, one could actually write some simple apps. That
will push the focus back to the BBX-Python core and the launcher, plus
tools.  Next step will be to make the launcher able to run code specified
in an environment variable (that gets into the &lt;tt class="docutils literal"&gt;MANIFEST.MF&lt;/tt&gt; Entry-Point),
and make a basic tool to generate .bar files combining the canned launcher code
plus the developer's Python code.  That would probably constitute completion
of the first phase of this project...&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What else?  Now's a good time to start chiming in with some comments
here, or discussion on the #bbx-python IRC chat on freenode.net (go to
&lt;a class="reference external" href="http://webchat.freenode.net/"&gt;webchat.freenode.net&lt;/a&gt; if you don't have an
IRC client installed, and join the #bbx-python channel.&lt;/p&gt;
&lt;p&gt;Alternatively, follow the &lt;a class="reference external" href="http://twitter.com/#!/search/%23bbx-python"&gt;#bbx-python hash tag&lt;/a&gt;
on Twitter to stay abreast of progress.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note that one purpose of this project is to make visible the existence
of a potential Python/PlayBook community: if you're interested but staying
silent, you're working against your own interests!&lt;/em&gt;  &lt;strong&gt;Speak up and be seen!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
</summary></entry><entry><title>BBX Python: Next Steps</title><link href="http://www.peterhansen.ca/blog/bbx-python-next-steps.html" rel="alternate"></link><updated>2011-11-21T08:42:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-21:/blog/bbx-python-next-steps.html/</id><summary type="html">&lt;p&gt;My
&lt;a class="reference external" href="http://peterhansen.ca/blog/bbx-python-proof-of-concept.html"&gt;recent&lt;/a&gt;
&lt;a class="reference external" href="http://peterhansen.ca/blog/bbx-python-progress-stage-two.html"&gt;posts&lt;/a&gt;
have talked about running &lt;a class="reference external" href="http://peterhansen.ca/blog/bbx-python-project-site.html"&gt;Python 3.2 on the PlayBook&lt;/a&gt;.
While all versions of the PlayBook OS have used Python internally &lt;a class="footnote-reference" href="#id6" id="id1"&gt;[1]&lt;/a&gt;, the
&lt;a class="reference external" href="https://bdsc.webapps.blackberry.com/android/beta/bbtablet20/register/"&gt;beta 2.0 OS&lt;/a&gt;
is the first to have a Python interpreter with read permissions set such that apps
can access it... for now, anyway.  (Unfortunately we have no guarantees that it will
remain accessible, but your input to RIM will help influence decisions about that.)&lt;/p&gt;
&lt;p&gt;This project is in an early stage, and could go any number of directions (perhaps
all at the same time).&lt;/p&gt;
&lt;div class="section" id="user-interfaces"&gt;
&lt;h2&gt;User Interfaces&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://twitter.com/#!/rpaskowitz"&gt;Rob Paskowitz&lt;/a&gt; is taking a stab at hooking up
the &lt;a class="reference external" href="https://github.com/blackberry/Qt"&gt;Qt port&lt;/a&gt; through the LGPL &lt;a class="reference external" href="http://www.pyside.org/"&gt;PySide&lt;/a&gt;
bindings.&lt;/p&gt;
&lt;p&gt;There's also an &lt;a class="reference external" href="https://github.com/blackberry/SDL"&gt;SDL&lt;/a&gt; port,
so getting &lt;a class="reference external" href="http://pygame.org/wiki/about"&gt;Pygame&lt;/a&gt;
running is a definite possibility.&lt;/p&gt;
&lt;p&gt;Another step for Flash-loving people would be to use an ANE layer from an AIR app
replacing the Python launcher, so that a Flash user interface could be hooked to &amp;quot;back-end&amp;quot;
business logic written in Python.  May sound crazy to some people, but from a
testability point of view, Python is potentially unmatched, while from a UI point of
view Flash has a lot of things working for it.&lt;/p&gt;
&lt;p&gt;I'm personally not highly concerned about the UI, partly because I can leave that
to others, partly because I have some confidence we'll eventually see RIM release
their &lt;a class="reference external" href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/a6a27b7f53e7f5fa/0e8a452537834b9c?lnk=gst&amp;amp;q=pycascadessdk#0e8a452537834b9c"&gt;PyCascadesSDK&lt;/a&gt;
package (presumably layered on Qt as well) and the issue will be
moot, and partly because I'm better at the plumbing...&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-plumbing"&gt;
&lt;h2&gt;The Plumbing&lt;/h2&gt;
&lt;p&gt;One idea I have is to simplify the &amp;quot;native stub&amp;quot; launcher code so that it doesn't
even bother with initializing anything aside from Python.  Maybe it would still
have to do a &lt;a class="reference external" href="https://bdsc.webapps.blackberry.com/native/reference/com.qnx.doc.bps.lib_ref/com.qnx.doc.bps.lib_ref/topic/bps_initialize.html"&gt;bps_initialize()&lt;/a&gt;
and a few basics, but I could skip the screen stuff.  It would invoke a Python
script named probably in an environment variable (specified in MANIFEST.MF),
and that's it.  Anything else would be done through libraries, from Python.&lt;/p&gt;
&lt;p&gt;Doing this would allow me to prepare a simple app packager, which would itself be in Python,
which would combine the native stub, the Python code, and a generated MANIFEST.MF
file together into a .bar file which would be a complete self-contained app.  For now
it could rely on having one of the other SDKs installed (Native, AIR, or WebWorks)
for the code-signing capability, but aside from that it appears possible to do already.
A couple of the required entries in a MANIFEST.MF file appear to be &amp;quot;opaque&amp;quot; hashes
of some kind (the short ones like Package-Version-Id) but I believe those could
be reverse-engineered if necessary, and the rest is straight-forward.  (If you have
any knowledge of those hashes, aside from the obvious SHA512 ones, please let me know.)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="third-party-native-extensions"&gt;
&lt;h2&gt;Third-Party Native Extensions&lt;/h2&gt;
&lt;p&gt;While any 3.2-compatible pure Python packages will work perfectly and
without change in this environment, there are also many interesting
third-party libraries which include some native code.  While I expect many
of them will work without much problem, there's still a need to compile
them with the NDK to make binaries available, and to test them out.  First one
I'd like to see, personally, is &lt;a class="reference external" href="http://pypi.python.org/pypi/greenlet"&gt;Greenlet&lt;/a&gt;
though I don't even see that they've built it for Python 3.2 yet.&lt;/p&gt;
&lt;p&gt;We might also just want to start compiling a list in the repository's
&lt;a class="reference external" href="http://hg.microcode.ca/bbx-python/wiki/Home"&gt;wiki&lt;/a&gt; (which anyone with a
&lt;a class="reference external" href="https://bitbucket.org/account/signup/?plan=5_users"&gt;free bitbucket account&lt;/a&gt; can
edit).  Which such packages would provide functionality that would really
add value on the PlayBook?  Which won't work that well, because of memory
requirements, performance issues, or maybe other dependencies that aren't
yet supported under Python 3.2?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="documentation"&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;There's hardly enough here yet to document, but if there's one thing that's
been the downfall of many an otherwise-promising open source project, it's
documentation.  I noticed I'm already short one key thing: a license!
For the record, I'm planning on using MIT &lt;a class="footnote-reference" href="#id7" id="id2"&gt;[2]&lt;/a&gt; or maybe BSD &lt;a class="footnote-reference" href="#id8" id="id3"&gt;[3]&lt;/a&gt; unless there's a good
reason to use something else (such as, maybe RIM insists on Apache 2.0,
as I want to keep this compatible with their plans).&lt;/p&gt;
&lt;p&gt;I think I've made a reasonable start already, for a project that's only four
days old! Still, what &lt;em&gt;I&lt;/em&gt; think needs to be documented isn't the same as what
some &lt;em&gt;other&lt;/em&gt; people think needs to be documented.  Are you being held back from
participating because something's missing?  What is it?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bbx-specific-packages"&gt;
&lt;h2&gt;BBX-specific Packages&lt;/h2&gt;
&lt;p&gt;This one is an interesting area.  RIM's already got a whole batch of libraries
in the 2.0 beta, with no major issues seen yet with any of them.  They're
wholly unsupported, of course, and as I've mentioned earlier we've got no
guarantee that RIM will continue to expose these for us to use.  Here's a few
of the packages available so far:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="16%" /&gt;
&lt;col width="84%" /&gt;
&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.audio&lt;/td&gt;
&lt;td&gt;Play and record WAV/RIFF files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.device&lt;/td&gt;
&lt;td&gt;Access device properties: versions, PIN, serial number (requires &lt;em&gt;read_device_identifying_information&lt;/em&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.dialog&lt;/td&gt;
&lt;td&gt;PPS dialog service: alerts, file browse, login, popup, prompt, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.geolocation&lt;/td&gt;
&lt;td&gt;PPS geolocation service (GPS, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.mmaudioplayer&lt;/td&gt;
&lt;td&gt;Control playback of an audio file (MP3 or other)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.notification&lt;/td&gt;
&lt;td&gt;Display notification messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;qnx.pps&lt;/td&gt;
&lt;td&gt;General-purpose interface to PPS objects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Those were presumably written to be used by RIM's own code, however, and
third-party apps may have other needs.  Packages could be written to add
useful new functionality.  One option is to use the
&lt;a class="reference external" href="http://docs.python.org/py3k/library/ctypes.html#module-ctypes"&gt;ctypes&lt;/a&gt;
module to wrap existing dynamically loaded (shared) libraries (.so files).
This is relatively straightforward if you have the header file for the
library, and provides a very quick way to expose native functionality to Python.
You could do useful work in this area if you know C well, even if you're
just starting to learn Python.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="get-involved"&gt;
&lt;h2&gt;Get Involved!&lt;/h2&gt;
&lt;p&gt;This project represents a real frontier for hackers (in the old-style meaning
of the term: those who find cool ways to make technology behave).  The PlayBook
is being revealed as an
&lt;a class="reference external" href="http://www.berryreview.com/2011/05/05/blackberry-playbook-tat-cascades-user-interface-engine-and-native-sdk-on-video/"&gt;awesome&lt;/a&gt;
and
&lt;a class="reference external" href="http://n4bb.com/windows-3-ms-dos-run-blackberry-playbook"&gt;versatile&lt;/a&gt; platform,
and will be an excellent
place for high-performance &lt;a class="footnote-reference" href="#id9" id="id4"&gt;[4]&lt;/a&gt; Python programs to run as apps.  Now's a good
time to &lt;a class="reference external" href="http://microcode.ca/bbx-python/"&gt;get involved&lt;/a&gt;,
so you can have a direct influence on the direction this
initiative will take.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;Footnotes:&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="id6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Python 2.7, used for either the system updates and/or when installing apps.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="id7" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The MIT License: &lt;a class="reference external" href="http://www.opensource.org/licenses/mit-license.php"&gt;http://www.opensource.org/licenses/mit-license.php&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="id8" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The BSD License: &lt;a class="reference external" href="http://www.opensource.org/licenses/bsd-license.php"&gt;http://www.opensource.org/licenses/bsd-license.php&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="id9" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Benchmarking reports 11330 pystones/sec, in line with the 1GHz clock speed,
compared to my 2.4GHz Intel CPU at 29000 pystones/sec&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</summary></entry><entry><title>BBX Python: Project Site</title><link href="http://www.peterhansen.ca/blog/bbx-python-project-site.html" rel="alternate"></link><updated>2011-11-19T18:19:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-19:/blog/bbx-python-project-site.html/</id><summary type="html">&lt;p&gt;In case you've been following the work on a native launcher for Python apps
on BBX (PlayBook), you'll be happy to I've just set up a
&lt;a class="reference external" href="http://microcode.ca/bbx-python/"&gt;BBX-Python project web page&lt;/a&gt;
with the code hosted the
&lt;a class="reference external" href="http://hg.microcode.ca/bbx-python/wiki/Home"&gt;bbx-python bitbucket repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There's a &lt;a class="reference external" href="http://microcode.ca/bbx-python/downloads/"&gt;downloads&lt;/a&gt; folder
(not using the Bitbucket one... wouldn't let me upload
because of some Amazon service crashing apparently), with a first release of the
launcher.  Also a wiki page with Quick Start instructions to get you going, and
some sample code.&lt;/p&gt;
&lt;p&gt;One fellow (artoo) in the IRC chat (#bbx-python on freenode.net) has already
written an &lt;a class="reference external" href="http://snozzberries.ca/bbx-python/sample-apps/launcher/"&gt;extended launcher&lt;/a&gt;
in Python, which uses a &amp;quot;popup&amp;quot; dialog to show
you a list of other Python scripts from which you can select one to run.&lt;/p&gt;
</summary></entry><entry><title>BBX Python: Progress, Stage Two</title><link href="http://www.peterhansen.ca/blog/bbx-python-progress-stage-two.html" rel="alternate"></link><updated>2011-11-18T20:49:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-18:/blog/bbx-python-progress-stage-two.html/</id><summary type="html">&lt;p&gt;So without much more effort today, I'm got it running a separate script (bbxmain.py)
that is bundled into the .bar file.  Again, the heart of things is trivial, just these
two lines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bbxmain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;app/native/bbxmain.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;PyRun_SimpleFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbxmain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the record, here's the first script I wrote:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/accounts/1000/shared/misc/bbxmain.out&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;arg &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;It&amp;#39;s alive!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;__name__ is &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;myver is &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And here's the output in that file in shared/misc:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
---------------------------------------- 1321663133.906571
arg 0: com.example.study_poc.testDev_e_study_pocc037301d
It's alive!
__name__ is __main__
myver is BBX Python! v3.2.1 (default, Sep  1 2011, 14:08:17) [GCC 4.4.2] on qnx6
&lt;/pre&gt;
&lt;p&gt;If you know Python and don't recognize &lt;tt class="docutils literal"&gt;sys.myver&lt;/tt&gt;, don't worry... it's just
a string built using an earlier call to &lt;tt class="docutils literal"&gt;PyRun_SimpleString()&lt;/tt&gt; in my setup code
from an older experiment, from sys.version and sys.platform.  I've got the same thing
displayed as output in the OpenGL screen context:&lt;/p&gt;
&lt;img alt="/blog/static/files/bbxpython_1.jpg" class="pbscreenshot" src="/blog/static/files/bbxpython_1.jpg" /&gt;
&lt;p&gt;Join me on #bbx-python on freenode.net if you're interested in following this, add
add a comment to this post, or &lt;a class="reference external" href="http://twitter.com/#!/peter9477"&gt;follow &amp;#64;peter9477 on Twitter&lt;/a&gt;.
Thanks!&lt;/p&gt;
</summary></entry><entry><title>BBX Python: Proof Of Concept</title><link href="http://www.peterhansen.ca/blog/bbx-python-proof-of-concept.html" rel="alternate"></link><updated>2011-11-18T01:37:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-11-18:/blog/bbx-python-proof-of-concept.html/</id><summary type="html">&lt;p&gt;Short post, since it's late.&lt;/p&gt;
&lt;p&gt;Python on the PlayBook.  What will be BBX-Python, some day...&lt;/p&gt;
&lt;p&gt;So I wrote an app.  First time using the &lt;a class="reference external" href="https://bdsc.webapps.blackberry.com/native/"&gt;Tablet OS Native SDK&lt;/a&gt;
so lots of learning curve to climb with Momentics (the IDE) and some of its warts.
Generally it was way better than I'd expected actually, and the warts are the sort of
thing you work around then gradually forget they're even there.&lt;/p&gt;
&lt;p&gt;The app for now pretty much consists of the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;py_initialize&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Py_VerboseFlag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Py_Initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ... other stuff in a loop waiting for the end of the world&lt;/span&gt;

&lt;span class="n"&gt;Py_Finalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There's a bit more to it than that, but nothing that's relevant to the Python aspect.
I did have to set up an environment variable to point to the library, so there's
an &amp;quot;LD_PRELOAD=/usr/lib/libpython3.2m.so.1.0&amp;quot; somewhere, too.&lt;/p&gt;
&lt;p&gt;The beautiful thing is that it just worked.  Here's the output, courtesy
of the one debug line above and the output triggered by the verbose flag:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
py_initialize
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
import encodings # directory /usr/lib/python3.2/encodings
import encodings # precompiled from /usr/lib/python3.2/encodings/__init__.pyc
import codecs # precompiled from /usr/lib/python3.2/codecs.pyc
import _codecs # builtin
...
import bisect # precompiled from /usr/lib/python3.2/bisect.pyc
dlopen(&amp;quot;/usr/lib/python3.2/lib-dynload/_bisect.so&amp;quot;, 2);
import _bisect # dynamically loaded from /usr/lib/python3.2/lib-dynload/_bisect.so
dlopen(&amp;quot;/usr/lib/python3.2/lib-dynload/_heapq.so&amp;quot;, 2);
import _heapq # dynamically loaded from /usr/lib/python3.2/lib-dynload/_heapq.so
import weakref # precompiled from /usr/lib/python3.2/weakref.pyc
import reprlib # precompiled from /usr/lib/python3.2/reprlib.pyc
import _thread # builtin
import _locale # builtin
import encodings.ascii # precompiled from /usr/lib/python3.2/encodings/ascii.pyc
&lt;/pre&gt;
&lt;p&gt;Next step will be to tell it to execute a script with PyEval_EvalCode() or something
like that.&lt;/p&gt;
&lt;p&gt;Join me on #bbx-python on freenode.net if you're interested in following this, or
add a comment to this post.  I'll also be tweeting a bit as
&lt;a class="reference external" href="http://twitter.com/#!/peter9477"&gt;&amp;#64;peter9477&lt;/a&gt;.  Thanks!&lt;/p&gt;
</summary></entry><entry><title>SQLite: Negative Integer Primary Keys</title><link href="http://www.peterhansen.ca/blog/sqlite-negative-integer-primary-keys.html" rel="alternate"></link><updated>2011-06-19T09:16:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-06-19:/blog/sqlite-negative-integer-primary-keys.html/</id><summary type="html">&lt;p&gt;I was working on the design of a PlayBook app which would perform
some data logging, and considered using SQLite as the primary
mechanism.  Alternatives included a simple text file (CSV format),
XML, or SharedObject (not really).&lt;/p&gt;
&lt;p&gt;Since the user may want to acquire data for a very long time,
possibly on an ongoing basis for years, it seemed important to
spend at least a bit of time considering the storage space that
would be used.&lt;/p&gt;
&lt;p&gt;With my prototype, which simply appends rows to a CSV file each
time a reading occurs, the file would grow to approximately 50MB
in the course of a year if the app were always running.  Each
record is roughly 204 bytes including newline.&lt;/p&gt;
&lt;p&gt;The nature of the data is largely integers, but I realized that
many of them would be negative, and wondered about how this would
affect the file size of a SQLite database.&lt;/p&gt;
&lt;p&gt;SQLite is interesting in many ways, one of which is that it uses
a &lt;a class="reference external" href="http://sqlite.org/datatype3.html#storageclasses"&gt;variable-length format for integers&lt;/a&gt;,
using anywhere from 1 to 8 bytes depending on the size.  That page
may be inaccurate, because in a more
&lt;a class="reference external" href="http://www.sqlite.org/fileformat2.html#varint"&gt;detailed description&lt;/a&gt;
it says it could be 1 to 9 bytes.&lt;/p&gt;
&lt;p&gt;I built a small test database with an INTEGER PRIMARY KEY column,
some text, and another integer column, and created rows with a variety
of data.  I then analyzed a hex dump of the records in the data area.&lt;/p&gt;
&lt;p&gt;I immediately noted that my rows that had negative primary key values
were taking up space for lots of FF bytes for the primary key.  Yikes!
I thought, is it really this bad for storing negative integers?  Here's
a couple of samples (note, this output doesn't actually match the schema
I mentioned above, but it doesn't matter for this analysis):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
0A FF FF FF FF FF FF FF FF 81 05 00 17 00 00 66 2D 31 32 37 &amp;quot;f-127&amp;quot;
08 FF FF FF FF FF FF FF FF FD 05 00 13 00 00 66 2D 33       &amp;quot;f-3&amp;quot;
08 FF FF FF FF FF FF FF FF FE 05 00 13 00 00 66 2D 32       &amp;quot;f-2&amp;quot;
08 03 05 00 13 00 00 66 2B 33                               &amp;quot;f+3&amp;quot;
09 40 05 00 15 00 00 66 2B 36 34                            &amp;quot;f+64&amp;quot;
0A 81 00 05 00 17 00 00 66 2B 31 32 38                      &amp;quot;f+128&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Note all those FF bytes.  What a waste of space.  The positive integers
are stored compactly, with 3 and 64 requiring only a single byte, and 128
taking up two bytes.  (Note that it would have made comparison easier had
I used the same length of text in each row.)&lt;/p&gt;
&lt;p&gt;Upon further inspection and reading, I sorted it out.  Every row,
even if you don't specify an INTEGER PRIMARY KEY, has a ROWID assigned
by the database to track it.  If you specify any &lt;em&gt;other&lt;/em&gt; column as the INTEGER type,
even negative values will be stored compactly.  A -3 is stored as just FD,
rather than FF FF FF FF FF FF FF FD as shown in the ROWID sample earlier.&lt;/p&gt;
&lt;p&gt;Here's the key point: if you have a column which is defined as the
INTEGER PRIMARY KEY, then SQLite doesn't bother creating a real column
just for that data.  It will reuse the ROWID instead.  But if you plan
to store lots of small negative values in that field, you'll potentially
be using up lots of extra bytes for all those FFs!  The &amp;quot;varint&amp;quot; format
for ROWID is compact only for positive values.&lt;/p&gt;
&lt;p&gt;It would take a very particular type of data for this even possibly
to be a problem.  You'd have to have lots of negative values between
-1 and maybe -16 million or so.&lt;/p&gt;
&lt;p&gt;If this were an issue, the &amp;quot;fix&amp;quot; would be to define a separate column
for your data, and a INTEGER PRIMARY KEY which you mostly ignore,
allowing SQLite to auto-assign and increment as positive values.&lt;/p&gt;
&lt;p&gt;As a crude estimate of the difference in space used, here are file
sizes for the two versions, one where we store our negative values
in the INTEGER PRIMARY KEY column where they end up becoming the
ROWID, and the other where we assign a second column just for that
data.  Each example assumes a million rows, with data going from
-1 to -999,999, and I'm ignoring any overhead for tracking b-tree pages,
the database header, etc.&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="50%" /&gt;
&lt;col width="50%" /&gt;
&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;File Size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;reuse ROWID&lt;/td&gt;
&lt;td&gt;10.5MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;separate field&lt;/td&gt;
&lt;td&gt;6.6MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Okay, well, that about ties things up.  Quite clearly, even on the
PlayBook, it's unlikely a difference of 4MB is going to matter to anyone.
And none of this would have affected me anyway, as the values I need
for my primary key fields turn out not to be negative!&lt;/p&gt;
</summary></entry><entry><title>PlayBook: Power Consumption</title><link href="http://www.peterhansen.ca/blog/playbook-power-consumption.html" rel="alternate"></link><updated>2011-06-15T12:40:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-06-15:/blog/playbook-power-consumption.html/</id><summary type="html">&lt;p&gt;I've been taking power consumption measurements while running the PlayBook
under various loads, and some of the results are pretty interesting.  I'll
write up more later, but here's an initial overview of some data that may
be useful to you, either as a user, or as a developer.&lt;/p&gt;
&lt;p&gt;First a bit of background.  The PlayBook has two battery packs in it,
with the combined pair providing nominally 5400mAh, which at an average
voltage of 3.7V provides 19.98Wh of energy.  See for example the
&lt;a class="reference external" href="http://www.ifixit.com/Teardown/BlackBerry-PlayBook-Teardown/5265/1#s23433"&gt;ifixit.com teardown&lt;/a&gt;
for some pics of the labelling.&lt;/p&gt;
&lt;p&gt;In actual fact, Lithium-Ion Polymer batteries
&lt;a class="reference external" href="http://batteryuniversity.com/learn/article/how_to_prolong_lithium_based_batteries"&gt;never provide the full rated capacity&lt;/a&gt; and,
at least in the case of my own PlayBook, I can confirm that the capacity as shipped
was only around 93% of that.  The initial drop can be disconcertingly rapid, too,
and after 42 recharge cycles their capacity is now only 90%, or about 18Wh.&lt;/p&gt;
&lt;p&gt;That Watt-hour capacity value can tell you roughly how long a battery will run
your device by dividing by the average power used.  If, for example, the
device used 1W on a continuous basis, 18Wh would give 18h of use.&lt;/p&gt;
&lt;p&gt;A PlayBook, sitting idle but with the screen turned on, backlight at 50%,
running no apps, uses about 2.3W.  That means even if you basically didn't
do anything useful with it, you'd get only about 7.8h under those conditions.
There's a reason the screen and backlight turn off so quickly!&lt;/p&gt;
&lt;p&gt;Here are some other basic numbers for you to compare.  The values shown are in
milliwatts (50mW is the same as 0.05W).  The &amp;quot;Life at Constant Load&amp;quot; value is
an approximation based on a battery at 90% health, which is probably typical
for most PlayBook owners as of this date.&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;caption&gt;Power consumption (in mW) under different loads for PlayBook&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col width="33%" /&gt;
&lt;col width="33%" /&gt;
&lt;col width="33%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;Load&lt;/th&gt;
&lt;th class="head"&gt;Power&lt;/th&gt;
&lt;th class="head"&gt;Life at Constant Load&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;Standby&lt;/td&gt;
&lt;td&gt;52mW&lt;/td&gt;
&lt;td&gt;15 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Screen on/backlight 0%&lt;/td&gt;
&lt;td&gt;1680mW&lt;/td&gt;
&lt;td&gt;10.7h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Screen on/backlight 50%&lt;/td&gt;
&lt;td&gt;2300mW&lt;/td&gt;
&lt;td&gt;7.8h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Screen on/backlight 100%&lt;/td&gt;
&lt;td&gt;3000mW&lt;/td&gt;
&lt;td&gt;6.0h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Standby/White Noise on/volume 50%&lt;/td&gt;
&lt;td&gt;360mW&lt;/td&gt;
&lt;td&gt;50h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Standby/GPS &amp;#64;2Hz&lt;/td&gt;
&lt;td&gt;213mW&lt;/td&gt;
&lt;td&gt;85h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Video 720P/volume 0%/backlight 30%&lt;/td&gt;
&lt;td&gt;2300mW&lt;/td&gt;
&lt;td&gt;7.8h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Video 720P minimized/volume 10%/backlight 100%&lt;/td&gt;
&lt;td&gt;3500mW&lt;/td&gt;
&lt;td&gt;5.1h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Video 720P fullscreen/volume 10%/backlight 100%&lt;/td&gt;
&lt;td&gt;3240mW&lt;/td&gt;
&lt;td&gt;5.6h&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Flash video on CNN site (not fullscreen)/backlight 100%&lt;/td&gt;
&lt;td&gt;4000mW&lt;/td&gt;
&lt;td&gt;4.5h&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;a class="reference external" href="http://appworld.blackberry.com/webstore/content/24592"&gt;White Noise app&lt;/a&gt;
mentioned there is my own, available from App World.  It's written &amp;quot;properly&amp;quot;
so it will generate smooth, pure, non-repeating random noise even when the
PlayBook is on standby, just as you'd want for masking background noise and
letting you get a good sleep!&lt;/p&gt;
&lt;p&gt;The most interesting results so far are that the GPS consumes so little
power (yay!) and that the backlight and screen together consume so much.
It also appears that playing fullscreen video uses less power than
running it in a web page or with the video player app minimized (but active).
I need more measurements to say for sure but it looks like this holds true
whether it's a Flash player in the browser or the standard video player.&lt;/p&gt;
&lt;p&gt;Advice for maximizing battery life?  Keep the screen off as much as possible!
Set the timeouts for as short as you can live with and make liberal use of that
shiny new &amp;quot;Stand By&amp;quot; button found in the System Tray battery popup.&lt;/p&gt;
&lt;p&gt;If you have to actually use the screen (i.e. for most real uses), keep the
backlight as low as possible.  Depending on lighting conditions, you may
find that having the backlight at minimum is acceptable, or as low as 25% may be okay.&lt;/p&gt;
&lt;p&gt;Finally, run video fullscreen where possible.&lt;/p&gt;
&lt;p&gt;So, who wants a battery monitor app?  You won't find anything better
than &lt;a class="reference external" href="http://www.engcorp.com/apps/"&gt;Battery Guru for the BlackBerry PlayBook&lt;/a&gt;. :-)&lt;/p&gt;
</summary></entry><entry><title>PlayBook Browser Viewport Size</title><link href="http://www.peterhansen.ca/blog/playbook-browser-viewport-size.html" rel="alternate"></link><updated>2011-05-27T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-05-27:/blog/playbook-browser-viewport-size.html/</id><summary type="html">&lt;p&gt;Although the resolution of the screen on the 7&amp;quot; PlayBook is 1024x600,
the browser window size is always less.&lt;/p&gt;
&lt;p&gt;In the default configuration, the browser viewport is 1024x512 pixels.
That's when the back/forward buttons, address field, history/bookmark
and fullscreen toggle switch are showing.&lt;/p&gt;
&lt;p&gt;I think it would have been nice if &amp;quot;fullscreen&amp;quot; mode on the browser
eliminated &lt;em&gt;all&lt;/em&gt; window chrome, including the title bar, but unfortunately
that's not how they've done it.&lt;/p&gt;
&lt;p&gt;With only the title bar showing, your window size is 1024x569 pixels,
so the title bar steals 31 of those valuable pixels just to show you
the name of the page you're on, as if you didn't know already and couldn't
tell easily by doing a top-swipe to see the address field.&lt;/p&gt;
&lt;p&gt;I found &lt;a class="reference external" href="http://elundmark.se/demo/viewport-dimensions/"&gt;this site&lt;/a&gt;
helpful in identifying these numbers, and it also has a nice bit
of code (&lt;a class="reference external" href="http://jquery.com/"&gt;jQuery&lt;/a&gt;-based) that looks useful
for making a site which can adjust its content to fit the browser
window size, which seems especially helpful for mobile devices.&lt;/p&gt;
&lt;p&gt;I have some internal-use sites which I will be adapting to better
fit the limited resolution of tablets.  There was never a reason to
with smartphones, as I find them just too tiny to be effective for
real work, but after almost a month of use I've definitely
concluded that a tablet is a different story, and has serious
productivity advantages when used appropriately.&lt;/p&gt;
</summary></entry><entry><title>PlayBook: Errata #1</title><link href="http://www.peterhansen.ca/blog/playbook-errata-1.html" rel="alternate"></link><updated>2011-04-17T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-04-17:/blog/playbook-errata-1.html/</id><summary type="html">&lt;p&gt;Wow, I've been slow getting back to this non-blog.  Sorry for the long silence, and I
do intend to post more often again.&lt;/p&gt;
&lt;p&gt;In the last couple of months, much has happened and, unfortunately, a few things have not.
For one thing, we don't have our PlayBooks yet, as of this writing.  Nor do we have
a 1.0 SDK and a decent simulator.  Nor, for that matter, has the PlayBook even been released,
except to a few lucky members of the press.&lt;/p&gt;
&lt;p&gt;Nevertheless, information does ooze out, be it ever so slowly.  A few things
contradict or outdate things I said earlier.  I'll summarize the changes here:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-top-swipe-menu.html"&gt;Top-Swipe Menu&lt;/a&gt;:
I believe my design was flawless for the simulator up to 0.9.4, but reports from someone
at RIM who tested my app suggest that the SWIPE_START behaviour is different
in 1.0.  He describes my menu as being usable only once... he can open it,
change settings, and close it, but after that the menu doesn't respond any more.
&lt;strong&gt;If you used the design in that post, your menu stands a good chance of not
working and I suggest you switch to SWIPE_DOWN until the problems are sorted out.&lt;/strong&gt;
I will post an update as soon as I get something with 1.0 on it for testing.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-application-lifecycle.html"&gt;Application Lifecycle&lt;/a&gt;
describes invoking, exiting, and activate/deactivate, but only in the context of the
simulators before 1.0.  Now there will be three modes for multitasking,
only one of which acts the same as the current simulator.  In &lt;em&gt;Showcase&lt;/em&gt;
mode you will &lt;em&gt;not&lt;/em&gt; get any ACTIVATE/DEACTIVATE events.  The simulator is
currently representative only of the &lt;em&gt;Default&lt;/em&gt; multitasking mode in the real thing.
(The &lt;em&gt;Paused&lt;/em&gt; mode basically freezes an app when inactive, so it probably looks
like a DEACTIVATE followed by a long pause with no scheduling of the app before
it later gets an ACTIVATE again.)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-font-list.html"&gt;Font List&lt;/a&gt; noted the fonts
from an early simulator.  In more recent ones, several fonts have been added,
but more importantly the default font was quietly changed to &amp;quot;Myriad Pro&amp;quot;.
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Label-font-size-in-0-9-4/m-p/948911/message-uid/948911/highlight/true#U948911"&gt;This can mess up formatting&lt;/a&gt;
compared to &amp;quot;BBAlpha Sans&amp;quot;, the previous default font.&lt;/li&gt;
&lt;/ul&gt;
</summary></entry><entry><title>PlayBook: debug trace() statements</title><link href="http://www.peterhansen.ca/blog/playbook-debug-trace-statements.html" rel="alternate"></link><updated>2011-02-10T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-02-10:/blog/playbook-debug-trace-statements.html/</id><summary type="html">&lt;p&gt;When debugging AIR apps in the PlayBook simulator, you build your
app using the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-debug&lt;/span&gt;&lt;/tt&gt; option to the amxmlc compiler... or your
IDE does it for you.  With that flag, and appropriate options
passed to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;blackberry-airpackager&lt;/span&gt;&lt;/tt&gt; (specifically &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-target&lt;/span&gt; &lt;span class="pre"&gt;bar-debug&lt;/span&gt;&lt;/tt&gt;)
and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;blackberry-deploy&lt;/span&gt;&lt;/tt&gt; (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-debugHost&lt;/span&gt; X.X.X.X&lt;/tt&gt;), your app will
attempt to connect to the debugger running at the specified address,
and among other useful things you'll be able to see the output of
your &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/package.html#trace()"&gt;trace()&lt;/a&gt;
calls.&lt;/p&gt;
&lt;p&gt;But what if you decide to cancel the debug session,
or just never start it, and only then find a problem
with your app?  You might have to restart, this time connecting to
the debugger.  This is never a good situation, and you'll be lucky
if you can reproduce the problem.&lt;/p&gt;
&lt;p&gt;Fortunately, if the app was compiled with the debug flag, &lt;em&gt;and&lt;/em&gt; if
you included the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt; option when you packaged, your trace()
output is available anyway.&lt;/p&gt;
&lt;p&gt;First, &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/731801/highlight/true#M5548"&gt;connect using SSH&lt;/a&gt;.
Change directories with &lt;tt class="docutils literal"&gt;cd /accounts/1000/appdata&lt;/tt&gt;, then type &lt;tt class="docutils literal"&gt;ls&lt;/tt&gt; to
list the subfolders.  Find the one for your app and change into it with
another &lt;tt class="docutils literal"&gt;cd&lt;/tt&gt; command.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt; option is what allows you to do this, as without it
the sandbox is protected from other users, including the one you've
connected with (&amp;quot;devuser&amp;quot;).
With this option the app is installed under one of six special
user groups, named dev0 through dev5, and devuser is a member of
each of those groups.
(Note &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Problem-with-0-9-3-beta-simulator-limit-of-6-devMode-installs/m-p/783099/highlight/true#M8914"&gt;the devMode bug&lt;/a&gt;
which may interfere with this if you have installed more than 6 apps
using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt;.)&lt;/p&gt;
&lt;p&gt;In the &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Application-sandbox-file-system-layout/td-p/732177"&gt;app sandbox&lt;/a&gt;
there are several subfolders.  Three of them,
&lt;cite&gt;data/&lt;/cite&gt;, &lt;cite&gt;logs/&lt;/cite&gt; and &lt;cite&gt;tmp/&lt;/cite&gt; are created when the app is installed,
while four symlinks (&lt;cite&gt;app&lt;/cite&gt;, &lt;cite&gt;db&lt;/cite&gt;, &lt;cite&gt;pps&lt;/cite&gt;, &lt;cite&gt;shared&lt;/cite&gt;) are created the first time
the app is launched.&lt;/p&gt;
&lt;p&gt;The output of the trace() calls is recorded in the file &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;logs/air-trace&lt;/span&gt;&lt;/tt&gt;,
provided you used &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-debug&lt;/span&gt;&lt;/tt&gt; when compiling.  (If you did not,
those statements are stripped out, taking up no space or
CPU time in &amp;quot;release mode&amp;quot; apps.)&lt;/p&gt;
&lt;p&gt;The best way to view the file for a running app is this command (with the
dollar sign being the command line prompt, so don't type it):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tail -f air-trace
XMLList:
extensionsDeviceBundledDirectory is null
app:/META-INF/AIR/extensions
Extensions to load: 0
&lt;/pre&gt;
&lt;p&gt;The next four lines shown are the output I see with my own app.
I assume you'll see the same, as those are not from my own trace() calls.&lt;/p&gt;
&lt;p&gt;If you want more help on the &lt;tt class="docutils literal"&gt;tail&lt;/tt&gt; command, type &lt;tt class="docutils literal"&gt;use tail&lt;/tt&gt;.
Note above that I've used the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-f&lt;/span&gt;&lt;/tt&gt; option, which makes &lt;cite&gt;tail&lt;/cite&gt; stay
running so it shows new lines as they are appended by your app.
Hit Ctrl-C to get back to the prompt.  Note also that if you exit
the app and restart it, &lt;cite&gt;tail&lt;/cite&gt; doesn't notice that a new &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;air-trace&lt;/span&gt;&lt;/tt&gt;
file has been created so it won't switch to it automatically
and you won't see any more output until you run &lt;cite&gt;tail&lt;/cite&gt; again.&lt;/p&gt;
&lt;p&gt;If your app has crashed and you just want to see the full file contents,
use &lt;tt class="docutils literal"&gt;cat &lt;span class="pre"&gt;air-trace&lt;/span&gt;&lt;/tt&gt; to dump it to the console.  You could also
use &lt;cite&gt;sftp&lt;/cite&gt; or &lt;cite&gt;scp&lt;/cite&gt; to transfer the file to your host machine.&lt;/p&gt;
</summary></entry><entry><title>PlayBook: SWIPE_START Simplified</title><link href="http://www.peterhansen.ca/blog/playbook-swipe_start-simplified.html" rel="alternate"></link><updated>2011-02-05T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-02-05:/blog/playbook-swipe_start-simplified.html/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; in the 1.0 release, SWIPE_START may no longer work exactly as described here.
If you use it in your app, you may need to switch to SWIPE_DOWN until the 1.0 software
has been released and can be analyzed fully.&lt;/p&gt;
&lt;p&gt;In my &lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-top-swipe-menu.html"&gt;previous post&lt;/a&gt;
I wrote at length about the two ways to handle top-swipe events with the Adobe AIR SDK
in the BlackBerry PlayBook.&lt;/p&gt;
&lt;p&gt;As always happens after I spend a long time polishing some code and
writing documentation for it, shortly afterwards I realized it could be
simplifier.  In this case, there's a way to use &lt;cite&gt;swipeStart&lt;/cite&gt;
without dealing with &lt;cite&gt;mouseMove&lt;/cite&gt; at all.&lt;/p&gt;
&lt;p&gt;From the last post, here's the sequence of events that you'll get if you subscribe to
&lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/events/QNXApplicationEvent.html#SWIPE_START"&gt;QNXApplicationEvent.SWIPE_START&lt;/a&gt;
and perform a top-swipe:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;QNXApplicationEvent.SWIPE_START&lt;/li&gt;
&lt;li&gt;MouseEvent.MOVE (once only)&lt;/li&gt;
&lt;li&gt;MouseEvent.DOWN (at same coords)&lt;/li&gt;
&lt;li&gt;MouseEvent.MOVE (many)&lt;/li&gt;
&lt;li&gt;MouseEvent.UP&lt;/li&gt;
&lt;li&gt;MouseEvent.CLICK&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now as I pointed out in the previous post, it's possible to contrive to generate
the same sequence without really doing a swipe, but just tapping and releasing
in the top bezel (i.e. don't move your mouse/finger),
then down in the screen area doing a proper swipe.&lt;/p&gt;
&lt;p&gt;The simplification to my &lt;a class="reference external" href="http://hg.microcode.ca/playbook-air/src/tip/studies/ca/microcode/menu/TopSwipeMenu.as"&gt;ca.microcode.menu.TopSwipeMenu&lt;/a&gt;
code would be to ignore &lt;tt class="docutils literal"&gt;MouseEvent.MOVE&lt;/tt&gt; entirely, and just use the
&lt;tt class="docutils literal"&gt;MouseEvent.DOWN&lt;/tt&gt; which follows the &lt;cite&gt;swipeStart&lt;/cite&gt; as the signal that the top-swipe
gesture has really begun &lt;em&gt;provided the mouse coordinates lie in the bezel area&lt;/em&gt;.
That is, check for &amp;quot;&lt;tt class="docutils literal"&gt;stage.mouseY &amp;lt; 0&lt;/tt&gt;&amp;quot; and cancel the swipe if that's not &lt;cite&gt;true&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;There's a minor defect with this approach, since it's possible to tap just off
the top of the screen (Y value just below 0) to generate the &lt;cite&gt;swipeStart&lt;/cite&gt;,
yet not have the &lt;cite&gt;mouseDown&lt;/cite&gt; event be issued until the position is already at 0 or higher.
You can choose how to deal with this, but the simple approach would be to ignore it.
That would mean users have to start the top-swipe just the slightest bit above the
top edge of the screen (depending on how fast they swipe), but it seems unlikely
anyone would ever notice the limitation so this is a mere technicality.&lt;/p&gt;
&lt;p&gt;I won't post sample code for this (yet) as I haven't tried it out myself, but
anyone who can deal with the state machine code should have no trouble modifying it
to work this way.  I'd also like to just wait until I have real hardware on
which to test, since:&lt;/p&gt;
&lt;ol class="loweralpha simple"&gt;
&lt;li&gt;the behaviour may be different by release time, and&lt;/li&gt;
&lt;li&gt;the response to touches may differ slightly from mouse clicks in the simulator.&lt;/li&gt;
&lt;/ol&gt;
</summary></entry><entry><title>PlayBook: Top-Swipe Menu</title><link href="http://www.peterhansen.ca/blog/playbook-top-swipe-menu.html" rel="alternate"></link><updated>2011-02-05T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-02-05:/blog/playbook-top-swipe-menu.html/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; the approach described here for SWIPE_START was carefully designed based on the observed
performance of the simulator as it was at the time.  Unfortunately, at least one app
built around this approach does not work correctly on the &amp;quot;1.0&amp;quot; software running on the
real hardware.  If you've used this code in your app, you may encounter the same issue,
in which case for now, switching to the more primitive SWIPE_DOWN mechanism.&lt;/p&gt;
&lt;p&gt;In the BlackBerry PlayBook Developer Forum (Tablet OS SDK for Adobe AIR) there have been
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/App-specific-system-menu/m-p/693819"&gt;several&lt;/a&gt;
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Swipe-Down-Event/td-p/756437"&gt;threads&lt;/a&gt;
about the &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/SWIPE-START-and-SWIPE-DOWN-together-not-firing-correctly/td-p/645587"&gt;SWIPE_START event&lt;/a&gt;
and &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Simulator-Swipe-Down-behavior/m-p/770823"&gt;SWIPE_DOWN event&lt;/a&gt;
and how to use them to implement an application menu.
None of these have yet given a complete picture of how those events really work.
But don't worry, I've analyzed it all for you!&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;SWIPE_DOWN Event&lt;/h2&gt;
&lt;p&gt;I'll cover this one first, because with it you can implement a simple &amp;quot;top-swipe&amp;quot;
app menu with only a few lines of code.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/events/QNXApplicationEvent.html#SWIPE_DOWN"&gt;SWIPE_DOWN&lt;/a&gt;
is one of two events dispatched by the
&lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/system/QNXApplication.html"&gt;QNXApplication.qnxApplication&lt;/a&gt;
singleton instance to signal user swiping activity in the top bezel area.&lt;/p&gt;
&lt;p&gt;To top-swipe, the user begins swiping in the top bezel &lt;em&gt;in the appropriate region&lt;/em&gt;.  This region
lies between X (horizontal) coordinates 50 and 975, leaving a 50-pixel-wide margin at either side
for the top-left and top-right swipes (see image).  These &amp;quot;corner&amp;quot; swipes are used to &amp;quot;peek&amp;quot; at the
system status bar (as long as you hold your finger down) or to expose it completely if you
raise your finger.  (Note how the status bar &amp;quot;pushes&amp;quot; the app stage down, rather than
sliding over.)&lt;/p&gt;
&lt;img alt="static/files/top_swipe_regions.jpg" src="static/files/top_swipe_regions.jpg" /&gt;
&lt;p&gt;If the user continues swiping down far enough into the screen area (apparently to a Y value
of around 21) then the SWIPE_DOWN event is issued immediately.  That's all there is to it.&lt;/p&gt;
&lt;p&gt;Given that your app has no advance knowledge of the imminent arrival of SWIPE_DOWN, it
can't do anything before receiving it.  Upon receipt, it could either
&lt;a class="reference external" href="http://hosted.zeh.com.br/tweener/docs/en-us/"&gt;tween&lt;/a&gt; a menu panel down into place,
or even just make it appear instantly (e.g. with &lt;tt class="docutils literal"&gt;addChild()&lt;/tt&gt;).  That's about
as simple as you can get.  The following few lines add this to any app, as a starting
point.  Imports are left out to simplify the example.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;QNXApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;qnxApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QNXApplicationEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SWIPE_DOWN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onSwipeDown&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MENU_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;function &lt;/span&gt;&lt;span class="nf"&gt;onSwipeDown&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;Sprite&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;graphics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;beginFill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x654321&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;graphics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;drawRect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stageWidth&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MENU_HEIGHT&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CLICK&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;closeMenu&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;addChild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// include the next two lines to animate the menu opening&lt;/span&gt;
    &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;MENU_HEIGHT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Tweener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addTween&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Sprite&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;function &lt;/span&gt;&lt;span class="nf"&gt;closeMenu&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;removeChild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note, however, how the animation completes regardless of what you do.  It doesn't
&amp;quot;track&amp;quot; the position of your finger, and you can't change your mind and return to the
top: the menu will open no matter what.  This approach is simple, but a bit crude.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;SWIPE_START Event&lt;/h2&gt;
&lt;p&gt;In contrast to SWIPE_DOWN, there's not much you can do with
&lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/events/QNXApplicationEvent.html#SWIPE_START"&gt;SWIPE_START&lt;/a&gt;
that doesn't involve a lot more lines of code.
SWIPE_START is sent &lt;em&gt;immediately&lt;/em&gt; whenever your finger touches the top bezel area
in the top-swipe region.  There are several interesting behaviours associated with it.&lt;/p&gt;
&lt;p&gt;One is that you don't actually have to respond to any MouseEvents or touch events...
you can watch for SWIPE_START and take some action based on that, even opening
a menu as shown above for SWIPE_DOWN.  That's neat, but possibly unfriendly to users
who are used to the more conventional swiping behaviour.&lt;/p&gt;
&lt;p&gt;If you want to respond to the actual swiping gesture you'll need to monitor
several MouseEvents (on the stage), which is the reason this one is more complex than
SWIPE_DOWN.  The second interesting thing about SWIPE_START is that if you
are listening for it, and the user's finger moves (as opposed to just being raised
again), you will receive MouseEvents associated with the top-swipe.
&lt;strong&gt;You won't see these MouseEvents if you don't listen for SWIPE_START.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But wait, there's more!  You'll get the MouseEvents even if the swiping finger stays
in the bezel area, and even if it moves across the top and down along the sides
to the bottom!  That should suggest a few interesting (but again, unconventional
and possibly annoying) ways of responding to user actions.&lt;/p&gt;
&lt;p&gt;The actual sequence of events for a real swipe will be this:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;QNXApplicationEvent.SWIPE_START [also known as &lt;cite&gt;swipeStart&lt;/cite&gt;]&lt;/li&gt;
&lt;li&gt;MouseEvent.MOVE (a single one) [&lt;cite&gt;mouseMove&lt;/cite&gt;]&lt;/li&gt;
&lt;li&gt;MouseEvent.DOWN [&lt;cite&gt;mouseDown&lt;/cite&gt;]&lt;/li&gt;
&lt;li&gt;MouseEvent.MOVE (zero or more)&lt;/li&gt;
&lt;li&gt;MouseEvent.UP [&lt;cite&gt;mouseUp&lt;/cite&gt;]&lt;/li&gt;
&lt;li&gt;MouseEvent.CLICK [&lt;cite&gt;click&lt;/cite&gt;]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;cite&gt;mouseDown&lt;/cite&gt; event will be seen immediately after the first &lt;cite&gt;mouseMove&lt;/cite&gt;.
If the finger keeps moving, you'll get lots more &lt;cite&gt;mouseMove&lt;/cite&gt; events,
followed eventually by a &lt;cite&gt;mouseUp&lt;/cite&gt; and &lt;cite&gt;click&lt;/cite&gt; (even if the finger never leaves the
bezel region).&lt;/p&gt;
&lt;p&gt;If the user simply touches and lifts the finger without moving it, you'll see just this:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;QNXApplicationEvent.SWIPE_START [&lt;cite&gt;swipeStart&lt;/cite&gt;]&lt;/li&gt;
&lt;li&gt;MouseEvent.MOVE (a single one) [&lt;cite&gt;mouseMove&lt;/cite&gt;]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You don't need to handle all the events shown, but you'll likely want at least
the &lt;cite&gt;mouseDown&lt;/cite&gt; event along with either &lt;cite&gt;mouseMove&lt;/cite&gt; or an
&lt;cite&gt;enterFrame&lt;/cite&gt; handler, followed by the &lt;cite&gt;mouseUp&lt;/cite&gt; event.
(That's assuming you are still interested in implementing a conventional menu, and not
heading right off to play with odd top-bezel gestures like a kid with a new toy.)&lt;/p&gt;
&lt;p&gt;It's your choice which event to use to track the mouse motion, but you'll get way more
&lt;cite&gt;mouseMove&lt;/cite&gt; events than you need, so to reduce CPU usage you're probably better
off with an &lt;cite&gt;enterFrame&lt;/cite&gt; handler for the tracking.&lt;/p&gt;
&lt;p&gt;The reason you should listen for the &lt;cite&gt;mouseDown&lt;/cite&gt; event is to avoid taking action
when the user merely brushes the bezel (&amp;quot;touch and release&amp;quot;).  A naive implementation
would use &lt;cite&gt;swipeStart&lt;/cite&gt; to set up the position tracking, but then you'd do the
wrong thing if the user tapped the bezel, then started a real swipe gesture inside
the screen area.&lt;/p&gt;
&lt;div class="section" id="faking-a-top-swipe-gesture"&gt;
&lt;h3&gt;Faking a Top-Swipe Gesture&lt;/h3&gt;
&lt;p&gt;Actually, you may have noticed there's a loophole in RIM's current design.
If you touch-and-release in the bezel, generating a &lt;cite&gt;swipeStart&lt;/cite&gt; then &lt;cite&gt;mouseMove&lt;/cite&gt;,
then touch and drag inside the screen, generating a &lt;cite&gt;mouseDown&lt;/cite&gt; and more &lt;cite&gt;mouseMove&lt;/cite&gt; events,
the sequence is the same as a real top-swipe.  (If you try this with a mouse, you'll
see more &lt;cite&gt;mouseMove&lt;/cite&gt; events as soon as the pointer moves into the screen area, but
that's cheating.  Without a mouse, there's no pointer and no &lt;cite&gt;mouseMove&lt;/cite&gt; events
unless you're touching the screen.)&lt;/p&gt;
&lt;p&gt;The problem with ignoring this is that the user could abort a top-swipe but
you'd respond to the next actual drag inside the app stage as if the user
were still swiping.  My
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/App-specific-system-menu/m-p/694485/highlight/true#M3054"&gt;original top-swipe implementation&lt;/a&gt;
in the support forums suffers from this problem.  Try it: click above the app
(but don't swipe), then click and drag inside the screen area... you
should see the menu open even though this isn't a valid top-swipe gesture.&lt;/p&gt;
&lt;p&gt;There are probably several workarounds.  The simplest would be to check
whether the &lt;cite&gt;mouseDown&lt;/cite&gt; event has coordinates very close to the &lt;cite&gt;swipeStart&lt;/cite&gt;
event, cancelling the top-swipe if it does not.  The problem with this is that
the coordinates reported for &lt;tt class="docutils literal"&gt;stage.mouseX&lt;/tt&gt; (and &lt;tt class="docutils literal"&gt;mouseY&lt;/tt&gt;) seem to correspond
to the last-seen position (from a previous MouseEvent), not where the finger
actually is at &lt;cite&gt;swipeStart&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;A more complex approach involves listening for &lt;cite&gt;mouseMove&lt;/cite&gt; following
&lt;cite&gt;swipeStart&lt;/cite&gt;, and noting the coordinates.  Then filter the next &lt;cite&gt;mouseDown&lt;/cite&gt;
event and check that it's coordinates are the same.  (I assume they should
be exactly the same, especially as the &lt;cite&gt;mouseDown&lt;/cite&gt; seems to be generated,
not the real one that presumably triggered the &lt;cite&gt;swipeStart&lt;/cite&gt;.)  If the next
mouse event is not &lt;cite&gt;mouseDown&lt;/cite&gt;, or if the &lt;cite&gt;mouseDown&lt;/cite&gt; position is different,
then the user cancelled the swipe and is doing a non-top-swipe somewhere,
even if it's right at the edge of the screen.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-implementation"&gt;
&lt;h3&gt;The Implementation&lt;/h3&gt;
&lt;p&gt;The code for this is a bit long, so I'm not including it directly here.
If you want to peek at it, look at
&lt;a class="reference external" href="http://hg.microcode.ca/playbook-air/src/tip/studies/ca/microcode/menu/TopSwipeMenu.as"&gt;ca.microcode.menu.TopSwipeMenu&lt;/a&gt;
and the demo program that uses it in
&lt;a class="reference external" href="http://hg.microcode.ca/playbook-air/src/tip/studies/MenuTest.as"&gt;MenuTest&lt;/a&gt;.
(By putting it there, I can also make changes more easily, and you can
submit issues to the tracker, if you like.)&lt;/p&gt;
&lt;p&gt;The code implements a 7-state finite state machine that cleanly steps
through the various stages possible.  The design ensures that
only the necessary listeners are active at any given time, so you
don't wastefully watch for (especially) &lt;cite&gt;mouseMove&lt;/cite&gt; or &lt;cite&gt;enterFrame&lt;/cite&gt;
events when it's not required.  See the figure below.&lt;/p&gt;
&lt;img alt="static/files/TopSwipeStates.png" src="static/files/TopSwipeStates.png" /&gt;
&lt;p&gt;As implemented, it requires you to specify a width and height for the menu,
and optionally a background colour for the panel.  You can adjust the
&amp;quot;swipe_region&amp;quot; (probably not a good term for it, but it defines how far
you have to swipe into the screen before you can release and have the
menu continue opening on its own) and &amp;quot;slide_time&amp;quot; (duration in seconds
for the complete menu slide) as class properties.&lt;/p&gt;
&lt;p&gt;To close the menu you can either click below it, add a Done button
as in the MenuTest example code, or touch the top bezel again.&lt;/p&gt;
&lt;p&gt;I hope it proves useful to someone.  It's taken quite a few hours to
get it to this stage; I would appreciate a small credit somewhere in
your app or docs if you choose to use it.  At least let me know where
it's been used, for my own satisfaction.  (Legally you don't have to do
either, as I've released it under the
&lt;a class="reference external" href="http://www.opensource.org/licenses/mit-license"&gt;MIT License&lt;/a&gt;,
but you must preserve my copyright notice and the license even if you
change the code.)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="addendum"&gt;
&lt;h2&gt;Addendum&lt;/h2&gt;
&lt;p&gt;I wrote a follow-up with a suggestion for a
&lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-swipe_start-simplified.html"&gt;simplified version&lt;/a&gt;
that doesn't require listening for &lt;cite&gt;mouseMove&lt;/cite&gt; at all.&lt;/p&gt;
&lt;/div&gt;
</summary></entry><entry><title>Convert EPS to PNG with ImageMagick</title><link href="http://www.peterhansen.ca/blog/convert-eps-to-png-with-imagemagick.html" rel="alternate"></link><updated>2011-01-24T00:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-24:/blog/convert-eps-to-png-with-imagemagick.html/</id><summary type="html">&lt;p&gt;Coincidentally, after getting by &lt;a class="reference external" href="http://peterhansen.ca/blog/using-imagemagick-to-filter-page-scans.html"&gt;until recently&lt;/a&gt;
without having a good reason to try ImageMagick, I needed it again
just today.  I had a company logo in EPS format which
I needed turned into PNG format.&lt;/p&gt;
&lt;p&gt;Since I'm on Windows, and don't have &lt;a class="reference external" href="http://www.photoshop.com/"&gt;Adobe Photoshop&lt;/a&gt;,
this isn't a 10-second operation.  At least, not until you install the right
stuff.
Even on Windows, however, &lt;a class="reference external" href="http://www.imagemagick.org/script/index.php"&gt;ImageMagick&lt;/a&gt;
knows how to call out to &lt;a class="reference external" href="http://pages.cs.wisc.edu/~ghost/"&gt;Ghostscript&lt;/a&gt; if it's installed.&lt;/p&gt;
&lt;p&gt;The first attempt to convert produced a nice clean 52K PNG file at 2254x751.  Okay,
so basic conversion works:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert myfile.eps foo.png
&lt;/pre&gt;
&lt;p&gt;I wanted it to be 300 pixels wide, however, so I tried the obvious.  Yes, without reading
the docs... but who reads the docs the first time?&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert myfile.eps -size 300x76 foo.png
&lt;/pre&gt;
&lt;p&gt;This gave the same output... Hmm.  Better actually read the docs.&lt;/p&gt;
&lt;p&gt;Okay, so &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-size&lt;/span&gt;&lt;/tt&gt; is for when an image doesn't have known dimensions, such as can
happen with certain file formats.
I want &lt;a class="reference external" href="http://www.imagemagick.org/script/command-line-options.php#resize"&gt;-resize&lt;/a&gt; instead:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert myfile.eps -resize 300x76 foo.png
&lt;/pre&gt;
&lt;p&gt;That works well, except the resulting file is 60K, which is too big.  Why?  Explorer
shows that it's a 48-bit image... rather more than I need.  How to get less depth?&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert myfile.eps -resize 300x76 -depth 8 foo.png
&lt;/pre&gt;
&lt;p&gt;Well, same quality but 24-bit depth and only 28K.  Huh?  Where did 24-bit come from
when I asked for 8?  It looks like the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-depth&lt;/span&gt;&lt;/tt&gt; option specifies
&lt;em&gt;per-colour depth&lt;/em&gt;.  Using &lt;tt class="docutils literal"&gt;identify &lt;span class="pre"&gt;-verbose&lt;/span&gt; foo.png&lt;/tt&gt; gives more detail than
I need to learn all about that.  Trying again with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-depth&lt;/span&gt; 4&lt;/tt&gt; gives me as much
quality as I need, at 4 bits per colour, and just over 13K.&lt;/p&gt;
&lt;p&gt;But the file is still larger than I'd like... using &amp;quot;strings foo.png&amp;quot; shows me there
is lots of metadata present in the file, leftover from the original EPS file which
was apparently built in &lt;a class="reference external" href="http://www.adobe.com/products/illustrator/"&gt;Adobe Illustrator&lt;/a&gt;.
The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-strip&lt;/span&gt;&lt;/tt&gt; option will &amp;quot;strip the image of any profiles or comments&amp;quot;
&lt;a class="reference external" href="http://www.imagemagick.org/script/command-line-options.php#strip"&gt;say the docs&lt;/a&gt; so
let's try that:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert myfile.eps -resize 300x76 -depth 4 -strip foo.png
&lt;/pre&gt;
&lt;p&gt;That shrinks it down to only 3.8K, which is even smaller than I'd hoped for
and, incidentally, 0.075% of the original EPS file size.
Job done: thanks &lt;a class="reference external" href="http://www.imagemagick.org/script/sponsors.php"&gt;ImageMagick sponsors&lt;/a&gt;!&lt;/p&gt;
</summary></entry><entry><title>PlayBook Simulator FTP Transfer Fails</title><link href="http://www.peterhansen.ca/blog/playbook-simulator-ftp-transfer-fails.html" rel="alternate"></link><updated>2011-01-21T07:29:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-21:/blog/playbook-simulator-ftp-transfer-fails.html/</id><summary type="html">&lt;p&gt;This morning one of the forum posts was a question about problems using
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Loading-data-from-FTP-in-simulator/m-p/747137"&gt;URLLoader to retrieve a file over FTP&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Loading-data-from-FTP-in-simulator/m-p/747199/highlight/true#M6615"&gt;first response&lt;/a&gt;
was to suggest that the poster may be mistakenly thinking
he could use the HTTP protocol to get to something over FTP.  There was
nothing in the &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLLoader.html"&gt;URLLoader docs&lt;/a&gt;
to suggest it handles FTP, and as usual with my ActionScript3 queries I found almost
nothing on the web with a search or two, other than
one post where &lt;a class="reference external" href="http://www.actionscript.org/forums/showthread.php3?t=155825"&gt;people said you can't do it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out I was quite wrong and, as with the Python urllib tools,
URLLoader transparently handles FTP under the covers.  You can even
include a userid and password in the URL, as with Python's approach.
(It works, but I still find no docs or search results saying that.)&lt;/p&gt;
&lt;p&gt;Unfortunately, with the current simulator (Beta 2, v0.9.2) it doesn't
actually work.  I analyzed with &lt;tt class="docutils literal"&gt;tcpdump&lt;/tt&gt; on my router and was able
to see the full FTP session, with login, switch to
&lt;a class="reference external" href="http://slacksite.com/other/ftp.html"&gt;passive mode&lt;/a&gt;, checking size of
file, and retrieval of data.  For my test case, it was a local FTP
site with authentication and an 82 byte text file, but I also tried
with an external anonymous site and a larger file.&lt;/p&gt;
&lt;p&gt;Basically the complete transfer succeeds, with all data received,
yet before sending Event.COMPLETE the data seems to be simply
discarded, with no indication why.&lt;/p&gt;
&lt;p&gt;The original poster filed this as ticket &lt;a class="reference external" href="https://www.blackberry.com/jira/browse/TABLET-50"&gt;TABLET-50&lt;/a&gt;.
(Note that the link won't work for you unless you're logged into the BlackBerry issue
tracker, and they make the ticket public.  In the past all tickets were visible
but I guess as they get closer to release they've decided it's time to make
tickets private by default, so they can vet them for security risks and such.)&lt;/p&gt;
&lt;p&gt;Here's the code for a simple test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;package&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.display.Sprite&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.text.TextFieldAutoSize&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.text.TextFormat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.events.&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.utils.&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flash.net.&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;mx.utils.ObjectUtil&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;qnx.ui.text.Label&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SWF&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1024&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;600&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backgroundColor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#5588ff&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frameRate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;20&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)]&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="n"&gt;FtpTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Sprite&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;URLLoader&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;function &lt;/span&gt;&lt;span class="nf"&gt;FtpTest&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;logoFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;TextFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;TextFormat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;logoFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;TextFormat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;logoFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;logo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logoFormat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FTP Test&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;autoSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextFieldAutoSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LEFT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;addChild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;URLRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ftp://ftp2.bom.gov.au/anon/gen/fwo/IDA00001.dat&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// next one shows how to do authenticated login, the above is anonymous&lt;/span&gt;
            &lt;span class="c1"&gt;// var request:URLRequest = new URLRequest(&amp;quot;ftp://user:password@example.com/path/myfile.text&amp;quot;);&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;URLRequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;URLLoader&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMPLETE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onEvent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOErrorEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IO_ERROR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onEvent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addEventListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecurityErrorEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECURITY_ERROR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onEvent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;function &lt;/span&gt;&lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;):&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMPLETE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ObjectUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
                &lt;span class="n"&gt;logo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Got &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bytesLoaded&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; bytes&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                    &lt;span class="s2"&gt;&amp;quot;\nData: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ObjectUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary></entry><entry><title>PicasaPhotoViewer Process Doesn't Terminate</title><link href="http://www.peterhansen.ca/blog/picasaphotoviewer-process-doesnt-terminate.html" rel="alternate"></link><updated>2011-01-20T15:43:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-20:/blog/picasaphotoviewer-process-doesnt-terminate.html/</id><summary type="html">&lt;p&gt;I have the Picasa photo viewer (PicasaPhotoViewer.exe) set up as my default app for
basic image viewing.  It's generally fast, makes it easy to scroll through a
folder full of images, and lets me zoom in and out at lightning speed using the
mouse wheel.  All good.&lt;/p&gt;
&lt;p&gt;Unfortunately, sometimes I would notice in my Task Manager window (this is on
Windows 7 Pro) that I had a whole pile of PicasaPhotoViewer.exe processes still
running, even with no photos left open onscreen.  It was easy to terminate them
(though with 30 processes a bit tedious) but it's always annoying when things
like that happen, especially when you can't find an obvious answer.&lt;/p&gt;
&lt;p&gt;I googled several times but never saw any mention of it, until I checked again
today and found others &lt;a class="reference external" href="http://www.google.com/support/forum/p/Picasa/thread?tid=663a092f5de98ec1&amp;amp;hl=en"&gt;had asked about it&lt;/a&gt;
and, amazingly, actually got a &lt;a class="reference external" href="http://www.google.com/support/forum/p/Picasa/thread?tid=663a092f5de98ec1&amp;amp;hl=en&amp;amp;fid=663a092f5de98ec10004975ffaf52a64&amp;amp;hltp=2"&gt;useful answer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As it turns out, the process may (or perhaps &lt;em&gt;will&lt;/em&gt;) stay resident if you
are loading files across the network.  I have a server with a largish hard
drive (RAID5) and keep lots of photos and such on it, so from time to time
I browse a folder on the network.  If I'm repeatedly viewing an image then
closing the viewer, regenerating the image (say) at the command line, then
reloading it, each iteration opens a new process and leaves the old one in memory.&lt;/p&gt;
&lt;p&gt;So there's no fix, but at least I now have an answer and can stop worrying about
it.  It's just another of those little annoyances from Google, where if you
could only just figure out how to get someone there to hear about, acknowledge,
and fix your problem -- or do any one of those! -- life would be great.&lt;/p&gt;
&lt;p&gt;Thanks &amp;quot;neilwales&amp;quot;, whoever you are. :)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edit:&lt;/em&gt; this is fixed in &lt;a class="reference external" href="http://www.google.com/support/forum/p/Picasa/thread?tid=64e854c3a5511ffb&amp;amp;hl=en&amp;amp;fid=64e854c3a5511ffb00049d8467ab7bf1&amp;amp;hltp=2"&gt;build 117.38&lt;/a&gt;
and later, &lt;a class="reference external" href="http://zornsoftware.talsit.info/blog/picasa-photo-view-process-staying-in-memory.html"&gt;at least for some people&lt;/a&gt;.&lt;/p&gt;
</summary></entry><entry><title>Using ImageMagick to Filter Page Scans</title><link href="http://www.peterhansen.ca/blog/using-imagemagick-to-filter-page-scans.html" rel="alternate"></link><updated>2011-01-20T12:13:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-20:/blog/using-imagemagick-to-filter-page-scans.html/</id><summary type="html">&lt;p&gt;I had a need to clean up some not-so-great scans of photocopies.  The pages
included both text and music.  This made it a bit tricky to process since the
music had very thin lines.  I needed the text darker, but without amplifying the
background noise, and this tended to fade out the lines in the
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Staff_(music)"&gt;staff&lt;/a&gt;.
I was able to get good results from &lt;a class="reference external" href="http://www.getpaint.net/download.html"&gt;Paint.NET&lt;/a&gt;
using just the Auto Levels adjustment but I had 48 pages to process and there's no way
I was going to do it manually; as far as I know you can't script Paint.NET.&lt;/p&gt;
&lt;p&gt;I briefly considered a few options, including &lt;a class="reference external" href="http://www.gimp.org/"&gt;GIMP&lt;/a&gt;, before
re-stumbling over &lt;a class="reference external" href="http://www.imagemagick.org/script/index.php"&gt;ImageMagick&lt;/a&gt;,
which I've known about for ages but actually never had a need to use before.
Quoting from its web site, it's &amp;quot;a software suite to create, edit, compose,
or convert bitmap images.... [It is] typically utilized from the command line....&amp;quot;
It handles just about every format under the sun including JPEG and PDF,
which is what I needed.&lt;/p&gt;
&lt;p&gt;There are a gazillion things you can do with it, including writing very sophisticated
scripts around it, such as those included on &lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/textcleaner/index.php"&gt;Fred's ImageMagick Scripts&lt;/a&gt;
page.  I tried out a couple meant for thresholding (i.e. making your background fade
out more while your foreground is strengthened... like boosting the contrast),
including
&lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/kmeansthresh/index.php"&gt;kmeansthresh&lt;/a&gt;,
&lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/textcleaner/index.php"&gt;textcleaner&lt;/a&gt;,
and &lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/2colorthresh/index.php"&gt;2colorthresh&lt;/a&gt;
before finding the excellent
&lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/threshold_comparison/index.php"&gt;threshold comparison study&lt;/a&gt;
which, for my purposes, suggested that the &amp;quot;Local Adaptive&amp;quot; filter
(&lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/localthresh/index.php"&gt;localthresh&lt;/a&gt;) could
be the best bet.&lt;/p&gt;
&lt;p&gt;I cycled through a series of test runs with varying parameters (manual optimization).
I settled on &lt;tt class="docutils literal"&gt;localthresh &lt;span class="pre"&gt;-n&lt;/span&gt; yes &lt;span class="pre"&gt;-m&lt;/span&gt; 3 &lt;span class="pre"&gt;-r&lt;/span&gt; 35 &lt;span class="pre"&gt;-b&lt;/span&gt; 20&lt;/tt&gt;
which means:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-n&lt;/span&gt; yes&lt;/tt&gt;: &amp;quot;negate&amp;quot;, since my image was black-on-white and the tool needs the inverse&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-m&lt;/span&gt; 3&lt;/tt&gt;: &amp;quot;local mean and mean absolute deviation&amp;quot; mode, because the other two modes gave bad results&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-r&lt;/span&gt; 35&lt;/tt&gt;: radius of 35 pixels, just larger than the thickest feature, which was some title text&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-b&lt;/span&gt; 20&lt;/tt&gt;: a bias of 20, chosen empirically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The radius value matches roughly the thickness of the largest text in the page, and anything
less would result in an outline (black around white regions) rather than solid lines making
up the letters.&lt;/p&gt;
&lt;p&gt;The scans were JPG format at 600dpi, about 4900x6900 pixels.  I used PNG for the output files to
avoid any incremental degradation, as JPG uses lossy compression (PNG is lossless).
I did this as I expected to need some subsequent processing, but as it turns out this
first pass was adequate (quite good, really) so that's as far as it went.&lt;/p&gt;
&lt;p&gt;To ease printing, I wanted to combine all the images into a PDF as well.  ImageMagick
does that, too.
Note that ImageMagick's &lt;a class="reference external" href="http://www.imagemagick.org/Usage/formats/#pdf_options"&gt;default PDF output is uncompressed&lt;/a&gt;
so to avoid massive file sizes I specified zip compression:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
convert -compress zip *.png foo.pdf
&lt;/pre&gt;
&lt;p&gt;I packaged all this up into a Python script (see below), so the whole thing was
automatic (except the scanning, intermittently feeding sheets to the scanner over several hours
while reading news online).&lt;/p&gt;
&lt;p&gt;And now some before and after pictures to compare the results.  Note that the main goal
here was to make it easier to read the music (when reprinted) and note how much
stronger the staff lines are.  The text was fine either way, though
it didn't hurt if it improved a bit (or lost a tiny bit of clarity, if that was the
tradeoff we had to accept).&lt;/p&gt;
&lt;p&gt;Here's a small section of music as a raw scan:&lt;/p&gt;
&lt;img alt="static/files/music_before.png" src="static/files/music_before.png" /&gt;
&lt;p&gt;And the same section after filtering:&lt;/p&gt;
&lt;img alt="static/files/music_after.png" src="static/files/music_after.png" /&gt;
&lt;p&gt;For comparison here's a small bit of text:&lt;/p&gt;
&lt;img alt="static/files/text_before.png" src="static/files/text_before.png" /&gt;
&lt;p&gt;And the filtered output:&lt;/p&gt;
&lt;img alt="static/files/text_after.png" src="static/files/text_after.png" /&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;Here's the script.  Note that it is meant for Linux, mainly because of the &amp;quot;localthresh&amp;quot;
script which uses Bash shell syntax.  The script assumes you have ImageMagick installed
and that you have downloaded &lt;a class="reference external" href="http://www.fmwconcepts.com/imagemagick/localthresh/index.php"&gt;localthresh&lt;/a&gt;
into the current directory, and did &lt;tt class="docutils literal"&gt;chmod +x localthresh&lt;/tt&gt; to make it executable.
Make appropriate changes for other systems and note that as usual
&lt;a class="reference external" href="http://www.imagemagick.org/Usage/windows/"&gt;Windows is a second class citizen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To invoke it, make sure to escape any wildcards with single quotes, as in
&lt;tt class="docutils literal"&gt;./scans2pdf.py &lt;span class="pre"&gt;'/home/foo/*.jpg'&lt;/span&gt;&lt;/tt&gt; or the shell will expand them and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;Mass filtering of page scans to improve text quality using ImageMagick.&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;glob&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;shutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tempfile&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;tempdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdtemp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Output file &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot; exists.  Use -f or --force to overwrite.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;convert &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;/*.png -compress zip &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempdir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;inf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;outf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;out-&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;inf&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;./localthresh -n yes -m 3 -r 35 -b 20 &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Mass filtering of page scans using ImageMagick.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Files or glob pattern(s) for input file, e.g. /home/foo/scan-*.jpg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;-o&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;--output&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;output.pdf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Name of output file, default &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%(default)s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;-f&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;--force&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;store_true&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Overwrite if output file already exists.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All this is offered up primarily for beginners looking for examples, rather than
as a paragon of image processing virtuosity.  Experts could do better, but this did
just fine for my purposes and I hope some part of it helps out someone else.&lt;/p&gt;
</summary></entry><entry><title>PlayBook Simulator File Access</title><link href="http://www.peterhansen.ca/blog/playbook-simulator-file-access.html" rel="alternate"></link><updated>2011-01-17T09:25:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-17:/blog/playbook-simulator-file-access.html/</id><summary type="html">&lt;p&gt;Some developers have a &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/735859/highlight/true#M5924"&gt;legitimate need to share files&lt;/a&gt;
with the PlayBook simulator.  This is broken in the Beta 2 simulator.
If you don't care why, &lt;a class="reference external" href="#workarounds"&gt;jump ahead to the workarounds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the first (Beta 1) simulator this could be done using FTP.  The simulator had little in the
way of security: all apps ran as &amp;quot;root&amp;quot; and you could log in via Telnet or FTP as the
root user.  They didn't even make any attempt to make &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/local-folder-location-in-simulator/m-p/717919/highlight/true#M4479"&gt;the password&lt;/a&gt;
difficult to guess!&lt;/p&gt;
&lt;p&gt;Unfortunately, with the Beta 2 simulator, they've tightened up security substantially.
This is overall a good thing, since the final release should be very secure so we need
to test under the same conditions, but it has hampered some testing efforts.&lt;/p&gt;
&lt;p&gt;So in Beta 2, they removed Telnet and FTP, and added Secure Shell (SSH) access.  Hurray!
Except... what you can do with it is very limited due to several bugs, for now.&lt;/p&gt;
&lt;p&gt;While SSH normally supports &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Secure_copy"&gt;scp&lt;/a&gt; or
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/SSH_file_transfer_protocol"&gt;sftp&lt;/a&gt;, someone at QNX
got a bit creative with security and made &lt;tt class="docutils literal"&gt;/etc/passwd&lt;/tt&gt; unreadable to non-root users.
This has the unfortunate side-effect of
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/735849/highlight/true#M5923"&gt;breaking scp and sftp&lt;/a&gt;
as I discovered.
It's also entirely unnecessary because, in spite of its name, &lt;tt class="docutils literal"&gt;/etc/passwd&lt;/tt&gt;
is &lt;em&gt;not&lt;/em&gt; a password file.  It used to be, but in modern times the password hashes
have all been moved to &lt;tt class="docutils literal"&gt;/etc/shadow&lt;/tt&gt;, which of course is not readable by regular users.&lt;/p&gt;
&lt;p&gt;There's another problem which makes things difficult, even if you figure out how to transfer
files using just SSH.  They &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/733709/highlight/true#M5758"&gt;apparently intended&lt;/a&gt;
to make an app's &amp;quot;sandbox&amp;quot; folder accessible
to the development user when running in development mode (specifically, with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt;
option on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;blackberry-airpackager&lt;/span&gt;&lt;/tt&gt;).  It looks like that doesn't actually work either --
at least, I can't get it to work, and no one else reports success yet either.  When you log
in with SSH, you become &amp;quot;devuser&amp;quot; (uid 100).  Unfortunately the sandbox folders are all
under &lt;tt class="docutils literal"&gt;/accounts/1000&lt;/tt&gt; and &amp;quot;devuser&amp;quot; cannot access or read any of them, even those for
apps installed with that mystical &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-devMode&lt;/span&gt;&lt;/tt&gt; option.  [This was fixed in 0.9.3. -Ed]&lt;/p&gt;
&lt;div class="section" id="workarounds"&gt;
&lt;h2&gt;Workarounds&lt;/h2&gt;
&lt;p&gt;I've found a few primitive workarounds so far.  Depending on your needs, one or more
of these may work:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Your app can of course access its own files (in &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filesystem/File.html#applicationDirectory"&gt;File.applicationDirectory&lt;/a&gt;,
which maps to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/accounts/1000/appdata/MyAppName.MY-APP-ID-HASH/data&lt;/span&gt;&lt;/tt&gt;.
The simplest approach
is not to use external access via SSH, but just bundle your files with your app,
and provide app-specific ways of manipulating them.  Use things like
&lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filesystem/File.html#copyTo()"&gt;File.copyTo()&lt;/a&gt;
in the simulator, or &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/FileReference.html"&gt;flash.net.FileReference&lt;/a&gt;
to transfer files between your web server and the simulator.  Doesn't help if you don't
have a web server and don't know how to set one up, even locally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Use basic command-line tools via SSH.  This won't work well for binary data,
but if you just need to get a text file into the sim, something like this will
work when executed at the command line on your host machine:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
# transfer myfile from simulator to host
ssh devuser&amp;#64;MYSIMIP cat myfile &amp;gt;myfile

# transfer myfile from host to simulator
type myfile | ssh devuser&amp;#64;MYSIMIP &amp;quot;cat &amp;gt;myfile&amp;quot;
&lt;/pre&gt;
&lt;p&gt;The first command executes &amp;quot;cat myfile&amp;quot; remotely on the simulator, and
the output is redirected into a file on your host machine.&lt;/p&gt;
&lt;p&gt;The second command outputs local &lt;tt class="docutils literal"&gt;myfile&lt;/tt&gt; to stdout, piping it through SSH,
and on the remote side redirects stdin to a new copy of &lt;tt class="docutils literal"&gt;myfile&lt;/tt&gt;.
That will end up in &lt;tt class="docutils literal"&gt;/accounts/devuser/myfile&lt;/tt&gt;.
To read this in your app, you'll need to do two things.&lt;/p&gt;
&lt;ol class="loweralpha simple"&gt;
&lt;li&gt;Make your devuser folder world-readable: &lt;tt class="docutils literal"&gt;chmod a+rx ~&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Use an absolute path of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;File('/accounts/devuser/myfile')&lt;/span&gt;&lt;/tt&gt; to read it in your app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you need to get files &lt;em&gt;from&lt;/em&gt; the app, do &lt;tt class="docutils literal"&gt;chmod a+wrx ~&lt;/tt&gt; to make that folder
writable as well as readable, and make sure your app writes to that folder rather
than &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filesystem/File.html#applicationStorageDirectory"&gt;File.applicationStorageDirectory&lt;/a&gt;
where it normally would.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Transfer files using FTP, with the simulator as the client, to the devuser home folder.
You first need to run an FTP server outside the simulator.  Log
into the simulator using SSH and type &amp;quot;ftp MYHOSTIP&amp;quot; then log in to FTP.
Transfer files the usual way, making sure to type &amp;quot;binary&amp;quot; to switch to binary
mode for file transfers unless you're doing just text files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;If you're desperate to the file transfers, you could run Python2.7 on the
simulator and use Python's &lt;a class="reference external" href="http://docs.python.org/release/2.7/library/ftplib.html#module-ftplib"&gt;ftplib&lt;/a&gt;
module.  In the old simulator you could just do &amp;quot;python2.7&amp;quot; but another minor issue
in the new one means you have to use a full path of &lt;tt class="docutils literal"&gt;/base/usr/bin/python2.7&lt;/tt&gt;.
You can write a script that will, for example, run on the simulator side and
maintain a mirror with periodic updates to keep things in sync.  [In 0.9.4 they
changed the permissions so &amp;quot;devuser&amp;quot; cannot run Python on the simulator,
rather sadly for me. -Ed]&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you combine options 1 and 4, you can have a fully automated way of moving files
between your app's storage directory and your host machine.  Just set up a Timer,
have it trigger some &lt;tt class="docutils literal"&gt;File.copyToAsync()&lt;/tt&gt; calls to exchange files with the
&lt;tt class="docutils literal"&gt;/accounts/devuser&lt;/tt&gt; folder, and after logging in via SSH run a timed Python
script to exchange files with your host machine.  Crufty, but until the next release
it's the best I can think of!&lt;/p&gt;
&lt;p&gt;Well, that's it.  There are always options...&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Originally the post referred to this simulator version as &amp;quot;Beta 3&amp;quot; because
we all thought that's what it was.  As RIM seems to think confusing us is a good idea,
they issued the Beta3 SDK with the Beta2 simulator even though both are
called v0.9.2... Go figure!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</summary></entry><entry><title>PlayBook Beta 3 SDK</title><link href="http://www.peterhansen.ca/blog/playbook-beta-3-sdk.html" rel="alternate"></link><updated>2011-01-12T15:08:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-12:/blog/playbook-beta-3-sdk.html/</id><summary type="html">&lt;p&gt;Hurray!  The next SDK and simulator for the PlayBook are out.  Actually,
not only have the Beta 3 AIR SDK and simulator been released, but there's now a
&lt;a class="reference external" href="http://devblog.blackberry.com/2011/01/blackberry-webworks-sdk"&gt;Blackberry WebWorks SDK for PlayBook&lt;/a&gt;
available on the &lt;a class="reference external" href="http://us.blackberry.com/developers/tablet/"&gt;Tablet OS Development site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="http://docs.blackberry.com/en/developers/deliverables/21880/New_in_this_release_1398756_11.jsp"&gt;AIR SDK release notes&lt;/a&gt;
tell us what is new and changed.  Here are the highlights, from my point of view:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&amp;quot;application control permissions&amp;quot; need to be set in your blackberry-tablet.xml
file (note: that's not the same as the application.xml file!) to access certain
things, such as camera or microphone.&lt;/li&gt;
&lt;li&gt;audio is working! Sort of.  And apparently video should work, but I don't think it really
does yet for anyone.&lt;/li&gt;
&lt;li&gt;numerous bug fixes (and some new bugs!)&lt;/li&gt;
&lt;li&gt;Secure SHell (SSH) connections to the tablet, so they've ditched telnet and
used something sensible (i.e. secure), not to mention making this an officially
supported way to access the device: I don't have to be coy about using telnet any more.&lt;/li&gt;
&lt;li&gt;custom splash screen for any app&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://us.blackberry.com/developers/platform/paymentservice.jsp"&gt;Payment Service SDK&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;the QNXStageWebView is documented, thus basically available, though still flaky&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for the simulator, it now supports orientation changes
(using the &amp;quot;bottom right&amp;quot; swipe &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Simulate-Low-Memory/m-p/728599/highlight/true#M5288"&gt;that I mentioned earlier&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Given how long it took, that's actually a fairly small list of significant items.
I was expecting at least to see Notification support, among many other things that
are still missing.&lt;/p&gt;
&lt;p&gt;There are several bugs to note, and in fact many are thinking this version is showing
pretty poor quality control, but given how late it is we're mostly just grateful to
finally see it at all.&lt;/p&gt;
&lt;p&gt;Some bugs with the auto-orientation support:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;When you swipe to rotate, the &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Orientation-change-problem/m-p/735441/highlight/true#M5890"&gt;app appears to be minimized&lt;/a&gt;
afterwards.  You can't just
click on it.  Instead, bottom-swipe (the regular &amp;quot;minimize app&amp;quot; gesture) and then
click on the app.  It will now expand with the new orientation.&lt;/li&gt;
&lt;li&gt;Although stage.orientation is deprecated, &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Listen-for-rotation-problem-with-vertical-centering/m-p/737225/highlight/true#M6046"&gt;stage.deviceOrientation always contains &amp;quot;unknown&amp;quot;&lt;/a&gt;
so we have no choice about which to use yet.  The orientation event has an &amp;quot;afterOrientation&amp;quot;
property you can use, but that doesn't help with the next item.&lt;/li&gt;
&lt;li&gt;If you rotate while the app is minimized, not only will it not get an event (which could
let it re-render so it can update its minimized view) but after you restore it the
value in &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Listen-for-rotation-problem-with-vertical-centering/m-p/737977/highlight/true#M6137"&gt;stage.orientation will not have changed&lt;/a&gt;.
There's no known workaround other
than just re-rotating back and forth again while it's active.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The audio works, at least for &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html"&gt;flash.media.Sound&lt;/a&gt;,
but so far not for the &lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/media/package-detail.html"&gt;qnx.media&lt;/a&gt; stuff.
And lots of people are seeing their
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Simulator-freezing/m-p/732715#M5668"&gt;simulator freeze&lt;/a&gt;
while playing audio, though at the
moment we suspect it's not directly related to audio.  QNX is overly mum on the matter,
as before, and so we waste significant quantities of developer time investigating things
they probably already know about.  I just wish they had a manager in charge who was capable
of improving their communications with the dev community.  Hey, I'm available!&lt;/p&gt;
&lt;p&gt;There are also problems with the SSH support.  For now,
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/735849/highlight/true#M5923"&gt;scp and sftp do not work&lt;/a&gt;,
because QNX went overboard in their efforts to secure the thing and protected /etc/passwd from
reading by anyone but the root user.  They must have thought it actually contained passwords
or something, which it does not.  [They fixed this in the 0.9.3 release. -Ed]&lt;/p&gt;
&lt;p&gt;The worst thing from my point of view is that they also set
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/How-to-enable-connect-with-SSH/m-p/733389/highlight/true#M5736"&gt;incorrect permissions&lt;/a&gt;
on the app sandbox folders, so that even with the &amp;quot;-devMode&amp;quot; option on blackberry-deploy
you cannot see into your app's data, or the shared folder, when you connect via SSH as &amp;quot;devuser&amp;quot;.
The workaround here is to do &amp;quot;chmod o=rwx /accounts/devuser&amp;quot; and have your app read and
write to the /accounts/devuser folder, for any state that you need to access for testing
purposes.  [This was also fixed in 0.9.3. -Ed]&lt;/p&gt;
&lt;p&gt;All in all, I'm glad it's out, but it could have been so much better.&lt;/p&gt;
</summary></entry><entry><title>PlayBook Tidbits #2</title><link href="http://www.peterhansen.ca/blog/playbook-tidbits-2.html" rel="alternate"></link><updated>2011-01-07T07:54:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-07:/blog/playbook-tidbits-2.html/</id><summary type="html">&lt;p&gt;More small observations from the goings-on at &lt;a class="reference external" href="http://www.cesweb.org/"&gt;CES&lt;/a&gt; in 2011.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;In the &lt;a class="reference external" href="http://www.slashgear.com/blackberry-playbook-demo-and-hands-on-by-mike-lazaridis-07124552/"&gt;SlashGear.com video with Mike Lazaridis&lt;/a&gt;
we can see some interesting new navigating gestures Mike uses.  Note that
these aren't available on the SDK yet:&lt;ol class="loweralpha"&gt;
&lt;li&gt;While swiping sideways between running apps without minimizing
them so the Navigator is visible, he can flick an app upwards
to terminate it.  This is similar to how you close them in the
shuttle bar area in Navigator but it's new.&lt;/li&gt;
&lt;li&gt;In the &amp;quot;between-app&amp;quot; view (as above), you can just drag
left or right to continuing moving between apps, rather than having
to swipe in from one of the bezels as you do in the current SDK.
He even shows holding position between two apps while they both
keep rendering.
Obviously you can also just swipe from the bezel but
that's really needed only to enter this new &amp;quot;switching mode&amp;quot;.&lt;/li&gt;
&lt;li&gt;(This wasn't Mike, but my own observation on the simulator.)  You can
not only swipe up to expand the icon area, but you can swipe up
again to minimize it.  Not sure that will make it through to the
production unit since it might be too inconsistent for user comfort.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;In the Navigator, in the category selection area above the app icons,
there are arrow icons that you use to maximize or shrink the icon area.
In many of the CES demo units you can now also see a little &amp;quot;pencil&amp;quot; icon
at the left edge.  &lt;a class="reference external" href="http://www.youtube.com/watch?v=8Wps624RkyM"&gt;CrackBerry.com's latest video&lt;/a&gt; shows that you can use
this to reorganize your app icons in the Navigator.&lt;/li&gt;
&lt;li&gt;In the beta SDK a minimized app had a red X close widget in the upper
right corner.  In the &lt;a class="reference external" href="http://liliputing.com/2011/01/hands-on-with-the-blackberry-playbook.html"&gt;demo units&lt;/a&gt;
it has moved down to follow the app title (a good move).&lt;/li&gt;
&lt;li&gt;The three simultaneous ray-tracing demos running side-by-side,
with Mike interacting with them in realtime, pretty much prove that this
baby kicks any wimpy Star Trek gadgetry &lt;em&gt;in the teeth&lt;/em&gt;.  Take that,
24th century technology!&lt;/li&gt;
&lt;li&gt;Someone pointed out in one video that along the top is not just
one but two microphones... stereo.  In theory that could be a big
help for noise cancellation, though I don't know if the stereo
nature of it will be exposed up through to the AIR APIs.&lt;/li&gt;
&lt;li&gt;Mike L. mentions that the &amp;quot;USB connection can drive Ethernet&amp;quot;, so
they either have or intend to have driver support for some
USB-Ethernet adapters.  This is good for anyone thinking of driving
serious business presentations out the HDMI without risking wireless
glitches (assuming your source is on a network).
(For anyone who hadn't heard, by the way, the HDMI output
can technically function as an independent display, which would
totally rock for business presentations, or just for letting someone
watch a video on your TV while you surf the web.)&lt;/li&gt;
&lt;li&gt;Mike commented that running his third instance of the ray-tracing app
would start to slow down the system, so clearly they have the multicore
support functioning in the demo units now.  Or, at least, in his!&lt;/li&gt;
&lt;/ol&gt;
</summary></entry><entry><title>PlayBook Tidbits #1</title><link href="http://www.peterhansen.ca/blog/playbook-tidbits-1.html" rel="alternate"></link><updated>2011-01-05T23:58:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2011-01-05:/blog/playbook-tidbits-1.html/</id><summary type="html">&lt;p&gt;Lots of interesting tidbits starting to come out from CES 2011 with a slew
of new videos (well, I've seen two so far, but compared to the recent
dearth of new stuff I call that a slew).&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Product Manager Ryan Bidan tells &lt;a class="reference external" href="http://www.informationweek.com/news/showArticle.jhtml?articleID=229000175"&gt;Information Week&lt;/a&gt;
that the &amp;quot;target&amp;quot; battery life is 8 hours &amp;quot;in regular use&amp;quot;.  So much
for Shaw Wu's bogus and questionably slanted claims that the device
&lt;em&gt;will&lt;/em&gt; have only &amp;quot;a few hours&amp;quot; of battery life.&lt;/li&gt;
&lt;li&gt;In the same video, you can see him swipe through the installed
apps on that particular beta unit, and one of the games is Quake III,
and indeed &lt;a class="reference external" href="http://news.yahoo.com/s/yblog_technews/20110106/tc_yblog_technews/hands-on-with-the-blackberry-playbook"&gt;Today in Tech&lt;/a&gt;
refers to this and shows a screenshot.
CNET senior editor Donald Bell has a &lt;a class="reference external" href="http://ces.cnet.com/8301-32254_1-20027522-283.html"&gt;BlackBerry PlayBook hands-on video&lt;/a&gt; that shows a few seconds
of live video from Quake III.&lt;/li&gt;
&lt;li&gt;Bidan says they are still &amp;quot;committed to delivering this product in Q1&amp;quot;
but he can't be more specific.  For a brief time Google had cached a WSJ
article with the title &amp;quot;RIM Tablet Delayed Until Summer&amp;quot;, but obviously someone
with a clue thought better of that title as it now leads to an article
titled &lt;a class="reference external" href="http://online.wsj.com/article/SB10001424052748704405704576064671337373858.html"&gt;&amp;quot;RIM Joins With Sprint on Tablet&amp;quot;&lt;/a&gt;,
where it talks about the &lt;em&gt;4G version in partnership with Sprint&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Some of the earliest approved apps by us little guys are even showing up
in that InfoWeek video, including &lt;a class="reference external" href="http://www.jasonfincanon.com/"&gt;Jason Fincanon's&lt;/a&gt;
&lt;a class="reference external" href="http://appworld.blackberry.com/webstore/content/20762?lang=en"&gt;Memory4Kidz&lt;/a&gt;.
There's also Nic Nac Noe (Ninja Tic Tac Toe), with a couple of screen shown
in the CNET video mentioned above, though I don't see that on App World yet.&lt;/li&gt;
&lt;/ol&gt;
</summary></entry><entry><title>PlayBook: Exit From an App Using ActionScript</title><link href="http://www.peterhansen.ca/blog/playbook-exit-from-an-app-using-actionscript.html" rel="alternate"></link><updated>2010-12-27T19:35:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-27:/blog/playbook-exit-from-an-app-using-actionscript.html/</id><summary type="html">&lt;p&gt;In a previous post I talked about several non-obvious
&lt;a class="reference external" href="http://peterhansen.ca/blog/closing-or-switching-apps.html"&gt;gestures that let you exit from an app&lt;/a&gt;
but, if you're a developer, you'll sometimes want to provide a Close button or some
other way for users to edit more directly.&lt;/p&gt;
&lt;p&gt;The most straightforward way is &lt;tt class="docutils literal"&gt;stage.nativeWindow.close()&lt;/tt&gt;.  This is
actually a call that must be made from within a method in your main
Sprite class, or any other suitable &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html"&gt;DisplayObject&lt;/a&gt;
since it references the read-only &lt;tt class="docutils literal"&gt;stage&lt;/tt&gt; property.&lt;/p&gt;
&lt;p&gt;The actual call is to the &lt;a class="reference external" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/NativeWindow.html#close()"&gt;NativeWindow.close()&lt;/a&gt;
method.  There are certain events associated with closing a window, or deactivating it,
which I've covered &lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-application-lifecycle.html"&gt;in a previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To summarize, here's a snippet to give yourself a Close button in your Sprite:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
    ...
    var closeBut:LabelButton = new LabelButton();
    closeBut.label = &amp;quot;Close&amp;quot;;
    closeBut.addEventListener(MouseEvent.CLICK, closeApp);
}

private function closeApp(event:MouseEvent):void {
    stage.nativeWindow.close();
}
&lt;/pre&gt;
</summary></entry><entry><title>PlayBook: Font List</title><link href="http://www.peterhansen.ca/blog/playbook-font-list.html" rel="alternate"></link><updated>2010-12-23T17:10:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-23:/blog/playbook-font-list.html/</id><summary type="html">&lt;p&gt;Using the &lt;tt class="docutils literal"&gt;flash.text.Font.enumerateFonts()&lt;/tt&gt; routine one can see the following
fonts available (at the moment... back at SDK beta 2) in the PlayBook simulator
(skipping over some Japanese, Thai, and Indian fonts, and grouping related
ones with slashes, to keep the list shorter):&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Andale Mono&lt;/li&gt;
&lt;li&gt;Arial&lt;/li&gt;
&lt;li&gt;BBAlpha Sans (plus Condensed/Mono)&lt;/li&gt;
&lt;li&gt;BBAlpha Serif&lt;/li&gt;
&lt;li&gt;BBArabic Keypad&lt;/li&gt;
&lt;li&gt;BBGlobal Sans&lt;/li&gt;
&lt;li&gt;BBGlobal Serif&lt;/li&gt;
&lt;li&gt;Bitstream Vera Sans (plus Mono)&lt;/li&gt;
&lt;li&gt;Bitstream Vera Serif&lt;/li&gt;
&lt;li&gt;Comic Sans MS&lt;/li&gt;
&lt;li&gt;Courier New&lt;/li&gt;
&lt;li&gt;DejaVu Sans (plus Mono)&lt;/li&gt;
&lt;li&gt;DejaVu Serif&lt;/li&gt;
&lt;li&gt;Droid Sans Mono&lt;/li&gt;
&lt;li&gt;Georgia&lt;/li&gt;
&lt;li&gt;Impact&lt;/li&gt;
&lt;li&gt;Liberation Mono/Sans/Serif&lt;/li&gt;
&lt;li&gt;Tahoma&lt;/li&gt;
&lt;li&gt;Times New Roman&lt;/li&gt;
&lt;li&gt;Trebuchet MS&lt;/li&gt;
&lt;li&gt;Verdana&lt;/li&gt;
&lt;li&gt;Webdings&lt;/li&gt;
&lt;li&gt;Wingdings (plus 2 and 3)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It seems they're also &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/List-of-available-fonts/m-p/635104#M1034"&gt;taking requests for other fonts&lt;/a&gt;
to be available in the final release.&lt;/p&gt;
&lt;p&gt;[Edit: a handful of new fonts was added in the 0.9.4 release, and most
importantly the default font changed from &amp;quot;BB Alpha Sans&amp;quot; to &amp;quot;Myriad Pro&amp;quot;.]&lt;/p&gt;
</summary></entry><entry><title>Fixing cibcvisagold.com</title><link href="http://www.peterhansen.ca/blog/fixing-cibcvisagoldcom.html" rel="alternate"></link><updated>2010-12-21T20:10:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-21:/blog/fixing-cibcvisagoldcom.html/</id><summary type="html">&lt;p&gt;I did a little technical support tonight for a major Canadian
bank.  Unpaid.  Unrequested, too, actually.  Not unappreciated though.&lt;/p&gt;
&lt;p&gt;We were browsing the &lt;a class="reference external" href="https://www.cibcgoldvisa.com/"&gt;World of Gold Rewards&lt;/a&gt; site to see what
&amp;quot;reward&amp;quot; my wife might want as a birthday present
from her father.  (Yes, we have everything we need, so
she wanted my help choosing. :-) )&lt;/p&gt;
&lt;p&gt;The pictures were not showing up on the rewards, just
empty boxes where they should have been.
I was using my daughter's computer, which runs Ubuntu, so
I popped down to my own Windows machine to compare, and
got the same results.  Checking the source for the
page showed me lots of Javascript, plus some IMG elements
with their source URL pointing to &lt;a class="reference external" href="https://www.fairlanezip.com"&gt;https://www.fairlanezip.com&lt;/a&gt;,
whoever they are.  Clicking on the links in Firefox's
source view showed me a security warning because of an
SSL certificate expiry three days ago.  I guess
maybe these fairlanezip people aren't particularly
competent or something.&lt;/p&gt;
&lt;p&gt;Anyway, that was the easy part.  The hard part, of course,
was trying to tell CIBC about it.  Their &amp;quot;Contact Us&amp;quot; page
has only a phone number (toll-free), so a simple email was
out of the question.  At least their hours of operation
were generous -- until midnight.&lt;/p&gt;
&lt;p&gt;To avoid a long story: I called the number, faced five menu
items with no suitable option, pressed a few random numbers
and the pound sign, got to someone who heard the word &amp;quot;web&amp;quot;
and passed me off to their &amp;quot;online banking&amp;quot; department...
who said they were only for personal banking, not VISA,
but they could transfer me back and would talk to someone
there first to smooth the way.&lt;/p&gt;
&lt;p&gt;They did that for a few
minutes, then told me the best approach would be to just
call the number again and ask for a supervisor.  Rather
remarkably, given that I was doing this as a favour,
I did call back, got a supervisor
with no hassle, and told him I'd seen a problem and knew what
was causing it.  He was actually grateful, as they had had
reports of a problem but obviously no answer yet, and
took the information I had to pass on to their in-house
IT staff (who, presumably, are about as on-the-ball as
the fairlanezip people, which is to say not very since
they hadn't seen or fixed the problem after three days).
With any luck, they'll have it fixed shortly, maybe by tomorrow
morning.&lt;/p&gt;
&lt;p&gt;The nice thing about this was that everyone I
spoke to was pleasant even while not necessarily being able to
help, and all who understood what I was trying to do for them
expressed their thanks.  I'll stay a happy TD Canada Trust
customer, but it's nice to know a big bank, even when their
own size and possible dead-weight is working against them,
can have nice and polite people answering the phone.&lt;/p&gt;
</summary></entry><entry><title>PlayBook Usability: Discoverability</title><link href="http://www.peterhansen.ca/blog/playbook-usability-discoverability.html" rel="alternate"></link><updated>2010-12-21T07:31:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-21:/blog/playbook-usability-discoverability.html/</id><summary type="html">&lt;p&gt;As mentioned in my &lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-usability-consistency.html"&gt;previous post&lt;/a&gt;
I have some concerns about UI design in the tablets.  One of those concerns
is &amp;quot;discoverability&amp;quot;, as described in Jakob Nielsen's
&lt;a class="reference external" href="http://www.useit.com/alertbox/ipad.html"&gt;summary posting&lt;/a&gt; about his early iPad usability study.&lt;/p&gt;
&lt;p&gt;I found this to be a problem the first time I touched an iPad.
While some things are done very well -- it didn't take a second to
understand how to unlock the device -- others are pretty obscure.
Note that this first screen a user ever sees
even has a nice clear instruction to &amp;quot;slide to unlock&amp;quot;, and a sharp-looking
slider, but they could have done as well with other features inside.&lt;/p&gt;
&lt;p&gt;I was using my father-in-law's new iPad in a quick attempt to learn enough
to provide basic instruction.  I got it hooked to the house network easily
enough... well, with minor annoyances, but I don't recall the specifics.
I do recall, however, once we got his email loaded up that the first thing
we wanted to do after viewing a message was delete it.  Hmm... how do you
do that?  Is there a nice X widget somewhere?  A trash can?  A button
labelled &amp;quot;Delete&amp;quot;?  No such luck...  fortunately I'm an old hand at UI testing
and troubleshooting, so after a few trial-and-error efforts I quickly found
that you &amp;quot;swipe&amp;quot; sideways within the list and a shiny red &amp;quot;Delete&amp;quot; button
magically appears for you to tap.  Thanks for hiding that, since deleting
emails is something I do, like, so rarely.&lt;/p&gt;
&lt;p&gt;The real lesson is this: you no longer have your desktop OS
highlighting the active components as you &amp;quot;hover&amp;quot; the mouse over them.
With a direct-interaction interface like these tablets have, there's no
&amp;quot;hover&amp;quot;... you either touch something or you don't.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My advice:&lt;/strong&gt; look for ways to make sure the user knows what the heck she
can tap, press, swipe, flick, or otherwise fiddle with.  How about
having a nice blue glow &amp;quot;evanesce&amp;quot; around all the active elements
when a page is first displayed?  Or a subtle animation where those
elements periodically have a &amp;quot;gleam&amp;quot; appear in one corner (possibly
supplemented by a more 3D appearance than we often see on tablets so far).
Or some nice tooltip/hint things, like balloons in a comic strip,
which appear next to the key controls for all new users, or if
new user doesn't discover a particular feature (like that email delete
button on the iPad) soon enough.  These could all be subtle, and
made to disappear gradually over time or even immediately upon first
use of any given feature by a new user.&lt;/p&gt;
&lt;p&gt;A related effect works reasonably well when a page has lots of content
but few other controls.  Just touching the content area makes
the hidden controls appear briefly, then fade again after a second or
two.  Users will quickly learn that there are controls available at
the touch of a finger, at which point they're all clearly visible.
This wouldn't be as safe in a complex view, where touching certain
elements could have an irreversible effect, so use it wisely.
(I believe the &lt;a class="reference external" href="http://www.rim.com/news/kit/media/images/product/playbook_videoconference.jpg"&gt;PlayBook camera app&lt;/a&gt;
uses this technique, with only a couple of primary controls always shown.
Yes, I know that's actually a chat app, but the camera app looks
similar and I didn't find a good picture of it yet.)&lt;/p&gt;
</summary></entry><entry><title>PlayBook Usability: Consistency</title><link href="http://www.peterhansen.ca/blog/playbook-usability-consistency.html" rel="alternate"></link><updated>2010-12-21T06:24:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-21:/blog/playbook-usability-consistency.html/</id><summary type="html">&lt;p&gt;While responding to a question in the &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/bd-p/tablet"&gt;Tablet OS Developers' Forum&lt;/a&gt;
I ran across links to a &lt;a class="reference external" href="http://www.nngroup.com/reports/mobile/ipad/"&gt;free 93-page iPad usability report&lt;/a&gt;
by Jakob Nielsen.  (Actually, you may prefer his &lt;a class="reference external" href="http://www.useit.com/alertbox/ipad.html"&gt;summary posting&lt;/a&gt;
if you don't have time to read a 93 page PDF.)&lt;/p&gt;
&lt;p&gt;Jakob's comments about inconsistency in the initial iPad apps reminded me of
my first concern as I listened to the &lt;a class="reference external" href="http://devblog.blackberry.com/2010/11/playbook-webcast-series-4/"&gt;Fourth PlayBook Webcast&lt;/a&gt;.
I thought that &lt;a class="reference external" href="http://www.rim.com/"&gt;RIM&lt;/a&gt;
was being pretty sparse on the guidelines.&lt;/p&gt;
&lt;p&gt;I think they've had a year to review the iPad situation and learn from
its mistakes, and they would do well to provide more
thorough and substantial guidelines.  Unfortunately they seem to be too busy with
getting the product ready to give due attention to the quality of the user experience.&lt;/p&gt;
&lt;p&gt;It seems clear that this lack of guidance will lead to each app being different.
Users won't have a clue what to do in many apps, especially those written by
Flash-only developers with no usability training, no experience with tablets
(since who among us does?), and a growing desperation to get that &lt;a class="reference external" href="http://devblog.blackberry.com/2010/11/qualify-for-the-free-blackberry-playbook-offer/"&gt;free PlayBook!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nielsen certainly found inconsistent designs among the 35 apps and web sites they
used in their usability study.  Touching an image produced one of five outcomes,
including doing nothing, enlarging the picture, and hyperlinking.  I think
generally the user was not given any hint ahead of time as to what the outcome
might be in any given case.  Advancing in a block of text could be done at least
three ways: scrolling (with the finger), swiping left, swiping up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My advice:&lt;/strong&gt; watch closely other apps as they come out, try to identify the most
intuitive, obvious, and effective mechanisms, and try to reuse them in your
own apps.  With diligence and speed, we can avoid the problems that will
doubtless be caused by a lack of adequate design (by RIM) up front.&lt;/p&gt;
</summary></entry><entry><title>PlayBook: Application Lifecycle</title><link href="http://www.peterhansen.ca/blog/playbook-application-lifecycle.html" rel="alternate"></link><updated>2010-12-19T11:33:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-19:/blog/playbook-application-lifecycle.html/</id><summary type="html">&lt;p&gt;On the PlayBook an application goes through several stages in its lifecycle, and
various events are issued to allow an app to monitor its externally controlled state.
I say &amp;quot;externally controlled&amp;quot; because these state changes are generally out of the
control of an application.&lt;/p&gt;
&lt;p&gt;When an app is first launched, the &lt;tt class="docutils literal"&gt;NativeApplication.nativeApplication&lt;/tt&gt;
object will get an &lt;tt class="docutils literal"&gt;InvokeEvent.INVOKE&lt;/tt&gt; event.  This is likely not of
much use, as an application knows it was just invoked when it enters its main
constructor routine (generally a subclass of &lt;tt class="docutils literal"&gt;flash.display.Sprite&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;When the application first becomes visible and fills the screen, where it's considered
to be really running, an &lt;tt class="docutils literal"&gt;Event.ACTIVATE&lt;/tt&gt; event will be sent and can be captured on the
main Sprite.  This same event is sent whenever a previously minimized app is restored,
or when side-swiping changes to your application from another one.&lt;/p&gt;
&lt;p&gt;An &lt;tt class="docutils literal"&gt;Event.DEACTIVATE&lt;/tt&gt; is sent when the user switches away from your application, either
by side-swiping or by swiping up from the bottom bezel to minimize the application in the
&amp;quot;shuttle bar&amp;quot;.&lt;/p&gt;
&lt;p&gt;The call &lt;tt class="docutils literal"&gt;NativeApplication.nativeApplication.addEventListener(Event.EXITING, callback)&lt;/tt&gt;
can be used to subscribe a callback routine to an event sent when the user closes your
application, either by clicking on the X button in the upper right of the minimized app's
window, or by dragging it up from the shuttle bar to close it.  This event is also sent
when your application calls &lt;tt class="docutils literal"&gt;stage.nativeWindow.close()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Because you can't call &lt;tt class="docutils literal"&gt;event.preventDefault()&lt;/tt&gt; on the Event.EXITING event, you can't
prevent your application from closing, it appears.  For that reason and probably others,
it's definitely best to try to preserve &lt;em&gt;all&lt;/em&gt; important state in response to a DEACTIVATE
event, so that if the user subsequently closes your app you have already saved.&lt;/p&gt;
&lt;p&gt;Lastly, though perhaps of no more use than EXITING, you can call
&lt;tt class="docutils literal"&gt;stage.nativeWindow.addEventListener()&lt;/tt&gt; with Event.CLOSING to hear about a CLOSING
event that is sent after the EXITING event.  It also is not cancellable with &lt;tt class="docutils literal"&gt;preventDefault()&lt;/tt&gt;,
even though both report true on their &lt;tt class="docutils literal"&gt;cancelable&lt;/tt&gt; properties.&lt;/p&gt;
&lt;p&gt;[Edit: Note that if the PlayBook is set for &amp;quot;Showcase&amp;quot; mode, where apps are
left fully running even when you switch away from them, you may never receive
a &lt;tt class="docutils literal"&gt;DEACTIVATE&lt;/tt&gt; event.  You shouldn't rely &lt;em&gt;solely&lt;/em&gt; on this event to signal
that it's time to save your state.]&lt;/p&gt;
</summary></entry><entry><title>PlayBook Screen Template</title><link href="http://www.peterhansen.ca/blog/playbook-screen-template.html" rel="alternate"></link><updated>2010-12-19T10:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-19:/blog/playbook-screen-template.html/</id><summary type="html">&lt;p&gt;One of the first things I did with the PlayBook -- or, rather, with the lack of one --
was to build a simulator.  Not the SDK simulator... everyone has one of those.  I mean
a &lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Simulator-Screen-size-actual-screen-size/m-p/715679/highlight/true#M4335"&gt;physical one&lt;/a&gt;.
It's nothing more than an old copy of a Rand McNally world atlas
with a couple of sheets of thin steel wrapped around it to stiffen it and add weight,
some black construction paper and a sheet of clear plastic for the screen area.&lt;/p&gt;
&lt;p&gt;It has the same dimensions as the real thing except that it's thicker.  Turns out
there aren't that many &lt;a class="reference external" href="http://en.wikipedia.org/wiki/List_of_elements"&gt;materials with the same density&lt;/a&gt;
as the PlayBook (1.6 g/cm&lt;sup&gt;3&lt;/sup&gt;)...
straight metal is way too heavy, paper is too light, and although a solid block
of magnesium would be almost perfect I just didn't have any kicking around.
The combination of paper and metal brings this
one to precisely 400g; I figured having the right weight was more important than
having the right thickness.&lt;/p&gt;
&lt;p&gt;To simulate the screen I can slide a screenshot under the plastic window.
I can also just use it to draw screen designs on paper and often tape them
to the front on top of the plastic.  At the moment I have about 10 sheets
representing different pages of the app taped one on top of the other so I can
flip through them.&lt;/p&gt;
&lt;p&gt;The screen area of the PlayBook, based on 0.15mm per pixel and 1024 by 600 pixels,
is exactly 153.6mm by 90.0mm.  A regular A4 sheet of paper (8.5&amp;quot; by 11&amp;quot;) turns
out to hold three of those screens nicely.&lt;/p&gt;
&lt;p&gt;I'm making a PDF available for anyone to use if they want to make their
own simulator, or just want to draw some screen ideas on paper.  The Python
code (using ReportLab) is also available:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://peterhansen.ca/blog/static/files/pbscreen_3.pdf"&gt;PlayBook screen template PDF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://peterhansen.ca/blog/static/files/pbscreen.py"&gt;screen template generator (Python)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</summary></entry><entry><title>PlayBook: Showing System Menu</title><link href="http://www.peterhansen.ca/blog/playbook-showing-system-menu.html" rel="alternate"></link><updated>2010-12-17T15:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-17:/blog/playbook-showing-system-menu.html/</id><summary type="html">&lt;p&gt;On the PlayBook, not only can you drag from the lower left corner to make the
virtual keyboard appear, but inside an application you can still get the System
menu to appear by dragging from either the left or right upper corners.&lt;/p&gt;
&lt;p&gt;The top bezel &amp;quot;swipe down&amp;quot; action is reserved for applications to use for their
own purposes, but they've left a region about 50 pixels wide at either end
along the top edge of the viewable region where if you swipe down you'll get
the System menu instead of the application's own menu.&lt;/p&gt;
&lt;p&gt;So far, I can't see anything associated with the bottom right corner.
[Update: although this may of course be different by the release date,
or the third beta SDK, the bottom right swipe would trigger an orientation
change.  Since the simulator doesn't support this yet the swipe is ignored.]&lt;/p&gt;
</summary></entry><entry><title>ActionScript: Useful Bits #1</title><link href="http://www.peterhansen.ca/blog/actionscript-useful-bits-1.html" rel="alternate"></link><updated>2010-12-17T06:25:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-17:/blog/actionscript-useful-bits-1.html/</id><summary type="html">&lt;p&gt;I'm rather new to ActionScript3 (and AIR) though I've done a lot of Javascript in the past.
In fact, I'm so new I wasn't aware until a week ago that ActionScript had evolved so
much since I first checked it out when AIR was in its first beta.  I was impressed
to see that it is now a &amp;quot;real&amp;quot; language.  Anyway, following are some random notes
covering useful features I've stumbled over, as a reference for myself.&lt;/p&gt;
&lt;div class="section" id="string-operations"&gt;
&lt;h2&gt;String Operations&lt;/h2&gt;
&lt;p&gt;The String class is okay, but still feels a bit clunky (compared to strings
in Python) for your basic wet work.  There are a few utility routines buried
in different places that look useful.&lt;/p&gt;
&lt;p&gt;Package &lt;tt class="docutils literal"&gt;mx.utils.StringUtil&lt;/tt&gt; has a few goodies, including:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;restrict()&lt;/tt&gt; to strip out unwanted characters (could also use a regex)&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;substitute()&lt;/tt&gt; does what it says, like %s in C and various techniques in Python&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;trim()&lt;/tt&gt; removes leading and trailing whitespace.  What, they couldn't put this
in the base class?!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="debugging"&gt;
&lt;h2&gt;Debugging&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;mx.utils.ObjectUtil.toString()&lt;/tt&gt; gives a great debug dump of any object, and the class
has a bunch of other useful functions like &lt;tt class="docutils literal"&gt;dateCompare()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;copy()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;clone()&lt;/tt&gt;
(though it's unclear to me what's different about the latter two).&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;flash.utils.describeType()&lt;/tt&gt; barfs back an XML representation of an object,
with signatures for all methods, properties, etc.&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;flash.utils&lt;/tt&gt; also has &lt;tt class="docutils literal"&gt;getDefinitionByName()&lt;/tt&gt; for retrieving classes by name
and &lt;tt class="docutils literal"&gt;getQualifiedClassName()&lt;/tt&gt; for retrieving names (String) of classes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary></entry><entry><title>PlayBook Internals: Part 1</title><link href="http://www.peterhansen.ca/blog/playbook-internals-part-1.html" rel="alternate"></link><updated>2010-12-16T08:30:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-16:/blog/playbook-internals-part-1.html/</id><summary type="html">&lt;p&gt;As mentioned in &lt;a class="reference external" href="http://peterhansen.ca/blog/playbook-internal-secrets.html"&gt;an earlier post&lt;/a&gt;
I've been perusing the PlayBook simulator's filesystem in an effort to learn
more about its architecture so I can improve my ability to build good apps for it.&lt;/p&gt;
&lt;div class="section" id="pps-service"&gt;
&lt;h2&gt;PPS Service&lt;/h2&gt;
&lt;p&gt;I didn't know anything about QNX before getting into PlayBook development, but
one very interesting looking technology from that side is the
&lt;a class="reference external" href="http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.neutrino_pps/pps.html"&gt;Persistent Publish/Subscribe (PPS)&lt;/a&gt;
mechanism that was added fairly recently to QNX.  Paul Leroux has written
a &lt;a class="reference external" href="http://onqpl.blogspot.com/2010/02/qnx-persistent-publishsubscribe-service.html"&gt;nice overview on PPS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can see signs this may be used in numerous interesting ways in the PlayBook,
though possibly it will all end up being under the covers, hidden behind
API calls that make it look like something else.&lt;/p&gt;
&lt;p&gt;For now, my main use of it has been to toggle development mode (which you can
just do through the UI anyway) and to change my wallpaper (which will obviously
be supported later but which I'm happy to be able to do now).&lt;/p&gt;
&lt;p&gt;I think I'll ask someone at RIM whether they'd consider documenting a number
of the PPS objects and attributes for developers to use.
It would likely let us get more things working for the initial release date
than it currently appears we will be able.  Maybe it would also let RIM
focus their efforts on more critical things than, say, exposing an API
for changing the wallpaper.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="python-2-7"&gt;
&lt;h2&gt;Python 2.7&lt;/h2&gt;
&lt;p&gt;Wow... I didn't expect to see this here.  I have no idea if it will survive
into the release version, but it looks like someone had the excellent idea
of using Python (2.7) to manage firmware updates (or maybe it's something else...)
in the PlayBook.  Python has proven highly effective (and robust) in such
roles thousands of times over, and I consider this another sign of strong
technical merits in the product, even if they never expose Python to third-party
developers.&lt;/p&gt;
&lt;p&gt;On the other hand, if they did provide some API support for Python
(or just let others build one), I think it would be great.  ActionScript3
is fun and all, and especially effective for UIs (duh), but for the business
logic in a complex app it's hard to beat Python for productivity and
simplicity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="qconn"&gt;
&lt;h2&gt;qconn&lt;/h2&gt;
&lt;p&gt;The &lt;a class="reference external" href="http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.neutrino_utilities/q/qconn.html"&gt;qconn service&lt;/a&gt;
provides an interface used by the QNX Momentics IDE for remote debugging.
Since this is listening on port 8000 and announces itself rather clearly,
I figured it's safe for me to mention it:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ telnet pbsim 8000
QCONN
&amp;lt;qconn-broker&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Try the &amp;quot;info&amp;quot; command for output that largely duplicates what you can see in the
PlayBook Settings &amp;quot;About&amp;quot; page in the simulator.&lt;/p&gt;
&lt;p&gt;This isn't much use right now to most of us, but will obviously be a huge boon
for those using the native (C/C++) SDK when it's released, as it should provide
support for (among many other things) profiling, memory analysis, tracing
and other debugging goodies.&lt;/p&gt;
&lt;/div&gt;
</summary></entry><entry><title>PlayBook Remote Debugger</title><link href="http://www.peterhansen.ca/blog/playbook-remote-debugger.html" rel="alternate"></link><updated>2010-12-16T00:12:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-16:/blog/playbook-remote-debugger.html/</id><summary type="html">&lt;p&gt;Since I don't have any Flash/Flex development tools other than the freebie command line
stuff, I tried using the command line debugger to monitor &lt;tt class="docutils literal"&gt;trace()&lt;/tt&gt; output in my
ActionScript code.  It didn't work.&lt;/p&gt;
&lt;p&gt;The BlackBerry Development Knowledge Base has an article called
&lt;a class="reference external" href="http://supportforums.blackberry.com/t5/Tablet-OS-SDK-for-Adobe-AIR/Compile-and-Debug-without-Flash-Builder-Using-a-Command-Line/ta-p/628675"&gt;Compile and Debug without Flash Builder Using a Command Line&lt;/a&gt;
which describes how it's supposed to work.&lt;/p&gt;
&lt;p&gt;In a nutshell, you compile with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-compiler.debug&lt;/span&gt;&lt;/tt&gt;, and package with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-target&lt;/span&gt; &lt;span class="pre"&gt;bar-debug&lt;/span&gt; &lt;span class="pre"&gt;-connect&lt;/span&gt; [YOUR COMPUTER'S IP ADDRESS]&lt;/tt&gt;.  This sets up the
application to connect back to your PC when it runs.  Before you launch it, you
run &lt;tt class="docutils literal"&gt;fdb&lt;/tt&gt; locally, then enter the &lt;tt class="docutils literal"&gt;run&lt;/tt&gt; command.  At this point the debugger
starts lisening on port 7935 for connections, and you go deploy/launch your app.&lt;/p&gt;
&lt;p&gt;At this point, magic things should happen.  They don't, at least for me.
I'm pretty sure it's an incompatibility between the version of the debug fixture
code built into the app and the version of &lt;tt class="docutils literal"&gt;fdb&lt;/tt&gt; in use.  Either way I had
no luck, and things would simply stall until the app gave up and continued,
while the debugger showed no activity.&lt;/p&gt;
&lt;p&gt;So I built my own debugger.  Using Python, naturally.  It's very crude,
but since all I wanted was the equivalent of &amp;quot;print&amp;quot; statements (which in
ActionScript3 is your &lt;tt class="docutils literal"&gt;trace()&lt;/tt&gt; calls), it's Good Enough.&lt;/p&gt;
&lt;p&gt;In all it's crude glory then, I present &lt;a class="reference external" href="http://peterhansen.ca/blog/static/files/pyfdb.py"&gt;pyfdb&lt;/a&gt;
and the following instructions for use:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Build your app for debug mode.&lt;/li&gt;
&lt;li&gt;Launch the debugger: &lt;tt class="docutils literal"&gt;python pyfdb.py&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;The debugger should print &amp;quot;listening on 7935&amp;quot; (the Flash debug port)&lt;/li&gt;
&lt;li&gt;Deploy/launch your app.&lt;/li&gt;
&lt;li&gt;The debugger should show interesting things, followed by the output of
any &lt;tt class="docutils literal"&gt;trace()&lt;/tt&gt; statements in your code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'm absolutely certain there are many things it could do that it doesn't,
not the least of which is sending back from the debugger to the application
a bunch of configuration changes that I can see &lt;tt class="docutils literal"&gt;fdb&lt;/tt&gt; send when I connect
to it with telnet.&lt;/p&gt;
&lt;p&gt;But it works for me.  Released under the
&lt;a class="reference external" href="http://www.opensource.org/licenses/bsd-license.php"&gt;Simplified BSD License&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Download it here: &lt;a class="reference external" href="http://peterhansen.ca/blog/static/files/pyfdb.py"&gt;pyfdb v0.0&lt;/a&gt;&lt;/p&gt;
</summary></entry><entry><title>PlayBook Internal Secrets</title><link href="http://www.peterhansen.ca/blog/playbook-internal-secrets.html" rel="alternate"></link><updated>2010-12-15T22:41:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-15:/blog/playbook-internal-secrets.html/</id><summary type="html">&lt;p&gt;While building a filesystem explorer I discovered several mechanisms left for
developers, which let you get into the PlayBook simulator.  The most obvious
and useful one is a simple telnet interface, to which you merely need to know
the userid and password (but these were pretty obvious).  [This feature
was replaced with an SSH interface in more recent versions. -Ed]&lt;/p&gt;
&lt;p&gt;Over the next few days I'll be posting details about some interesting discoveries
I've made, not the least of which is that the unit will have &lt;a class="reference external" href="http://python.org/"&gt;Python 2.7&lt;/a&gt;
inside!&lt;/p&gt;
&lt;p&gt;Edit: after re-reading the BlackBerry Table OS SDK License Agreement, I think
I'd be wise to take into account section &amp;quot;12. Confidentiality&amp;quot;.
I'll limit myself to things that are fairly far from being considered potential
trade secrets or RIM-confidential information.  That means I'll just
go hide my draft article that describes the filesystem layout...&lt;/p&gt;
</summary></entry><entry><title>BlackBerry PlayBook Webcast 5 of 5</title><link href="http://www.peterhansen.ca/blog/blackberry-playbook-webcast-5-of-5.html" rel="alternate"></link><updated>2010-12-09T14:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-09:/blog/blackberry-playbook-webcast-5-of-5.html/</id><summary type="html">&lt;p&gt;This post contains notes taken during the PlayBook webcast on December 9, 2010, not
necessarily understandable out of context.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;BlackBerry Payment Service&lt;ul&gt;
&lt;li&gt;can use for digital stuff, in-app only&lt;/li&gt;
&lt;li&gt;not for physical goods, shared across apps, or virtual currencies&lt;/li&gt;
&lt;li&gt;one approach: free app with paid upgrade/turn-on of features&lt;/li&gt;
&lt;li&gt;70% share to developer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BlackBerry Advertising Service&lt;ul&gt;
&lt;li&gt;RIM partnership with many ad agencies&lt;/li&gt;
&lt;li&gt;60% share to developer &lt;em&gt;(supposedly standard in industry, but AdSense is 68%. - Ed)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;device-side SDK simplifies it all&lt;/li&gt;
&lt;li&gt;HTML 5, rich media, app world click-throughs&lt;/li&gt;
&lt;li&gt;mediation platform: can customize to e.g. exclude an advertiser/network&lt;/li&gt;
&lt;li&gt;can specify keywords to exclude certain ads that don't fit your app&lt;/li&gt;
&lt;li&gt;full schedule available &amp;quot;soon&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BlackBerry Analytics Service&lt;ul&gt;
&lt;li&gt;powered by Webtrends&lt;/li&gt;
&lt;li&gt;see who is using your app how, when, where&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Free BlackBerry PlayBook Offer&lt;ul&gt;
&lt;li&gt;one tablet per vendor&lt;/li&gt;
&lt;li&gt;free marketing around the apps&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;App World Approval Process&lt;ul&gt;
&lt;li&gt;10-day turnaround&lt;/li&gt;
&lt;li&gt;submitted, reviewed by RIM, then approved (or feedback)&lt;/li&gt;
&lt;li&gt;vendor then lists app in App World&lt;/li&gt;
&lt;li&gt;code-signing apps: Dec 15 will open new servers, free, no cost for keys&lt;/li&gt;
&lt;li&gt;differences for PlayBook from regular BlackBerry: just the .bar files&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Questions (long but incomplete list)&lt;ol class="arabic"&gt;
&lt;li&gt;BlackBerry/PlayBook app sharing?  &lt;em&gt;No&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Monthly subscriptions in-app: how?  &lt;em&gt;Alex outlines an approach.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;When will simulator have sound?  &lt;em&gt;Later...?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can users opt out of analytics service?  &lt;em&gt;No.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Czech Republic: is free PlayBook offer available there?  &lt;em&gt;Yes.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;To register as vendor?  &lt;em&gt;No promo or code needed now, need PayPal to offer app for sale.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Is there a Bluetooth API in AIR to connect PBs together?  &lt;em&gt;APIs not solidified yet.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;When will Payment SDK be avail?  &lt;em&gt;For BlackBerries, now.  For PB will have sched &amp;quot;shortly&amp;quot;.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;SWF decompilation risks?  &lt;em&gt;&amp;quot;Theoretical maybe but risk is limited by security features,
e.g. code-signing.  Major risk is loss of IP, consider other tools to help.&amp;quot; (paraphrased)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;In-game currency, can I use third-party system for that?  &lt;em&gt;Yes.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What are in-app credits?  &lt;em&gt;Buy something to use in future, effectively virtual, so no.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;PlayBook has existing gestures, how do we add others?  &lt;em&gt;Swipe down is only app-wide
gesture available to developer.  Can role own but have to be within screen, not
from bezel.  (So you can't override app-switch side-swipe in your app, but you can
do one within your own app.)&lt;/em&gt;  See &lt;a class="reference external" href="http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/system/QNXApplication.html"&gt;qnx.application class&lt;/a&gt;
or forum for more.&lt;/li&gt;
&lt;li&gt;How do I get code-signing keys?  &lt;em&gt;Go to portal, need credit card to validate identity.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can I use GPS from Torch in PB app?  &lt;em&gt;Not defined yet.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Will Flex Mobile apps compiled with Hero be approved by App World?  &lt;em&gt;Should be.
Reasons you might get rejected won't be related to the technology used.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What is cost for registration?  &lt;em&gt;Waived... free for now to register or submit apps.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Timeline on app approvals etc?  &lt;em&gt;10 biz days.  For PB apps will be longer.  Should
see some approved before end of year.  Should be 10 days by launch.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can we provide app for free and charge for use?  &lt;em&gt;Yes.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Will PB support USB storage etc?  &lt;em&gt;At launch: USB slave not host (so no).&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Does PB have native text-to-speech API?  &lt;em&gt;Not yet.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Are there plans for Adobe Flash Pro to publish for PB?  &lt;em&gt;Yes, planned.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Will PB support SilverLight?  &lt;em&gt;Not planned.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Will AIR support geolocation soon?  &lt;em&gt;GPS will be on device... (?)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can we reserve app id etc ahead of time?  &lt;em&gt;Yes, can do in advance...&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What is cost to publish on App World?  &lt;em&gt;Today everything is free...&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;If more than 10 days to approve app (so it's past launch date),
can we still get free PB?  &lt;em&gt;Yes!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Support USB On The Go (USB OTG) in future?  &lt;em&gt;Can't answer that today. (But note Mike L's clear
indication that they can support an Ethernet interface via USB, so it's clearly more
than a simple USB slave, in hardware.)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;When does WebWorks for BB training start?  &lt;em&gt;As soon as tool gets out.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;If app approved, when will freebie ship?  &lt;em&gt;Mike says ahead of launch... contradicts web.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can we get full schedule for release of unsupported APIs?  &lt;em&gt;Yes, will get it together
and Renaun says there's some info in release notes already.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Does existing PB have GPS?  Yes!  &lt;strong&gt;(We have yet to hear another confirmation of this,
which was clearly stated but still may possibly have meant just
&amp;quot;using GPS on tethered phone&amp;quot;. -Ed)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Will external KBs etc be supported?  &lt;em&gt;Yes, intended, not sure of details.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can PB tether to non-BB phone?  &lt;em&gt;No answer at this point.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Next steps for simulator, cookies, etc?  &lt;em&gt;Next version will have browser support etc.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Is there much hardware access in PB AIR SDK?  Clock etc?  &lt;em&gt;Yes, not supported in
simulator yet.  Renaun says standard APIs supported.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Sensors supported?  &lt;em&gt;Accelerometer, GPS two biggest.&lt;/em&gt;
&lt;strong&gt;(Note: again a clear mention of GPS on the unit, as a &amp;quot;sensor&amp;quot;. -Ed)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Does RIM have online training for newbies?  &lt;em&gt;No real rookie stuff but lots of docs.
On Adobe side, Adobe Developer Connection lots of resources for AIR.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Same BB id active on phone and PB?  &lt;em&gt;Yes, same on PB for AppWorld etc.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Since App World may reject, could a proposed app get reviewed before code developed?
&lt;em&gt;Answer: should be no real need, no, but don't worry about it.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Hello World avail?  &lt;em&gt;Yes.  Also &amp;quot;Full RSS Reader&amp;quot; app.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Orientation in AIR?  &lt;em&gt;Get event, need to adjust height/width etc.  If app lays itself
out properly it won't actually have to do anything (other than perhaps listening to
an event).&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can RIM announce when new stuff available on forums?  &lt;a class="reference external" href="http://devblog.blackberry.com/"&gt;Developer blog&lt;/a&gt; &lt;em&gt;used heavily, but maybe they'll get the info
into the forums as well.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;For early approvals, how much will RIM assist in troubleshooting problems since
we don't have PBs?  &lt;em&gt;Yes, RIM will have to help initially of course.  If not using
QNX stuff, can test on desktop on webcam etc if there's AIR support for it.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What dimension should screenshots be?  &lt;em&gt;Will get back to us.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Print from PB?  &lt;em&gt;Not in core product, will look to community for help.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Can you explain digital rights when submitting apps etc?  &lt;em&gt;Basically do we have
the rights to submit content with an app.  User-generated content, e.g. content
or stories... do we have safeguards to reject objectionable content etc?
Example: keeping porn away from kids.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Possible to lock orientation of app?  &lt;em&gt;Yes, in application descriptor file (XML).&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Wire transfer to receive money for apps?  &lt;em&gt;Other options being looked at, yes, including
wire transfer, direct deposit, etc.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;In BB dev days in Mexico, would only give away 50 PBs: true?  &lt;em&gt;No, the overall offer
is for all registered App World vendors, no limits.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
</summary></entry><entry><title>Closing or Switching Apps</title><link href="http://www.peterhansen.ca/blog/closing-or-switching-apps.html" rel="alternate"></link><updated>2010-12-09T10:30:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-09:/blog/closing-or-switching-apps.html/</id><summary type="html">&lt;p&gt;The first time I built and installed the sample HelloWorld app I was annoyed to
find that it didn't include a way to close itself.  It has only a &amp;quot;Push Me&amp;quot;
button which opens a page to ask for your name so it can greet you with it.&lt;/p&gt;
&lt;p&gt;As it says carefully hidden away
&lt;a class="reference external" href="http://docs.blackberry.com/en/developers/deliverables/21880/Product_information_1360894_11.jsp"&gt;on this page&lt;/a&gt;
it's quite simple to close any app, or to switch between them.  That page describes
&amp;quot;swiping&amp;quot; with the mouse from bottom to top of screen.  This has the effect of
minimizing the application into a region showing it and all other active
applications (if there are any).&lt;/p&gt;
&lt;p&gt;The app shown in the centre has a red X widget to let you close it, but you can actually
close any of the applications shown by dragging it up to the top of the screen, sort of
like a &amp;quot;toss it&amp;quot; gesture.  Feels nice...  Play a bit and see what else you can do by
dragging and swiping around.&lt;/p&gt;
</summary></entry><entry><title>Uninstalling apps from PlayBook Simulator</title><link href="http://www.peterhansen.ca/blog/uninstalling-apps-from-playbook-simulator.html" rel="alternate"></link><updated>2010-12-08T13:00:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-12-08:/blog/uninstalling-apps-from-playbook-simulator.html/</id><summary type="html">&lt;p&gt;The BlackBerry Help Center page on &lt;a class="reference external" href="http://docs.blackberry.com/en/developers/deliverables/21877/Remove_app_cmd_line_1375416_11.jsp"&gt;removing your application using the command line&lt;/a&gt;
says that the command line &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;blackberry-airpackager&lt;/span&gt;&lt;/tt&gt; utility supports an &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-uninstallApp&lt;/span&gt;&lt;/tt&gt; argument.
In the version I downloaded (as part of SDK 0.9.1) this option is actually on the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;blackberry-deploy&lt;/span&gt;&lt;/tt&gt; utility (presumably having been moved).&lt;/p&gt;
&lt;p&gt;Also, the arguments shown are now incorrect.  After checking the help output
(by running the utility with no options) and experimenting a bit, the following
pattern worked:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
blackberry-deploy -uninstallApp -device 192.168.40.128 -password XXX -package MyApp.bar
&lt;/pre&gt;
&lt;p&gt;If you don't have your .bar file, you can use the Package-Id instead.  If you don't
know it, you can discover it using another option:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
blackberry-deploy -listInstalledApps -device 192.168.40.128 -password XXX
blackberry-deploy -uninstalledApp -device 192.168.40.128 -password XXX -package-id YYYYYYY
&lt;/pre&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;There's also another approach which may be much simpler in a given situation.
The simulator runs a little web server accessible via http and https.  The
http one seems useless, but if you go to https://192.168.40.128/appInstaller.html
(substituting your sim's IP address) you'll see a few useful things.&lt;/p&gt;
&lt;p&gt;Your package's Id is available in numerous places including the console output of
the deploy tool, the MANIFEST.MF file inside your .bar file (which is just a .zip
file with a different extension), or you can find it by clicking on the List
button at the end of the above appInstaller.html page.&lt;/p&gt;
&lt;p&gt;Once you know it, enter it into the Package Id field and click Uninstall.
[This interface was removed in later versions, so use the command line approach
described above. -Ed]&lt;/p&gt;
</summary></entry><entry><title>Performance Comparison of Micro-Frameworks in Python</title><link href="http://www.peterhansen.ca/blog/performance-comparison-of-micro-frameworks-in-python.html" rel="alternate"></link><updated>2010-04-16T21:05:00Z</updated><author><name>Peter Hansen</name></author><id>tag:www.peterhansen.ca,2010-04-16:/blog/performance-comparison-of-micro-frameworks-in-python.html/</id><summary type="html">&lt;p&gt;Micro-frameworks are all the rage lately.
Though they've doubtless existed for as long as Python web development
has been taking place, the recent release of bubble, juno, and now
Flask have more people talking about them.&lt;/p&gt;
&lt;p&gt;I've been fighting with the complexities of the major frameworks
for a while now, lately getting fed up with the shocking list of
dependencies brought in by TurboGears2, and fighting with Pylons
and its view of how I should do unit testing and many other things.&lt;/p&gt;
&lt;p&gt;I wanted to try something lighter weight in setting up this
new site, which was initially running on a 64MB VPS running Ubuntu 9.04.
Pylons was incapable of running in this environment, as merely
launching it with the default demo site consumed all available
memory!  (Note that this VPS allows a reasonable amount of &amp;quot;burst&amp;quot;
RAM to be temporarily used, but provides no swap space.  Using up
memory leads to a hard failure and kills the app.)
So I was curious how well the micro-frameworks would do, and how they
would stack up against each other.&lt;/p&gt;
&lt;p&gt;What follows is a very simple comparison of memory usage and
performance of three recent micro-frameworks.  The test program
was basically &amp;quot;Hello world&amp;quot;, taken directly off each framework's
web site and adjusted only to ensure the Content-Length was the
same.  (Note that the header lengths were slightly different:
flask sent 15 bytes more because it included the charset (utf-8)
in the Content-Type header.)&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;caption&gt;Performance shows transactions per second (tps) as measured using
    openload running on the same host.&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col width="33%" /&gt;
&lt;col width="33%" /&gt;
&lt;col width="33%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;Framework&lt;/th&gt;
&lt;th class="head"&gt;Memory (K)&lt;/th&gt;
&lt;th class="head"&gt;Performance (tps)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;Bottle 0.6.4&lt;/td&gt;
&lt;td&gt;8900&lt;/td&gt;
&lt;td&gt;1680&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Flask 0.1&lt;/td&gt;
&lt;td&gt;14300&lt;/td&gt;
&lt;td&gt;1220&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Juno 0.1.2&lt;/td&gt;
&lt;td&gt;16350&lt;/td&gt;
&lt;td&gt;1570&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All three frameworks loaded the CPU to about the same degree.&lt;/p&gt;
&lt;div class="section" id="other-comments"&gt;
&lt;h2&gt;Other Comments&lt;/h2&gt;
&lt;p&gt;I don't think it's right to offer benchmark results without some
comment on qualitative aspects.&lt;/p&gt;
&lt;p&gt;Bottle comes in a single file (39K) and has no dependencies
outside the standard library for basic operation.  It can integrate
with WSGI, CherryPy, Flup, Paste, and Fapws.  It features
auto-reload and supports several popular templating engines.
The source is clean but has no tests included.  It clocks in
at 844 lines of code plus 181 doc/comment lines.&lt;/p&gt;
&lt;p&gt;Flask itself is a single file (25K) but requires Werkzeug (which
isn't tiny) and installs Jinja2 (also not small) even if you don't
plan to use it.
Of the code in that file, over half is comments:
only 215 lines of code, 376 doc/comment lines!
As it builds on Werkzeug, you can likely make use
of most of the functionality included in that package.&lt;/p&gt;
&lt;p&gt;Juno is also a single file (31K) with no non-stdlib dependencies
for basic operation.  You can also run behind WSGI, SCGI or FCGI (with
Flup), or Google appengine.  The code appears clean, reasonably
commented and organized, with no automated tests included.
It manages what it does in only 536 lines of code, with 168 doc/comment lines.&lt;/p&gt;
&lt;/div&gt;
</summary><category term="python"></category><category term="micro-framework"></category><category term="performance"></category></entry></feed>
