by Joseph Javier Perla http://www.jperla.com/blog The site design looks balanced when this sentence is long Sun, 21 Mar 2010 00:07:23 http://webify.ivycall.com/ hourly 1 en Apple's amazing customer support system /blog/2009/08/23/apples-amazing-customer-support-system/ /blog/2009/08/23/apples-amazing-customer-support-system/#comments Sun, 23 Aug 2009 17:50:45 Joseph Perla /blog/2009/08/23/apples-amazing-customer-support-system/

Pick up your phone. Dial 1-800-MY-APPLE, 1-800-692-7753.

Listen to the automated system tell you that he can understand complete sentences. Shake your head in disbelief. There's no way thi ]]>

Pick up your phone. Dial 1-800-MY-APPLE, 1-800-692-7753.

Listen to the automated system tell you that he can understand complete sentences. Shake your head in disbelief. There's no way this is going to work.

Say 'I want to know if I can buy an AppleCare protection plan for my Mac Mini I bought 15 months ago.'

Notice how it asks you if you are asking for personal or business use. Stare in disbelief as it responds instantly and without a long awkward pause. Listen to the quick and conversational, not slow and stilted, tone of the computer voice. Let it automatically send you to the AppleCare department where you have no wait to begin speaking to someone.

Best phone system ever. I understand that it is very limited, but it fools you well enough to be a pleasant experience. It's a big stepping stone to even more powerful interactive phone systems.

]]>
Poem #0 /blog/2009/07/22/poem-0/ /blog/2009/07/22/poem-0/#comments Wed, 22 Jul 2009 02:11:00 Joseph Perla /blog/2009/07/22/poem-0/
Ease, loose, lax cannot,
Cheeks and eyes they tie tight knots.
Happiness, I caught.
]]>
Ease, loose, lax cannot,
Cheeks and eyes they tie tight knots.
Happiness, I caught.
]]>
Hot Stock Tip #0 /blog/2009/03/05/hot-stock-tip-0/ /blog/2009/03/05/hot-stock-tip-0/#comments Thu, 05 Mar 2009 19:45:00 Joseph Perla /blog/2009/03/05/hot-stock-tip-0/

I’m very, very good at trading stocks. I do not gamble. I, literally, mathematically, like clockwork, always make money. I have not posted my Year 3 returns yet (I have for Years 1 and 2 ), but they are better than ever. I have surprisingly consistent annual returns in excess of 20%+ in all conditions: both boom times, flat markets, record-breakingly volatile markets, and now deep recessions. I will write about my 2008 returns as soon as I finish my taxes.

Right now, however, I do not have significant excess investment capital outside of my Roth IRA. My Roth IRA I use for long-term investments in which I do not trade in and out frequently. Therefore, I now sometimes see some trades which I may or may not have taken if I did have some capital. I want to share one idea I had today with you.

First, please note that this information is not to be construed as either an endorsement or a recommendation; as investment advice or as an offer to buy or sell securities of any kind. Please consult with your own advisor before using this information.

I read that Amazon just launched an online game trade-in systemGamestop dropped almost 14% upon the news.  I know Amazon. I love Amazon.  I have made lots of money off of Amazon recently.  But this will not affect GameStop’s sales in the long run.  As the analyst in the article notes:

GameStop has previously tested out online trade-ins, but with limited success because of the time consumers had to wait to receive store credit, Sebastian said. The retailer’s trade-in model is successful in part because it gives gamers instant gratification.

The best products have the best design.  They make customers fall in love with their simplicity and instant feedback.  Amazon’s mail in system offers none of that.  Netflix works because, with its queue system, you passively receive new content.  Amazon’s system requires quite a bit of active involvement before you receive game credits.

If anything, GameStop will receive extra attention because of Amazon’s offering.  It may even grow more quickly.  I would buy GameStop right now.

