Sunday, October 24, 2010

The #1 success principle

In a video, Brian Tracy talks about a series of 4 books he read containing 1000 principles of success (there were 250 principles per book). He managed to meet the author one day, and asked what the most important principle was. And the answer the author gave was: "Learn from the Experts".

Saturday, October 23, 2010

An open relay for thimbl

I am experimenting with ideas in open social networking - thimbl has caught my attention the last few weeks. I have activated the finger daemon on my EC2 account. You can find the latest tweet by doing
   finger ossa@nummo.strangled.net

I have also devised an open relay for thimbl. Anyone can now make a microblog post, using only telnet. You can explore it right now (where now is defined as 23-Oct-2010, 18:19) as I have the open relay set up on my server. Here's what you do:
   telnet nummo.strangled.net 2993

You can type
   rece
to see the last 10 tweets. You can add your own tweet using the "say" command. For example:
   say hello from the internet
Type "rece" again, and you should see your post. When you've have enough, type
   quit

For further proof that it's worked, type
    finger ossa@nummo.strangled.net
and you should see your post.

The code behind it (VERY hacky):

#!/usr/bin/env tclsh
# Run this open relay server using
# retweet.tcl
# Example usage from the 'client' perspective:
# telnet localhost 2993
# C: OK Retweet says hello
# S: rece <-- obtain a list of recent posts
# C: blah blah 1
# C: ...
# C: OK Done
# C: say i don't care what i say <-- create a posting
# S: OK Done
# C: quit <-- quit the server
# socketry taken from
# http://www.tcl.tk/about/netserver.html
#fconfigure 0 -buffering line -blocking 0
#fconfigure 1 -buffering line -blocking 0
proc out { text } {
    puts 1 $text
    flush 1
}
# out "OK Retweet says hello"
proc in {} {
    gets 0 inp
    return $inp
}
proc handle_input {out inp} {
    if {[regexp {^say (.+)} $inp _ tweet]} {
# write the tweet to a file
set f1 [open "tweets" "a"]
        puts $f1 $tweet
        close $f1
# save the tweet in .plan
        set f1 [open ".plan" "w"]
        puts $f1 $tweet
        close $f1
puts $out "OK Done"
#flush stdout
return
    }
    if {[regexp {^rece} $inp]} {
set f1 [open "| tail tweets" "r"]
        puts $out [read $f1]
        close $f1
puts $out "OK Done"
#flush stdout
return
    }
    if {$inp == "help"} {
puts $out "Commands: help quit rece say"
puts $out "OK Done"
#flush stdout
return
    }
    if {$inp == "quit"} {
puts $out "OK Quitting"
#flush stdout
close $out
return
    }
    puts $out "FAIL Didn't understand command"
    #flush stdout
}
# Echo_Server --
#Open the server listening socket
#and enter the Tcl event loop
#
# Arguments:
#portThe server's port number
proc Echo_Server {port} {
    set s [socket -server EchoAccept $port]
    vwait forever
}
# Echo_Accept --
#Accept a connection from a new client.
#This is called after a new socket connection
#has been created by Tcl.
#
# Arguments:
#sockThe new socket connection to the client
#addrThe client's IP address
#portThe client's port number
proc EchoAccept {sock addr port} {
    global echo
    # Record the client's information
    puts "Accept $sock from $addr port $port"
    set echo(addr,$sock) [list $addr $port]
    # Ensure that each "puts" by the server
    # results in a network transmission
    fconfigure $sock -buffering line
    puts $sock "OK Greetings from fritter"
    # Set up a callback for when the client sends data
    fileevent $sock readable [list Echo $sock]
}
# Echo --
#This procedure is called when the server
#can read data from the client
#
# Arguments:
#sockThe socket connection to the client
proc Echo {sock} {
    global echo
    # Check end of file or abnormal connection drop,
    # then echo data back to the client.
    if {[eof $sock] || [catch {gets $sock line}]} {
close $sock
puts "Close $echo(addr,$sock)"
unset echo(addr,$sock)
    } else {
handle_input $sock $line
#puts $sock $line
    }
}
Echo_Server 2993
 
To run it, do the following:
cd ~
echo first post >~/.plan
echo first post >~/tweets
tclsh retweet.tcl
You may want to combine it with the nohup command so that it isn't killed.

The code is also avialabe for download .

Wednesday, October 13, 2010

A stateful web counter in Racket

The idea of using Racket as a stateful web server is really beginning to attract me interest. I present below a simple web counter. Each time you click on the ++ link, it increments the counter. If you start it in a new tab/window, then it begins at 0. So each tab has its own state.


#lang racket
;;;; a stateful web server

(require web-server/formlets
         web-server/servlet
         web-server/servlet-env)


