Archive for November, 2008

when adults talk to kids

November 28th, 2008

Have you ever noticed the way in which adults talk to little kids? I say talk to because it's completely one way. It's a conversation that doesn't happen anywhere else. Kids up to a certain age are too young to assert themselves. It's not that they can't talk, they just don't have any comments to make. They haven't watched enough tv, heard enough gossip or seen enough popular culture to be fluent in the conversations. Kids do not talk for the sake of talking itself, adults do.

So when an adult talks to a kid of say 2 years of age, or 4, it's a constant stream of inanities. And there seems to be an unwritten rule that says when you meet a kid you have to talk. It's a precious opportunity for the adult to yap away without being judged on what he's saying. "Look at how big you are!" I may only have been alive for four years, but I've figured out that we have such a thing as growth. Adults talk to kids like they're idiots because adults have this urge to play idiots. They think "hey, a kid, what a wonderful opportunity to escape the judgment of my peers". And adults of all ages agree on this, they're just as eager to be around little kids whether they're 30 or 80.

This wouldn't be happening if the kid said "I'll have to stop you there buster, what you just said doesn't make any sense". The adult, after recovering from the stunning blow, would mutter "you're a clever one aren't you" and turn around on his heel. Victory! But this is not gonna happen.

See, adults *know* that kids that age don't have the confidence to talk back. There are so many factors in their favor. They're 3 times taller, have a deep voice, have the approval of all the other adults, aren't treated as kids by everyone. So if a kid doesn't have the confidence to engage in small talk, he's definitely not gonna have the courage to criticize. In fact, that's what the liberation of puberty is all about. Finally you have the courage to criticize all the things that have been pissing you off since the start.

But that's not what I do. I don't like the talking. Why should I talk when the other person isn't? Kids have this curious gaze in their eyes which is very conducive to mind games. "Does he think that I think that.."

deferred aliasing

November 27th, 2008

Shell users like to tailor their environment to speed up common tasks. The alias mechanism is very handy for this, you bind a short idiom to the sequence you run a lot. For instance, I have this line in my alias list:

alias lh='ls --color -Flah'

Having done that, you can also rig up a system of pulleys so that you can take the whole thing with you wherever you go.

All is well so far, but now comes the icky part. If you take this bundle of joy to murky neighborhoods like BSD or commercial Unices you'll find out that the userland isn't the same everywhere, even though you have the shell. BSD (DesktopBSD), for instance, doesn't support the whimsical --color switch, they like monochrome.

So what to do? What I would like to have is the same alias bound to something that works on the given platform, let it degrade gracefully. The only way to know that is to test for it, then bind the alias accordingly. That's what happens here, I try the incantation I want and if that doesn't work, I use the failsafe one.

setalias() {
	if eval $2 &>/dev/null; then
		eval "alias $1='$2'"
	else
		eval "alias $1='$3'"
	fi
}

setalias "lh" "ls --color -Flah" "ls -Flah"

But this is still a bit lacking. You obviously set up the aliases to run at shell startup, not manually. But there are instances when you might need a new shell, but you might have high io latency, or the io might be locked up through a system error. In such a case, you really just want to do as much as is necessary to start the shell, without doing a lot of io stuff in the startup files. So running ls and things like that for the purpose of setting up an alias is to be avoided.

Here's where an idea from compilers can help. First, let's think about the setalias function as code to be executed. This code runs on shell startup. But it doesn't have to. We could just as well bind the alias to the function code itself, to make it run the first time the alias is executed. That's what happens here, the shell starts and binds the alias to a string. The first time the alias is executed, it runs the test and then does the binding. And then runs the actual command we wanted to run.

setalias() {
	alias "$1"="if eval $2 &>/dev/null; then
		eval \"alias $1='$2'\"
	else
		eval \"alias $1='$3'\"
	fi; eval $1"
}

setalias "lh" "ls --color -Flah" "ls -Flah"

It's like a just-in-time compiler, we do some extra work the first time, but from then on it's all set up.

There's a lot more you can do with eval, so go nuts!

hierarchical temporal memory

November 26th, 2008