Of coure, I would also hedge against the market by buying a short or double-short (more leverage!) ETF like QID.  That way, you can buy into the pure alpha of GameStop, without exposing yourself to the crazy movements of the market as a whole which nobody in the world can predict or even understand.  I will write more about this later.

]]>
Labmeeting rocks /blog/2008/12/23/labmeeting-rocks/ /blog/2008/12/23/labmeeting-rocks/#comments Tue, 23 Dec 2008 00:21:00 Joseph Perla /blog/2008/12/23/labmeeting-rocks/

I want to tell you a little about Labmeeting.  I work at Labmeetin ]]>

I want to tell you a little about Labmeeting.  I work at Labmeeting.  Actually, thinking about it, I have too much to say about Labmeeting.  I cannot tell you everything in one post.  I will tell you a little bit at a time as I think of cool things to talk about.  Let me tell you about our goals.

First, understand that science is broken.  Not in the traditional sense.  Science has not been speeding along the freeway and then suddenly tore a gasket and broke down.  No.  Science is puttering along reliably as it has for decades, centuries.  Exactly as it has been.  No faster.

Yes, scientists do an incredible job of being on the cutting edge of technology while simultaneously pushing that edge further and further.  Nevertheless, it takes between months and years to publish interesting results.  Labmates email cumbersome PDF’s back and forth.  Literature search tools frustrate even the most patient of users.  Conferences help disseminate knowledge quickly, but not when abstracts lose themselves amidst a shuffle of papers and when fellow scientists’ contact information evaporates. Publishers almost seem to try to restrict access to fulltext research articles, so much so that the government must force them to share knowledge.   Graduate students find professors and professors find grad students by pure luck, not by targeted searches.  Professors spend little time at the lab bench due to the skyscraper of paperwork required for modern research grants.

At Labmeeting, we are well on our way to solving all of these problems and many more.  Science operates best when people can develop good ideas securely and communicate good ideas rapidly.  We created a platform to do both like nobody has ever seen before.

Thousands of biomedical scientists, both at top US Universities and smaller ones around the world, already use and love Labmeeting.  We want to help all researchers communicate and work more efficiently so that they can focus on what they do best: science.

]]>
Log Reader 3000 /blog/2008/11/21/log-reader-3000/ /blog/2008/11/21/log-reader-3000/#comments Fri, 21 Nov 2008 04:33:00 Joseph Perla /blog/2008/11/21/log-reader-3000/

I wanted to show off another python ]]>

I wanted to show off another python script today.  I think it’s pretty cool.  It’s kind of like a very rudimentary version of something you might see in Iron Man.  And, of course, anything in Iron Man is cool.

I dub it Log Reader 3000.  It’s purpose?  It helps me monitor logs.  How?  Well, sometimes I need to follow a log in real time as it is written, but I can quickly get bored.  The log scrolls by endlessly while, very often, little new information spits itself out.  I can quickly lose focus, or at the very least, damage my vision after staring at a screen intently for extended periods.

Ideally, I want the log to simply flow through me, and if my subconscious notices something odd, then I can act on it.  If the log is read aloud to me, then I can work on other tasks and let my auditory memory and auditory processing take note of oddities on which I need to act.

So, I made a python script to read the log out to me as it is written. It is my first Python 2.6 script.  I take advantage of the new multiprocessing module built into the standard library.  I also use the open-source festival text-to-speech tool.

First, install festival.  sudo apt-get install festival in Ubuntu.  You probably want to set it up to work with ALSA or ESD sound.  By default, festival uses /dev/dsp, which means that you can’t use festival and any other program that uses audio (like Skype) at the same time.   Fortunately, and as usual, Ubuntu provides detailed, simple instructions to set up festival with ALSA: https://help.ubuntu.com/community/TextToSpeech .

Finally, just find an appropriate use case.  Note that most log monitoring applications would not be improved with Log Reader 3000.  If you just want to be notified of errors, you should have a program email you when an error appears in a log.  If you want to understand the log output of a program that has already run, understand that Log Reader 3000 is meant for live-running programs.  Yes, Log Reader 3000 can be modified to read any text file line-by-line.  But, you will find that reading ends up being much faster than listening to a slow automated voice, so I recommend that you just try to skim a completed program’s output with VIM.

