Fucking Java

If you happen to suck with Ubuntu on Amazon EC2 because you launched a 32bit micro instance you might want to fix it as advised in https://bugs.launchpad.net/ubuntu/+source/linux-ec2/+bug/634487

ec2-stop-instance ${IID}
ec2-modify-instance-attribute --instance-type m1.small ${IID}
ec2-start-instances ${IID}
ssh -t instance 'sudo dpkg --configure -a'
ec2-stop-instance ${IID}
ec2-modify-instance-attribute --instance-type t1.micro ${IID}
ec2-start-instances ${IID}

I was even upgrading from Lucid to Maverick and to get a newer kernel I practically had to hunt for the right kernel ID. Just for the record, the command to change to the - presumably right - kernel was this:

ec2-modify-instance-attribute --kernel aki-13d5aa41 \
--region ap-southeast-1 i-ce96a99c# aki-de1e608c was the one for Lucid

This article helped the hunt: http://ubuntu-smoser.blogspot.com/2010/04/upgrading-ebs-instance.html

But that's not the end of the story. You might want to turn this machine into your Amazon infrastructure's command-line control-center, by installing the ec2-api-tools package. This depends on Java, so you will be forced to install a Java implementation. It turns out the default Java implementation is OpenJDK which just sucks because any ec2 utilities will throws an error like this:

java.net.SocketException: java.security.NoSuchAlgorithmException:
Error constructing implementation (algorithm: Default, provider: SunJSSE,
class: sun.security.ssl.DefaultSSLContextImpl)

Googling for "Java Ubuntu" we can end up at https://wiki.ubuntu.com/LucidLynx/ReleaseNotes thru https://help.ubuntu.com/community/Java which tells us how to pull the original Sun Java which is a heresy to install on Ubuntu since it has some non-GNU license... Anyway, their advised procedure looks like this:

sudo update-java-alternatives -l
sudo update-java-alternatives -s java-6-sun
sudo add-apt-repository "deb http://archive.canonical.com/ maverick partner"
sudo apt-get update
sudo apt-get install sun-java6-jre    # or sun-java6-jdk

Summary: It's pathetic... I don't even use Java for anything else at the moment... I really should create a Rebol version of the EC2 tools, precompiled as 1MB executables for the 3 major platforms, just like http://cheyenne-server.org/ does.

SSH agent forwarding versus GNU screen

Problem

If you

  1. start ssh-agent on your local machine
  2. import your private key into it
  3. SSH into another remote machine with agent forwarding (-A)
  4. start a screen session
  5. SSH into a another machine just works fine
  6. disconnect from SSH
  7. login again
  8. resume the screen session
  9. try to login into that other machine again
  10. you get Permission Denied

I solved it, so it worked in all my desired situations well. (Tested connecting from a Mac to an Ubuntu Lucid machine.)

There were couple of solutions dangling around the net but none of them worked for properly for each situations I met... 

Gory details for the curious

In my system administrator mode I have to connect to shitloads of servers from where I'm connecting further to other ones. Managing account password just doesn't scale, so I'm using public key authentication. It's good until I have to login from my local machine to a remote one.

To login further from these remote machine to "even more remote" ones, these machines somehow need my private key. SSH agent forwarding has been invented to solve this exact situation. It uses a UNIX domain socket file to tunnel back key challenges and their solutions from the remote machine to the local one which actually holds the private key unencrypted in the memory. There is such a socket file created each and every new SSH connection. The name of these files are quite random, just as the assigned client TCP ports used for each connections for example.

There is an environment variable (SSH_AUTH_SOCK) which keeps track of the SSH agent's socket. Each process inherits this environment variable. Once... Which sounds obvious, right? But what happens if I disconnect from SSH and reconnect again? A new process is started remotely which will have a new socket. If a screen is started at that point, it will just pull out the previous processes running in its windows. Those processes will remember the socket file name allocated for the previous connection. There is no regular or easy way to send a message to them to update an environment variable.

The solution is to use a symlink pointing to the latest agent file and have the environment variable pointing to this symlink. It means though we can only have 1 socket per user (per remote machine). In other words you can only connect to a remote machine once to make this work. It can be a problem if you are connecting to this remote machine via other commands which use SSH as their transport layer, such as rsync, darcs, git, etc... To overcome this, we have to check what is the case. A good approximation is to check whether are we in an "interactive" session and only do this linking trick in that case.

