Tuesday, December 11, 2007

easier networking with hamachi

Sorry for the crappy formatting. Blogger is doing too much for me and thereby preventing me from doing what I want easily, css-wise. So I've hacked styles into spans manually for now. I'll get this fixed later.

I'm a big fan of hamachi. It's an easy way to access all of your machines whether they have a static IP address or not and it's probably more secure than setting something up with a dynamic IP address and port forwarding.

Hamachi is a "zero-config, centrally managed VPN" that allows you to setup networks and join them with some simple client software. I won't go into the details of how to install and set it up. There's a pretty good description for Mac OS X and for linux. Once you've gotten your machines logged into the same network and given each a name with hamachi set-nick, you should be able to get a list of machines in your virtual network with their names like this:


[aykroyd@entoto ~]$ hamachi get-nicks
Retrieving peers' nicknames ..
[aykroyd@entoto ~]$ hamachi list
* [aykroyd-network]
* 5.71.134.95 electric-monk 71.200.230.164:33000
* 5.22.143.15 entoto 192.160.10.100:52000


You can now use the first IP address to get to your other machines. This is pretty cool, but the obvious next step is to want those nicknames to be in your /etc/hosts file so that you can refer to them by their name rather than the IP. To that end, I've put together a python script that I run in my system crontab every 15 minutes.


refresh-hosts.py
#!/usr/local/bin/python

import re
import subprocess

start_comment = "### start auto-generated hamachi hosts"
end_comment = "### end auto-generated hamachi hosts"

start_pattern = re.compile("^" + start_comment)
end_pattern = re.compile("^" + end_comment)

hostfile = "/etc/hosts"
username = "aykroyd"

def command_output(cmd):
" Capture a command's standard output. "
import subprocess
return subprocess.Popen(cmd.split(), stdout=subprocess.PIPE).communicate()[0]

def get_hamachi_hosts():
" Returns a list of (ip,name) tuples. "
output = command_output("sudo -H -u " + username + " hamachi list")
hosts = list()
for line in output.splitlines():
values = line.split()
if len(values) == 4:
hosts.append((values[1], values[2]))
return hosts

def main():
# make sure that hamachi is started and logged in
status = subprocess.call(("sudo -H -u " + username + " hamachi start").split())
if status != 0 and status != 255:
print "ERROR: problem starting hamachi status " + str(status)
return 1

status = subprocess.call(("sudo -H -u " + username + " hamachi login").split())
if status != 0:
print "ERROR: problem logging into hamachi"
return 1

# populate the nicknames so that we can create host entries
status = subprocess.call(("sudo -H -u " + username + " hamachi get-nicks").split())
if status != 0:
print "ERROR: problem getting nicknames from hamachi"
return 1

buffer = ""
in_hamachi_hosts = False

file = open(hostfile)
for line in file.readlines():
if not in_hamachi_hosts and start_pattern.match(line) != None:
in_hamachi_hosts = True
elif in_hamachi_hosts and end_pattern.match(line) != None:
in_hamachi_hosts = False
elif not in_hamachi_hosts:
buffer += line

file.close()

buffer += start_comment + '\n'

hosts = get_hamachi_hosts()
for host in hosts:
buffer += host[0] + '\t' + host[1] + '\n'

buffer += end_comment + '\n'

file = open(hostfile, 'w')
file.write(buffer)

return 0

if __name__ == "__main__":
import sys
sys.exit(main())


This setup has made life a lot easier for me. I can always get to my server at home and scripts to rsync my development environment now can refer to just a host name, instead of a parameterized IP that I figure out at the time that I run it.

Monday, October 22, 2007

Torture and Complicity

I read and was outraged by Jane Mayer's article in the New Yorker detailing the C.I.A.'s torture program at black sites. It details a scientifically executed program of torture by agency professionals who, called upon to "get answers" by the administration, dusted off information gleaned from behavioral experiments in the 1950s to produce a chillingly exact system for breaking down human subjects.