As is often said, we humans (if you are not one of us you can join on the website, membership fees are high but not impossible) are pattern seeking animals. This implies that it is difficult for us to understand a completely "new kind of thing", we tend to seek something else that we can compare it to. Psychology got a minor win when computers emerged, because it finally had a model for the brain. Psychology professors could point to the computer and say "the brain, it's somewhat like that". It behooves psychology that the computer we know has a distinct memory, a processing/reasoning unit, and input channels that receive transmissions of "sensory perception".

The computer as we know it is the so called Von Neumann architecture, every computer we've ever had has been designed in those basic components. This design is simple enough (and, in fact, dumb enough) to handle just about anything at all, it is the general purpose computer (a way of saying that it doesn't have any purpose).

Now a bunch of neuroscientists have figured out that the memory in our computers is too dumb to do certain things well. Our linear memory, where a memory cell has no relationship to the neighboring cells, is abstract and general enough for anyone's pleasure, but it's not the way human memory works. Our memory is hierarchical, that is to say it's made up of levels where the bottom levels remember very simple things, like shapes and sounds in time. As you ascend the hierarchy, the levels above that do not remember "discrete" things, they remember unifications over the simple things. That is the way in which you understand that a leg is both a discrete thing as well as it can be part of a human body, one part in something larger.

Now, if you think about it, this is a crude first model for learning, you are being fed a lot of facts in the hope that you will be able to unify them and see "meaning" to them as a whole. This, unfortunately, is necessary, because we don't know how to transmit the meaning itself, we think the only way is to send the facts and then the mind will infer the meaning by itself. (It's quite an optimistic strategy, isn't it?) Interestingly, there is a trade off at this point. Apparently, you cannot both remember all the discrete facts *and* be able to unify them. So that could explain how some people have a propensity for lots of facts without seeing the bigger picture, while others can't hold on to all the little pieces. In a way it makes sense, doesn't it? Like doing research. Once you've stated your thesis, you don't need all those little notes anymore, they are subsumed in the larger unifying rationale.

But now back to technology. A bunch of people have built this model of memory in software, calling it a "hierarchical temporal memory". It's an absolutely fascinating premise.

The appeal of London

November 22nd, 2008

London, it's a wonderful city. The culture, the entertainment, the architecture. Historical and contemporary at once. Everyone and everything is there.

Oh sure, initial impressions can be disappointing. The drab landmarks of postcard tourism.. the baroque London Bridge, the utterly pointless Tower of London, the entirely forgettable Buckingham Palace, the simplistically named Big Ben, the gaudy Westminster Abbey. Next to Rome or Paris they look almost barbaric, like the Stone Henge next to the Eiffel Tower. But I cannot for a second imagine that someone could come away from London without absorbing the magic and the culture inherent to it. There's something for everyone to love.

The most striking thing about London to outward appearances is the architecture. There is no shortage of classical buildings, but then there is none of modernity either. Soho, Picadilly, Westminster for a bite of classical; St. Paul's, Queen Victoria, Cornhill for the modern. But you don't have to chase it down, architecture is everywhere and the urbanism is top class, it all fits no matter what it is.

Walking around the wide streets there is that feeling of a real metropolis. The streets are buzzing, both motorized traffic and pedestrian. And they do not fall asleep after dark, there are always people. For that warm and cuddly city feeling Oxford Street is a good bet. When you're ready to take a load off, look for a Starbucks (they're everywhere). Then walk across the street to Caffè Nero, a cozy café chain without the fast food atmosphere.

If you're after shopping there is a huge Borders off Oxford Circus, 4 storeys of bookstore. Be there at 9am and you have the whole thing to yourself! And it's well worth it. Books have always been cheaper in England. You can walk out with two shopping bags for the price of a sports jersey or some silly fashion item.

London's subway system is unique and something of a contradiction. When you look at the map you notice that the stations cover the city very laboriously, it's obviously a huge network. But then you enter the underground and everything is so cramp, the passage ways are narrow, there's little space above your head, the platforms are about 4m wide, and the trains themselves are no different, only wide enough for 3 seats and a passage - less than a bus. So why is a network so vast, designed to transport so many people so cramped? And still, the trains run with such regularity that you're never actually obstructed or stalled, it's very efficient. The maximum waiting time in zone 1 is 3 minutes in the daytime.

State instituted paranoia