So then why ever use Log Reader 3000?  It is useful for applications which fit all of the following criteria:

  1. you want to monitor a live running program
  2. and the debugging information is nuanced and you need a human to interpret it (i.e. it cannot be filtered programmatically) and/or you want to be able to intervene while the program is running to keep it doing what it ought to be doing in real time.

Applications:

  • Say that you are spidering the web, and what the spider should and should not be spidering is not yet well-defined, but a human knows, then the Log Reader 3000 can read aloud where the spider is, and the human can correct course as he or she notices the spider going astray.
  • Or, say that you are working on some kind of artificial intelligence.  Perhaps, the AI program can reason aloud and a human can correct or redirect the machine’s reasoning as it goes along.  I have no idea how or why an AI would do that.
  • Maybe you want to protect against bot attacks, but your aggressor is particularly clever and seems to avoid looking like a bot in all of the obvious ways.  You can pipe the output of your log into Log Reader 3000 and notice new kinds of suspicious patterns live while reclining in your chair or surfing the web.
  • You run a securities trading program.  You have numerous checks and double-checks to ensure that everything works correctly.  Nevertheless, you need to have a human monitoring the system as a whole continuously anyway, so you have Log Reader 3000 read aloud total portfolio value, or live trades, or trading efficiency, or fast-moving securities, or all of the above.
  • The lobby of your startup has a TV screen with graphs of user growth and interaction on the site.  You want to increase the coolness factor by having a computer voice read aloud some of the searches or conversations happening on your site live.
  • You make a living by selling cool techy art projects which blend absurdity with electronics.  You read aloud live google searches, or live wikipedia edits, or inane YouTube comments out of what looks like a spinning vinyl record.  Passersby whisper of your genius.

Once you have the application, just tail -f the log, parse out the parts you want the log reader to read (you can use awk for that, for example, or maybe a simple python script), and pipe that into the Log Reader 3000.

tail -f output.log | awk “{ print $1 }” | ./log_reader_3000.py

How does Log Reader 3000 work?  The main process reads in one line at a time.  As it reads in each line from stdin, it sends it to the processing queue.  The child process reads the last item in the queue (it discards the items at the top of the queue because those are old and we need to catch up with the latest output line) and then calls a function to say() the line.  The say() function simply uses the subprocess module to call festival in a separate process and then blocks until it is done saying it aloud.

Because having a computer voice read aloud a sentence takes a while, the log probably outputs many more lines than can be read aloud.  That is why a multiprocess queue is needed, and that is why Log Reader 3000 only reads out the most recent line which has been output, which is why it is most useful for specific applications.

Here is the script, log_reader_3000.py:

#!/usr/bin/env python2.6
import sys
import subprocess
from multiprocessing import Process, Queue
def say(line):
    say = '(SayText "%s")' % line
    echo = subprocess.Popen(['echo', say], stdout=subprocess.PIPE)
    subprocess.call(['festival'], stdin=echo.stdout)
def listen_to_lines(queue):
    line = 'I am Log Reader 3000.  The world is beautiful.'
    while True:
        while not queue.empty():
            line = queue.get()
        say(line)
queue = Queue()
p = Process(target=listen_to_lines, args=(queue,))
p.start()
while True:
    line = sys.stdin.readline()
    sys.stdout.write(line)
    queue.put(line)
]]>
A Clean Python Shell Script /blog/2008/11/17/a-clean-python-shell-script/ /blog/2008/11/17/a-clean-python-shell-script/#comments Mon, 17 Nov 2008 23:00:00 Joseph Perla /blog/2008/11/17/a-clean-python-shell-script/

Guido van Rossum, the creator of Guido van Rossum, the creator of Python, recently wrote a post on his blog about how Python makes great shell scripts, even (especially?) compared to shell scripts traditionally created in Bash and using purely shell commands.

