Tuesday, March 17, 2015

How to WIN CASH in the Maina and Kingangi's Cash Cow Game (Count the Cash)

If you are the lucky caller, wait till Maina tells you which of the 3 possible options can be ruled out, and then change your answer to whatever other option remains, I repeat, DO NOT STICK TO YOUR ORIGINAL ANSWER.

If you want to know why, continue reading below...

Firstly, for those who don't know what am talking about, Maina's Cash Cow is a challenge that runs on a weekdays radio progamme popularly know as Maina and King'ang'i in the morning, on Classic FM, a popular radio station in major Kenyan towns and their environs, especially Nairobi.

Here is how it basically runs:

  • Maina, the presenter, invites radio listeners to call the station and attempt their luck in counting his cash; only one lucky caller gets his call picked up, he will listene the sound of a Note Counting Machine and all he has to do is guesstimate the correct number of notes.
  • After the lucky caller guesses the number of notes, say 51, Maina goes ahead and gives the callewr two more possibilities. e.g 'What if I told you it's either 51, 52 or 53?', (should you still stick to your original answer? at this point it does not matter, change to whatever of the 3 you want, it was a guess anyway)
  • After the caller settles on one of the three numbers, Maina discloses that one of them is not correct. e.g The user settled on 51, and Maina goes like, 'What if I told you it's either 51 or 53?' (i.e rules out 52).
Apparently,  the correct probability solution will predict that SWITCHING from your original answer to whatever remaining option (i.e from 51 to 53 in this example) doubles your chances, from 33% to 67%. Well, it did not make sense to me too at first, I initially worked out that it's just two options (51, 53) and thus the probabilities should be 50% vs 50%. I will not delve into the probability theories that explain this, instead, I will direct you to a simplified python snippet that you can study and also execute to see the results for yourself. 

I implemented a simple computer algorithm to simulate the scenario and demonstrate why it is always NOT advisable to stick to your original answer as the caller tackling Maina's Cash Cow challenge. The simulation simply runs 10,000 challenges for each of two guys, one who always sticks to the original answer, and the other always switches. The simulation clearly demonstrated those who stick to their original answer only win ~ 33% of the time while those who switch their answers won ~ 67% of the time. The  code is here.


Some of the assumptions made are that:
- Maina knows the correct number of notes even before the caller begins guessing.
- Maina is going to be honest
- Of course it does not have to be real notes, it could be computer generated sound based on a predetermined number of notes or a real Note Counter, the math still stands.


Note: This is a classic probability puzzle known as the Monty Hall Problem.

Saturday, November 15, 2014

Running Background Jobs in Parallel on Linux

Background jobs are very easy to execute and monitor yet very powerful, allowing you to stay focused on what needs your attention the most while still fully utilizing your Computer's resources.

Let me give an example with conversion of MP4 files to MP3 files, a simple task I have to do every once in a while since my car music player only accepts mp3 on USB (of course, I have used the feature to do more advanced stuff).

The program I use is avconv, it's straight forward to install if you don't already have it. ffmpeg also works the same and is available on Windows and Mac. These are free software for handling multimedia data.

The following commands will only execute on bash though, the default shell on Ubuntu. which is also available on other Linux flavours, and probably available on the rest of the platforms.

I am using 3 bash concepts here i.e looping, substitution and of course background jobs.

First cd into the directory containing the mp4 files.

for f in *.mp4; do avconv -i $f ${f%.mp4}.mp3 & done

The above command will start the conversion of all mp4 files in the directory; but how? let's break it down, in my next article.

To monitor the status of your background jobs, just run

jobs

The output, something like this
 
[1]+  Stopped                 avconv -i $f ${f%.mp4}.mp3
[2]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[3]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[4]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[5]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[6]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[7]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[8]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[9]   Running                 avconv -i $f ${f%.mp4}.mp3 &
[10]-  Running                 avconv -i $f ${f%.mp4}.mp3 &




Thursday, October 23, 2014

My Name is going to Mars

I submitted my name to be included on a NASA microchip to destinations beyond low-Earth orbit, including Mars. The micro-chip will take off aboard Orion, NASA's nextgen deepspace spacecraft,  on Dec. 4 2014 on a 4.5 hour flight-test, a two-orbit mission around Earth to test Orion’s systems. At the end of this short mission, my name will have to survive cringing speeds approaching 20,000 mph and temperatures near 4,000 degrees Fahrenheit, before splashing down in the Pacific Ocean.

If all goes as planned, the  microchip will be carried aboard in future NASA exploration flights and missions to Mars in an arrangement that could see me accrue space miles as a member of a global-space-faring society, exciting stuff!

Below is my official 'boarding pass'


Wednesday, October 8, 2014

JuiceSSH: My favorite Android App

This app has helped me incredibly. Well, what does it do? It allows you to ssh into a server and do everything you can accomplish on a regular terminal,  and this is from your mobile device.
It comes with an awesome keyboard feature set such as pop up keys for ctrl, tab e.t.c As a bonus, it allows you to connect to the mobile device's localhost and violate it in so many ways.
Personally I use an android version of it. Get to know it and it could turn out to be just what you needed to provide 99.9 uptime commitment on your applications.