Solution

So, here is the actual implementation with some commented out debug statements:

#echo $SSH_AUTH_SOCK >> ~/debug
# in case of rsync for example, don't modify the socket link
# also don't do a link if it has been done already
if [ "$SSH_TTY" -a "$SSH_AUTH_SOCK" != ~/.screen.sock ]; then
    ln -sfn $SSH_AUTH_SOCK ~/.screen.sock
    export SSH_AUTH_SOCK=~/.screen.sock
fi
#echo === result: $SSH_AUTH_SOCK >> ~/debug

Put it into your ~/.bashrc first. If it worked there, you can install it globally in /etc/bash.bashrc too.

Battery life, Bandwidth, Gmail, PivotalTracker

What's the connection between these things?

  • ~1hour less battery life on my MacBook
  • lagging SSH connection. can't type fluently...
  • more sweat on my wrists or legs

To make the story short, if you run on batteries, my advice is:

  1. Switch Gmail into standard HTML mode, so it doesn't pull advertisements or updates chat status (1-3kB/s each account)
  2. Close PivotalTracker because it eats up ~1KB/s for polling state changes and prepare stories for offline usage with Pickler.

As a result, the CPU will work less (not just doesn't generate network traffic, but doesn't update the DOM to display ads..), the network interface works less (which is important if I'm connected via bluetooth), the phone battery life can be longer too and finally my SSH connections are not that sluggish during typing, since they are interrupted a lot less often and with smaller packages only.

Since I live in tropical environment, such a small change can make my laptop cooler enough to make my wrists sweat not that much if at all.

I experience from time to time how much wasting is going on everywhere and although I enjoy some benefits of these wastes myself too -because it's hard to avoid -, I can't overlook these funny drawbacks which actually causes inconveniences.

As a software developer, I feel responsible for these effects too. The inefficiencies in technologies we use nowadays are multiplied, since millions are using it, but we still have control over many of them, because a lot of them are open source.

When I write code I try to make it conservative with resources at least as an excercise. I try to promote software which follows these principles. REBOL is one of these of course, but I just noticed recently, that the father of Forth is still active at the age of 72 and he is blogging crazy shit about some low-powered supercomputer. He is the most extreme pioneer in rejecting today's complexity. He has even rejected the concept of daylight saving:

Why am I doing this? Out of disgust with Daylight Savings Time. I get up at dawn and don't care what Washington wants to call it. The cost and confusion of changing clocks twice a year is ridiculous. Especially when the dates of doing so also change. I'll live on local time.

-- Haypress Creek Weblog, 10 November 11:00 Tuesday

Amazon Payment fun

I love Amazon Web Services as you can see from the direct tone below. I'm using EC2 since ~2007.

A had a little funny smalltalk with them yesterday. Probably (hopefully? :) they didn't read my full mail, just checked whether I'm a human or not... Btw, these names in their emails look like some random names just to make their customer service system feel more human, aren't they? ;)

from        Amazon Web Services 
reply-to        "aws-verification+XXXXXXXX@amazon.com" 
to        "hermantamas@gmail.com" 
date        Fri, Oct 1, 2010 at 6:58 PM
subject        Your Amazon Inquiry
mailed-by        bounces.amazon.com
signed-by        amazon.com

Greetings,

Thank you for contacting Amazon Web Services. We appreciate your business and interest in our product.

We have verified the details provided by you and are glad to inform that we have activated your Amazon Web Services account.

Thank you for your interest in Amazon Web Service!

Best regards,

Sunil S
aws.amazon.com

---- Original message: ----

Jason, or whoever reads it,

Can I just add a different credit card info?
I tried to visit the "Payment Method" page
(http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=edit-payment-method)
where I'was told to login but my password is not accepted (I have even
went through the "Forgot Password?" procedure but it's still not
accepted)
On the other hand the reserved instance I paid for seems to be active,
so I can't really interpret this email...

in a summary: wtf?