Guido is absolutely correct.  Shell scripts birth themselves painfully from my fingertips.  Bash’s kludgy syntax irks my orderly sensibilities.  Typos frequent my unreadable scripts.  iffi?  Who invented this?

On the other hand, Python sticks to just a handful of language constructs, so the language does not force me to google how to create else statement every time I need to do it.  Python just makes sense.

One of the comments asks if Guido can show him some “really beautiful” python shell scripts.  I don’t mean to brag, and by no means do I think that my scripts in particular invite the light of the heavens to shine upon them, but I think I follow PEP 8 fairly closely and I pay attention to the brevity and clarity of my language.  I find that I can quickly debug my scripts because of their transparency at run-time and their concise self-annotating source code.

So, below I show a script which I call merge_branch.py. Do

chmod +x merge_branch.py 

so that you can run it from the command line with a simple ./merge_branch.py.  I alias it in ~/.bashrc.

alias mb='../path/to/merge_branch.py'

The script simplifies what I would have to do manually in git many times a day.  You see, git exemplifies a great version control system for keeping track of source code.  I create branches instantly.  This encourages me to work on bug fixes and new features separate from the main code base.  As others make changes, I can easily integrate their changes by merging the changed branch into my branch.  Git’s merge algorithm embarrasses any other I have ever used.  Some of Subversion’s merges still haunt my nightmares to this day.

So, git rocks.  Unfortunately, conflicts sometimes do occur.  So, the proper procedure for merging a branch needs to be followed carefully.  People are bad at doing things carefully. That’s okay.  We should spend more time on making mistakes being creative.  That is why we invented computers to do work for us.

For best results, merge the latest changes people made to master into your branch as often as possible.  Small changes incrementally will probably mean small merge fixes.  One big change will probably cause you major pains.  So, merge from master into your branch often.

If you use GitHub or another central repository with a number of other people, then you must do a number of things.  First, make sure that all the commits that you wanted to make are commited to your branch and that you didn’t leave any files out that you have not explicitly git-ignored.  This happens a lot in SVN and Git if you are not careful, and it is the greatest source of frustration for anyone who uses a system like this.  To human is to err, c’est la vie.  Then, git-checkout master.  Make sure that origin has the latest changes from your master.  Then git-pull the latest changes form origin (github) into master.  Then git-checkout your branch again.  Then git-merge master into your branch.  If there are any errors, fix them and commit, otherwise you are done.

Also, when you complete all the changes in your branch and all the tests pass, then you need to git-merge your branch into master and git-push it back up to origin (possibly github).  You need to follow the procedure above to ensure the latest master changes are included in your branch (preferably before you run the tests).  Then, you check out master, git-merge master into the branch (this will be clean since it should just be a fast forward because you already have the latest master).  git-push the changes to origin.  Finally, delete the branch that you just completed.

This tedium rotted my brain for weeks.  Finally, I resolved to write a script to solve the tedious parts, but bring possible errors to my attention if they occur.

Please let me describe to you a few features of the script.  First, I try to follow PEP 8 as much as I can.  I have read it at least times; you should too. Also, recite the Zen of Python every night before you go to bed.

Notice how I start the script with a shebang line which says /usr/bin/env python, the preferred way to start Python since it is most flexible.  For example, I can use Python 2.6, or my own local version of Python.

I use the logging module which is part of Python’s very large standard library.  Logging gives you so much for free.  For example, instead of commenting out print statements, just change the default logging level threshold.  Always use the logging module instead of using print for everything.  Always.  It’s as easy as import logging; logging.error(’…’).  Also, the logging.basicConfig(…) I use here is the same one I use everywhere.  Logging the time that a message appeared saves hours and hours when I debug long-running scripts.

Use the optparse module in every Python shell script you write (getopt is too weak and will end up being much, much less simple by the end of a non-trivial program).  Again, you get so much for free, like a -h help command.  The documentation for optparse explains how to do everything in detail.  Make sure you set the usage parameter.  Also, make sure you call parser.error() for input option errors instead of raising an exception yourself.