The one thing that everyone knows about London and Britain nowadays is that it's a surveillance society. I didn't actually take any pictures myself, but I bet I could cover every last site of interest just with the pictures taken for me and of me in every location. I'm not sure whom I have to call to recoup those photos, though. It's no exaggeration, there really is a camera everywhere, and often, several.

All of this for my protection, naturally. The subway is already entirely covered in cameras, but you'll still see signs reading "for your protection we are installing more cameras". Ditto in the commercial realm, the same cameras wrapped in tinted glass (so as to be less obvious) greet you in a café as the ones you see in the street.

London feels like a pretty safe place if it wasn't for the police crawling everywhere. I don't know about you, but seeing a police unit doesn't make me feel particularly safe. Presumably they are on scene to stop, intervene, apprehend, pursue and I don't want to get stuck with a ticket for crossing the street at my own choosing just because the restless cops feel they have to justify their presence somehow.

State instituted paranoia is on show. There's a warning sign on everything to alert you to the magnificent danger. Walking down Horse Guards Road in Westminster I saw an entirely unremarkable statue surrounded by a fence on all sides, with a plaque stating that it would be a criminal act to climb the fence. This kind of thing is systemic, there is so much distrust and hostility in the announcements and signage. A security circus.

The thing is though, I don't think the public is buying it. They are tolerating it, because it hasn't impacted their lives much, but London doesn't strike me as a society in anxiety or panic, far from it. London was the site of a bombing since the era of paranoia ensued, fair enough, but is the solution to that not police work rather than a paranoia epidemic? The public seems to think so. Terrorism is shamelessly used for political currency, as is the current trend. In the same area there's a monument to the Bali bombing victims. Not that Bali was unimportant, but how many other people have died tragically through various other causes in the same period, starting with the civilian casualties caused by the Iraq invasion (concentrate on the territories under British control, say), ending with the armed conflict du jour on the African continent? No political gain from that, so let's not dwell on those shall we.

Left is right, except when it's not

It is so typical of the British to be different. Not different in a useful way, just arbitrarily so. It might be illusions of grandeur over the long lost empire. One of those differences is driving on the other side of the road. Britain is part of a small minority of countries that drive on the left. To what end? Cars have to be built special for those markets. Traffic rules cannot be made universal worldwide. And for what? There is no trade-off to make, it's completely inconsequential which side you take. The only justification is "it must be this way because it's always been this way", which is a popular non-argument.

To the extent that motorized traffic works smoothly on the "left system", it also affects pedestrians. And in London there are some very clear signs that the left system isn't all that smooth. For starters, there's printing on the street at every pedestrian crossing, "look left", "look right", to tell us where the traffic is coming from. I've never seen this anywhere else, and it wouldn't be necessary if people understood how the traffic works.

You would expect that if the Brits are dedicated to the left system then everything would work accordingly. But it doesn't. When you're walking down the street on the right hand side, sometimes you're against the stream, sometimes with it. In the subway, where they have instructions for everything, they often have partitions in the middle of a walkway. In some places the sign says "keep left", in others "keep right". When you get to the escalator, you're supposed to stand on the right, and walk on the left, in blatant contradiction to the left system. The escalators themselves are flimsy on it, sometimes the one going up is on the right, sometimes it's on the left. Sometimes you're coming out of a walkway on the right and crossing over to the escalator on the left, clashing with the people coming down and switching to the right.

havenet: network perimeter test

November 17th, 2008

Network connections fail all the time, we've all been there. There are so many things that can go wrong, the network adapter driver can fail, the dhcp server can revoke the lease, the wifi router can disappear, the routing may be wrong at some point along the line, the dns server can be overloaded, or the remote host may be down. Those are some of the possibilities, and it can be quite a pain to track down the problem.

But the first thing to do is to figure out exactly what is working and what isn't. If you know that much then at least you know where to start. My goal here is to create a fairly simple test to examine the status of the network connection, leading up to a working internet connection. One constraint that I have is that I like it to be portable, so that I can carry it around along with my dotfiles. That means I would like it to work in any location just as long as I can get a shell, it should not require any dependencies.

A fully functional network connection looks like this:

What I do is try to detect the parameters of the network step by step, using the regular tools like route, ifconfig. Once I know what the hosts are, I do a ping. Now, a ping obviously isn't a foolproof test; if you're on a network that doesn't allow outgoing icmp then it's entirely possible that you can tcp out anyway. So what you really should do is tcp on port 80, not ping. But ping is extremely portable, whereas doing a tcp/udp probe is asking a lot more from the environment, needing something like nmap or hping.