Sunday, September 28, 2014

Thin SIM Technology Is Welcome

Am ready to try it out. Anything that cuts market entry costs opening up the industry to more competitors is good in my books. Instead of Safaricom trying to block it, they should just embrace it and use it to avail its MPesa products to 99.9% of all Kenyan mobile phone users.

Good call by CCK to let Equity try the technology for a year.

Looking forward to accessing Equity services from my SIM toolkit. Top on my wishlist is better payment APIs to help local devs create more powerful applications, anything to keep the fire in the Nairobi tech scene burning.

Wednesday, September 17, 2014

The Rapid Prototyping Toolkit for Mobile Apps

I am working on a set of tools to help mobile developers to quickly prototype apps. The platform will consist of an online dashboard for editing and publishing prototypes, a mobile app for running the prototypes and an emulator for testing prototypes before publishing. The mobile app will initially be available for android only. The platform will communicate with 3rd party apps via a HTTP REST, with JSON formatted data. Developers will be able to develop their prototypes in their language of choice provided they host behind an HTTP server.

Wednesday, September 3, 2014

Happy Birthday President Moi

Wishing a happy birthday to our former president, Daniel Torotich Arap Moi. Yesterday he turned 90. We share a birthday and that is why he is the only politician I always remember to wish a 'happy birthday'.

I am so grateful to Moi, he kept the peace at the expense of a few individuals, my view is, overall, it was better for everyone. It's time he wrote a book exposing all, he is 90, we will let him walk. I give his presidency a B+ for the peace, we could have been Rwanda, DRC or Somalia (No offense guys) had he missed a step.

Kibaki on the other hand, resurrected the economy, created infrastructure, reduced our dependency on donors at the expense of even more widespread corruption. He gets a B-, for letting people die in 2007.

Now its up to you Mr Uhuruto, My prediction, these guys will score a A-, mainly because 2 heads are better than 1 and also because of the pressure they are facing from all directions (ICC, Referendum, Impossible promises i.e laptops) and the economic vision set by Kibaki which we must try to live up to.

Kenya is going to be an African super power if we stay on track, mend fences with the west and negotiate better terms with the East. Its time Kenya corrected the imbalance of payments.

Monday, June 9, 2014

Generating Git Stats By Author

Ever wonder how many contributors your git-versioned project has, and how much each of them has contributed to the project. If yes, then here is a simple solution for you. It is based on the git blame command. Observe the section that contains the file extensions, you can customize that to ignore some file extensions.

git ls-tree --name-only -z -r HEAD|egrep -z -Z -E '\.(php|py|html)$'   |xargs -0 -n1 git blame --line-porcelain|grep "^author "|sort|uniq -c|sort -nr


Its not ussually entirely accurate. e.g if a coder adds an if .. else block to enclose existing code, formatting shifts the whole block right by a tab/space and git attributes the authorship of the whole block to this author. Another example is an coder who uses a lot of external libraries and git assumes he is the author.

Nevertheless, its a nice trick to know.

Tuesday, March 25, 2014

New Stuff Coming Up Soon

The year 2014 has been great, my focus has remained on Mobile solutions i.e SMS, USSD and Mobile Web. Integration solutions have also interested me a lot especially when it comes to interfacing 2 or more systems without relying on a defined API (when there is none). This automates tasks that have been previously manually done improving efficiency and cutting costs (and some jobs) there by improving productivity.

I have got a lot of exciting stuff coming out soon and am looking forward to writing more about it here once its ready, tested and deployed.

Sunday, December 29, 2013

IT'S Been Long

It's been long, but I promise I will be back in 2014. For the time been, take note that I have added a link to my other almost abandoned non-tech blog 'Tuwakenya' (added as 'Kenya Today'). This one is shared and anybody can post on it, all you need is a Google Account, and in fact some of the articles were authored by my friends. I coded it from scratch back in 2011 when I was experimenting the App Engine platform, which was the same time I was doing my 4th year project on the same platform (http://smszangu.appspot.com).

App Engine turned out to be a great platform and the whole of 2012 and 2013 I have been coding almost exclusive on the platform. I especially loved the powerful APIs availed, that are easy to integrate into the application. My Favourite APIs are Memcache Taskqueues and Full Text Search.

Recently I have started exploring other platforms because App Engine, like all other platform still has its weaknesses but I have no plans abandoning it. I will be playing around with Amazon EC2 a lot in the coming days, I already have some apps running the and I am loving it. Unlike Google Appengine, on EC2 I am able to fire up machines running my favourite OS and configured to my tastes. I am able to experiment with other alternatives of what App Engine offers. E.g Lucene Solr for full text search and Celery/Rabbitmq for Task Queues. I will hopefully be writing a lot about my findings.

Lets see how 2014 shall be!! BYE and Wishing you all a happy new year.

Saturday, November 3, 2012

KIKAMBA TEXT TO SPEECH SYSTEM - The Source Code

This article was first published in April 2010 on my previous blogging site

It written in PYS60, a python version for Series 60 phones. If you want to study and reuse it, do exactly that. If you want to get a feel of it on your s60 phone, you will need the resources (sound files, free of charge with some conditions) which you can get if you contact me.