The C.I.A.’s interrogation program is remarkable for its mechanistic aura. “It’s one of the most sophisticated, refined programs of torture ever,” an outside expert familiar with the protocol said. “At every stage, there was a rigid attention to detail. Procedure was adhered to almost to the letter. There was top-down quality control, and such a set routine that you get to the point where you know what each detainee is going to say, because you’ve heard it before. It was almost automated. People were utterly dehumanized. People fell apart. It was the intentional and systematic infliction of great suffering masquerading as a legal process. It is just chilling.”


The article goes on to detail how suspects were kidnapped, taken to black sites, and then subjected to sensory deprivation, nudity, prolonged periods of loud unbearable noise, hypothermic conditions, waterboarding (which is simulated drowning), among other things. Not surprisingly, those carrying out this program were concerned by the legal ramifications of their actions and so everything inflicted on the prisoners was noted and approved by the chain of command. However, the use of forms, approvals, and other trappings of the banality of corporate America, do not create a morally justifiable program of interrogation. Those who would defend the tactics employed by agency officials would be hard pressed to justify a system whose effects over the course of months are so severe that suicide is frequently attepted by prisoners who, lacking any better means of committing the act, have resorted to trying to beat themselves to death by banging their head aganst concrete walls to the point of unconsciousness.

I knew all of this and I felt sick. I read Frank Rich's excellent column in the New York Times, The ‘Good Germans’ Among Us, in which he points out that we are all complicit in our nation's flagrant abuses of human rights and international laws because we have done nothing. And yet, although the story was nothing new to me, watching Rendition's sadly accurate story of an innocent man abducted by American officials and taken to an unnamed African country to be tortured for information based on a possible link to an Egyptian terrorist this weekend still had a profound effect on me. Maybe it's a credit to the medium that it was so effective, but watching the movie did what none of my news tracking had done before. It made me ask the question, "What am I doing about it?" For some reason, I had never before quite realized that right this moment innocent men, wrongfully and illegally abducted by Americans without the benefit of due process, are shivering in cold darkness without any hope of seeing a familiar face again. All of my self-congratulatory awareness of the problem doesn't do shit for the guy who's slowly losing his mind being asked questions he can't answer by people whose payroll is financed in part by my tax dollars. It had always felt just a bit abstract.

Supporters of what is currently being called enhanced interrogation techniques like to conjure up our war of civilizations against an enemy that is different than any we have ever faced. The defense, and indeed the general motivation behind the program, is basically that terrorists can strike at any moment and as they demonstrated on September 11th have the ability to kill thousands of Americans. Given this new threat, we can't afford to leave any stone unturned in our hunt for terrorists. The immediacy of the danger means that we have to be willing to get tough, be real, and get answers anyway possible. According to this logic, if that means throwing out the Geneva Conventions and Habeus Corpus then that's what we'll do to prevent another catastrophic attack. For me, however, this line of reasoning runs into murky waters for several reasons. First, not everyone who's being subjected to this treatment is guilty. Second, torture has time and time again been shown to be ineffective. More importantly, regardless of the first two points, is this who we are as a people? As a nation, we are outraged by the winning at all costs mentality that leads to blood doping and corporate stock scandals. How then can we not be similarly outraged by an intelligence program founded in the same mentality, which as a consequence shows an absolute disregard for human rights?