Write utility functions.  Use the power and simplicity of Python to your favor.  Here, I use call_command().  I use it throughout the script and it makes the code so clean and clear.

Finally, I like to put the main() function of scripts at the top.  That makes the most sense to me.  If I open a file, I want to instantly read what it does, not read what its utility functions do.  I put the utility functions below.  Of course, at the bottom, after everything else has loaded, I place the if __name__=”__main__” code and then call main().   This way, I can import this as a module (in, for example, py.test or iPython) to test the utility functions without running the actual script.  (warning:  Do not put anything except the call to main() at the bottom.  Otherwise, you may not realize under what circumstances you call main() and with what parameters.)

Here is the script:

#!/usr/bin/env python
import os
import re
import subprocess
import logging
import optparse

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(levelname)s %(message)s')

def main():
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser(usage)
    parser.add_option("-m", "--merge-master", dest="merge_master",
                    action="store_true",
                    default=False,
                    help="Merges the latest master into the current branch")
    parser.add_option("-B", "--merge-branch", dest="merge_branch",
                    action="store_true",
                    default=False,
                    help="Merge the current branch into master; forces -m")
    options, args = parser.parse_args()

    if not options.merge_master and not options.merge_branch:
        parser.error('Must choose one-- try -m or -B')

    # Merging branch requires latest merged master
    if options.merge_branch:
        options.merge_master = True

    if options.merge_master:
        output,_ = call_command('git status')
        match = re.search('# On branch ([^\s]*)', output)
        branch = None
        if match is None:
            raise Exception('Could not get status')
        elif match.group(1) == 'master':
            raise Exception('You must be in the branch that you want to merge, not master')
        else:
            branch = match.group(1)
            logging.info('In branch %s' % branch)

        if output.endswith('nothing to commit (working directory clean)\n'):
            logging.info('Directory clean in branch: %s' % branch)
        else:
            raise Exception('Directory not clean, must commit:\n%s' % output)

        logging.info('Switching to master branch')
        output,_ = call_command('git checkout master')

        output,_ = call_command('git pull')
        logging.info('Pulled latest changes from origin into master')
        logging.info('Ensuring master has the latest changes')
        output,_ = call_command('git pull')
        if 'up-to-date' not in output:
            raise Exception('Local copy was not up to date:\n%s' % output)
        else:
            logging.info('Local copy up to date')

        logging.info('Switching back to branch: %s' % branch)
        output,_ = call_command('git checkout %s' % branch)

        output,_ = call_command('git merge master')
        logging.info('Merged latest master changes into branch: %s' % branch)
        logging.info('Ensuring latest master changes in branch: %s' % branch)
        output,_ = call_command('git merge master')
        if 'up-to-date' not in output:
            raise Exception('Branch %s not up to date:\n%s' % (branch, output))
        else:
            logging.info('Branch %s up to date' % branch)

        logging.info('Successfully merged master into branch %s' % branch)

    if options.merge_branch:
        logging.info('Switching to master branch')
        output,_ = call_command('git checkout master')

        output,_ = call_command('git merge %s' % branch)
        logging.info('Merged into master latest branch changes: %s' % branch)

        output,_ = call_command('git branch -d %s' % branch)
        logging.info('Deleted safely branch: %s' % branch)

        call_command('git push')
        logging.info('Pushed master up to origin')
        logging.info('Ensuring that origin has latest master')
        stdout,stderr = call_command('git push')
        if stderr == 'Everything up-to-date\n':
            logging.info('Remote repository up to date: %s' % branch)
        else:
            raise Exception('Remote repository not up to date:\n%s' % output)

        logging.info('Successfully merged branch %s into master and pushed to origin' % branch )