import appuifw,audio,e32,messaging,inbox
class Analyser:
def __init__(self):
self.counter=0;
self.t_pos=0
self.speech=Speech(self)
self.enoughMemory=True
self.analysed=""
#print "new analyser"

def isSpecial(self,c):
return self.isNum(c) or c == " "
def getToken(self,s):
p = ""
if (self.t_pos < len(s) and s[self.t_pos] == ' '):
self.t_pos=self.t_pos+1
return " "
if (self.t_pos < len(s) and self.isNum(s[self.t_pos])):
while (self.t_pos < len(s) and self.isNum(s[self.t_pos])):
p =p+s[self.t_pos]
self.t_pos=self.t_pos+1
return p;
while (self.t_pos < len(s) and (not self.isSpecial(s[self.t_pos]))):
p += "" + s[self.t_pos]
self.t_pos=self.t_pos+1
return p
def isNum(self,k):
return k=='0' or k=='1' or k=='2' or k=='3' or k=='4' or k=='5' or k=='6' or k=='7' or k=='8' or k=='9'
def getDigitName(self,num,loc,plu):
if loc== 0:
if num==0:
return u"noti"
if num==1:
return u"\xedmwe"
if num==2:
if (plu == 1):
return u"el\xed"
return u"il\xed"
if num==3:
if (plu == 1):
return u"atat\xfa"
return u"itat\xfa"
if num==4:
if (plu == 1):
return u"ana"
if (plu == 2):
return u"ena"
return u"inya"
if num==5:
if (plu == 1):
return u"ataano"
return u"itaano"
if num==6:
return u"thanthat\xfa"
if num==7:
return u"moonza"
if num==8:
return u"nyaanya"
if num ==9:
return u"keenda"
return ""
if loc==1:
if num==1:
return u"\xedkumi"
return u"m\xedongo " + self.getDigitName(num, 0, 2)
if loc==2:
if num== 1:
return u"\xedana " + self.getDigitName(num, 0, 0)
return u"maana " + self.getDigitName(num, 0, 1)
if loc==3 or loc==4 or loc== 5:
return u"ngili " + self.getDigitName(num, loc - 3, 0)
if loc== 6 or loc==7 or loc ==8:
return u"milioni " + self.getDigitName(num, loc - 6, 0)
if loc==9 or loc==10 or loc==11:
return u"t\xfalilioni " + self.getDigitName(num, loc - 9, 0)
return u"namba \xedtasomeka"

def numToStr(self,num,phone):
if phone:#number requires to be read digit per digit not as a figure
fin=""
for k in range (0,len(num)):
fin+=self.getDigitName(int(num[k]),0,0)+" "
return fin
else:#read number as a figure
k = len(num) - 1;
if (k > 11):
return self.numToStr(num,True)
fin = ""
for y in range(0,k+1):
l = int(num[y])#store the current digit in l
m = 0
if (y < k):#if we are not reading the last digit
m = int(num[y + 1])#store the next digit in m
if (l != 0):#read the current digit only if its not zero
fin += self.getDigitName(l, k - y, 0)
if (y < k and m > 0):#if this is not the last digit and the next digit is not zero then add 'na' in btw the 2 digits
fin += u" na "
return self.corrector(fin)


def isVowel(self,a) :
return a=="a" or a=="e" or a=="i" or a=="o" or a=="u" or a==u'\xfa'\
or a== u'\xda'or a== u'\xed'or a== u'\xcd'or a== u'\xd9'or a== u'\xf9'\
or a== u'\xec'or a== u'\xcc'
def corrector(self,s):
try:
k = s.index(u"t\xfalilioni ")
if (k >= 0):
s = s.replace(u"t\xfalilioni ", "");
end = s[k:]
start = s[:k]
s = start + u"t\xfalilioni " + end
except ValueError:
pass
try:
k = s.index(u"milioni ")
if (k >= 0):
s = s.replace(u"milioni ", "")
end = s[k:]
start = s[:k]
s = start + u"milioni " + end
except ValueError:
pass
try:
k = s.index(u"ngili ")
if (k >= 0):
s = s.replace(u"ngili ", "")
end = s[k:]
start = s[:k]
s=start + u"ngili " + end
except ValueError:
pass
return s