I live in Singapore for more than 2 years.
I use my Hungarian credit card to pay online,
but I do not contact my bank in any other way than
net-banking and via SMS to my hungarian phone number.
My statements are delivered somewhere in Hungary
(to my parents? ex girlfriend? who the fuck remembers?
damn dead tree based stone age administration...
probably they are wiping their ass with those statements...)

Would it be satisfactory if we could retry the phone authorization
using my hungarian phone number?
How could you be so last century anyway in 2010 that you are asking
for FAXing?... I can't even recall how a FUX machine looks like, damnit!

I have 2 Singaporean debit cards (Citibank and POSB) too which are
successfully registered to my PayPal account together with their
corresponding bank accounts, but usually they are not accepted
directly to pay online, only via PayPal.
I would still like to try with You guys, because I hope if PayPal
could accept them, u can accept them too...

I turn on my hungarian phone: +36 (70) 38x xxxx
and here is my Singaporean one too: +65 97xx xxxx

please call me.

--
 tom



ps: ah, i just see your vague reference to this "payments account disabled".
well, the

 There was a problem with your request
 There was an error with your E-Mail/Password combination. Please try again.

error message on the sign in page doesn't really express the current
situation...

An Amazon EBS constraint

Amazon Web Services are awesome in general. They have comprehensive documentation for each of their products. Even though the docs are concise, it's quite a lot of reading. So it has happened I missed a fact recently.

Amazon has 4 REGIONs, 2 in the US, 1 in Europe and 1 in Asia. They are identified by the following strings

  • us-east-1
  • us-west-1
  • eu-west-1
  • ap-southeast-1

(See more explanatory names under EC2 pricing for example)

These Regions are connected via the Internet.

Regions have multiple (Availability) ZONEs:

  • eu-west-1a
  • eu-west-1b
  • us-east-1a
  • us-east-1b
  • us-east-1c
  • us-east-1d
  • us-west-1a
  • us-west-1b
  • ap-southeast-1a
  • ap-southeast-1b

These are connected via a dedicated Internal network.

Which means Amazon doesn't have control over the connection between the Regions. They also have to pay for data transfers between Regions, so they will charge you for that too.

Another consequence is a constraint on EBS usage. The documentation states that EBS volumes can be snapshotted to S3 even in an incremental way and you can restore them into different Availability ZONEs. They don't say anything about how different these AZs can be. Apparently you can only do this within the same REGION where the snapshot was created. It's not bad, but it was a bit unexpected for me...

A quick reference how to obtain Region and Zone names:

$ ec2dre   # is short for ec2-describe-regions

REGION  eu-west-1       ec2.eu-west-1.amazonaws.com
REGION  us-east-1       ec2.us-east-1.amazonaws.com
REGION  us-west-1       ec2.us-west-1.amazonaws.com
REGION  ap-southeast-1  ec2.ap-southeast-1.amazonaws.com

$ for region in `ec2dre | cut -f2`; do ec2daz --region $region; done
# ec2daz is short for ec2-describe-availability-zones

AVAILABILITYZONE        eu-west-1a      available       eu-west-1
AVAILABILITYZONE        eu-west-1b      available       eu-west-1

AVAILABILITYZONE        us-east-1a      available       us-east-1
AVAILABILITYZONE        us-east-1b      available       us-east-1
AVAILABILITYZONE        us-east-1c      available       us-east-1
AVAILABILITYZONE        us-east-1d      available       us-east-1

AVAILABILITYZONE        us-west-1a      available       us-west-1
AVAILABILITYZONE        us-west-1b      available       us-west-1

AVAILABILITYZONE        ap-southeast-1a available       ap-southeast-1  
AVAILABILITYZONE        ap-southeast-1b available       ap-southeast-1

 

Whois in REBOL

Since it was not obvious to figure out what server should I use for querying IP's whois info, I make this note as a remainder

>> print read whois://8.8.8.8@whois.arin.net
connecting to: whois.arin.net
Level 3 Communications, Inc. LVLT-ORG-8-8 (NET-8-0-0-0-1)
                                  8.0.0.0 - 8.255.255.255
Google Incorporated LVLT-GOOGL-1-8-8-8 (NET-8-8-8-0-1)
                                  8.8.8.0 - 8.8.8.255

