|
nuthole.com
"bare and phalanged"
contact: subscribe: follow me on twitter: 2007 |
|
|
2007 12 07 - Fri wake up, patriotsposted by jack at 04:42 CET in / politics
I've been so busy (and having so much fun with) work lately, that I've been neglecting politics to some extent, especially here. In fact, I now see that my latest entry filed under politics was 19 months ago!
Well, time to catch up. Here's an interview with Naomi Wolf, discussing topics from her latest book, The End of America. In this interview, she describes having discerned 10 steps that tyrants of the 20th century used to subvert democratic systems in their own countries, converting them to dictatorships. It shouldn't surprise anyone to learn that the piratical crew at the helm of the U.S. government have already implemented a number of these items, with more on the way.
Near the end she mentions the American Freedom Campaign, a bi-partisan movement determined to take away the powers that Bush has grabbed for himself, and restore the checks and balances described by the constitution. This seems like a good thing to me.
Really, it's hard for me to understand head-in-the-sand republicans who willfully ignore the power imbalance that the current administration has created, giving so much power to the executive branch. It works out well for republicans as long as there's a republican president, but what if (gasp) a democrat actually wins the presidency the next time? Do they want a democratic president having the same kinds of powers that Bush now has, but applying them towards the progressive goals they so despise? Or is there a unspoken understanding amongst this crowd that things have been sufficiently "fixed" that there simply cannot be anything but republicans in the presidency, come hell or high water?
(via Giles)
|
|||||||||||||||||||||||||||||||||||||||||||||||||
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
Yesterday I installed Apple's new Logic Studio. The system I was installing it on was already crowded, with the first four Jam Packs among other things, and I only had about 11 gigs free. To top it off, the Jam Packs weren't properly installed; I had manually copied them from an older machine, but in a slightly non-standard location, without the .pkg files etc, so the Logic Studio installer couldn't see them and wanted to do a fresh install of the new versions included with Logic Studio.
So I figured I'd wipe out the old Jam Packs manually, and let Logic reinstall them, and hope I'd have room for all the parts of Logic I wanted. I stumbled across this thread on Apple's support site, which mentioned that the new versions of the Jam Packs in Logic Studio now have audio saved in compressed (but lossless) format, so they're a bit smaller. Cool!
So, I wiped out my old Jam Packs, and installed most of Logic Studio, including all software and all 5 Jam Packs, but not the new extra audio content (which as far as I can tell seems to be intended mostly for soundtrack use). After installing all that, I ended up with 17 gigs of free space! Installing the new version, with more stuff, saved me 6 gigs! Woot!
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
There seems to be a sort of mystique around the concept of metaprogramming, but in Ruby it's really not mystical at all. It's all about leveraging a few existing methods in smart ways to let you eliminate boring code. This sort of thing is possible in my "native language" of Objective-C, but in Ruby it turns out to be even easier.
Today I'm going to talk about how to use the method_missing method to eliminate repetitive boilerplate code. method_missing is Ruby's fallback strategy for unresolvable method names encountered at runtime. If you try to call a non-existent method on any object, the Ruby runtime will instead call method_missing on that object; The default behavior of this method is to raise an exception, but we can override it to do smart things based on the method name.
The Rails application I'm working on has a role-based permissions scheme, with a ManagementRole model that sits between User and Program models, allowing us to define roles that a User can have relative to a given Program, which in turn constrain what they're allowed to do with the application. These roles are expressed concretely as simple subclasses of ManagementRole, with names like RoleSearchMembers and RoleCreateMemberships. Up until recently, checking whether a User were allowed to perform certain tasks within a Program consisted of calling one of several nearly-identical class methods defined on ManagementRole, such as these:
def self.allow_search_members?(user, program)
return User.is_administrator?(user) ||
self.program_role_exists?(user, program, "RoleSearchMembers")
end
def self.allow_create_memberships?(user, program)
return User.is_administrator?(user) ||
self.program_role_exists?(user, program, "RoleCreateMemberships")
end
# etc
# the program_role_exists? method, not listed here, simply checks
# for the existence of a matching ManagementRole object
As you can see, this is extremely repetitive, and adding new types of permissions means adding new, nearly-identical methods. As of now there are 18 methods like this, and that number will just go up in the future, leading to even more boilerplate code. Where will this madness end?
Providing a simple definition for method_missing in the same class lets me eliminate all those 18 methods, and will automatically deal with any new ManagementRole subclasses. It looks like this:
# instead of a bunch of allow_xxx_xxx_xxx? methods that differ only slightly,
# we just catch all such calls here.
def self.method_missing(method_id, *args)
if match = /allow_([_a-zA-Z]\w*)\?/.match(method_id.to_s) and args.size==2
return User.is_administrator?(args[0]) ||
self.program_role_exists?(args[0], args[1], "Role#{match[1].camelize}")
else
super
end
end
The first thing this does is examine the method and the argument list, to determine if it looks like the kind of method we are trying to replace. If the method name looks anything like "allow_xxx_yyy_zzz?", and if there are exactly 2 arguments, then we'll do something interesting. Otherwise, we'll just call super and let the parent class deal with it.
In the "interesting" case, we simply perform the same checks we did before to determine whether we return true or false, but now we're using indexed values from the args array, and constructing the string naming the MangementRole subclass by using the result of the earlier regexp match. Voila!
Of course, software development being what it is, any time you revisit an old design to try to improve it, the act of improving it can lead you to discover new, further improvements. While writing this, I realized something that would have avoided all this boilerplate code, and the metaprogramming it led to, in the first place: Instead of asking the ManagementRole class explicitly about each of these permissions, I'll be better off writing a single method called allow? in the ManagementRole class, which will do a lookup based on the recipient's class-name, e.g. RoleSearchMembers, RoleCreateMemberships. And then instead of calling ManagementRole.allow_search_members?(u,p) , I will call RoleSearchMembers.allow?(u,p). That will lead to even less code than the metaprogramming version, and less code is always better code. I haven't written it yet, but it'll probably look something like this:
def self.allow?(user, program)
return User.is_administrator?(user) ||
self.find_by_user_and_program(user, program)
end
So this problem, with its metaprogramming-to-the-rescue solution, turned out to be easily solvable with more traditional object-orientation, but that's OK! Hopefully this post will be helpful anyway, for someone else whose problem doesn't have the same easy solution that mine turned out to have...
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
| permalink | digg slashdot del.icio.us | 1 comment (add more!) |
sudo port install freetype sudo port install ghostscript sudo port install imagemagick #sudo port install graphicsmagick sudo gem install rmagickSomewhere I got the idea to also install graphicsmagick after imagemagick, but for some reason port doesn't seem to be able to find the package; It tries a few dozen sites and fails, so I commented it out above, but feel free to try it yourself. But no matter, it seems to not be necessary; I can now create images, render text, write them to disk, etc. On Ubuntu (6.10), the incantation is different, but even simpler (via EXPRESSICA:
sudo apt-get install imagemagick sudo apt-get install libmagick9-dev ruby1.8-dev sudo gem install rmagickThe only caveat is that if you're running without swap space and have less than a couple hundred megs of free RAM (e.g. on a VPS server) you may need to stop some of your processes before attempting that last line, or you'll get this not-so-helpful set of errors after it runs for a while, consumes all available RAM, and subsequently crashes:
Building native extensions. This could take a while...
ERROR: While executing gem ... (Gem::Installer::ExtensionBuildError)
ERROR: Failed to build gem native extension.
Hopefully this will save someone a few hours.
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
grep "^DEPRECATION WARNING:" development.log | awk '{print $3, $4, $5, ":", $NF}' | sort | uniq
This gives me output something like this:
@params is deprecated! : script/../config/../app/views/waiting_messages/prepare_reply.rhtml:9)
@request is deprecated! : ./script/../config/../app/controllers/account_controller.rb:10)
You called render('new_member_in_program'), : /opt/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/li [...]
end_form_tag is deprecated : script/../config/../app/views/members/bulknew.rhtml:10)
find_all is deprecated : (irb):3)
start_form_tag is deprecated : script/../config/../app/views/members/bulknew.rhtml:2)
It's not perfect; I'm missing some useful info from some of the lines (such as the 'You called render...') that I'll have to go back and pick over. But in broad strokes, it gives me a fairly concise list of some things that need to be cleaned up.
However, that one-liner is fairly meaty. Who wants to remember that, or make an alias for it, or need to look it up? Yuck.
How about a rake task? I've never written one before, but everyone's always raving about how simple it is, so I figured I'd go ahead. Hopefully this helps show how simple it is. While I'm at it, I'll go ahead and include the full text of the warning (except for the redundant "DEPRECATION WARNING" at the beginning, since we already know we're looking for that) instead of truncating it like I did in my awk-based one-liner.
Here it is:
namespace :utils do
desc "List deprecation warnings in development log"
task :find_deprecated do
File.open('log/development.log') do |file|
lines = file.select {|line| line =~ /^DEPRECATION WARNING:/}
lines.sort.uniq.each {|line| puts line.split('DEPRECATION WARNING: ')[1]}
end
end
end
Put that in a file called utils.rake inside your lib/tasks directory, and call it by typing rake utils:find_deprecated, and you'll get something like this (lines chomped for presentation purposes):
@params is deprecated! Call params.[] instead of @params.[]. Args: [:response_text] See http://www. [...]
@request is deprecated! Call request.accepts instead of @request.accepts. Args: [] See http://www.r [...]
You called render('new_member_in_program'), which is a deprecated API call. Instead you use render : [...]
end_form_tag is deprecated and will be removed from Rails 2.0 See http://www.rubyonrails.org/deprec [...]
find_all is deprecated and will be removed from Rails 2.0 (use find(:all, ...)) See http://www.ruby [...]
start_form_tag is deprecated and will be removed from Rails 2.0 (use form_tag instead) See http://w [...]
There are certainly improvements that could be made, such as adding the ability to search test.log and production.log as well, but this'll do for now.
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
Hot on the heels of the release of Your Myspace Page, we at Band of None have now released yet another single, Hoffburger. Download the mp3 with the clicking action here, or use the fun thingy below to listen to it immediately:
Hoffburger is inspired, as you may imagine, by David Hasselhoff's drunken hamburger-eating escapade, captured on video by his daughter and reported widely throughout all media. Band of None considers it an honor (and a duty) to take that feel-bad viral video of the late spring and turn it into the feel-good hit of the summer.
Sing it with me! Hoffburger with extra cheese!
| permalink | digg slashdot del.icio.us | 1 comment (add more!) |
After much hemming and hawing, the second single from Band of None is hereby foisted upon the world. It's called Your Myspace Page, and you can download it here or listen to it with the following gadget:
This is a pretty big departure from the previous single. I don't know what, if anything, this implies about Band of None's "musical direction", but time will tell. Meanwhile, comments are welcome!
| permalink | digg slashdot del.icio.us | 1 comment (add more!) |
Many of you have heard of web application deployment using the LAMP set of technologies that came into vogue a few years ago. Later, MARS was thrown about as a four-letter acronym to describe a Rails-centric deployment scheme, but some of the choices (Solaris? Apache? Please.) leave me cold.
So, without further ado, let me introduce you to RUMP:
Why these choices? Well, Rails goes without saying (if you aren't interested in Rails, then RUMP is not for you); Ubuntu because it offers a lightweight server config with a package system that is even better than Debian's; Mongrel because it's currently the best web server targetted at Ruby application deployment and is getting better all the time; and Postgresql because MySQL, despite all the good it's done for the world, still falls behind on a number of features.
To help get you started, what follows is a reasonably accurate description of what I went through to get my RUMP in gear. I had occasion to do this a couple times within a few days a little while ago, and kept some reasonably complete notes as I went along. Hopefully this will help others experience the satisfaction of a nice, fit RUMP.
Wherever possible, I've tried to find the simplest configuration that works. Of course each component can be installed and configured in a variety of ways, and YMMV. For what it's worth, the following is what seems to be working well for me.
I started off with an empty image installed by my hosting company of choice. This was a bare-bones Ubuntu server install, containing a single root account with ssh enabled, and pretty much nothing else.
First, log in to your new system and use adduser to create a user named "deploy" with homedir /home/deploy, and then run visudo to let the "deploy" user run commands with sudo. Then log in as "deploy" and do the rest of this.
Start off with editing /etc/apt/sources.list to enable some packages:
deb http://se.archive.ubuntu.com/ubuntu/ edgy main restricted deb-src http://se.archive.ubuntu.com/ubuntu/ edgy main restricted ## Major bug fix updates produced after the final release of the ## distribution. deb http://se.archive.ubuntu.com/ubuntu/ edgy-updates main restricted deb-src http://se.archive.ubuntu.com/ubuntu/ edgy-updates main restricted ## Uncomment the following two lines to add software from the 'universe' ## repository. ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to ## your rights to use the software. Also, please note that software in ## universe WILL NOT receive any review or updates from the Ubuntu security ## team. deb http://se.archive.ubuntu.com/ubuntu/ edgy universe # deb-src http://se.archive.ubuntu.com/ubuntu/ edgy universe ## Uncomment the following two lines to add software from the 'backports' ## repository. ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. deb http://se.archive.ubuntu.com/ubuntu/ edgy-backports main restricted universe multiverse # deb-src http://se.archive.ubuntu.com/ubuntu/ edgy-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu edgy-security main restricted deb-src http://security.ubuntu.com/ubuntu edgy-security main restricted # deb http://security.ubuntu.com/ubuntu edgy-security universe # deb-src http://security.ubuntu.com/ubuntu edgy-security universe
After that, run sudo apt-get update to get the latest package definitions, and then start installing:
Some common tools you will surely need at some point:
sudo apt-get install man curl wget
and some dev tools for later compilation steps
sudo aptitude install build-essential
Time for ruby:
sudo apt-get install ruby ri rdoc irb ri1.8 ruby1.8-dev libzlib-ruby zlib1g
and then postgres:
sudo apt-get install postgresql-8.2 sudo apt-get install postgres82-dev
Now we'll configure postgres for our purposes. Creating a role with the same name as the user we're running with makes everything a little easier:
sudo -u postgres createdb NAME_OF_YOUR_APP_HERE_production sudo -u postgres createuser -P Enter name of role to add: deploy Enter password for new role: Enter it again: Shall the new role be a superuser? (y/n) n Shall the new role be allowed to create databases? (y/n) y Shall the new role be allowed to create more new roles? (y/n) nafter that you should be able to do execute
psql NAME_OF_YOUR_APP_HERE_production as the deploy user and get right in.
One piece of the puzzle that didn't quite make it into the RUMP moniker is pound, a handy reverse-DNS and load-balancer that fronts for our multiple mongrels. Install it thusly:
sudo apt-get install pound sudo vi /etc/default/pound
setting startup=1 in there, and then:
sudo vi /etc/pound/pound.cfg
making it something like this:
## Minimal sample pound.cfg
##
## see pound(8) for details
######################################################################
## global options:
User "www-data"
Group "www-data"
#RootJail /chroot/pound
## allow PUT and DELETE also (by default only GET, POST and HEAD)?:
#ExtendedHTTP 0
#WebDAV 0
## Logging: (goes to syslog by default)
## 0 no logging
## 1 normal
## 2 extended
## 3 Apache-style (common log format)
LogLevel 1
## check backend every X secs:
Alive 30
## use hardware-accelleration card supported by openssl(1):
#SSLEngine <hw>
######################################################################
## listen, redirect and ... to:
## redirect all requests on port 8888 ("ListenHTTP") to the local webserver see "UrlGroup" below):
#ListenHTTP 127.0.0.1,8080
##
#UrlGroup ".*"
#BackEnd 127.0.0.1,80,1
#EndGroup
ListenHTTP
Address 0.0.0.0
Port 80
Service
BackEnd
Address 127.0.0.1
Port 8000
End
BackEnd
Address 127.0.0.1
Port 8001
End
BackEnd
Address 127.0.0.1
Port 8002
End
Session
Type COOKIE
TTL 900
ID "_myappname_session_id"
End
End
End
That sets us up with pound listening on port 80, transferring the request to one of our three mongrel instances (see Mongrel section). Note the Session section, which may help keep things sorted out for some Rails session schemes.
Now start pound, like this:
sudo /etc/init.d/pound start
Try to connect to the site with a browser. you should get a 503 error, and something like this in /var/log/syslog:
Mar 15 23:51:31 ubuntu pound: backend 127.0.0.1:8000 connect: Connection refused Mar 15 23:51:31 ubuntu pound: backend 127.0.0.1:8001 connect: Connection refused Mar 15 23:51:31 ubuntu pound: backend 127.0.0.1:8002 connect: Connection refused Mar 15 23:51:31 ubuntu pound: no back-end "GET / HTTP/1.1" from 123.123.123.123 Mar 15 23:51:31 ubuntu pound: no back-end "GET /favicon.ico HTTP/1.1" from 123.123.123.123
If you want to run subversion on this server, here's how to do it. If you are running subversion elsewhere and don't want to move it, skip this section.
sudo apt-get install subversion xinetd
Create a user that will own the repositories:
sudo adduser --system --no-create-home --home /var/svn --group --disabled-login svn
Create the directory that will hold the repositories:
sudo mkdir /var/svn sudo chown svn:svn /var/svn
Create file /etc/xinetd.d/svnserve with the following content, to autolaunch svn when it's called upon:
service svn
{
port = 3690
socket_type = stream
protocol = tcp
wait = no
user = svn
server = /usr/bin/svnserve
server_args = -i -r /var/svn
}
Restart xinetd so that svn will work
sudo /etc/init.d/xinetd restart
Create a test repository:
sudo -u svn svnadmin create /var/svn/testrepo
It should be possible to check out the repository and work on it:
svn co svn://localhost/testrepo
Assuming that worked, create the real repository for your project:
sudo -u svn svnadmin create /var/svn/myproject
Add a little security:
cd /var/svn/myproject/conf sudo vi svnserve.conf
Set up like this:
anon-access = none
auth-access = write
password-db = passwd
Create users for your remote username(s), and the local deploy user. This simplifies login for everyone, and makes it easier to spot changes that were committed from the production server! sudo vi passwd, making it look about like this:
# create a user/pw or two
joe_user = superseekrit
deploy = soopersecret
Now try to check out, it should demand a valid username/password:
svn co svn://localhost/myproject
Assuming you have an existing repository you'd like to bring over, go to the old server and do this:
svnadmin dump /path/to/repos > my_repos.dump gzip my_repos.dump scp my_repos.dump.gz deploy@my_ubuntu_host:/home/deploy
Then, on the new machine:
cd /home/deploy gunzip my_repos.dump.gz cd /var/svn sudo -u svn svnadmin load myproject < /home/deploy/my_repos.dump
Then make sure you can check it out:
cd /home/deploy # delete the myproject directory if it's there, then: svn co svn://localhost/myproject
Finally it's time to install rails etc. I've installed them with rubygems:
curl -O http://rubyforge.org/frs/download.php/17190/rubygems-0.9.2.tgz tar xzf rubygems-0.9.2.tgz ; cd rubygems-0.9.2 sudo ruby setup.rb sudo gem update
sudo gem install rails --include-dependencies sudo gem install postgres-pr sudo gem install mongrel
(ignore warnings about not being able to compile fastthread stuff, it's optional)
sudo gem install mongrel_cluster
If you're using BackgroundRb, you'll want these:
sudo gem install slave sudo gem install daemons
Very soon we'll have our app up and running. Create the database schema:
cd ~/myproject rake db:schema:load
Configure a little mongrel cluster:
cd ~/myproject mongrel_rails cluster::configure -p 8000 -N 3
As of this writing (May 2007), there's a small bug that will bite you if you're using both postgres and BackgroundRb. This is fixed in edge rails, but not yet in the released version. If you fall into this category, patch this file, as shown in http://dev.rubyonrails.org/attachment/ticket/7727/postgres_async_patch.diff:
sudo vi /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.2/lib/active_record/connection_adapters/postgresql_adapter.rb
Make sure you're always running in production on this machine by putting the following line into your .bashrc:
export RAILS_ENV=production
If you're using BackgroundRb, start the background processes:
cd ~/myproject script/backgroundrb start
Tail log/backgroundrb.log to make sure it looks OK. Something like:
20070316-13:56:35 (12680) Starting WorkerLogger 20070316-13:56:35 (12681) In ResultsWorker ...
At long last, start the mongrel cluster:
cd ~/myproject mongrel_rails cluster::start
At this point you should be able to smack your RUMP on port 80 and watch it wiggle!
In no particular order, here are some of the sites where I found information to put this all together:
http://wiki.rubyonrails.org/rails/pages/PostgreSQL/
http://happycodr.com/blog/view/13-putting-a-ruby-on-rails-application-into-production
http://mongrel.rubyforge.org/docs/pound.html
http://www.die.net/doc/linux/man/man8/pound.8.html
http://kurup.org/blog/tag/pound
http://ubuntuguide.org/wiki/Ubuntu_Edgy#How_to_install_Subversion_version_control_server_.28svnserve.29
http://blog.tupleshop.com/2006/7/8/deploying-rails-with-pound-in-front-of-mongrel-lighttpd-and-apache
That's it, I guess. I hope this proves helpful to someone. Feel free to leave feedback in the comments below!
| permalink | digg slashdot del.icio.us | 2 comments |
This "nigeria letter" (aka advance fee fraud) arrived in my inbox today:
From Mr. Abibe Yala
Dear Friend,
Very Urgent & Confidential
I know you do not know me before, I am Mr. Abibe Yala, younger brother to Mr. Kumba Yala the Ex-President of Guinea-Bissau. I got your contact information during my private search for a reliable and trustworthy person to carry out this urgent transaction with.
In view of the political crisis happening in my country today, I discovered that my brother Mr. Kumba is just trying to impose himself as a leader on his people who are not proud and satisfied with his past administration.
My brother sent me on a mission to South Africa to purchase fire arms which he intend to use in fighting a political war against his opponent so he can become the President again. I am not in support of his intensions but I do not have any other options than to do what he asked me. He provided the sum of US$22,100,000.00 (Twenty Two Million, One Hundred Thousand United States Dollars), which we brought into South Africa through diplomatic means. On getting to South Africa, I found out that the person (Mr. Jacob Zuma Ex- Vice President of South Africa) whom he instructed me to meet for the operation was under government probation for related crime and never want to get himself involved in such deals anymore. Since I have never been in support of my brother's intentions, I made up my mind never to go back to my country (Guinea-Bissau). I want to relocate immediately to a better country especially in the Europe or Asia, where I can have good investment with this money since I cannot stay here in Africa.
My reason of contacting you is that, I want you to support me as my foreign partner to move the funds and myself out of Africa as soon as possible. Presently, the funds are deposited as consignment with a depository company in Johannesburg South Africa for safekeeping. Why I am presently residing in West Africa for security reasons. I am willing to offer you 40% of the whole money for the inconveniences this will cost you and for your support in this transaction, while the remaining 60% will be for me to setup a profitable investment in your country through your guidance and directions.
As a matter of urgency, please do let me know if you can assist me in handling this transaction and the investment involve.
I anticipate your quick response.
Best Regards. Mr. Abibe Yala
The funny thing about this is how the story he tells to gain our sympathies is basically about how he wants to steal his brother's money and move to Europe. (See the bold bits above) Nice guy! Here's my response:
OK, I'm not stupid, I recognize a so-called "Nigeria letter" when I see one. You're obviously a con-man, and if that's what works for you, fine. I just hope you don't hurt anybody.
But anyway: You really need to work on your story. The way you describe it, it sounds like you're basically trying to steal $22 million from your brother. It makes you sound like a thief. Even with the part about your brother trying to become a dictator, etc. He's supposed to be your BROTHER for god's sake. He TRUSTED you with the money, right? And you respond with BETRAYAL? No one will sympathize with you about that.
Instead, you need to first make it seem that HE betrayed YOU. Say that your brother decided to kill you, and you're fleeing from his paramilitary death squads. Then maybe someone will say, "Wow, that poor Mr Yala, he needs my help". With the story you sent me, anyone too stupid too realize you're a con-man will probably just think, "This Abibe seems like a real asshole, trying to steal his brother's money".
--
// jack
// http://www.nuthole.com
| permalink | digg slashdot del.icio.us | 3 comments |
OK, i haven't posted in ages, but what can I say, life is keeping me busy. Recovering from a bit of minor surgery, followed by a long Easter break, followed by stomach flu, consumed the past few weeks.
But, more importantly than all that, I changed jobs at the end of January, and am now spending most of my work time (not to mention free time) programming with Ruby on Rails!
Ah, ruby. I've used python for a variety of side projects over the past few years, and I've long held the opinion that the two languages are largely equal, but in the short time since I started using ruby full-time, I'll admit that I've started acquiring a definite ruby bias. Things like ruby's block syntax, for instance, don't really have a corresponding language feature in python (at least, not anything quite as succinct).
Above all though, I'm mainly happy to be back in the world of dynamic languages. At my last job, I spent two years using C++, which taught me a lot: mainly that I don't like C++. In fact, I've started to get the feeling that using C++ at all, when other options are available, is in many cases a textbook example of premature optimization. You end up consuming lots more programmer-hours (which means greater expense, and later releases) chasing the chimera of an end-product which "runs faster" than a similar program written in a dynamic language would run. I put "runs faster" in quotes because in reality, most software is I/O-bound most of the time (either waiting for user input, or waiting for disk or network traffic), so the amount of time that your particular program is actually running is probably pretty small (and getting smaller as CPU speeds increase), no matter what language it's written in.
| permalink | digg slashdot del.icio.us | 1 comment (add more!) |
In London on business this week, first time in England. Here are some observations:
| permalink | digg slashdot del.icio.us | 5 comments |
I'm going to resist the urge to blog about the iPhone by instead blogging about a man named Jonathan Coulton, who could just as well be me in an alternate universe. Jonathan has a burgeoning career as an internet troubadour going on, with an impressive online song catalog, most of which turned up during a one-year period from September 2005 to September 2006, in which time he recorded a song a week, every week. Some people sure do have spare time!
I just heard about JoCo (as his fans call him) from my old friend and collaborator Paul Hagstrom about a week ago, and I have to tell you that the nuthole household has been revolutionized by the power of JoCo's music. Finally, music that both my children, my wife, and I all think is entertaining, catchy, and rewarding to listen to! JoCo's songs wander across all sorts of genres, and many of them are obvious homages to one well-known group or another; most of them are also very, very funny. Some of my personal faves:
And those are just the best 50% or so of what I've listened to SO FAR! I'm sure by the time I've listened to all the songs, I'll have over 30 "faves". Oh well.
So, why do I think that JoCo is actually an alternate version of myself? For one thing, similar dashing good looks:
|
<=> |
|
| separated at birth? | ||
Then, there are the startling similarities in our musical histories. A little background info is in order. Consider this narrative, which I did not write but which pretty well describes a chunk of my teen years:
I played quad drums in the high school marching band, which was fun, but did not attract any girls (even when I played my tender quad arrangement of "Flight of the Bumblebee"). I switched to guitar and wrote a series of sweet and sad songs about being a teenager and having a vague feeling of overwhelming sadness and sweetness. This worked only marginally better.
Now consider this direct quote from Jonathan's bio page:
I played snare drum in the high school marching band, which was fun, but did not attract any girls (even when I played my tender snare drum arrangement of "You've Got a Friend"). I switched to guitar and wrote a series of sweet and sad songs about being a teenager and having a vague feeling of overwhelming sadness and sweetness. This worked only marginally better.
The discerning reader may notice a number of similarities between these two life stories.
In any case, I hereby declare Jonathon Coulton an honorary Nuthole Boltmaster (the first ever!) and send the rest of you off on your way to pay tribute.
OK, obligatory bloggage about yesterday's big product announcement. I'll just say that iWant an iPhone. That's all I have to say about that for now.
| permalink | digg slashdot del.icio.us | 0 comments (why don't you write the first?) |
"Re: I Can't Believe I'm Not a Millionaire" by "Jin Ryu"