Once you've established that the connection is working, and you want to know more about the network, you can go further with something like netscan.

The code is relatively stupid and messy, but that's the way bash is.

# Author: Martin Matusiak <numerodix@gmail.com>
# Licensed under the GNU Public License, version 3


function havenet {
	local init="$(toolsinit)"

	platforminit
	case "$PLATFORM" in
		"Linux")
			echo "Platform: $PLATFORM"
			run_havenet "$init";;
		*)
			echo "Platform: $PLATFORM (local network detection not supported)"
			run_haveinet "$init";;
	esac
}

function haveinet {
	local init="$(toolsinit)"
	platforminit
	echo "Platform: $PLATFORM"
	run_haveinet "$init"
}

function platforminit {
	if $(which uname &>/dev/null); then
		PLATFORM=$(uname 2>/dev/null)
	fi
}

function toolsinit {
	local tools="true"
	local missing=()


	local cmds=(/sbin/route /sbin/ifconfig ping nmap)
	local args=(" -n" "" " -c1 -W2" " -T3")
	local names=(route ifconfig ping nmap)

	local i=-1
	while [ $i -lt $(( ${#names[@]} - 1 )) ]; do i=$(( $i+1 ))
		if [ 0 -eq $(which ${cmds[$i]} &>/dev/null ; echo $?) ]; then
			tools="$tools;local ${names[$i]}=\"${cmds[$i]}${args[$i]}\""
		else
			missing[${#missing[@]}]="${cmds[$i]}"
		fi
	done


	if [ ${#missing[@]} -gt 0 ]; then
		echo -e "Missing tools: ${cred}${missing[*]}${creset}" 1>&2
	fi

	echo "$tools"
}

function run_havenet {

	eval "$@"

	local localranges="169.254 10 172.(1[6-9]|2[0-9]|3[0-1]) 192.168"


	### Scan networks
	
	echo -e "${cyellow} + Scanning for networks...${creset}"
	test=$($route 2>/dev/null | egrep "^[1-9]")
	if [[ $? != 0 ]]; then
		echo -e "    ${cred}none found${creset}"
	else
		local nets=$(echo "$test" | sort | awk '{ print $1 }')
		for net in $nets; do
			local gw=$($route 2>/dev/null | egrep "^$net" | awk '{ print $3 }')
			printf "    ${cgreen}%-15s${creset} ${ccyan}%s${creset}\n" "$net" "/ $gw"
		done

		### Detect ips

		local ips=
		for net in $nets; do
			local r=$(echo $net | sed "s/.0$//g" | sed "s/.0$//g" | sed "s/.0$//g")
			local ip=$($ifconfig 2>/dev/null | grep "inet addr:$r" | sed "s/inet addr:\([0-9.]*\).*$/\1/g")
			ips="$ip $ips"
		done

		echo -e "${cyellow} + Detecting ips...${creset}"
		test=$(echo "$ips" | egrep -v "^[ ]+$")
		if [[ $? != 0 ]]; then
			echo -e "    ${cred}none found${creset}"
		else
			local on_lan=1
			for ip in $ips; do
				printf "    ${cgreen}%-15s${creset}  %s" "$ip" "ping: "
				test=$($ping $ip 2>/dev/null)
				if [[ $? != 0 ]]; then
					echo -e "${cred}failed${creset}"
				else
					local t=$(echo "$test" | grep "min/avg" | sed "s/.*= \([0-9.]*\)\/.*$/\1/g")
					echo -e "${cgreen}$t ms${creset}"
				fi

				### Test ips for lan
				local ip_on_lan=0
				for prefix in $localranges; do
					test=$(echo "$ip" | egrep "^$prefix" 2>/dev/null)
					if [[ $? == 0 ]]; then
						ip_on_lan=1
					fi
				done
				on_lan=$(( $on_lan & $ip_on_lan ))
			done


			if [ $on_lan -eq 1 ]; then
				
				### Detect gateways if on lan

				echo -e "${cyellow} + Detecting gateways (network is local)...${creset}"
				test=$($route 2>/dev/null | grep UG)
				if [[ $? != 0 ]]; then
					echo -e "    ${cred}none found${creset}"
				else
					local gws=$(echo "$test" | awk '{ print $2 }')
					for gw in $gws; do
						printf "    ${cgreen}%-15s${creset}  %s" "$gw" "ping: "
						test=$($ping $gw 2>/dev/null)
						if [[ $? != 0 ]]; then
							echo -e "${cred}failed${creset}"
						else
							local t=$(echo "$test" | grep "min/avg" | sed "s/.*= \([0-9.]*\)\/.*$/\1/g")
							echo -e "${cgreen}$t ms${creset}"
						fi
					done

					### Try inet connection if we have a gateway 
					run_haveinet "$@"
				fi
			else

				### Try inet connection, we're on wan
				run_haveinet "$@"
			fi
		fi
	fi

}


function run_haveinet {

	eval "$@"

	local rootname="A.ROOT-SERVERS.NET."
	local rootip="198.41.0.4"
	
	local dnsport="53"

	local inethosts="yahoo.com google.com"
	local inetport="80"


	### Test inet connection

	echo -e "${cyellow} + Testing internet connection...${creset}"
	echo -en "    ${ccyan}$rootname  ${cgreen}$rootip${creset}   ping: "
	test=$($ping $rootip 2>/dev/null)
	if [[ $? != 0 ]]; then
		echo -e "${cred}failed${creset}"
	else
		local t=$(echo "$test" | grep "min/avg" | sed "s/.*= \([0-9.]*\)\/.*$/\1/g")
		echo -e "${cgreen}$t ms${creset}"
	fi

	### Detect dns

	echo -e "${cyellow} + Detecting dns servers...${creset}"
	test=$(cat /etc/resolv.conf 2>/dev/null | grep ^nameserver)
	if [[ $? != 0 ]]; then
		echo -e "    ${cred}none found${creset}"
	else
		local dnss=$(echo "$test" | awk '{ print $2 }')
		for dns in $dnss; do
			printf "    ${cgreen}%-15s${creset}  %s" "$dns" "ping: "
			test=$($ping $dns 2>/dev/null)
			if [[ $? != 0 ]]; then
				echo -en "${cred}failed${creset}"
			else
				local t=$(echo "$test" | grep "min/avg" | sed "s/.*= \([0-9.]*\)\/.*$/\1/g")
				echo -en "${cgreen}$t ms${creset}"
			fi


			local proto="tcp" ; local udpflags=""
			if [[ `whoami` = "root" ]]; then
				proto="udp"; udpflags="-sU -PN"
			fi
			echo -en "  dns/$proto: "
			test=$($nmap $dns $udpflags -p $dnsport 2>/dev/null)
			if ! echo "$test" | grep "$dnsport/$proto" | grep "open" &>/dev/null; then
				echo -e "${cred}failed${creset}"
			else
				local t=$(echo "$test" | grep "scanned in" | sed "s/^.*in \([0-9.]*\) seconds.*$/\1/g")
				t=$(echo $t*1000 | bc)
				echo -e "${cgreen}$t ms${creset}"
			fi
		done
	fi

	### Test inet dns

	echo -e "${cyellow} + Testing internet dns...${creset}"

	for inethost in $inethosts; do
		printf "    ${cgreen}%-15s${creset}  %s" "$inethost" "ping: "
		test=$($ping $inethost 2>/dev/null)
		if [[ $? != 0 ]]; then
			echo -en "${cred}failed${creset}"
		else
			local t=$(echo "$test" | grep "min/avg" | sed "s/.*= \([0-9.]*\)\/.*$/\1/g")
			echo -en "${cgreen}$t ms${creset}"
		fi

		echo -en "  http: "
		test=$($nmap $inethost -p $inetport 2>/dev/null)
		if ! echo "$test" | grep "$inetport/tcp" | grep "open" &>/dev/null; then
			echo -e "${cred}failed${creset}"
		else
			local t=$(echo "$test" | grep "scanned in" | sed "s/^.*in \([0-9.]*\) seconds.*$/\1/g")
			t=$(echo $t*1000 | bc)
			echo -e "${cgreen}$t ms${creset}"
		fi
	done

}

UPDATE: Replacing with newer version that is a bit more clever.

UPDATE2: Added tool detection and platform detection.