At the beginning of the War On Terror, in a moment bit of free market inspiration, we offered cash rewards for tips on members of terrorist groups. This led equally innovative entrepreneurs in countries such as Pakistan to povide tips to U.S. officials about their rivals and enemies. Anger one of these budding free market enthusiasts and you might well find yourself in jail for alleged ties to extremist groups as the NPR show "This American Life" revealed in Habeus Schmabeas in 2006. This episode relates the stories of men who were wrongfully imprisoned in Guantanamo. In stark contrast with the administration's claims that the only people there are "the bad guys" a significant number of Guantanomo detainees are not terrorists. A Seton Hall study cited in the show found that less than 5% of the detainees studied were even captured by Americans on the battlefield. Less than 8% were characterized as al Qaeda fighters. This is not to say that everyone abducted by soldiers in the War On Terrorism are innocent, but how are we to tell? Of course, Guantanamo isn't the only American prison in which people have been unlawfully detained... there are also the black sites that we weren't supposed to know about. So how are we to tell if those were populated mostly by actual terrorists? Amnesty International keeps a list of some people who have wrongfully detained and there have been other cases of people wrongfully imprisoned such as that of Khalid El-Masri. But the complete lack of transparency makes it difficult to make an accurate assessment. The only thing that is clear from these cases is that there are a lot of innocent people being tortured and held indefinitely without reason and no recourse in a court of law.

One actual terrorist who we do know was detained is Khalid Shaikh Mohammed, who was without question a "bad guy". Unfortunately, even in the cases where we have the right guy, torture proves problematic as a means of gathering useful information. Aside from the obvious moral issues in play, it doesn't work. Repeatedly, seasoned interrogators have asserted that torture is an ineffective means of gathering actionable intelligence (Google it). As Mayer's notes in the New Yorker, Khalid Shake Mohammed's confession became confused by what he confessed to,

Perhaps under duress, he claimed involvement in thirty-one criminal plots—an improbable number, even for a high-level terrorist. Critics say that Mohammed’s case illustrates the cost of the C.I.A.’s desire for swift intelligence. Colonel Dwight Sullivan, the top defense lawyer at the Pentagon’s Office of Military Commissions, which is expected eventually to try Mohammed for war crimes, called his serial confessions “a textbook example of why we shouldn’t allow coercive methods.”


And since we are not only interrogating actual terrorists but also innocent men, torture often nets false confessions and fake intelligence designed to please the interrogator and end the pain. So we get inaccurate information from actual terrorists in addition to false confessions from innocent men.

Still, even if we were only capturing guilty men and torture was an effective means of gathering intelligence, I have to echo the fundamental question that Michael Moore asks us in regards to Health Care in Sicko: Who are we? Are we so seduced by our own rhetoric that we are blind to how we look to the rest of the world. In a country that we like to think of as a beacon for freedom, justice, and liberty for all, why are we so quick to throw these virtues out? How can we ignore the fundamental principles upon which our democracy was founded? How, after this display, can we look other countries in the eye and scold them for human rights abuses? We may not be the Chinese government in Tianemen square rolling over a protester with a tank, but how far from a global secret police are we? When Thomas Jefferson said, "Our liberty cannot be guarded but by the freedom of the press, nor that be limited without danger of losing it.", it wasn't a defense of the press's ability to publish trashy gossip columns and make personal attacks on public figures, these were side-effects. Jefferson knew that the only defense against tyranny in a democracy was a press which through its reporting kept the activities of the government transparent to its citizens. And so when our government abducts men in secret and creates secret policies advocating the use of torture at undisclosed locations, and inquiries into the government's practices are prevented by claims of endangering national security, where does that leave our democracy? Is it acceptable because most of the people imprisoned are not American? I hope not.

And all of this brings me back to the question that the movie left me with. What am I doing about this? I wondered if the movie alone was bringing more visibility to torture. So I plotted a report on Google Trends that shows over time the volume of search queries on different search terms: Abu Graihb, torture, and rendition.



As it shows, there was a huge increase in google searches on torture when the Abu Graihb scandal broke, but now although searches on rendition have increased since the release of the movie, there hasn't been a corresponding increase in searches on torture. So, although it's early, the movie doesn't seem to have led to increased interest in the torture issue, at least not on google. To add perspective to the search volumes, I plotted these against another search term to give some context about the level of interest in the torture scandal in the U.S.