(define (counter request (count 0))    
  (send/suspend/dispatch 
   (lambda (k-url)
     `(html (head (title "Counter"))
            (body
             (p "Computer says: " ,(number->string count))
             (a ([href 
                  ,(k-url (lambda (request)
                                (counter (redirect/get) (+ 1 count))))
                  ]) "++")
             (p "Enjoy!"))))))


(define log-file 
  (path->string 
   (build-path (find-system-path 'home-dir) ;(expand-user-path "~") 
               "racket-server-access.txt")))
; would this work better?:
; e.g. (list (build-path "js") (build-path "css"))


;;; Start the server
(serve/servlet counter 
               #:port 8080 
               #:listen-ip #f 
               #:log-file log-file 
               #:servlet-path "/counter.rkt")




Saturday, October 9, 2010

Is social networking a solution to a non-problem?

I have recently been turning my attention to Twitter, a microblogging site and thimbl, a free open-source distributed microblogging site. Thimbl are light on the details as to how their systen works, but it seems to revolve around the system admin enabling the finger daemon, and writing text in their ~./plan file. I am unaware as to how the sever-side works, though.

The blog entry OpenProvider stated that the ideal social network should have:
  1. Accessibility/virality - it should be easy to find your friends
  2. Privacy
  3. Low barrier to entry
  4. Portability
Here is some of my own thinking on the matter:
  1. Accessibility: I would say that accessability is a "solved" problem - it's called a URL
  2. Privacy: social networks seem, to me, to be inherently public. If something is published, even "privately", then it is effectively public if you stress the word "social".
  3. Low barrier to entry: I think it's very difficult to build distributed systems for non-technical people. Thimbl, for example, requires that an admin activate fingerd. That probably means that you need to be in a UNIX-like environment straight off the bat. Corporations are unlikely to be receptive to setting up these kinds of services unless it satisfies a corporate objective. Fingerd might make people nervous, too, "

    Since finger usually serves no useful purpose and reveals potentially sensitive information about accounts on the system, the best solution is to disable it.
    " (Source) I don't want to pick on finger in particular - I just want to note that if you want to set up some kind of distributed service, then basically you need to be technically knowledgeable, and running Linux (well, OK, maybe Windows will get you there EVENTUALLY). Perhaps I could envision a programmatic front-end that will set something up for a complete newbie, which provides an inflexible framework for becoming published, and incorporates its own little server. Even then, the user might be expected to know how to perform port forwarding on their router - this is likely to be surprisingly challenging for someone who is computer illiterate (hell, my dad doesn't even understand the concept that a picture is a "file").
  4. I think there is always going to be a trade-off between centralised and decentralised designs. Centralisation allows for technical people to set up the framework once, and allow non-technical people to access those services without complicated setups. Central servers are likely to be better backed up, and they don't suffer from users turning off their machines.
Having said that, I'm quite intrigued by the whole idea of distributed social sites. I now want to toy with the idea of a distributed forum system that doesn't require registration. I have been reading the suckless site, and their philosophy of keeping software simple. They seem to really like the Plan 9 OS. I'm not sure about what the big deal is, but it seems that everything is a file - which simplifies things like interprocess communications and networking.  There is software, plan9port, which implements this on Linux. The suckless site uses it for werc, "a sane web anti-framework". I plan to check it out.

Friday, October 8, 2010

My Twitter/thimbl rival: fritter (Free Twitter)

At Twitter, thimbl is writing a rival to Twitter, whose website is available here . Details are a little thin as to how it actually works, but it seems that a system admin must enable sshd and fingerd through xinetd. The user writes to his ~/.plan file, and thimbl picks this up in some way, and creates a log message.

I thought I'd have my own go at a rival system. It's a toy system, of course. My solution is to rely on Apache - so that an admin doesn't even have to enable fingerd. My solution uses the fact that Apache can be made to serve files in ~/public_html . It might be automatically enabled - but it wasn't for my Slackware 13.1 system. To enable it, I had to edit /etc/httpd/httpd.conf, uncomment the line

Include /etc/httpd/extra/httpd-userdir.conf


and re-start Apache.
I then require that anyone who wants to create a"fritter" post must put some text in the file ~/public_html/fritter.txt

That takes care of the server side.

Now, on to the client side.To follow people, you must create a file caller fritter.conf. Each line must have a host and username, separated by a space. Here is my example fritter.conf file:

localhost mcarter

As you can see, it only contains one line, because there's only one person making fritters at the moment. Here is  the code that prints out the fritters, which I called fritter.py

#!/usr/bin/env python

import datetime
import time
import urllib2



def once(conf, tweets):
    for line in conf:
        line = line.replace("\r","").replace("\n", "")
        host, person = line.split()
        url = "http://{0}/~{1}/fritter.txt".format(host, person)
        f = urllib2.urlopen(url)
        tweet = f.read()
        print_tweet = True
        if tweets.has_key(url):
            if tweets[url] == tweet: print_tweet = False
        tweets[url] = tweet
        if print_tweet:
            print "At {0}, {1} at {2} wrote:".format(datetime.datetime.now(), person, host)
            print tweet
 
            
        

# read configuration file
conf = file("fritter.conf","r").read().splitlines()
tweets = {}
while(True):
    once(conf, tweets)
    time.sleep(5)

It's pretty primitive stuff, and is open to lots of enhancements - but I think it's quite good that I created a Twitter clone in 32 lines of code. Simply run it, and it will cycle through your conf file, and spit out any new posts that appear.

Anyone got any better ideas?

Edits 09-Oct-2010 12:22:
  • You can get the code over at pastebin (Blogger seems to mess up the layout).
  • Changed "server" to "client", and vice versa.
  • Changed ~/.project to ~/.plan