def getLetterName(self,let):
if let=='@':return u"at\xed"
elif let=='.':return u"ndono"
elif let==',':return u"koma"
elif let=='+':return u"kwongela"
elif let=='-':return u"kumya"
elif let=='*':return u"k\xfand\xfa"
elif let=='=':return u"sy\xfakaa"
elif let=='$':return u"va\xfandi"
elif let=='#':return u"akyi"
elif let==u'\xa3':return u"ndola"
elif let=='a':return u"aa"
elif let=='b':return u"mbii"
elif let=='c':return u"sii"
elif let=='d':return u"ndii"
elif let=='e':return u"ee"
elif let=='f': return u"efu"
elif let=='g':return u"ngyii"
elif let=='h':return u"ekyi"
elif let=='i':return u"ii"
elif let=='j':return u"ngya\xed"
elif let=='k':return u"kei"
elif let=='l':return u"elo"
elif let=='m':return u"emu"
elif let=='n':return u"eni"
elif let=='o':return u"oo"
elif let=='p':return u"pii"#what happens , how do we differentiate with v
elif let=='q':return u"ki\xfa"
elif let=='r':return u"alla"
elif let=='s':return u"esi"
elif let=='t':return u"tiii"
elif let=='u':return u"yuu"
elif let=='v':return u"vii"
elif let=='w':return u"ndavili\xfa"
elif let=='x':return u"ekisi"
elif let=='y':return u"wae"
elif let=='z':return u"nzeti"
elif let==u'\xed':return u"\xed\xed"
elif let==u'\xfa':return u"\xfa\fa"
else:return ""
def expandWord(self,sente):
str=""
for k in range(0,len(sente)):
str+=self.getLetterName(sente[k])+" "
return str
def storedWord(self,sente):
return sente==u"\xedmwe" or sente== u"noti" or sente== u"\xedmwe" or sente== u"el\xed" or sente== u"il\xed"\
or sente== u"atat\xfa" or sente== u"itat\xfa" or sente== u"ana" or sente== u"ena" or sente== u"inya"\
or sente== u"ataano" or sente== u"itaano" or sente== u"thanthat\xfa" or sente== u"moonza" \
or sente== u"nyaanya" or sente== u"keenda" or sente== u"\xedkumi" or sente == u"m\xedongo"or sente== u"\xedana" or sente== u"maana"\
or sente== u"ngili" or sente== u"milioni" or sente== u"t\xfalilioni" or sente== u"namba"\
or sente== u"\xedtasomeka" or sente== u"at\xed" or sente== u"ndono" or sente== u"koma" or sente== u"aa"\
or sente== u"mbii" or sente== u"sii" or sente== u"ndii" or sente== u"ee" or sente== u"efu"or sente== u"ngyii"\
or sente== u"ekyi" or sente== u"ii" or sente== u"ngya\xed" or sente== u"kei" or sente== u"elo"\
or sente== u"emu" or sente== u"eni" or sente== u"oo" or sente== u"pii" or sente== u"ki\xfa" or sente== u"alla"\
or sente== u"esi" or sente== u"tiii" or sente== u"yuu" or sente== u"vii" or sente== u"ndavili\xfa" \
or sente== u"ekisi" or sente== u"wae" or sente== u"nzeti" or sente== u"\xed\xed" or sente== u"\xfa\fa"\
or sente== u"dr." or sente== u"mr." or sente== u"mrs." or sente== u"prof." or sente== u"pst."\
or sente== u"kwongela" or sente== u"kumya" or sente== u"k\xfand\xfa" or sente== u"sy\xfakaa"\
or sente== u"va\xfandi" or sente== u"akyi" or sente== u"ndola"
def validConsonant(self,sente):
return sente=="k" or sente=="kw" or sente== "ky" or sente=="l" or sente== "ly" or sente=="m" or sente== "mb" \
or sente=="mw" or sente== "n" or sente=="nd" or sente== "ndy" or sente=="ng" or sente== "ny" or sente=="nz" or\
sente=="s" or sente== "sy" or sente=="t" or sente== "th" or sente=="thy" or sente== "tw" or sente=="v"\
or sente== "w" or sente=="ngw" or sente=="nzy" or sente== "nthy" or sente=="y" or sente=="nthw"\
or sente== "thw" or sente=="vw" or sente== "ndw" or sente=="vy" or sente== "ng'" or sente=="sw"\
or sente== "mby" or sente=="mbw" or sente== "w'" or sente == "ngy" or sente == "lw"or sente == "lwy"\
or sente =="nth"
def isValidKikamba(self,sente):
if self.isVowel(sente[-1]):
if self.validConsonant(sente[0:-1]) or len(sente[0:-1])==0:
return True
else:
return False
else:
return False
def append(self,str):
self.analysed=self.analysed+str
def isPunctuation(self,str):
return str==',' or str=='.' or str==':' or str==';' or str=='?' or str=='\'' or str=='\"'\
or str=='\\' or str=='}' or str=='{' or str==')' or str=='(' or str=='/' or str=='~' or \
str=='_' or str=='^' or str=='!' or str=='|' or str=='#' or str=='+' or str=='=' or str=='*'\
or str=='-' or str=='$' or str==u'\xa3'
def insert(self,str,ins,index):
str1=str[:index]
str2=str[index:]
return str1+ins+str2
def process( self,input,play):
s=""
while True:
word = self.getToken(input)
#print "token:",word
readable=True
if (len(word) < 1):
break
if (self.isNum(word[0])):
temp=self.t_pos
self.t_pos=0
if word[0]=="0":
self.process(self.numToStr(word,True),False)#read as phone number
else:
self.process(self.numToStr(word,False),False)#read as number
self.t_pos=temp
continue
word=word.replace(u'\xf9',u'\xfa')
word=word.replace(u'\xec',u'\xed')
if self.storedWord(word):#if the word's phoneme is saved in memory as a whole
self.append(word)
continue
for k in range(0,len(word)):
if (self.isVowel(word[k])):
s =s+ word[k] #+ tone[t]
if not self.isValidKikamba(s) and play:#its this is not a recurse and its invalid
readable=False
temp=self.t_pos
self.t_pos=0
self.process(self.expandWord(word),False)
self.t_pos=temp
s=""
break
#print "very found:",s
s = "";
elif (word[k] == ' ' or word[k] == ',' or word[k]=='.'or word[k]==':'or word[k]==';'):
pass
elif self.isPunctuation(word[k]):
punc=word[k]
#print word," ",word[k]
word=self.insert(word,' ',k)
k=k+1
#word=self.insert(word,' ',k+1)
#print word," ",word[k]
word=word.replace(word[k],self.expandWord(word[k]))
else:
s =s+word[k]
if len(s)>0 and play:#if the word is valid except it does not end with a vowel
temp=self.t_pos
self.t_pos=0
self.process(self.expandWord(word),False)
self.t_pos=temp
s=""
continue
if readable:
#print "its readble"
self.append(word)
if play:
print "Normalised:\n"+self.analysed
self.speech.read(self.analysed)