And still, where do I go from here? Writing a blog posting isn't going to help. I may write to my congressman, but I'm fairly positive that that won't help. The best answer that I've had so far is donating and/or getting involved with Amnesty Internation, which has setup a campaign specifically for human right's abuses in the War On Terror. Unfortunately, reading through the campaign's website doesn't give me a huge amount of hope that there are many ideas of how to tackle the problem, inspiring as a virtual flotilla is. But I guess getting 30,000 people to board a fake flotilla is a start, and in digitally boarding it each one of those people has done more than I have so far.

Friday, September 14, 2007

The Five Ages of a TSM Office Manager

I wrote this last year about TSM. It became relevant again as I heard through the TSM grapevine that a new office manager was once again doing something about that fridge situation

1. The first age dawns on day one of TSM employment. Fresh faced, filled with enthusiasm and vigor, the new office manager arrives at Black Falcon Ave. in clean and pressed professional attire and is carted around to meet all of the employees. Names are forgotten and awkward pleasantries exchanged—at least that’s how it works in the development office. Still, optimism rules the hour and coffee is promptly brewed and setup with pleasant presentation in the kitchen.

2. The second age comes after the office manager has been on the job for a few weeks. Flushed with the success of the coffee and getting to know co-workers, the office manager sets about to make a difference. Accordingly, the refrigerator is soon cleaned.

3. In the third age, the small details that delighted colleagues have become drab. Routine is the by-word of this age and frankly the routine is getting old. The pleasantly presented coffee pots of earlier ages are forgotten, and the brewing of coffee mostly ceases. Coffee drinkers are left to fend for themselves. They do. No one expects coffee to be made for them. By this point, the office manager is starting to realize his or her true purpose: executive assistant.

4. In the fourth age of the office manager, the last age’s foreshadowings have come to rule the day. Coffee and refrigerator be damned, the office manager is solely responsible to the C and Vs. Cream shortages are rampant with the occasional water shortage. Murmurs echo in the hallway as co-workers speculate about the difficulty of keeping the coffee system running smoothly and noticing that all of the water jugs are empty.

5. The fifth and final age begins as the office manager realizes that in spite his or her aptitude for assisting executives, lowly co-workers circumvent his attempts to be a buffer by speaking directly to the executives. They don’t seem to understand the value of a middleman. They also still seem miffed by the lack of cream. Appearance starts to suffer and cigarette intake increases. The age ends with a mishandled airline ticket, one too many over-important interruptions of the CEO, or a simple disinterested resignation leading to early termination. Life remains largely the same and former co-workers of the once-upon-a-time Office Manager look forward to the cycle renewing itself again. The fridge is starting to get a little grimy, after all.

Tuesday, September 11, 2007

Record macro and Repeat

I've been slowly updating my IntelliJ keybindings so that unbound keys are bound in ways that my hands expect from using emacs. It's been giving me a lot of "wow that makes me happy" moments from doing stupid things like splitting windows or closing the current editor without leaving the keyboard. But what I really need now is a command that will let me repeat the next command n times as in emacs C-x [n] [command] syntax. I'm probably missing something and am too lazy to research this just yet, but it seems likes it makes macros much less powerful if you can't record a macro that does something to one line and then have it executed an arbitrary number of times.

Wednesday, August 22, 2007

Zen, C++, IDE reloaded

So I think my initial thought when I started this blog was that within some months of getting started, emacs would have proved itself; I would have gathered helpful hints from around the internet, consolidated them, and turned my emacs work environment into a killer, "have fun developing" environment. Not only that but I would be able to sleep easy at night knowing that I had done it all in emacs. If I was more into being green and less into cars, it would be the same sort of moral superiority that some people derive from owning and operating hybrids... or not. I may just be making random stabs at the hybrid crowd for no good reason, vainly trying to mask my frustration with my own failure to achieve a sense of 'holier-than-thouness'.

Perfect... 1 paragraph and I've insulted a bunch of (oops almost used do-gooders there) people trying to make a difference and help the planet and invented a word... gratuitously.