# ARIN WHOIS database, last updated 2010-07-13 20:00
# Enter ? for additional hints on searching ARIN's WHOIS database.
#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at https://www.arin.net/whois_tou.html
#
# Attention! Changes are coming to ARIN's Whois service on June 26.
# See https://www.arin.net/features/whois for details on the improvements.

Singapore's "limits"

The emergence of location based applications drifts programmers towards geography. There seems to be a need for country boundaries regularly. Many times it's enough to tell if a point is within a 1 certain country or outside or maybe in another additional one... For such a simple case, it's accurate enough to test if the point is within a certain rectangle or not. No need to mingle with more complex polygons! It would be an overkill!

So here is a link with simplified coordinates for the bounding box of Singapore, visualized on Google Maps:

http://maps.google.com/maps/api/staticmap? center=1.3477,103.8302&zoom=10&size=800x400& sensor=false&path=color:0x00000000%7Cweight:5%7Cfillcolor:0xFFA00040 %7C1.48,103.6%7C1.48,104.05%7C1.24,104.05%7C1.24,103.6

So the 4 corners are the following:

1.48,  103.6
1.48,  104.05
1.24,  104.05
1.24,  103.6

It's even almost very easily memorable. :)

1.24 x 103.6 -- 1.48 x 104.05

Path datatype! craziness

Just have a look at this example. It talks for itself

>> x: 'some-word/'and-lit-word/#I55ue/USD$123.45/email@addre.ss/:var/(paren thesis 123)/1.2.3.4/-2x+3/#"A"/protocol://host/path?bull=shit&cant_escape:/
== some-word/'and-lit-word/#I55ue/USD$123.45/email@addre.ss/:var/(paren thesis 123)/1.2.3.4/-2x3/#"A"/protocol://host/path?bull=shi...
>> foreach e x [print [e type? e]]
some-word word
and-lit-word word
I55ue issue
USD$123.45 money
email@addre.ss email
var get-word
paren thesis 123 paren
1.2.3.4 tuple
-2x3 pair
A char
protocol://host/path?bull=shit&cant_escape:/ url

I'm not sure yet where could I use this ability of specifying diverse (but not all kind of) datatypes concatenated by slashes into a series! instead of using blocks. Maybe until 2-3 elements and certain datatype! combinations would look more "natural" this way compared to the bracketed and space separated version?

string! and block! types can't be path elements, although the paren! type can. Interesting... All of them are series!

>> foreach e [(asd 123) "asd" [blk]][print [e series? e]]
asd 123 true
asd true
blk true

Cross-platform Hash-a-Pass

In short:

paste first8 base64 enc "twitter" pwd?

In more detail:

I just met ecin of copypastel.com in HackerspaceSG last night. He showed me a cool little trick for managing passwords. Have a look at his article for more details and also visit the "original" web based implementation.

I had a look at his BASH implementation on the project homepage and I realized quite fast how this - otherwise quite neat - source code can be chopped down even further if we use the "right tool for the right job" >;P

The heart of the algorithm is this:

openssl dgst -sha1 -hmac $3 -binary | openssl enc -base64 | head -c 8

I have to nail down that the BASH piping is just as beautiful as powerful. It's more readable (at least after many years of experience) than what I translate it into now. BUT I can gain two great benefits if I rewrite it in some other language:

  1. cross platformness
  2. less dependencies

Let's see the translation pipe-by-pipe into my favorite language:

; head -c 8
first8: func[x] [copy/part x 8]

; openssl enc -base64
base64: func[x] [enbase/base x 64]

; openssl dgst -sha1 -hmac $3 -binary
enc: func[x pwd] [checksum/method/key x 'SHA1 pwd]

; read the password used as the hashing key
pwd?: does [ask/hide "password: "]

; pasting (text) into the clipboard is the least cross platform part of the application
; but with REBOL it's unified too (the 800kB graphical version has this functionality
; for Liunx X11, Windows GDI & Mac Cocoa)
paste: func[x] [write clipboard:// x]

So assembling all these together we get the following program:

paste first8 base64 enc "twitter" pwd?

Can it be more expressive? ;)