class Speech:
def __init__(self,master):
self.folder="c:\\res\\"
self.master=master
self.syl=None
self.playing=False
#print "new speech"
def read( self,text):
self.enoughMemory=True
self.master.t_pos=0
while self.enoughMemory:
word=self.master.getToken(text)
if len(word)==0:
break
s=""
if self.master.storedWord(word):#if the word's phoneme is saved in memory as a whole
self.addSyl(u""+self.folder+word + ".wav")
continue
for k in range(0,len(word)):
if not self.enoughMemory:
break
if (self.master.isVowel(word[k])):
s =s+ word[k]
self.addSyl(u""+self.folder+s + ".wav")
s = "";
elif (word[k] == ' ' or word[k] == ',' or word[k]==';'):
self.addSyl(u""+self.folder+"spc.wav")
elif (word[k] == '.' or word[k]==':'):
self.addSyl(u""+self.folder+"spc.wav")
self.addSyl(u""+self.folder+"spc.wav")
else:
s =s+word[k]
self.playQueue(self.enoughMemory)

def addSyl(self,h):
try:
if (self.syl == None) :
self.syl = Phone(h)
else:
temp = self.syl
while (temp.next != None):
temp = temp.next
temp.next = Phone(h)
except SymbianError:
#appuifw.note(u"No Memory! \xdayumbe nd\xfasomeka","error")
self.enoughMemory=False

def playQueue(self,okay):
if(self.playing):
return
self.playing=True
t = self.syl
print "\n"*3
print "SPEECH:"
while (t != None):
try:
t.phone.play(times=1)
e32.ao_sleep(t.length)
t.phone.close()
except AttributeError:
e32.ao_sleep(t.length)
except SymbianError:
okay=False
t = t.next
if okay:
appuifw.note(u"\xdayumbe N\xedwathela","conf")
else:
appuifw.note(u"\xdayumbe Nd\xfasomeka Wonthe","error")
self.playing=False
self.refresh()
def refresh(self):
t=self.syl
if t is not None:
while t.next is not None:
t.phone=None
t.syl=None
t.length=None
t.no=None
t=t.next
self.syl.next=None
self.syl=None

class Phone:
def __init__(self,y):
self.syl=y[y.index("res\\")+4:y.index(".wav")]
if self.syl=='spc':
self.length=0.1
self.phone=None
else:
self.phone=audio.Sound.open(y)
self.length=float(self.phone.duration())/1000000 #self.numVowels(self.syl)*0.12
self.next=None
#print self.syl," length=",self.length


class KikambaTTS:
def __init__(self):
self.prev=""
self.curr=""
self.reader=Analyser()
str=""
appuifw.app.title=u"K\xcdKAMBA TTS"
#print "new K_TTS"
#appuifw.app.screen='large'
#run("w\xedmuthokye m\xfatambon\xed wa k\xfaneena ndeto mband\edke kwa k\xedthyomo kya k\xedkamba")
choice=[u"And\xedka(Create Text)",u"Nd\xfam\xed\xedtwe(Inbox)",u"Nd\xfam\xedte(Sent)",u"\xdatethyo(Help)",u"Vinga(Exit)"]
while(True):
menu=appuifw.selection_list(choice)
# self.run(choice[menu])
if menu==None and appuifw.query(u"Vinga? (Exit?)","query"):
break
elif menu==0:
self.input()
elif menu==1 or menu==2:
self.folder(menu)
elif menu==3:
self.help()
elif menu==4:
print "System Exit!"
break
def quit(self):
self.app_lock.signal()
def sender(self):
text=appuifw.app.body.get()
if(len(text)>0):
self.send(text)
else:
appuifw.note(u"vathei!","error")
def runner(self):
text=appuifw.app.body.get()
if(len(text)>0):
self.run(text)
else:
appuifw.note(u"vathei!","error")
def input(self):
appuifw.app.body = appuifw.Text()
self.textMenus()
def folder(self,menu):
str=self.getFromFolder(menu)
if str is not None:
appuifw.app.body = appuifw.Text(str)
self.textMenus()
def textMenus(self):
self.app_lock=e32.Ao_lock()
appuifw.app.exit_key_handler=self.quit
appuifw.app.menu = [(u"Soma",self.runner ), (u"T\xfama", self.sender)]
self.app_lock.wait()