So I think where I was going with was that there's a lot of functionality in emacs and a lot of people get a lot out of it. I was just hoping to provide a friendly place to pick up some tips on maximizing its use targeted to people with similar (IDE-driven) sensibilities to mine. But, it won't be that way. So, I'll just walk through where I've been from there to now.

First, emacs. Built it for Mac OS X. And started playing. For one thing, it totally kicks ass at one of my basic requirements for work which is to be able to seamlessly develop on a remote machine via ssh. The baseline version TRAMP that ships with emacs 22 allows you to easily load files from a remote machine via ssh just by opening a file with the following syntax: '/ssh:user@machine:/path/to/file.cpp'. What's really nice about TRAMP (given our shady connection to the data center) is that it saves the file in /tmp and all autosaves are performed locally. Only when you make emacs save does it actually go over the network. And if you crash, TRAMP provides a way to restore those backed up files. It also caches directory information enough to make tab complete pretty useable even over a slow connection. The packaged version of TRAMP's only weakness was in building, grepping, and debugging. To do these, you had to use remote versions of the commands that were a bit buggy. However, if you patch to the latest version of TRAMP, the standard commands will 'just work' via ssh. So that's that. TRAMP is totally impressive.

CVS integration is also very good in emacs. It's another feature that seems to just work and is generally pretty good. Diffs and history for files are fairly easy to get at via windowed menus and I don't feel the need to perform those things via the keyboard.

I was also happy with emacs' editing capabilities and general configurability. It's satisfying to envy a simple editing command available in a different editor and just implement it. That said, if the feature you happen to be drooling over is continuous syntax checking, function completion, or god forbid refactoring support, you're in for a ride.

