one-time blog

less is more. more or less

Posts match “ English ” tag:

Bullet Journal in Simplenote

| Comments

January / 15

- Look into airplane tickets
• Max's is not open Saturdays :(
- FM Dinner
  + Plan Meal
  - Buy Food
° Salad for lunch
• Agave
• Dolphin auto tune
° Salad for dinner :(
+ Walk to the pier

Notation changed

Tasks, Notes, Events
- Task ToDo
+ Task done
* Cancelled task
• Just note
@ Event
! - Priority
» • Explore
> • Inspiration

> Inspired by

Quine in Lua

| Comments

Here is a simple quine in Lua:

s = [[s = %c%c%s%c%c

QPython - How To Start

| Comments

You wanna stop programming and start living start programming on Android but hate Java have no Java skills? It's easy!

Just go to Google Play Market and install QPython on your device. QPython is Python implementation for Android. It is based on Scripting Layer for Android (SL4A), but as for me, it is a bit more comfortable.

If you hate Python as well, you can install SL4A itself along with Perl, JRuby, Lua, BeanShell, JavaScript, Tcl, or shell instead. Go to that page and follow instructions.

After you installed QPython, start it in the usual way by tapping its icon in the menu. Screenshot on the top of this post shows what you should see when QPython just started.

By tapping the big button with Python logo in the center of the screen you can (1) launch any local script or project, (2) get script from QR code (funny brand new way to share and distribute your code).

If you swipe to the left instead of tapping, you will see another (second) main screen of QPython. As for me, it is much more useful and comfortable for developer.

Tools available here:

  • Console — yes, it's regular Python console, feel free to comunicate with interpreter directly
  • Editor — QPython has a nice text editor integrated with the rest, you can write code and run it without leaving the application
  • My QPython — here you can find your scripts and projects
  • System — maintain libraries and components: install and uninstall them
  • Package Index opens the page QPyPI in browser allowing to install packages listed there
  • Community leads to QPython Questions page. Signup and feel free to ask and answer questions in the community.

Next, let's see the console and the editor.

As I said before, there is an ordinary Python console. Many people usually use it to explore objects' properties, consult about syntax and test their ideas. You can type your commands directly and Python interpreter will execute them. You can open additional consoles by tapping the plus button (1) and use drop-down list on the upper left corner to switch between consoles (2). To close the console just tap the close button (3).

Please note, there will be notification in the notification bar unless you explicitly close the console and you always can reach the open console by tapping the notification.

The editor allows you obviously (hello Cap!) enter and modify text. Here you can develop your scripts, save them and execute. The editor supports Python syntax highlighting and shows line numbers (there is no ability to go to the line by number though).

When typing, you can easily control indentation level (which is critical for Python code) using two buttons on the toolbar (1). Next buttons on the toolbar are Save and Save As (2), then goes Run (3), Undo, Search, Recent Files and Settings buttons. Also there are two buttons on the top: Open and New (5).

When saving, don't forget to add .py estension to the file name since the editor don't do it for you.

That's it for now. Next time we'll try to write a short "helloworld" program and test it using QPython.

Hello, QPython!

| Comments

Well, after you became a bit more familiar with QPython, let's create our first program in QPython. Obviously, it will be ;)

Start QPython, open editor and enter the following code:
import androidhelper
droid = androidhelper.Android()
droid.makeToast('Hello, Username!')

No wonder, it's just similar to any other hello-world program. When executed, it just shows pop-up message on the screen (see screenshot on the top). Anyway, it's a good example of QPython program.

It begins with import androidhelper — the most useful module in QPython, which encapsulates almost all interface with Android, available in Python. Any script developed in QPython starts with this statement (at least if it claims to communicate with user). Read more about Python library here and import statement here.

By the way, if you're going to make your script compatible with SL4A, you should replace the first line with the following code (and use android instead androidhelper further in the program):

    import androidhelper as android
except ImportError:
    import android

Ok, next we're creating an object droid (actually a class), it is necessary to call RPC functions in order to communicate with Android.

And the last line of our code calls such function, droid.makeToast(), which shows a small pop-up message (a "toast") on the screen.

Well, let's add some more functionality. Let it ask the user name and greet them.

We can display a simple dialog box with the title, prompt, edit field and buttons Ok and Cancel using dialogGetInput call. Replace the last line of your code and save it as
import androidhelper
droid = androidhelper.Android()
response = droid.dialogGetInput("Hello", "What is your name?")

Well, I think it should return any response, any user reaction. That's why I wrote response = .... But what does the call actually return? Let's check. Just add print statement after the last line:
import androidhelper
droid = androidhelper.Android()
response = droid.dialogGetInput("Hello", "What is your name?")
print response

Then save and run it...

Oops! Nothing printed? Don't worry. Just pull notification bar and you will see "QPython Program Output:" — tap it!


As you can see, droid.dialogGetInput() returns a JSON object with three fields. We need only one — result which contains an actual input from user.

Let's add script's reaction:
import androidhelper
droid = androidhelper.Android()
response = droid.dialogGetInput("Hello", "What is your name?")
print response
message = 'Hello, %s!' % response.result

Last two lines (1) format the message and (2) show the message to the user in the toast. See Python docs if you still don't know what % means.

Wow! It works! ;)

Now I'm going to add a bit of logic there. Think: what happen if the user clicks Cancel button, or clicks Ok leaving the input field blank?

You can play with the program checking what contains response variable in every case.

First of all, I want to put text entered by user to a separate variable: name = response.result. Then I'm going to check it, and if it contains any real text, it will be considered as a name and will be used in greeting. Otherwise another message will be shown. Replace fifth line message = 'Hello, %s!' % response.result with the following code:

name = response.result
if name:
    message = 'Hello, %s!' % name
    message = "Hey! And you're not very polite, %Username%!"

Use < and > buttons on the toolbar to indent/unindent lines in if-statement (or just use space/backspace keys). You can read more about indentation in Python here; if-statement described here.

First of all, we put user input to the variable name. Then we check if name contains anything? In case the user left the line blank and clicked Ok, the return value is empty string ''. In case of Cancel button pressed, the return value is None. Both are treated as false in if-statement. So, only if name contans anything meaninful, then-statement is executed and greeting "Hello, ...!" shown. In case of empty input the user will see "Hey! And you're not very polite, %Username%!" message.

Ok, here is the whole program:
import androidhelper
droid = androidhelper.Android()
response = droid.dialogGetInput("Hello", "What is your name?")
print response
name = response.result
if name:
    message = 'Hello, %s!' % name
    message = "Hey! And you're not very polite, %Username%!"

Next time we will have closer look to androidhelper package. Stay tuned! :)

Instagram for BlackBerry 10

| Comments

Ну вот, наконец-то появилось нормальное, полноценное, нативное (и бесплатное!) приложение для Инстаграма на BlackBerry 10! iGrann позволяет смотреть ленту, лайкать, оставлять комментарии, искать и, конечно же, постить свои фоточки в Инстаграм.

В отличие от портированной с Андроида версии самого Инстаграма, не глючит. Отсутствуют инстаграмовские родные фильтры (ну и фиг с ними — я ими все равно почти никогда не пользуюсь). Не поддерживается загрузка видео и Instagram Direct. В остальном очень приятное приложение, умеющиее, кроме всего прочего, уведомлять штатным для Блэкберри способом и меняющее картинки в Active Frame (период обновления, как и тему, и некоторые другие параметры можно настроить).

iGrann is the first full native and free client for Instagram™ on BlackBerry 10. It is not just a viewer, it is a fully featured app. You can browse feed, like and comment photos and videos, receive notifications, follow/unfollow people, search users and hashtags and, of course, upload photos!

Instagram Direct, upload videos, apply IG filters are not available in the current version but will be implemented soon. And it's free! :)

File Selection Dialog in QPython

| Comments

Almost any program ask user for file or folder names. Android does not provide file dialog by default. Let's create our own.

It should be simple enough, but it should allow user to browse throuh the file system and select file. Also it should allow user to refuse selection by clicking Cancel button. Our function will take two arguments: text prompt (title) and initial folder to browse:

def chooseFile(title='Choose File', folder='.')

See here if you don't know how to define functions in Python.

Both parameters have default values — they will be used if you don't indicate an argument when calling the function. '.' means "current folder".

You will use it as follows:

import filechooser
filename = filechooser.chooseFile("Open File", myworkdir)

So, first of all we should list of files in the given directory (folder). There are several ways to do it in Python. We will use function glob in module glob. This function returns list of paths matching a pattern given. For instance, if you need to get list of all Python files in the current directory, you can get it using glob('*.py'). We need a list of the whole contents of the directory, so we will use '*' pattern, which means "any file or folder name".

The item selected by user (folder or filename) will be kept in a variable d. In case of filename it will be returned, otherwise we will show the directory's contents to the user. Initially we set it from argument folder:

d = folder

Then we should get the list of items of the directory d. In order to do it, we join the file pattern '*' with the directory name before passing it to the function glob. We can do it using os.path.join() function (os.path is extremely useful module, and we're going to use other functions from it). By the way, you can always get help on every module, every class, object or function in python. Just ask help(...):

>>> help(os.path.join)

This show you short help message about the function os.path.join:

join(a, *p)
    Join two or more pathname components, inserting '/' as needed.
    If any component is an absolute path, all previous path components
    will be discarded.

Help function is the most useful features of Python and probably the most often used in the console.

So, let's check in the console what we are going to do:

>>> from glob import glob
>>> import os.path
>>> d = '.'
>>> os.path.join(d, '*')
>>> glob(os.path.join(d, '*'))
['./', './', './']

Ok, there are three files in the current directory (obviously, you will see another file names). And we are ready now to show them to the user. But I don't really like these ./ at the beginning of each name showed to user. I want to show local file names without any path. Let's cut off them. There is a function split in the module os.path, which splits a pathname and returns tuple "(head, tail)" where "tail" is everything after the final slash — this "tail" is what we need! So, assuming fn contains any pathname, we could get the last portion as os.path.split(fn)[1] (tuples' and lists' index starts with 0, so x[1] is the second item in a tuple or list).

Stop! We need to cut off each item in our list which was returned by glob()! And here is one thing I love in Python very much:

flist = [ os.path.split(fn)[1] for fn in glob(os.path.join(d, '*')) ]

Variable flist receives the list of last parts ("tails") of pathnames returned by glob(). This line equals to the following code but much shorter and expressive:

flist = []
for fn in glob(os.path.join(d, '*')):
    tail = os.path.split(fn)[1]

See more about list comprehensions here.

Ok, even if you didn't understand how it works, flist variable already contains the list of files and folders ready to display to user. ;)

Just one little thing: glob() returns folders/files which is inside the certain directory. How a user can go outside? Let's add a "special item", indicating "upper, parent directory". It's a common practice to indicate this special item as two dots: ... Only root directory (/) has no parent, so we should check before adding:

if d != '/':
    flist.insert(0, '..')

If you don't know how insert() works, type in the console: help([].insert).

Now, I propose to move platform-specific code to the separate function. In this case we could port our code to another system much more easily just replacing this function. Let a function _dialog() draws dialog box itself and shows it to the user. It should take two arguments: title and filelist to show, and return selected item's index in the list. It should return None in case the user clicked "Cancel". So, our chooseFile() function should call this function this way:

selected = _dialog(title, flist)

I'll show this functions later. And now we are going to analize what it has returned. First of all, we must check is it None, or no, and return None if yes:

if selected is None:
    return None

Then, in case of not None value, we should understand what the user selected. Since selected is just a number, indicating selected position in the list, flist[selected] gives us the item (filename) itself. Then we are going to get full, absolute path of the selected item. First of all, we're joining it with the current directory name: os.path.join(d, flist[selected]), then we're using os.path.abspath() function to convert the value to the absolute path. Since abspath() understands ".." as a parent directory as well, we don't worry about this "special case". Finally, this absolute path should become a new value of d, and if it is not a directory, it should be returned:

d = os.path.abspath(os.path.join(d, flist[selected]))
if not os.path.isdir(d):
    return d

If d now contains directory (folder) name, we must go back and repeat the whole process. So, I'm wrapping the whole code to "infinite" loop using while True: (it is not actually infinite since there is an "exit" — return operator).

Here is the whole code of our function:

def chooseFile(title='Choose File', folder='.'):
    '''Display choose file dialog with title and a list of
    files/folders in specified folder and allow user to
    browse file system and select file.
    Return full name of the file choosen or None
    import os.path
    from glob import glob
    d = folder
    while True:
        flist = [ os.path.split(fn)[1] for fn in glob(os.path.join(d, '*')) ]
        if d != '/':               # if it is not root

            flist.insert(0, '..')  # add parent 

        selected = _dialog(title, flist)
        if selected is None:       # user cancelled

            return None
        d = os.path.abspath(os.path.join(d, flist[selected]))
        if not os.path.isdir(d):
            return d

Well, let's talk about user interface. We agreed to move it to the separate function _dialog(). It must be placed before chooseFile since it is called from the last. Here is the function:

def _dialog(title, flist):
    '''display dialog with list of files/folders title
    allowing user to select any item or click Cancel 
    get user input and return selected index or None
    import androidhelper
    droid = androidhelper.Android()
    droid.dialogCreateAlert(title, '')
    resp = droid.dialogGetResponse()
    print resp
    if resp.result.has_key('item'):
        print 'RETURN:', resp.result['item']
        return resp.result['item']
        return None

The code is really simple and self-explaining. The first line after the function's definition and documentation string imports androidhelper, the next one creates an object droid (see my previous post if you don't know what is it), then we construct a dialog box with title, scrollable list of selectable items and a cancel button. There can be up to three buttons in a dialog: "positive" (i.e. "Ok"), "negative" ("Cancel") and "neutral". We need only negative button.

Then we show the dialog to the user (droid.dialogShow()), get response (resp = droid.dialogGetResponse()) and finally we must dismiss the dialog (droid.dialogDismiss()).

The last portion of the code analizes the response. If the user seleted one of the items in the list, the item's index returned as 'item' element of rezult dictionary. Otherwise (the user clicked "Cancel"), resp.result has no 'item' at all. Condition resp.result.has_key('item') returns True if dictionary resp.result has a key "item", and False otherwise. In the first case we return the value of resp.result['item'] — index of selected item in the list, and in the second case we return None indicating that the user refused selection.

That's it. I understand that it's a bit hard to understand such long code. Believe me, it's hard to explain it as well! :) That's why I provide links to different explanations in Pythons documentation. If you are really new to Python, please read Python Tutorial first of all.

Finally, you can get the whole code of the file chooser here to use in your own programs. To test it just run — it should ask you for the file name. And the selected file name will be shown in the program's output.

Next time I'm going to make this code portable (so, we could use the same module on different platforms with different GUIs). Stay tuned! :)