def send(self,str):
number=appuifw.query(u"Namba","text")
if number is not None:
try:
messaging.sms_send(number,str)
appuifw.note(u"\xdayumbe N\xedwat\xfamwa","conf")
except SymbianError:
appuifw.note(u"\xdayumbe nd\xfanat\xfamwa","error")
#appuifw.note(u"Namba nd\xedvo","error")

def run(self,te):
te=te.lower()
self.curr=te
print "\n"*20
print '''INPUT:
\''''+te+'''\''''
print "\n"*2
print "ANALYSING......."
self.reader.t_pos=0
self.reader.syl=None
if self.curr == self.prev:
#print (u"equal")
self.reader.speech.read(self.reader.analysed)
else:
#print (u"Not Equal")
self.reader.analysed=""
self.reader.process(te,True)
self.prev=self.curr

def getMessage(self,str):
str=appuifw.query(u"And\xedka Vaa",u"text",str)
if str is not None:
return str
def getFromFolder(self,ch):
if ch==1:
mail=inbox.Inbox(inbox.EInbox)
elif ch==2:
mail=inbox.Inbox(inbox.ESent)
msg_ids=mail.sms_messages()
address=[]
for k in range(0,len(msg_ids)):
address.append(mail.address(msg_ids[k]))
index=appuifw.popup_menu(address,u"Sak\xfaa \xdayumbe")
if index>=0:
return mail.content(msg_ids[index]);
def help(self):
eng=u'''INTRODUCTION:
The Kikamba Text-To-Speech System Converts input text into speech and also allows you to send the text as an sms.

INPUTTING TEXT:
There are two ways to input Text:
(i). Create new Text: on the main menu, select 'And\xedka'. This opens a text box where you enter the Text.
(ii). Importing text: To import text from the 'inbox' folder or 'sent' folder of your phone, select on the main menu 'Nd\xfam\xed\xedtwe' or 'Nd\xfam\xedte' respectively. This displays a list of message addresses for the messages in the corresponding folder, select any address to import its text into the text box


GENERATING SPEECH:
From the 'options' menu, select 'soma'.

SENDING TEXT:
From the 'options' menu, select 'send'. This opens an input dialog. Enter the recipients address and click ok to send.

EXITTING:
Click 'Vinga' on the main menu.'''

kik=u'''MWAMB\xcd\xedO:
M\xfatambo \xfa\xfa n\xed wa k\xfav\xednd\xfaa ndeto sya \xfayumbe wa k\xedkamba ikatw\xedka \xfaneeni na \xednd\xed k\xfat\xfama \xfayumbe \xfasu ta sms

KW\xcdK\xcdA \xdaYUMBE M\xdaTAMBON\xcd:
Ve nz\xeda il\xed sya kw\xedk\xeda \xfayumbe:
(i). K\xfaand\xedka mbene: sak\xfaa 'And\xedka' kuma k\xedyoon\xed kya mbee. k\xedyoo k\xedng\xed kya k\xfaand\xedk\xeda n\xedk\xed\xfaving\xfaka na \xednd\xed \xfayand\xedka vo.
(ii). Kwosa \xfayumbe sim\xfan\xed: Wenda kwosa \xfayumbe \xfat\xfam\xed\xedtwe sak\xfaa 'Nd\xfam\xed\xedtwe' kuma k\xedyoon\xed kya mbee, wenda kwosa \xfayumbe \xfat\xfam\xedte sak\xfaa 'Nd\xfam\xedte'. Weeka ou w\xedonw'a masy\xedtwa kana namba sya and\xfa ala \xfamat\xfam\xed\xedte kana mak\xfat\xfam\xed\xedte ma\xfayumbe. Vau sak\xfaa \xfamwe n\xedkana \xfayumbe wake woswe w\xedk\xedwe k\xedyoon\xed k\xedla kya k\xfaand\xedk\xeda

KW\xcdTHUK\xcd\xcdSYA \xdaNEENI:
W\xed k\xedyoon\xed k\xedu kya k\xfaand\xedk\xeda, sak\xfaa 'options' na \xfaitina 'soma'

K\xdaT\xdaMA \xdaYUMBE:
W\xed k\xedyoon\xed k\xedu kya k\xfaand\xedk\xeda, sak\xfaa 'options' na \xfaitina 't\xfama'. Ve um\xedla k\xedyoo k\xedng\xed vala \xfak\xfaand\xedka namba ya sim\xfa \xedla \xfak\xfat\xfam\xeda \xfayumbe \xfasu na \xednd\xed \xfaisak\xfaa 'ok' n\xedkana \xfayumbe \xfat\xfamwe.

K\xdaVINGA M\xdaTAMBO:
Sak\xfaa 'Vinga' kuma k\xedyoon\xed kya mbee'''

choice=[u'K\xedkamba',u'English',u'Syoka(Back)']
while True:
t=appuifw.Text()
ch=appuifw.selection_list(choice)
if ch is 0:
t.set(kik)
elif ch is 1:
t.set(eng)
else:
break
t.set_pos(0)
appuifw.app.body=t
self.app_lock=e32.Ao_lock()
appuifw.app.exit_key_handler=self.quit
self.app_lock.wait()