The easiest thing to do for continuous syntax checking seems to be fly-make... a package that finds the Makefile for your current file and runs it with the target check-syntax. With gcc you can set this target up to be something along the lines of: g++ -fsyntax-only $(INCLUDES) $(CPP_FILES) and the module will run in the background highlighting errors. It's pretty useful and really easy to use, but it doesn't always work. Fairly often it would alert me that it was going to crap out... and then it would crap out. At some point, I even got it to take down all of emacs (which incidentally, it how I found out about TRAMP's awesome recovery features).

So that's not great, but then in terms of completion of functions, etc. There's just very little out there. The best thing is the probably CEDET which is collection of .el files to help make emacs into an IDE. Personally, I couldn't get it to even byte-compile the .el files on my mac and even running on the non-compiled version, it didn't do much for me. I've heard similar reviews from friends who have played with it. It may get there. It's an exciting idea. It's opensource, so if you're inclined you can work on it... but it's not there.

Crap... I just checked the length of this in preview and it's a monster. How do people write short blogs?

All of this led me to Eclipse C++. It, too, is opensource, so I figured I could work on problems that I found. And it already supports C++ and better yet I even found a remote plugin for it. But there were some problems. For one, yes it supports C++ but it seems to get tripped up on templates fairly easily and sometimes is just unhappy and won't offer completion hints. It quickly became my opinion that no hints were better than occasional hints. It's just too painful when it frequently doesn't work but you expect it to. I think that ends up being slower than planning to not get help from the IDE. Next, eclipse seems to have been designed with the keyboard forgotten. Everything is mouse centric from navigation to code inspection. Furthermore, I couldn't find any code generation features written (e.g., getters/setters or constructor). Next the code base is way too massive to think about doing anything quickly (as opposed to emacs). Finally, the remote stuff sucked after using TRAMP.

So what now? This is a two part answer, I guess. Answer 1: IntelliJ in textmode. And here's why. It has a lot of the great editing capabilities that I got with emacs including incremental search and macros (although the latter are not as convenient as they are in emacs). It has better file navigation -- I don't think I can live without the cmd-n interface... seriously. It doesn't have remote file editing/building (for C++ obviously) -- but I have handled both of those problems with shell scripts that make it all seamless. It has nicer CVS integration -- it's diffs are great. It has built in syntax highlighting for C++. And it's fast and looks nice.

Part 2 of the answer is that it also supports extension so I'm working on a C++ extension for it. This is a bit of large undertaking since it entails writing a full parser for C++, but at least I can do it in Java, in IntelliJ, be as ghetto about it as I want, and pretty much anything will be better than what I had before.

Thursday, July 26, 2007

Why Continuous Syntax Checking Matters

Today, I ran into a great example of why continuous syntax checking matters. Now, I understand that some of the slowness that I experienced in diagnosing this problem is because I'm still getting used to C++ and Boost and the resulting error messages. but still...

Here's the relevant chunk of code with the error in bold and line 69 pointed out for future reference.


--> Line 69

boost::program_options::options_description config( "Config File Options ");
config.add_options()
( "currentTime", boost::program_options::value()->default_value(defaultDateString), "YYYY-MM-DD HH:MM:SS" )
( "df", boost::program_options::value(), "description" )
( "debugDir", boost::program_options::value(), "location for log file" )
( "workingDir", boost::program_options::value(), "all intermediate files will go here" )
( "script", boost::program_options::value(), "script directory (location of func)" )
( "DBName", boost::program_options::value<std::string()>(), "name of database" )
( "DBUserName", boost::program_options::value< std::string >(), "username for database" )
( "DBPassword", boost::program_options::value< std::string >(), "password for database" )
( "DBSchema", boost::program_options::value(), "schema to be used for database" )
( "ASchema", boost::program_options::value(), "schema to access A tables" )
( "PSchema", boost::program_options::value(), "schema to access P tables" )
( "opsEmail", boost::program_options::value(), "operations email address" )
( "researchEmail", boost::program_options::value(), "research email address" );




And I'll just add the error message afterwards, for your enjoyment. I won't belabor the point by actually writing anything afterwards. I think it will be pretty clear. If I had had some kind of auto-syntax checking active, then this would have been a lot easier to find. Probably would have saved 5 minutes of staring at the code and 15 minutes of entering a blog to bitch about it. That's a 20 point swing!

/usr/include/boost/program_options/detail/value_semantic.hpp: In member function `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]':
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:28: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:28: error: function return type cannot be function
/usr/include/boost/any.hpp:172: error: function return type cannot be function
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:30: error: assignment of read-only location
/usr/include/boost/program_options/detail/value_semantic.hpp:30: error: cannot convert `std::string ()()' to `std::string ()()' in assignment
/usr/include/boost/program_options/detail/value_semantic.hpp: In function `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]':
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/program_options/detail/value_semantic.hpp:81: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:81: error: function return type cannot be function
/usr/include/boost/lexical_cast.hpp:185: error: function return type cannot be function
/usr/include/boost/any.hpp: At global scope:
/usr/include/boost/any.hpp: In instantiation of `boost::any::holder':
/usr/include/boost/any.hpp:159: instantiated from `ValueType* boost::any_cast(boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/any.hpp:167: instantiated from `const ValueType* boost::any_cast(const boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/program_options/detail/value_semantic.hpp:28: instantiated from `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/any.hpp:125: error: field `boost::any::holder::held' invalidly declared function type
/usr/include/boost/any.hpp: In function `ValueType* boost::any_cast(boost::any*) [with ValueType = std::string ()()]':
/usr/include/boost/any.hpp:167: instantiated from `const ValueType* boost::any_cast(const boost::any*) [with ValueType = std::string ()()]'
/usr/include/boost/program_options/detail/value_semantic.hpp:28: instantiated from `void boost::program_options::typed_value::notify(const boost::any&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/any.hpp:159: error: cannot convert `std::string (**)()' to `std::string (*)()' in return
/usr/include/boost/lexical_cast.hpp: In function `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]':
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:185: error: function return type cannot be function
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:191: error: invalid conversion from `std::string (*)()' to `int'
/usr/include/boost/lexical_cast.hpp:187: warning: address of local variable `result' returned
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits: At global scope:
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits: In instantiation of `std::numeric_limits':
/usr/include/boost/lexical_cast.hpp:131: instantiated from `boost::detail::lexical_stream::lexical_stream() [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/lexical_cast.hpp:186: instantiated from `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:290: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:292: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:295: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:297: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:299: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:301: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:304: error: function return type cannot be function
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/limits:308: error: function return type cannot be function
/usr/include/boost/lexical_cast.hpp: In member function `bool boost::detail::lexical_stream::operator>>(InputStreamable&) [with InputStreamable = std::string ()(), Target = std::string ()(), Source = std::basic_string, std::allocator >]':
/usr/include/boost/lexical_cast.hpp:189: instantiated from `Target boost::lexical_cast(Source) [with Target = std::string ()(), Source = std::basic_string, std::allocator >]'
/usr/include/boost/program_options/detail/value_semantic.hpp:81: instantiated from `void boost::program_options::validate(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&, T*, long int) [with T = std::string ()(), charT = char]'
/usr/include/boost/program_options/detail/value_semantic.hpp:149: instantiated from `void boost::program_options::typed_value::xparse(boost::any&, const std::vector, std::allocator<_T2> >, std::allocator, std::allocator<_T2> > > >&) const [with T = std::string ()(), charT = char]'
private/SVCExecutable.cpp:69: instantiated from here
/usr/include/boost/lexical_cast.hpp:149: error: ambiguous overload for 'operator>>' in '((boost::detail::lexical_stream, std::allocator > >*)this)->boost::detail::lexical_stream, std::allocator > >::stream >> output'
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:87: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>&(*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits]
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:93: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_ios<_CharT, _Traits>&(*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits]
/usr/lib/gcc/i386-redhat-linux/3.4.5/../../../../include/c++/3.4.5/bits/istream.tcc:102: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base&(*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits]
make[1]: *** [debug.obj/SVCExecutable.o] Error 1
make[1]: Leaving directory `/data/aykroyd/cvs/Optimization/five0/PredictionAndBidding/SegmentVolumeCalculator'
make: *** [default] Error 2
make: Leaving directory `/data/aykroyd/cvs/Optimization/five0/PredictionAndBidding/SegmentVolumeCalculator'
exit
Connection to master closed.

exit

Compilation exited abnormally with code 2 at Thu Jul 26 10:53:43

Tuesday, July 24, 2007

emacs and the search for tool zen

NOTE: Originally, this was going to be one post with everything that I've figured out so far about how to use emacs, what tools to extend it with, and what custom extensions to hand-roll based on my current needs. Unfortunately, my tendency towards diarrhea of the mouth being what it is, I've filled more space than I feel comfortable spending on drivel about why I care about this, why tools are important, and why my individual needs are like a unique snow flake that everyone should care about. So, in the interests of optimizing the organization of the information a bit, I'm breaking it up. So this post will contain only introductory and motivation of problem-type content. Future posts will cover what I've actually done, ideas that I like, and hopefully provide some value at least based on the combination of ideas, if not the originality.

So I recently moved from Boston to Northern California. Very shortly thereafter, the startup that I had been at for nearly 2 years was acquired and I was on the job market. I've ended up taking a job with the engineering group in a smallish R&D team that works on optimization problems. The environment is completely different and in many ways I feel like I've stepped back about 20 years into the history of programming. We have to do most of our builds, debugging, etc on remote machines across a connection that is too slow for X forwarding, so most of the coding happens remotely as well. Since I've spent 5 years in Java-based IDEs -- first Eclipse and then IntelliJ, writing C++ ssh'd into a server is unfamiliar ground for me. So I decided to figure out what everyone else was using to do their development. And I was stunned to learn that my new colleagues used vim + grep...

and that was it...

vim and grep ...

To be frank, after having just finished my first warm-up coding assignment during which I was reintroduced to compiler errors that results from misspelled variables and calls to functions that don't exist: m_InitDatabase not m_initDatabase or obj->Run() not obj->Start(), I was hoping for a bit more than that.

So that's the fluffy background... I like tools that make it easier, faster, and more enjoyable to cut code. So I'm in search of the "right" development environment to make me productive with this new set of environmental constraints. I suspect it will be a somewhat lengthy process to configure my environment as well as I'd like and this blog will hopefully reflect that as well other topics that I find interesting.

So why bother?

I have the sense that people who use stock VIM and whatever else is available from bash wonder why I care. The power offered by the standard toolset available on any Unix system is amazing and I think it's important for developers to be comfortable using those tools. Spend any amount of time debugging production issues on servers and your knowledge of UNIX will be rewarded. But I've also been pampered by the amazing development tools offered by IntelliJ and developing without such tools feels needlessly painful. So I'll throw out a random laundry list of things that I love about IntelliJ (not that most of them are exclusive to it. But they are well executed there):
  1. Auto Completion: First, you don't make spelling mistakes and the completion list is a crutch to jog your memory of just what you named a variable or method anyway. Second, it serves as an inline method of looking at simple documentation. Often you can avoid a trip to google to search for an API's documentation just by checking completion options on an object. Both of these uses save a lot of tme.
  2. Fast Keyboard-based File Access: IntelliJ has this feature that I'm in love with. I think more than anything, this is what won me over to it coming from Eclipse. If you press Command-n, and start typing a class name "mysimpl" it will generate a list of all the classes in the project that match that search string. If there are none it will search in your library. Alone, that's pretty cool. But it also has a number of shortcuts. For example, if you type only capital letters, it will let any lower case letter be in between them (e.g., MSS matches MySimpleServer or ManualSarcasmService). This same tool can also be used to search files (excluding java files) and for symbols.
  3. Code Generation: One of the things that I love about really expressive languages is how succinctly you can express yourself. But most of day to day use Java or C++ and with these languages there is a lot of boiler plate code: from class definitions to constructors, getters/setters, to equals and hashcode methods. After using IntelliJ for a while it stopped occurring to me that I should ever have to write these methods unless there was something out of the ordinary. Writing boiler plate code by hand is error-prone and a waste of time. What I like about IntelliJ's execution of this versus Visual Studio was that it's not wizard-based. I define a class member in the .java file and then position the cursor where I want the getter/setter to go, hit Ctrl-n, select getter/setter, and I'm done. No wizards, no mouse clicks, no graphic representations of my class... done.
  4. Finding Uses of Methods/Variables: When debugging a problem, learning a new code base, or thinking about a refactor, it's incredibly useful to be able to jump from a method invocation to its implementation or find all of the uses of a method. Similarly, IntelliJ provides tools to see a graphic representation of an object's hierarchy. By contrast, determining where the method or class is implemented, opening that file, and then moving to the definition is just too slow.
  5. Source Control Integration: I don't mind using svn or cvs command lines for some operations. But generally when I want to diff a file with a previous version or look at its history, I'm actually looking at the file in my editor. So it's handy (I might start to belabor the point... time saving) to perform that operation in the context of my editor.
  6. Integrated Debugging: I'll admit it. I'm a wus. I don't like using command line debuggers. Everything about typing list to see where I am in the file and setting breakpoints by file and line number feels wrong to me. I understand that this is because I'm lacking character. And I'm not hardcore. But I'm not going to change. I like having the option of using a mouse when I debug.
So there's a few of the high impact features that I've come to expect from my development environment. Without these, I find coding and code related activities to be markedly slower and I find myself doing work that would be better completed by a computer. Computers are way more patient than I am.

In the posts that I'll be adding soon I'm going to talk about emacs22, tramp, and a number of extensions that I've been testing.