It makes the algorithm obvious, however it fits a longer console line, so while I was developing it, I was just typing the following actually:

>> write clipboard:// probe copy/part enbase/base checksum/method/key "twitter" 'SHA1 ask/hide "password: " 64 8
password: ******
"dNbv5KY1"
>> <Apple-V>dNbv5KY1

Conclusion: Fuck complexity. Again. And REBOL rulez, ofcoz...

A card game on the iBasket. Part 1

Background story

We have a pack of cards in HackerspaceSG called SET. It's about giving different parts your brain a little excercise. Counts, colors, shapes and fillings are the four attributes of every card. You should recognize sets of 3 cards which has these 4 attributes all in common or all different. During play we faced 2 problems:

  1. there might be a set amongst the cards on the table but no one can find it.
  2. someone has pointed out a set, but what if he is wrong and no one notices it?

Since we have just revived an old touch screen in the hackerspace and put it into a shopping basket - hence the name iBasket, a'la iPad - I though it will be a nice platform for this card game.

Ibasket_w_set_game

Deck of cards

Each card is described by the vector of the 4 attributes, hence the complete deck consists of the direct multiplication of these attribute sets which has 3 elements each. It means we should end up with 3^4 = 81 cards.

counts: [1 2 3]  ; this is obvious :)fills: [h m l]  ; Heavy Medium Lightcolors: [r p g]  ; Red Purple Greenshapes: [~ ^ o]  ; Peanut Diamond Oval; the attributes in each vector are ordered like this:order: reduce [counts colors shapes fills]deck: copy [] ; we start with an empty deck

First I took a primitive approach: each attribute is like a digit in number base 3, so if I implement an increment function, then I can generate all the cards just by a loop. I will revisit this later, to see what kind of other algorithms can we apply here.

incr: func[ {Increment position in a non-empty series of
  non-empty serieses and stuck at the end} s] [
  s/1: next s/1
  if (tail? s/1) and (not empty? next s)
    [s/1: head s/1 incr next s] ; carry
  s
]

until [ ; generate cards into the deck
  insert/only tail deck collect [ foreach attrib order [keep attrib/1] ]
  incr order   tail? last order
]

Visualization

I could draw the cards with vector graphics, but it would be quite a distraction from the main goal and I don't have much experience in programmed artwork creation anyway. Luckily I saw on the game's website some small GIF files representing the cards, so I'm just referencing those for now.

As the 1st exercise I just display all the cards in a 9x9 matrix with the symbolic representation of them printed below each card, so the application layout should be like this:

image ... text ... image ... text ... (9times) return to the new column
(and this pattern is repeated 9 times)

With a little bit of meta programming we can generate this GUI description:

card-url: http://www.setgame.com/images/setcards/small/
gui: collect [ i: 1
  loop 9 [
    loop 9 [
      keep compose [
        image (rejoin [card-url either i > 9 [i] [join "0" i] %.gif])
        vtext blue (mold pick deck i)
      ]   i: i + 1
    ]
    keep 'return
  ]
]

We spice the display parameters a bit, so the whole deck can fit the 1024x768 screen:

view layout append [origin 5x5 space 1x1] gui

Interactivity

I remembered a small demo where you can move around a rectangle with the mouse, so I just the event handler code from there. It doesn't care about popping the grabbed card on top of the Z-order, though. We can deal with it later.

feel [
  engage: func [f a e] [  ;intercepts target face events
    if find [over away] a [
      f/offset: confine f/offset + e/offset - f/data f/size
        0x0 f/parent-face/size
      show [f]
    ]
    if a = 'down [f/data: e/offset]
  ]
]

Result

It can be downloaded from http://sa.sse.hu/~onetom/setcards for now. Later I will find a better place for it.

Download the <1MB, crossplatform (Win/Lin/Mac) script interpreter which is just 1 executable file. Put it into your PATH and run this from the command line:

rebol http://sa.sse.hu/~onetom/setcards

Wait until it downloads the card images for the 1st time. It automagically saves it into the application data folder, so next time it will just looks up whether they changed or not. This is a built-in functionality of the GUI system

Screenshot

The inevitable screenshot:

Setgame-shot

Posterous theme by Cory Watilo