#PROGRAM EXECUTES AS FROM HERE
run=KikambaTTS()




Have fun developers.

Kiswahili is Deficient in representing Numbers

This article was first published in March 2010 on my previous blogging site

It cant distinguish 11000 from 10001, both are written as 'ELFU KUMI NA MOJA', and this is the case for 12,000 and 10,002 and the like.

This means we can not reliably translate this text back to numbers using a computer.

A possible solution is to introduce a comma for 10,001 to be 'ELFU KUMI, NA MOJA' but this will only work if we are converting text assumed to be representing numbers only, Otherwise 'ELFU KUMI, NA MOJA' could mean both '10,001' and '10,000, and 1'. This now calls for the computer to analyse the context of the text and classify it in one of the two, which is not easy if you know what i mean. There goes a PHD RESEARCH TOPIC idea for those who are already there. And for Prof. Ali Mazrui and other custodians of the Kiswahili language, be careful next time you work on a language, it must be computer friendly.


Kiswahili is not my first language, if am wrong somewhere let me know.


Check out a system that converts numbers to text for Kiswahili and other 2 languages at http://numtotext.appspot.com/, this is the inverse of what we are talking about above.


This text also appeared on my blog at http://cymox1.blogspot.com/2010/08/kiswahili-is-deficient-in-representing.html

Sunday, June 5, 2011

Success today!

Success today, unlike yesterday does not come from being more powerful than others, taking advantage of others or being better than others. In a global world like the one we are living in, we compete on a level ground. We all have equal access to knowledge resources, the most important of all resources.

So how does success come, only by empowering others are you going to rise. The more you give, the more useful and necessary you are, the more you are going to go high. Sharing freely your resourceful information and other knowledge resources is going to bring home your dreams. Empowering individual souls will make you a god(dess) of opportunities and that is what we call power in the 21st century.

Tuesday, April 5, 2011

Tuwakenya Arrives with a Bang!

Finally Kenyans have an open discussion space where they can share ideas,crack jokes as well discuss and critique the current political drama.

http://tuwakenya.appspot.com is a is a simplified blog-like site that allows visitors to quickly browse articles posted by others. The articles are presented in two lists, one for Most Recently Posted articles and another for the Most Read Articles.

To make it all easy, you don't need to register to start using tuwakenya, provided you a kenyan (actually we don't have a way to know if you really are Kenyan). But you must be authenticated by google before you can Post content on Tuwakenya(e.g by logging with your gmail account)

You dont have to login to read or comment on the contents of Tuwakenya.

Again, be among the first 100 to post content on Tuwakenya. Share your views about the Hague and the Ocampo 6, about the world bank grant to improve slums or even about your village and let Kenyans read and comment on it.

Saturday, March 26, 2011

Aligning Text At the Top a Table Cell

Well, am back again to blogspot after a 9 months break, that was quite refreshing and eyeopening.

Quick to the point, I really had some trouble trying to align text at the top of a table cell, which is understandable, given my little experience in front end development.

Any HTML/CSS developer has heard of the 'text-align' CSS property that can be assigned to virtually all HTML elements. It not only controls horizontal alignment of text but all other HTML objects including div's, and tables. It only takes 3 values which set the alignment to be right, left or center. Notice you can set vertical alignment using this property. So what do you do if you have a table row, in which some cells have text spanning multiple lines while others have single lines but are displayed at the center (vertically)? which is the default for most browsers?

Here is the solution. use CSS property 'vertical-align' which takes 'bottom' and 'top' values for bottom alignment and top alignment respectively.

Here is sample CSS for setting all table data cells to be vertically aligned.

td{
vertical-align:top;
}

Well, have a good time coding in HTML.

Saturday, April 24, 2010

How big is the internet

The internet is huge with over a billion users, approximately 150 million websites and approximately 75 million servers. How heavy would it be, well , not that heavy only 50 grams. That is the combined weight of moving each of the trillions and trillions of bytes through the internet.

Sunday, April 11, 2010

Real Programmers Dont Write Specs

Well, this is not my original content, I have given a link at the end of the article. They are like rules for judging how real a programmer is and I really found them interesting and funny but not necessarily true. I modified some of them a little to fit my context. Enjoy reading.

Real Programmers don't write specs -- users should consider themselves lucky to get any programs at all, and take what they get.

Real Programmers don't comment their code. If it was hard to write, it should be hard to understand and even harder to modify.

Real Programmers never work 8 to 5. If they are around at 8 AM, it's because they were up all night.

Real Programmers don't play tennis, or any other sport which requires you to change clothes. Mountain climbing is OK, and Real Programmers wear their climbing boots to work in case a mountain should suddenly springs up in the middle of the computer room.

Real programmers don't think they should get paid at all for their work, but they know they are worth every shilling they make.

Real programmers log in first thing in the morning, last thing before they sleep and many times in between.

Real programmers don't like the team programming concept, unless of course they are the chief programmer.

Real programmers have no use for managers.

Real programmers ignore schedules.

Real programers only curse to inanimate objects such as loops, variables and monitors.

Real Programmers spend 70% of their work day fiddling around and then get more done in the other 30% than a user can get done in a week.