def call_command(command):
    process = subprocess.Popen(command.split(' '),
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    return process.communicate()
if __name__ == "__main__":
    main()
]]>
Mark Zuckerberg Wears My Sandals /blog/2008/11/15/mark-zuckerberg-wears-my-sandals/ /blog/2008/11/15/mark-zuckerberg-wears-my-sandals/#comments Sat, 15 Nov 2008 04:15:00 Joseph Perla /blog/2008/11/15/mark-zuckerberg-wears-my-sandals/

mark zuckerberg

Valleywag reports that Facebook still has not started firing employees as every other Silicon Valley startup has. But, the most interesting part of the article lies hidden within the picture.

Mark Zuckerberg (the billionaire) wears the same sandals I do: old-school Adidas sandals .  I don’t know anyone else who wears them.

I just bought these Rainbows in Miami which are pretty nice.

]]>
Ruby is a Ghetto /blog/2008/10/26/ruby-is-a-ghetto/ /blog/2008/10/26/ruby-is-a-ghetto/#comments Sun, 26 Oct 2008 23:14:00 Joseph Perla /blog/2008/10/26/ruby-is-a-ghetto/

Zed Shaw (the creator of Mongrel) not long ago des ]]>

Zed Shaw (the creator of Mongrel) not long ago described how the Ruby on Rails community is a ghetto.

Working with both Python and Ruby now, I learn every day how much Ruby, too, is a ghetto.  Nobody documents anything (e.g. solr-ruby).  The few projects that have documentation do not document clearly or completely (Rails…).

Moreover, take Ruby’s standard package management system: rubygems.  A simple gem install uses up 600+ MB of RAM on my SliceHost machine.  But again, lack of documentation scars this project even more deeply.  Take a look at its Frequenty Asked Questions Page:

[I lost my internet connection while composing the answer to this question. Unfortunately, I now no longer recall what I intended to write. The answer (or at least part of the answer) is buried deep in the RubyGems mail archive. I’ll try to update this after a bit of research. Sorry for leaving this question hanging.]

Seriously, “I now no longer recall what I intended to write.”  For how many months has this lunacy been online?  Ruby is a ghetto.

]]>
Redesigned the Blog /blog/2008/09/18/redesigned-the-blog/ /blog/2008/09/18/redesigned-the-blog/#comments Thu, 18 Sep 2008 20:43:00 Joseph Perla /blog/2008/09/18/redesigned-the-blog/

Blog redesign now enabled. Looks cleaner, fresher. Plus, it has more stuff to do in the sidebar!

Here’s what the site looks like as of today:

]]>
Switch windows quickly /blog/2008/09/18/switch-windows-quickly/ /blog/2008/09/18/switch-windows-quickly/#comments Thu, 18 Sep 2008 08:19:00 Joseph Perla /blog/2008/09/18/switch-windows-quickly/

I want to avoid RSI.  So, I want to use t ]]>

I want to avoid RSI.  So, I want to use the mouse as little as I possibly can while I focus on my keyboard.  Unfortunately, alt+tabbing between windows takes far too long and annoys me with how much I have to think to move between the windows.

I often have several windows open.  I want to switch between them very quickly.  So, I created a program using Python and Xlib that generates another program.

The program moves my mouse automatically to a specific location and then clicks automatically.

The program also creates a keyboard shortcut in Gnome.  So, I can type something like Alt+q which calls the program above, moves the mouse to a specific location, and then clicks.

Finally, the program also generates a program which, when called, opens up many windows at specific locations in a grid:

If I combine all of these programs, I can focus between windows very easily. I can move the mouse between 12 spots in a 4×3 grid using the keyboard letters Q,W,E,R, etc like below:

To move to the Top-Left window, I hit Alt+q, which moves my mouse to the top left and clicks, focusing the top-left window.  To move to the bottom right, I press Alt+v, then the mouse moves to the bottom right and clicks, focusing into the bottom right window.

Basically, when I’m programming, I never have to move to my mouse to switch between windows very quickly.  I can open up 12 files at once, and switch between them swiftly and deftly.  When you work on a large application, this becomes very useful.

I’ve open-sourced the program here: http://github.com/jperla/mouse-focus-shortcuts/tree/master .

]]>