Real Programmers don't do documentation. Documentation is for those who can't figure out the listing.

Real programmers are surprised when their cars' odometers dont turn from 9999 to 999A.

Real programmers think they know the answers to your problems and will happily tell them to you rather than answer your questions.

Real Programmers' programs never work right the first time. But if you throw them on the machine they can be patched into working in "only a few" 10-hour debugging sessions.

Real Programmers don't write in Visual BASIC. Actually, no programmers write in Visual BASIC... after age twelve.

Partly adopted from http://www.multicians.org/thvv/realprogs.html

Saturday, April 3, 2010

A window into Exceptions

A friend of mine asked me what exceptions are, and here is my reply in the English language of humans, as opposed to computer jargon.
I will discuss the concept of Exceptions in computer programming. Depending in the programming language you will use, it might come in a different keyword but the concept stands.

An Exception is an unexpected situation/state. When writing a computer program, you have to anticipate all possible states that the program might take during execution. For each possible state that the program would take, you have to tell it what to do. If a program takes a state which was not anticipated by the programmer, it doesn't know what to do and therefore it crashes, popularly referred as throwing an exception in some languages. For example, Lets take a program for dividing two numbers. The basic flow would be: request the user to enter the first number, then the second number, divide them and print the result on the screen. This program as described would be consist of sequential instructions, it assumes all inputs will be 'dividable' which is very wrong. In most circumstances it would run right, but there are two circumstances in which it wont:-
1. If the user entered a non-numerical input, the program would 'throw a fatal exception', in that it would crash with an error.
2. If the user entered a zero denominator, its not possible to divide a number by zero and this would result to a fatal exception too.

So whats the solutions. There are two ways of doing the program right:-

1. Validating input - after each input, the computer validates if the input is numerical, if its not, it doesn't perform the division but instead it prints an error message e.g "Error, invalid input". By doing this, the program does not crash on non-numerical input.
Once the program validates the inputs, it compares the second input (denominator) with zero, if they are equal, it reframes from the division and prints an error message.
If the denominator is not zero, the program may now perform the division and print the result.

2. Handling Exceptions - This means enclosing the program instructions which might throw exceptions in a 'Try...Catch' block. If anything fatal happens in the 'try' block, the program jumps into 'catch' block without crashing. Its therefore common to print an error message in the catch block, the message will be printed only if the program encounters an error. Not all programming languages support this, but most modern languages support it, it comes in differing keywords depending on the programming language.

For those who have a thing for programming, here is sample code in Java and python that demonstrates handling Exceptions, the second approach.

//In Java
import java.util.Scanner;
public class Example{
public static void main(String[] args ){
Scanner read=new Scanner(System.in);
int num1=0,num2=0, result=0;
System.out.println("This program divides two numbers and prints the result");
try{
System.out.println("Enter the numerator");
num1=read.nextInt();
System.out.println("Enter the denominator");
num2=read.nextInt();
}catch(Exception e){
System.out.println("You entered invalid numbers");
System.exit(0);
}
try{
result=num1/num2;
System.out.println("The result is "+result);
}catch(Exception e){
System.out.println("You cannot divide by zero");
}
}
}


#In Python
num1=0
num2=0
result=0
print"This program divides two numbers and prints the result"
try:
print "Enter the numerator"
num1=int(raw_input())
print "Enter the denominator"
num2=int(raw_input())
except:
print "You entered invalid numbers"
exit(0)
try:
result=num1/num2;
print "The result is ",result
except:
print "You cannot divide by zero"

There are different types of Exceptions and its possible to specify to the program on how to handle each type of Exception. For example, the Non-numerical input error would throw a 'NumberFormatException' in Java and a 'ValueError' in Python. A better version of the above program would specifically anticipate such exceptions.

Tuesday, March 30, 2010

If Jesus lived today ...

... Or rather if Jesus lived today, it would be great, Imagine saying today 'God the son is in Palestine( or Israel)'. I would watch him on TV, am sure he would be in 'plenty' on CNN News and have a programme on Family TV. If i happen to go to Israel and meet him, there is a photo of Me and God the Son. I would take his phone number and email address. I would add him as my Facebook Friend, If we happen to be logged on facebook together, we will chat and crack a few jokes here and there.

Jesus is God and has power over Nature, Stopping Earthquakes, Tsunamis and droughts will just be a phone call away. With all those miracles happening, what heart is stubborn enough to still think there is no God, Heaven and Hell? Maybe we will all be saved righteous people.

Jesus will definitely have his own website and although he was born poor, am sure he will drive a good SUV or even a private Jet, not for the prestige but the convenience, the goal is to reach masses here.

We don't crucify people who heal the sick, feed the hungry and raise the dead and those that try to entertain that will be sent to the Hague. The west will issue a statement offering Jesus maximum security and threatening any 'Pilate' of making a misstep,the 'Barabbas' will be crucified. Jesus will remain with us.

The Programmers Prayer

My code wherever you are, hallowed be thy syntax and semantics, thy bugs be not detected. Generate my daily income and forgive thy hosts insufficient speeds and memory. Lead the hosts not into crashing but catch all exceptions. Execute!