<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4777243148323391813</id><updated>2012-01-06T09:45:00.133-08:00</updated><category term='url'/><category term='rss emacs xml parsing bbc news'/><category term='rotten tomatoes'/><category term='emacs source browsing tags win32 etags Emacs cygwin'/><category term='clojure'/><category term='debugging'/><category term='emacs web searches web jump'/><category term='redis'/><category term='unxutils'/><category term='transparent'/><category term='c++ a* a star cpp games'/><category term='good code'/><category term='gzip'/><category term='finder'/><category term='gnu'/><category term='common lisp'/><category term='stack overflow'/><category term='windows 7'/><category term='server programming'/><category term='modified'/><category term='C++'/><category term='win32'/><category term='emacs-lisp'/><category term='test'/><category term='buffer'/><category term='mac osx'/><category term='growlnotify'/><category term='scraping'/><category term='mingw32 link errors GetProcessMemoryInfo EnumProcesses'/><category term='find'/><category term='for'/><category term='f#'/><category term='python'/><category term='tips'/><category term='inspect'/><category term='ratings'/><category term='open'/><category term='windows'/><category term='elisp'/><category term='emacs p4 perforce elisp'/><category term='svn google code sourceforge source control'/><category term='pbcopy'/><category term='msdos'/><category term='fail2ban'/><category term='dos command line'/><category term='emacs lispworks slime win32'/><category term='emacs send mail smtp'/><category term='mysqldb'/><category term='hai'/><category term='linux'/><category term='growl'/><category term='screen'/><category term='movie ratings'/><category term='linux cygwin secure file transfer'/><category term='browse'/><category term='emacs'/><category term='msdos win32 command line'/><category term='budget'/><category term='mysql'/><category term='rgrep'/><category term='emacs smtp sending mail windows win32'/><category term='ipin'/><category term='url-browse'/><category term='pbpaste'/><category term='transmission'/><category term='geek'/><category term='bash'/><category term='compile'/><category term='file search'/><category term='tar'/><category term='time'/><category term='log4j'/><category term='game programming'/><category term='terminal'/><category term='emacs perforce p4'/><category term='mp3 flac convert lame'/><category term='mac'/><category term='c++ astar a* game programming bugs'/><category term='mark files'/><category term='emacs rename files'/><category term='eredis'/><category term='command line'/><category term='duplicate files'/><category term='ubuntu'/><category term='md5'/><category term='dired'/><category term='ssh. security'/><category term='thread safe insert'/><category term='prototype'/><category term='msdos win32 command line batch files'/><category term='windows vista'/><category term='money'/><title type='text'>justinhj's coding blog</title><subtitle type='html'>Programming related tips and comments. Lots of emacs, C++, some game AI, common lisp, python, java, c#, sql and whatever else I'm working on.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>67</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3220472187204508366</id><published>2011-12-26T10:32:00.001-08:00</published><updated>2011-12-26T10:43:48.011-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs-lisp'/><title type='text'>Making a emacs lisp expression expand itself to XML</title><content type='html'>&lt;div&gt;&lt;span&gt;My response to the blog article &lt;a href="http://irreal.org/blog/?p=403" style="background-color: rgb(255, 255, 255); font-family: 'Helvetica Neue', Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 1.3em; text-align: -webkit-auto; "&gt;An Emacs Programming Challenge&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The goal is to make the emacs lisp record below execute itself and produce XML. My lisp has gotten rusty so it took me a couple of hours to get this working, but I think I got there...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see it properly formatted and coloured &lt;a href="http://paste.lisp.org/display/126697"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;It's fairly straightforward. The only complexity is the use of lexical-let. emacs lisp is dynamically scoped, so in the function I create for each keyword, where it prints the symbol name is a free variable at runtime. So if sym-name is not defined you'll get an error, otherwise you'll get whatever it is defined as instead of the value you wanted.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By using lexical-let any variables are bound lexically, that is stored in an environment that stays with the function we create when it is executed (a closure).&lt;br /&gt;&lt;pre&gt;(require 'cl) ;; uses lexical-let&lt;br /&gt;&lt;br /&gt;(defun make-xml-izer(name)&lt;br /&gt; "Given a symbol NAME this makes a function that outputs an xml string for that&lt;br /&gt;symbol and using fset binds it to the same symbol so it becomes executable.&lt;br /&gt;This pollutes the global function namespace so be careful with which names you&lt;br /&gt;pass in"&lt;br /&gt; (lexical-let ((sym-name name))&lt;br /&gt;   (fset (intern name)&lt;br /&gt;   (lambda(&amp;amp;rest input)&lt;br /&gt;     "returns a string representing the xml encoding of the input sexp"&lt;br /&gt;     (let ((res (format "&amp;lt;%s&amp;gt;" sym-name)))&lt;br /&gt;       (dolist (item input)&lt;br /&gt;  (if (listp item)&lt;br /&gt;      (setf res (concat res (eval item)))&lt;br /&gt;    (setf res (format "%s%s" res item))))&lt;br /&gt;       (setf res (format "%s&lt;!--%s--&gt;" res sym-name))&lt;br /&gt;       res)))))&lt;br /&gt;&lt;br /&gt;;; executing this makes all the symbols in the list below executable &lt;br /&gt;(mapcar (lambda(s)&lt;br /&gt;   (make-xml-izer&lt;br /&gt;    (symbol-name s)))&lt;br /&gt; '(record date millis sequence logger level class method thread emessage exception frame line))&lt;br /&gt;&lt;br /&gt;;; the sample record&lt;br /&gt;(record&lt;br /&gt; (date "2005-02-21T18:57:39")&lt;br /&gt; (millis 1109041059800)&lt;br /&gt; (sequence 1)&lt;br /&gt; (logger nil)&lt;br /&gt; (level 'SEVERE)&lt;br /&gt; (class "java.util.logging.LogManager$RootLogger")&lt;br /&gt; (method 'log)&lt;br /&gt; (thread 10)&lt;br /&gt; (emessage "A very very bad thing has happened!")&lt;br /&gt; (exception&lt;br /&gt;   (emessage "java.lang.Exception")&lt;br /&gt;   (frame&lt;br /&gt;     (class "logtest")&lt;br /&gt;     (method 'main)&lt;br /&gt;     (line 30))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3220472187204508366?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3220472187204508366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3220472187204508366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3220472187204508366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3220472187204508366'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/12/making-emacs-lisp-expression-expand.html' title='Making a emacs lisp expression expand itself to XML'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1310783275001628299</id><published>2011-07-30T00:03:00.001-07:00</published><updated>2011-07-30T00:09:08.545-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eredis'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='redis'/><title type='text'>eredis update</title><content type='html'>I've been busy on my emacs redis client &lt;a href="http://code.google.com/p/eredis/"&gt;eredis&lt;/a&gt; and it now supports the entire API. It still needs a bit more polish but it should be a workable Redis client now, and I will continue to play with the org-mode table integration which I think has a lot of potential uses: for example making a gui to edit server parameters in just a few seconds. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also made a new video showing some of the new org table creating commands and the monitor mode that shows the Redis commands as they are run on the server:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;iframe width="560" height="349" src="http://www.youtube.com/embed/zm9obhWkTdE" frameborder="0" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1310783275001628299?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1310783275001628299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1310783275001628299' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1310783275001628299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1310783275001628299'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/07/eredis-update.html' title='eredis update'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/zm9obhWkTdE/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-4641705860991542206</id><published>2011-07-25T01:06:00.000-07:00</published><updated>2011-07-25T01:24:31.059-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='redis'/><title type='text'>eredis: a Redis client in emacs lisp</title><content type='html'>&lt;a href="http://4.bp.blogspot.com/-vgnyCCDQNKA/Ti0npIdQ6YI/AAAAAAAAFvQ/iYAfeenzv68/s1600/exampleeredis.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 100px;" src="http://4.bp.blogspot.com/-vgnyCCDQNKA/Ti0npIdQ6YI/AAAAAAAAFvQ/iYAfeenzv68/s320/exampleeredis.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5633202296508705154" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I set up a google code project today for &lt;a href="http://bit.ly/noZp92"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;eredis&lt;/span&gt;&lt;/a&gt;. A &lt;a href="http://redis.io/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Redis&lt;/span&gt;&lt;/a&gt; client in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;emacs&lt;/span&gt; lisp. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The program consists of a single &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;emacs&lt;/span&gt; lisp file&lt;a href="http://code.google.com/p/eredis/source/browse/trunk/eredis.el"&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;eredis&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;el&lt;/span&gt; &lt;/a&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;emacs&lt;/span&gt; lisp includes facilities for writing network applications. In my code I use `make-network-process' to open a connection to a specified redis server. Then the Redis api is exposed. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One nice feature of emacs I have used is org-table-mode. This lets you edit and manage the data in a Redis server in an org table. For example, you can grab all keys matching a pattern and create an org table from the key value pairs, then edit that table. You can then send it back to Redis with interactive commands that send either the whole table, or just the current row back to Redis using mset or set.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This work flow is not safe when working with multiple users, if you care about overwriting each others data. For example, I could store the last values you got from Redis in addition to your edited values. When you go to set a new value I first grab it from Redis, check if it has changed since you got it, and if so warn you (showing you the new value). For many work flows this would work well. For example the use case of a group of users editing a shared DB of configuration data. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-4641705860991542206?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/4641705860991542206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=4641705860991542206' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4641705860991542206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4641705860991542206'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/07/eredis-redis-client-in-emacs-lisp.html' title='eredis: a Redis client in emacs lisp'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-vgnyCCDQNKA/Ti0npIdQ6YI/AAAAAAAAFvQ/iYAfeenzv68/s72-c/exampleeredis.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2921268486508874004</id><published>2011-06-14T15:12:00.000-07:00</published><updated>2011-06-14T15:37:32.516-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs-lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Emacs progress indication</title><content type='html'>&lt;div&gt;&lt;div&gt;When programming in emacs lisp, there is an easy way to show progress feedback to the user when a task will take some time. Here's a block of code from the elisp manual showing how to do it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(let ((progress-reporter&lt;/div&gt;&lt;div&gt;       (make-progress-reporter "Collecting mana for Emacs..."&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;       0 500)))&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;  (dotimes (k 500)&lt;/div&gt;&lt;div&gt;    (sit-for 0.01)&lt;/div&gt;&lt;div&gt;    (progress-reporter-update progress-reporter k))&lt;/div&gt;&lt;div&gt;  (progress-reporter-done progress-reporter))&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've incorporated this into my duplicate files code, linked below...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://code.google.com/p/justinhj-emacs-utils/source/browse/trunk/duplicates.el"&gt;http://code.google.com/p/justinhj-emacs-utils/source/browse/trunk/duplicates.el&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2921268486508874004?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2921268486508874004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2921268486508874004' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2921268486508874004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2921268486508874004'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/06/emacs-progress-indication.html' title='Emacs progress indication'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-635036105615980185</id><published>2011-06-05T20:41:00.000-07:00</published><updated>2011-06-06T09:47:33.196-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='md5'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='duplicate files'/><category scheme='http://www.blogger.com/atom/ns#' term='dired'/><title type='text'>More on duplicate file handling in emacs dired</title><content type='html'>I had some good feedback on my last post, that it would be useful to be leave just the superfluous duplicate files marked in the dired buffer. After doing that you can then copy them to another folder, or delete them.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've added a function to do this `dired-mark-duplicate-files', and updated the google code site with the &lt;a href="http://code.google.com/p/justinhj-emacs-utils/source/browse/trunk/duplicates.el"&gt;changes&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To copy to another folder use R and select a folder to move the dupes to. In order to delete them hit D. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-635036105615980185?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/635036105615980185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=635036105615980185' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/635036105615980185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/635036105615980185'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/06/more-on-duplicate-file-handling-in.html' title='More on duplicate file handling in emacs dired'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5738307875096175125</id><published>2011-06-01T21:31:00.000-07:00</published><updated>2011-06-01T22:40:49.421-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs-lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='md5'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='duplicate files'/><category scheme='http://www.blogger.com/atom/ns#' term='dired'/><title type='text'>Finding duplicate files in a dired buffer</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/-FpO96rrdz0E/TecTVZCglII/AAAAAAAAFg0/3PT00loebT4/s1600/twins.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 244px;" src="http://3.bp.blogspot.com/-FpO96rrdz0E/TecTVZCglII/AAAAAAAAFg0/3PT00loebT4/s320/twins.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5613476718760203394" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;picture by &lt;a href="http://www.flickr.com/photos/donaldmacleod/3439612846/"&gt;Donald MacLeod&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a an example of programming emacs in emacs-lisp just to give an idea of what you can put together in an hour or two. I was looking at a dired buffer with a bunch of photos in, and some were the same photo that I'd downloaded twice. So I started thinking about writing a utility in emacs to automatically find and remove the duplicate files. In this post I'll just show the code for finding the files and display their filenames in a buffer. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've put the &lt;a href="http://code.google.com/p/justinhj-emacs-utils/source/browse/trunk/duplicates.el"&gt;source&lt;/a&gt; on google code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After downloading you can load the source into emacs and call `eval-buffer', then open up a dired buffer to try it out. For this to be useful you need some duplicated files, so make some if you need to. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mark the files you want to check for duplicates. For example to mark all jpg files you would type %m to mark files matching a regexp and type .*\.jpg&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now execute the command `dired-show-marked-duplicate-files' and after a short delay (in my test 80 jpg photos took about 5 seconds) you'll see a buffer called 'Duplicated files' which contains a list of the files which have the same contents. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Next steps for this little project will be to give you an interactive way to delete the duplicated files. I haven't decided quite how I'd like that to work, drop me an email if you have an idea. I've been thinking about perhaps resetting which files are marked so that only the duplicates are marked. At that point you can then hit R to move them to another spot, or delete them with x.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now some comments about the code involved...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Most of the work is done in the function dired-show-marked-duplicate-files. First line "  (interactive)" makes it an interactive function, meaning the user of emacs can invoke it. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; "(if (eq major-mode 'dired-mode)" will check that we're in the right kind of buffer, because it makes no sense to run this in another mode. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to find the duplicate files I just need to walk the list of marked files, generate the md5 value of the contents of each one and add it to hash table. The keys in the hash table will be the md5, and the values will be a list of files with that md5. Once we've done that, finding duplicates is a simple matter of walking the hash table keys and displaying any where the value has multiple entries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"(let ((md5-map (make-hash-table :test 'equal :size 40)))" Creates the hash table, making sure we use 'equal to match our filenames.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;"(let ((filenames (dired-get-marked-files)))" this gets the marked files as a list of filenames&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The next little bit of code is just to store the item in the hash table after getting the md5. There's no function in emacs to get the md5 of a file, but you can get the md5 of a string, so I wrote a helper function for getting the contents of a file into a temporary buffer first. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;(defun md5-file(filename)&lt;/div&gt;&lt;div&gt;  "Open FILENAME, load it into a buffer and generate the md5 of its contents"&lt;/div&gt;&lt;div&gt;  (interactive "f")&lt;/div&gt;&lt;div&gt;  (with-temp-buffer &lt;/div&gt;&lt;div&gt;    (insert-file-contents filename)&lt;/div&gt;&lt;div&gt;    (md5 (current-buffer))))&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally I want to display the results, so I create a buffer and then use maphash (walks the keys of a hash table executing a function on each) with a helper function `show-duplicate' which simply writes the values of the hash table entry into that buffer. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5738307875096175125?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5738307875096175125/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5738307875096175125' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5738307875096175125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5738307875096175125'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/06/finding-duplicate-files-in-dired-buffer.html' title='Finding duplicate files in a dired buffer'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-FpO96rrdz0E/TecTVZCglII/AAAAAAAAFg0/3PT00loebT4/s72-c/twins.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3562574788450026175</id><published>2011-04-26T15:12:00.000-07:00</published><updated>2011-04-26T15:41:20.982-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hai'/><category scheme='http://www.blogger.com/atom/ns#' term='mac osx'/><category scheme='http://www.blogger.com/atom/ns#' term='pbcopy'/><category scheme='http://www.blogger.com/atom/ns#' term='open'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='finder'/><category scheme='http://www.blogger.com/atom/ns#' term='terminal'/><category scheme='http://www.blogger.com/atom/ns#' term='pbpaste'/><title type='text'>Programmer tips for Mac OSX</title><content type='html'>Some tips for programmers on the Mac.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;emacs: the best place to get emacs for Mac seems to be here &lt;a href="http://emacsformacosx.com/"&gt;http://emacsformacosx.com/&lt;/a&gt; which is also the most no nonsense website design ever&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Not really a Mac tip, but I stick my .emacs configuration file in a Dropbox folder, along with any emacs libraries and  emacs lisp code I write. Then where-ever I install emacs I make a simple .emacs that points to the one in the Dropbox folder. This also forces me to make sure any platform specific emacs stuff is properly handled. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Clipboard: copy and paste between the terminal and other apps can be done with pbcopy and pbpaste. For example a long complicated command line you want to email to yourself, just do:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;echo "long complicated bash command line you don't want to retype" | pbcopy &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And then you can Command-V that into your email window. Going the other way is just as simple; Command-C the text you want and pop it into the terminal window with pbpaste.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Open: If you want open an application from the command line you can do it like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;open -a SomeApp /Users/yourname/SomeFile.hai&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can open a folder in finder &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;open /Folder/&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;or &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;open /Folder/SomeFile.hai&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;to open that file with it's default application.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Check out the help 'man open', to see other stuff like how you pipe stdout into an application. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally check out this guys OpenTerminalHere script. This pops an icon in finder that lets you open a terminal window in the highlighted folder. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.entropy.ch/software/applescript/"&gt;http://www.entropy.ch/software/applescript/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;   &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3562574788450026175?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3562574788450026175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3562574788450026175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3562574788450026175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3562574788450026175'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/04/programmer-tips-for-mac-osx.html' title='Programmer tips for Mac OSX'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2233855747399164516</id><published>2011-04-26T15:00:00.000-07:00</published><updated>2011-04-26T15:04:57.269-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rotten tomatoes'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='movie ratings'/><title type='text'>MovieRatings</title><content type='html'>A little side project I did when learning about Clojure was to grab movie ratings from Rotten Tomatoes, which I did a post about here:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://justinsboringpage.blogspot.com/2011/01/grabbing-rotten-tomatoes-movie-ratings.html"&gt;http://justinsboringpage.blogspot.com/2011/01/grabbing-rotten-tomatoes-movie-ratings.html&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is just an update that I've posted the whole leiningen project onto github &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="https://github.com/justinhj/movieratings"&gt;https://github.com/justinhj/movieratings&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2233855747399164516?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2233855747399164516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2233855747399164516' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2233855747399164516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2233855747399164516'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/04/movieratings.html' title='MovieRatings'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-9174874971368109311</id><published>2011-04-25T17:40:00.000-07:00</published><updated>2011-04-25T19:56:15.010-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysqldb'/><category scheme='http://www.blogger.com/atom/ns#' term='mac osx'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Talking to mysql from Python on Mac OS X 10.6</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/-NKqwp2W_YmM/TbY0OvSTHsI/AAAAAAAAFSk/CIPn706RWrU/s1600/2923859802_c8a8dc9f5a_z.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 379px; height: 400px;" src="http://2.bp.blogspot.com/-NKqwp2W_YmM/TbY0OvSTHsI/AAAAAAAAFSk/CIPn706RWrU/s400/2923859802_c8a8dc9f5a_z.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5599720614497820354" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;image by &lt;a href="http://www.flickr.com/photos/spullara/2923859802/"&gt;Sam Pullara&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a problem I couldn't solve with Google, although it seems to be a moving target so YMMV. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wanted to do some work driving a MySQL database with Python. On Windows and Linux I've used MySQLdb so I decided to do the same on Mac. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For reference I got mysql (client and server) through mac ports.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;mysql5 --version&lt;/div&gt;&lt;div&gt;mysql5  Ver 14.14 Distrib 5.1.45, for apple-darwin10.4.0 (i386) using readline 6.1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and Python is the stock version:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) &lt;/div&gt;&lt;div&gt;[GCC 4.2.1 (Apple Inc. build 5646)] on darwin&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First download from here &lt;a href="http://sourceforge.net/projects/mysql-python/"&gt;http://sourceforge.net/projects/mysql-python/&lt;/a&gt; and extract the file somewhere...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;mkdir ~/pythondb&lt;/div&gt;&lt;div&gt;cd ~/pythondb&lt;/div&gt;&lt;div&gt;tar -vxf ~/Downloads/MySQL-python-1.2.3.tar.gz &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then you need open up the site.cfg file and make a change as below. Your mysql_config5 maybe in a different spot. You can find out with the command 'which mysql_config5'.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;# The path to mysql_config.&lt;/div&gt;&lt;div&gt;# Only use this if mysql_config is not on your PATH, or you have some weird&lt;/div&gt;&lt;div&gt;# setup that requires it.&lt;/div&gt;&lt;div&gt;mysql_config = /opt/local/bin/mysql_config5&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Now execute the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;python setup.py build&lt;/div&gt;&lt;div&gt;python setup.py install&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If everything works you can now import MySQLdb in your python program and start interacting with mysql. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-9174874971368109311?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/9174874971368109311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=9174874971368109311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/9174874971368109311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/9174874971368109311'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/04/talking-to-mysql-from-python-on-mac-os.html' title='Talking to mysql from Python on Mac OS X 10.6'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-NKqwp2W_YmM/TbY0OvSTHsI/AAAAAAAAFSk/CIPn706RWrU/s72-c/2923859802_c8a8dc9f5a_z.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1879481065595042616</id><published>2011-01-15T10:22:00.001-08:00</published><updated>2011-01-15T10:58:02.133-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scraping'/><category scheme='http://www.blogger.com/atom/ns#' term='ratings'/><category scheme='http://www.blogger.com/atom/ns#' term='rotten tomatoes'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><title type='text'>Grabbing Rotten Tomatoes movie ratings with Clojure</title><content type='html'>&lt;a href="http://www.flickr.com/photos/chocolateforest/3237898945/" title="Untitled by Gammelmark, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3129/3237898945_9402ea242d.jpg" width="500" height="333" alt="" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/chocolateforest/3237898945/" title="Untitled by Gammelmark, on Flickr"&gt;&lt;/a&gt;flikr pic by &lt;a href="http://flic.kr/p/5W85xT"&gt;Gammelmark&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Currently I'm teaching myself Clojure from Stuart Halloway's excellent book &lt;a href="http://www.amazon.com/Programming-Clojure-Pragmatic-Programmers-Halloway/dp/1934356336/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1295117421&amp;amp;sr=8-1"&gt;Programming Clojure&lt;/a&gt;.  Here's my first program that does something; a simple web page scraper to get the critics and audience ratings for movies off Rotten Tomatoes. Here's how it looks at the REPL:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;rottentomatoes.core&amp;gt; (pmap-get-movie-ratings "lord of the rings")&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/lord_of_the_rings_the_return_of_the_king/&lt;br /&gt;Audience 83&lt;br /&gt;Critics 94&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/lord_of_the_rings_the_fellowship_of_the_ring/&lt;br /&gt;Audience 92&lt;br /&gt;Critics 92&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/lord_of_the_rings_the_two_towers/&lt;br /&gt;Audience 92&lt;br /&gt;Critics 96&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/lord_of_the_rings/&lt;br /&gt;Audience 74&lt;br /&gt;Critics 50&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/master_of_the_rings_the_unauthorized_story_behind_jrr_tolkiens_the_lord_of_the_rings/&lt;br /&gt;Audience 34&lt;br /&gt;Critics null&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/jrr-tolkien-and-the-birth-of-the-lord-of-the-rings/&lt;br /&gt;Audience 93&lt;br /&gt;Critics null&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/jrr_tolkien_and_the_birth_of_the_lord_of_the_rings/&lt;br /&gt;Audience 32&lt;br /&gt;Critics null&lt;br /&gt;movie url: http://www.rottentomatoes.com/m/more_at_imdbpro_creating_the_lord_of_the_rings_symphony_a_composers_journey_through_middle_earth/&lt;br /&gt;Audience 100&lt;br /&gt;Critics null&lt;br /&gt;nil&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I use &lt;a href="http://bit.ly/dV7g6y"&gt;leiningen&lt;/a&gt; to develop with Clojure (it's like Maven for Java), so if you want to build the project here's my project configuration that includes the dependencies used.  I'm using swank-clojure which enables the REPL to function with emacs slime. http.async.client is a clojure API that builds on Netty and I use that for the GET requests to the Rotten Tomatoes server.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;(defproject rottentomatoes "1.0.0-SNAPSHOT"&lt;br /&gt;:description "Clojure code to grab movie ratings from Rotten Tomatoes"&lt;br /&gt;:dependencies [&lt;br /&gt;     [org.clojure/clojure "1.2.0"]&lt;br /&gt;             [org.clojure/clojure-contrib "1.2.0"]&lt;br /&gt;     [http.async.client "0.2.1"]&lt;br /&gt;     ]&lt;br /&gt;:main rottentomatoes.core&lt;br /&gt;:dev-dependencies [&lt;br /&gt;         [swank-clojure "1.2.1"]&lt;br /&gt;          ]&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;And here's the code:&lt;/div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;(ns rottentomatoes.core&lt;br /&gt;(:gen-class)&lt;br /&gt;(:require&lt;br /&gt;[clojure.contrib.str-utils2 :as s]&lt;br /&gt;[http.async.client :as c]))&lt;br /&gt;&lt;br /&gt;(import [java.net URLEncoder]&lt;br /&gt; [java.lang.Character])&lt;br /&gt;&lt;br /&gt;(def *base-url* "http://www.rottentomatoes.com")&lt;br /&gt;(def *search-end-point* "/search/full_search.php?search=")&lt;br /&gt;&lt;br /&gt;(defn first-match-after [re1 re2 seq]&lt;br /&gt;"Splits the sequence SEQ using RE1 then searches after the first match and before the next match for the first occurence of RE2"&lt;br /&gt;(let [[_ _ after] (s/partition seq re1)]&lt;br /&gt; (re-find re2 after)))&lt;br /&gt;&lt;br /&gt;(defn response-status-code [resp]&lt;br /&gt;(:code (c/status resp)))&lt;br /&gt;&lt;br /&gt;(defn scoop-url [url]&lt;br /&gt;"Use the http client to do a GET on the url"&lt;br /&gt;(let [resp (c/GET url)]&lt;br /&gt;   (c/await resp)&lt;br /&gt;   [(response-status-code resp) (c/string resp)]))&lt;br /&gt;&lt;br /&gt;;; Get movie urls&lt;br /&gt;;; Does a search of Rotten Tomatoes for the search text, then scrapes the results&lt;br /&gt;;; for the page for each movie. Returns a collection of the movie urls&lt;br /&gt;&lt;br /&gt;(defn get-movie-urls [search-text]&lt;br /&gt;(let [encoded-search-text (URLEncoder/encode search-text)&lt;br /&gt; [code body] (scoop-url (str *base-url* *search-end-point* encoded-search-text))&lt;br /&gt; ]&lt;br /&gt; (when (= code 200)&lt;br /&gt;   (let [[_ _ after] (s/partition body #"&amp;lt;span&amp;gt;Title&amp;lt;/span&amp;gt;")]&lt;br /&gt; (let [[_ &amp;amp; results] (s/partition after #"\"(/m/.*/)\"")]&lt;br /&gt;   (map #(str *base-url* (second %)) (take-nth 2 results)))))))&lt;br /&gt;&lt;br /&gt;;; Given a movie url GET the page then scrape it for the citic and audience rating&lt;br /&gt;&lt;br /&gt;(defn get-movie-rating [movie-url]&lt;br /&gt;(let [[code body] (scoop-url movie-url)]&lt;br /&gt; (if (= code 200)&lt;br /&gt;   {:critics (second&lt;br /&gt;     (first-match-after #"class=\"critic_side_container" #"&amp;gt;([0-9]+)&amp;lt;" body))&lt;br /&gt;    :audience (second&lt;br /&gt;       (first-match-after #"class=\"fan_side" #"&amp;gt;([0-9]+)&amp;lt;" body))})))   &lt;br /&gt;&lt;br /&gt;;; Finds the ratings for all Rotten Tomatoes movies that match the search string and prints them out&lt;br /&gt;&lt;br /&gt;(defn get-movie-ratings [search-str]&lt;br /&gt;(let [urls (get-movie-urls search-str)]&lt;br /&gt; (when (&amp;gt; (count urls) 0)&lt;br /&gt;   (doseq [url urls]&lt;br /&gt; (let [ratings (get-movie-rating url)]&lt;br /&gt;   (printf "movie url: %s\n\tAudience %s\n\tCritics %s\n" url (:audience ratings) (:critics ratings)))))))&lt;br /&gt;&lt;br /&gt;;; Slight variant on above that uses pmap so that the requests are done in parallel&lt;br /&gt;&lt;br /&gt;(defn pmap-get-movie-ratings [search-str]&lt;br /&gt;(let [urls (get-movie-urls search-str)]&lt;br /&gt; (when (&amp;gt; (count urls) 0)&lt;br /&gt;   (let [ratings (pmap #(get-movie-rating %) urls)&lt;br /&gt;     url-and-ratings (map vector urls ratings)]&lt;br /&gt; (doseq [[url ratings] url-and-ratings]&lt;br /&gt;   (printf "movie url: %s\n\tAudience %s\n\tCritics %s\n" url (:audience ratings) (:critics ratings)))))))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;I'm using the str-utils2 module for it's regex function partition, which will split a sequence up by regex matches. This made it easy to write the function `first-match-after', which finds a regex then finds the first occurrence of some text after that regex. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It was so easy to parallelize the requests. My first attempt at get-movie-ratings retrieved each movie page synchronously. By using pmap I was able to make it do the requests via thread pools, and thus return in a few seconds for many movie matches. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;The code is much shorter than it would have been in Common Lisp, at least the way I program. I love the destructuring syntax, and that maps, vectors and lists can be returned from functions and manipulated without much effort. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm still new to Clojure so if you feel you can improve the code or have any feedback please let me know.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1879481065595042616?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1879481065595042616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1879481065595042616' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1879481065595042616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1879481065595042616'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/01/grabbing-rotten-tomatoes-movie-ratings.html' title='Grabbing Rotten Tomatoes movie ratings with Clojure'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3129/3237898945_9402ea242d_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2152006006712419999</id><published>2011-01-11T11:09:00.000-08:00</published><updated>2011-01-15T10:07:37.719-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='inspect'/><title type='text'>View Data from the Clojure REPL</title><content type='html'>Here's a nice debugging feature in Clojure. The inspect module lets you look at variables in a popup JFrame. The two examples below show how you quickly view data in a table or tree format. This is really handy to quickly view data from the REPL.&lt;br /&gt;&lt;br /&gt;(require 'clojure.inspector)&lt;br /&gt;&lt;br /&gt;(clojure.inspector/inspect-tree '(1 (a b) 2 (c d)  3 (e f )))&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://4.bp.blogspot.com/_nkGbjVeC3i4/TTHh9yXhqbI/AAAAAAAAFIc/TENgl2G5uzI/s1600/inspect_tree.png"&gt;&lt;img src="http://4.bp.blogspot.com/_nkGbjVeC3i4/TTHh9yXhqbI/AAAAAAAAFIc/TENgl2G5uzI/s320/inspect_tree.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5562475466387990962" style="cursor: pointer; width: 320px; height: 273px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;(clojure.inspector/inspect-table '((1 2 3) (a b c) (e f g)))&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nkGbjVeC3i4/TTHh5GiErVI/AAAAAAAAFIU/yOK5Eudd5Ng/s1600/inspect_table.png"&gt;&lt;img src="http://4.bp.blogspot.com/_nkGbjVeC3i4/TTHh5GiErVI/AAAAAAAAFIU/yOK5Eudd5Ng/s320/inspect_table.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5562475385901591890" style="cursor: pointer; width: 320px; height: 156px; " /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2152006006712419999?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2152006006712419999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2152006006712419999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2152006006712419999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2152006006712419999'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2011/01/view-data-from-clojure-repl.html' title='View Data from the Clojure REPL'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/TTHh9yXhqbI/AAAAAAAAFIc/TENgl2G5uzI/s72-c/inspect_tree.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2861224012424900021</id><published>2010-12-15T10:26:00.000-08:00</published><updated>2010-12-15T12:29:00.447-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='game programming'/><category scheme='http://www.blogger.com/atom/ns#' term='common lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='f#'/><title type='text'>F# vs C#</title><content type='html'>&lt;div&gt;Nice article comparing directly some code written in C# vs one in F#&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://sharp-gamedev.blogspot.com/2010/12/on-performance-of-f-on-xbox-360.html"&gt;http://sharp-gamedev.blogspot.com/2010/12/on-performance-of-f-on-xbox-360.html&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://sharp-gamedev.blogspot.com/2010/12/on-performance-of-f-on-xbox-360.html"&gt;&lt;/a&gt;What's interesting is that now that VM's are starting to become the new platforms, we are starting to be less restricted by language choice. When it's native code with hand crafted memory management you want, it has to be C++. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But when you start to look at the JDK and the .Net VM's, the language choice has far less impact on performance... after all you're using the same garbage collector, same base libraries and so on. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is great news for those of us with more peculiar tastes in language (I like Clojure and Common Lisp for example).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Although I think it will be a few years until AAA console games run on VM's, if ever, due to the nature of that business. Memory is always at a premium, and the goal is to choke every last hz of CPU performance. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2861224012424900021?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2861224012424900021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2861224012424900021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2861224012424900021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2861224012424900021'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/12/f-vs-c.html' title='F# vs C#'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1676373477329837106</id><published>2010-11-02T11:04:00.000-07:00</published><updated>2010-11-02T11:11:07.168-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='url'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='buffer'/><category scheme='http://www.blogger.com/atom/ns#' term='url-browse'/><category scheme='http://www.blogger.com/atom/ns#' term='browse'/><title type='text'>Just browsing</title><content type='html'>It's handy in emacs to be able to go straight to your browser to view a page, and you can do fancy stuff with `webjump' as I mentioned in a &lt;a href="http://justinsboringpage.blogspot.com/2009/05/emacs-searching-programming-apis-with.html"&gt;previous post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Another handy function is `browse-url' which will prompt for the url but default to whatever your point is at. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're in a html file and you'd like to open that with your browser then `browse-url-of-file' will open it up.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally, and I just found this today, if you have some html code in a buffer that isn't even a file, you can open that in your browser to using `browse-url-of-buffer' and emacs will write it to a temporary file and open that in the browser for you. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1676373477329837106?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1676373477329837106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1676373477329837106' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1676373477329837106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1676373477329837106'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/11/just-browsing.html' title='Just browsing'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3950018987680156658</id><published>2010-10-19T16:14:00.000-07:00</published><updated>2010-10-19T16:15:05.318-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='windows vista'/><category scheme='http://www.blogger.com/atom/ns#' term='find'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='unxutils'/><category scheme='http://www.blogger.com/atom/ns#' term='rgrep'/><title type='text'>rgrep on windows 7 for emacs</title><content type='html'>I lost an hour configuring this, so seems worthy of a blog post.&lt;br /&gt;&lt;br /&gt;A fresh install of &lt;a href="http://ftp.gnu.org/gnu/emacs/windows/"&gt;emacs for windows&lt;/a&gt; will have functionality that does not work because it depends on unix style utilities.&lt;br /&gt;&lt;br /&gt;One very useful example is the command rgrep, which searches files recursively through subfolders looking for a regular expression in those files.&lt;br /&gt;&lt;br /&gt;Under the hood it uses the unix command line tools find, and egrep. Unfortunately the windows version of find takes entirely different parameters and will not function. In fact you will get an error that looks like this:&lt;br /&gt;&lt;br /&gt;FIND: Wrong parameter format&lt;br /&gt;&lt;br /&gt;Using the set of native ports of Unix command line tools &lt;a href="http://sourceforge.net/projects/unxutils/"&gt;UnxUtils &lt;/a&gt;you can easily fix this:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download the zip file and extract it to c:\unxutils&lt;/li&gt;&lt;li&gt;Add the following path to the very front of your path by editing your system environment variables C:\unxutils\usr\local\wbin\;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;That's it. You can run rgrep now and hopefully you're up and running. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If not make sure you have restarted emacs so it picks up the new setting of PATH. Open a shell in emacs and type 'find --version'. You should see something like this if your path is configured correctly:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;c:\find --version&lt;/div&gt;&lt;div&gt;find --version&lt;/div&gt;&lt;div&gt;GNU find version 4.1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and if not you will see:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;C:\Windows\system32&gt;find --help&lt;/div&gt;&lt;div&gt;FIND: Parameter format not correct&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3950018987680156658?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3950018987680156658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3950018987680156658' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3950018987680156658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3950018987680156658'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/10/rgrep-on-windows-7-for-emacs.html' title='rgrep on windows 7 for emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-6332396053021969167</id><published>2010-07-30T14:55:00.000-07:00</published><updated>2010-07-30T15:08:46.359-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='thread safe insert'/><title type='text'>Couple of mysql tips</title><content type='html'>&lt;b&gt;Wondering what the heck is going on on your mysql DB?&lt;/b&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;show processlist ;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Shows you all the active threads, which is very handy indeed. It shows what each thread is doing, and how long it has been doing it for.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Thread safe record insertion&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;When doing a record insert, another thread could be trying to insert a record that would violate any DB contraints, and if it gets there before you, then your insert will fail. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There may be cases where you want don't want to have it fail and try again; you may want to take a different action if the record already exists. For example lets say you have some data like this, where the Name is a unique key...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Name, Number of products purchase&lt;/div&gt;&lt;div&gt;Bob, 1, &lt;/div&gt;&lt;div&gt;Ben, 2,&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now if two threads try to insert a user 'Roger' who has just bought an item, then the one that arrives at the server last will fail. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;INSERT INTO purchase (Name, PurchaseCount) VALUES ('Roger',  '1') ON DUPLICATE KEY UPDATE PurchaseCount=PurchaseCount+1;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This will handle the key collision and execute the update clause instead, in the event that somebody beat you to it. This makes it much easier to write thread safe code that adds records.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-6332396053021969167?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/6332396053021969167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=6332396053021969167' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6332396053021969167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6332396053021969167'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/07/couple-of-mysql-tips.html' title='Couple of mysql tips'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-753817652935776038</id><published>2010-06-08T14:12:00.000-07:00</published><updated>2010-06-08T14:19:06.213-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='server programming'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='log4j'/><title type='text'>Adjusting server logging level at runtime</title><content type='html'>&lt;div&gt;log4j is an awesome logging library for Java. One thing I found out today is that you can change the logging level (debug, warn, info) at runtime, with a few lines of code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;static&lt;br /&gt;{&lt;br /&gt;       // This monitors the log4j for changes over a specified period of milliseconds&lt;br /&gt;       PropertyConfigurator.configureAndWatch("./resources/log4j.properties", 60000);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What this function does is to tell log4j to check the configuration file every minute (60000 ms) for changes. So you can deploy a production server with only warn and error logging, but if something goes wrong you can enable debug and info logging (for example) simply by editing the configuration file and waiting a minute. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;(source code formatted by this handy website &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="white-space: pre; "&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;&lt;a href="http://formatmysourcecode.blogspot.com"&gt;http://formatmysourcecode.blogspot.com&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;)&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-753817652935776038?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/753817652935776038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=753817652935776038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/753817652935776038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/753817652935776038'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/06/adjusting-server-logging-level-at.html' title='Adjusting server logging level at runtime'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-7962302601635061486</id><published>2010-05-16T18:28:00.000-07:00</published><updated>2010-05-16T18:46:55.847-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='growl'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='growlnotify'/><title type='text'>Growling Mac</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/S_Cf27TKAlI/AAAAAAAAEUM/PD_QMF-IWU4/s1600/1304953088_7ee7791e3c_o.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 254px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/S_Cf27TKAlI/AAAAAAAAEUM/PD_QMF-IWU4/s320/1304953088_7ee7791e3c_o.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5472049313234944594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/poenaru/1304953088/"&gt;(pic from flickr)&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Last year I wrote a &lt;a href="http://justinsboringpage.blogspot.com/2009/09/making-emacs-growl.html"&gt;blog post &lt;/a&gt;about how to make growl notifications (little pop ups driven by the application Growl) appear from emacs in windows. Since then I've become a total Mac-head. Here's an update on how you get that working from emacs on a mac... &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Everything is the same except you need to install Growl for Mac (obv) and also make sure you copy the folder called Extras somewhere. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Open up a terminal and then cd to where you put the Extras directory. Find a sub-directory called growlnotify. Enter that and run 'sudo ./install.sh' which will prompt you for your admin password, and then go ahead and install &lt;a href="http://growl.info/extras.php#growlnotify"&gt;growlnotify&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can now run growlnotify from a terminal window. Try it out, if it doesn't work you won't be able to growl from emacs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now follow the instructions in my blog post above but ignore all the windows parts. You'll need to customize the growl command (M-x customize group, todochiku) and replace the full path I used for windows with just 'growlnotify'.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If everything is cool you can now do M-x todochiku-in and type a message, a time in minutes (zero for now), and pop, you should have a notification.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-7962302601635061486?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/7962302601635061486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=7962302601635061486' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7962302601635061486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7962302601635061486'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/05/growling-mac.html' title='Growling Mac'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/S_Cf27TKAlI/AAAAAAAAEUM/PD_QMF-IWU4/s72-c/1304953088_7ee7791e3c_o.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8771409391257460996</id><published>2010-04-17T10:01:00.000-07:00</published><updated>2010-04-17T10:14:06.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tar'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='gzip'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><title type='text'>Using tar and gzip</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/S8nsKLMATgI/AAAAAAAAEPQ/btpIHlvjqiw/s1600/3687651747_8b3c7a8760.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/S8nsKLMATgI/AAAAAAAAEPQ/btpIHlvjqiw/s320/3687651747_8b3c7a8760.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5461155682709425666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;Picture from flickr by Windwirral&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Here are the basic steps to use tar and gzip to package up some files in a compressed archive, so that you can move them to another computer or back them up.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First you want to create and add files to the archive. Go to the target directory and enter individual filenames and directories you want to have included.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;tar -vzcf mystuff.tar.gz file1.txt file2.doc mypictures/&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now you can test if that worked by listing the files in the archive.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;tar -tvf mystuff.tar.gz &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you want to extract the files, go to the folder where you want to extract them, in this case 'targetfolder'.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cd targetfolder&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;tar -vxf mystuff.tar.gz &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8771409391257460996?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8771409391257460996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8771409391257460996' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8771409391257460996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8771409391257460996'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/04/using-tar-and-gzip.html' title='Using tar and gzip'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/S8nsKLMATgI/AAAAAAAAEPQ/btpIHlvjqiw/s72-c/3687651747_8b3c7a8760.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8381517633293471232</id><published>2010-01-23T22:18:00.000-08:00</published><updated>2010-02-03T02:01:08.615-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good code'/><category scheme='http://www.blogger.com/atom/ns#' term='ipin'/><category scheme='http://www.blogger.com/atom/ns#' term='transmission'/><title type='text'>Nice Code</title><content type='html'>Just wanted to point out a couple of very nice pieces of source code I came across recently.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;b&gt;ipin.py&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Firstly check out this Python code &lt;a href="http://www.axelbrz.com.ar/?mod=iphone-png-images-normalizer"&gt;ipin.py&lt;/a&gt;, by Axel E. Brzostowski, which converts png files from an iphone application into a format that you can read on any computer.&lt;br /&gt;&lt;br /&gt;The python code is clean, easy to read, almost like literate programming. Very useful if you want to write a similar application that processes every file in a directory. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;transmission&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Another really nice program, is really a website. When you run transmission-daemon (linux bittorrent program), you can connect to it with a command line app called transmission-remote. In addition you can connect via a built in web server, which is a really excellently designed application. The html and javascript is so well documented and tidy it's as beautiful as the actual web page. Check it out here. &lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;a href="http://trac.transmissionbt.com/browser/trunk/web"&gt;http://trac.transmissionbt.com/browser/trunk/web&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;a href="http://trac.transmissionbt.com/browser/trunk/web"&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8381517633293471232?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8381517633293471232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8381517633293471232' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8381517633293471232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8381517633293471232'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/01/nice-code.html' title='Nice Code'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-6479120968828439722</id><published>2010-01-01T19:26:00.000-08:00</published><updated>2010-01-01T19:55:25.211-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='ssh. security'/><category scheme='http://www.blogger.com/atom/ns#' term='fail2ban'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Securing an ssh server with fail2ban</title><content type='html'>There are all kinds of ways to secure an ssh server, with varying degrees of increasing security and decreasing flexibility. For example by limiting your server to only accept connections from certain known IP's, you are secure from random hackers on the internet, but you lose the ability to connect to your machine from anywhere you want to. Perhaps while travelling, for example. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.linuxjournal.com/article/6811"&gt;Port knocking&lt;/a&gt; and listening on a high numbered non-standard port. make it harder for an attacker to even start trying to hack your connection. But this also requires you connect with a machine that you have the knock program installed on. Again, less convenient, more secure. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, once an attacker does find your port there's nothing to stop brute force password hacking. If you look in your log file, you should see people connecting to your ssh port quite frequently and trying password attacks. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;cat /var/log/auth.log&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have a secure password then it would require days of brute force hacking to gain access to your ssh account, but even so, if you don't watch your logs then it's perfectly possible somebody will gain access eventually. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Brute force attacks can be limited using fail2ban. There's a great article on setting it up &lt;a href="http://www.howtoforge.com/fail2ban_debian_etch"&gt;here&lt;/a&gt;. This program will scan your auth.log for you, using a regular expression to find failed password attempts. On a specified number of failures from a given IP, it will then modify the iptables on your machine (the firewall), to lock that IP out for a specified time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now instead of watching your auth.log fill up with reams of failed passwords, you'll see a greatly reduced amount of brute force attacks, and you can watch your fail2ban log file fill up with the IP addresses of hackers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-6479120968828439722?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/6479120968828439722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=6479120968828439722' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6479120968828439722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6479120968828439722'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/01/securing-ssh-server-with-fail2ban.html' title='Securing an ssh server with fail2ban'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-4469694132027966504</id><published>2010-01-01T18:49:00.000-08:00</published><updated>2010-01-01T18:57:45.808-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='screen'/><category scheme='http://www.blogger.com/atom/ns#' term='gnu'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Using screen</title><content type='html'>When running a linux app, perhaps on a remote box, you don't want it to terminate when you close the terminal window. You can run some applications as daemons, or run them with the nohup command (no hang up). &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    nohup ./myapp &gt; output.txt &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;will run the program myapp and send the output to output.txt.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can then follow the output.txt with a command &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    tail -f output.txt &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;but if you hit Ctrl-C or close the terminal (or have a power cut), the application will still be running on the remote machine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A more powerful solution is the Gnu screen application. This lets you run multiple shell sessions and switch between them. Using screen you can be logged into a server in your office, then detach from the screen session, go home and reattach to it there (assuming you have network access to the computer). &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a cheat sheet for using screen. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Running it:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    screen&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Learning to use it:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ctrl-a help&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Important commands:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ctrl-a c  (open a new window)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ctrl-a p  (prev window)&lt;/div&gt;&lt;div&gt;Ctrl-a n (next window)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;exit or C-a q to exit &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How to reattach to the screen session:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    screen -ls  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That shows screen sessions on the machine your logged on to, and then you reattach using:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;screen -r name&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's all folks!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-4469694132027966504?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/4469694132027966504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=4469694132027966504' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4469694132027966504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4469694132027966504'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2010/01/using-screen.html' title='Using screen'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8882538686469456338</id><published>2009-10-12T21:35:00.000-07:00</published><updated>2009-11-13T22:30:24.102-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='transparent'/><category scheme='http://www.blogger.com/atom/ns#' term='win32'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Transparent emacs on windows</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nkGbjVeC3i4/StQIyYwON5I/AAAAAAAADMc/lvO2Qo2ZidE/s1600-h/transparentemacs.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 186px;" src="http://2.bp.blogspot.com/_nkGbjVeC3i4/StQIyYwON5I/AAAAAAAADMc/lvO2Qo2ZidE/s320/transparentemacs.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5391944315600517010" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a handy function which lets you choose a transparent level (0 is fully transparent and 100 is opaque), for the main emacs frame in both focused and unfocused state.&lt;/div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;(defun transparent(alpha-level no-focus-alpha-level)&lt;br /&gt; "Let's you make the window transparent"&lt;br /&gt; (interactive "nAlpha level (0-100): \nnNo focus alpha level (0-100): ")&lt;br /&gt; (set-frame-parameter (selected-frame) 'alpha (list alpha-level no-focus-alpha-level))&lt;br /&gt; (add-to-list 'default-frame-alist `(alpha ,alpha-level)))&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;To run M-x transparent. &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Enter the values you want for when the window has focus and when it does not. &lt;/span&gt;In the background you can see system status information on the desktop, which is another excellent utility from sysinternals called &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb897557.aspx"&gt;BgInfo&lt;/a&gt;. It let's you display useful info about your system right on your desktop, similar to tools you may find on linux. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8882538686469456338?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8882538686469456338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8882538686469456338' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8882538686469456338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8882538686469456338'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/10/transparent-emacs-on-windows.html' title='Transparent emacs on windows'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nkGbjVeC3i4/StQIyYwON5I/AAAAAAAADMc/lvO2Qo2ZidE/s72-c/transparentemacs.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8927566122962137801</id><published>2009-10-09T12:18:00.000-07:00</published><updated>2009-10-09T12:27:44.527-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dos command line'/><category scheme='http://www.blogger.com/atom/ns#' term='for'/><category scheme='http://www.blogger.com/atom/ns#' term='msdos'/><title type='text'>MSDOS iterating filenames in a file</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: 800;"&gt;&lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;div&gt;In an earlier post I covered finding the writable files in a directory, which is something you often need to do when messing around with source control. For example, if there's a writable file in your source folder that isn't checked out, then you know you need to add it before checking in. In fact I have a tool that compares my changelist with the list of writable files, and lets me know if I'm about to break the build when I check in.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway I digress. Once you have found the writable files using:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;dir source_folder /a-r-d /s /b &gt; files.txt &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;then you may want to run some operation on them; for example make them read only.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's how to do that with the windows for command (see here for documentation)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;for /F %i in (files.txt) do attrib -R %i&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The for command with the /F option can iterate through a file full of filenames, which is what we generated with the first command, and run the operation after the do instruction.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's actually quite powerful; you can specify comment markers, delimiters, and choose which of a number of columns you want to make into variables.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8927566122962137801?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8927566122962137801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8927566122962137801' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8927566122962137801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8927566122962137801'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/10/msdos-iterating-filenames-in-file.html' title='MSDOS iterating filenames in a file'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8712323945964535851</id><published>2009-09-23T16:18:00.000-07:00</published><updated>2009-09-23T16:25:10.287-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='win32'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='command line'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='msdos'/><title type='text'>Windows command window title</title><content type='html'>Did you know you could change the title in the window of a command prompt using the title command? Example:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;title Poop ha ha &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now that's only really useful for making windows with rude words in their title bars right? Well actually, I've found a great use for it. If you have a bunch of command prompt windows open then you have no idea which one is which on the Windows taskbar, once they are stacked. So naming them is a really useful habit since once named you can see which window is which. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nkGbjVeC3i4/SrquGUTEZfI/AAAAAAAADLw/tNrqeV64eGY/s1600-h/title.png"&gt;&lt;img src="http://2.bp.blogspot.com/_nkGbjVeC3i4/SrquGUTEZfI/AAAAAAAADLw/tNrqeV64eGY/s200/title.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5384807728025986546" style="cursor: pointer; width: 200px; height: 146px; " /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8712323945964535851?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8712323945964535851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8712323945964535851' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8712323945964535851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8712323945964535851'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/09/windows-command-window-title.html' title='Windows command window title'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nkGbjVeC3i4/SrquGUTEZfI/AAAAAAAADLw/tNrqeV64eGY/s72-c/title.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-6655036230173716868</id><published>2009-09-21T09:55:00.000-07:00</published><updated>2009-09-21T09:57:28.816-07:00</updated><title type='text'>English quote in Common Lisp</title><content type='html'>(defun today() (cadr days-of-your-life))&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-6655036230173716868?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/6655036230173716868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=6655036230173716868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6655036230173716868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6655036230173716868'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/09/english-quote-in-common-lisp.html' title='English quote in Common Lisp'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2647983504768597886</id><published>2009-09-10T07:13:00.000-07:00</published><updated>2010-03-26T13:02:26.272-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='growl'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Making emacs growl</title><content type='html'>&lt;a href="http://www.flickr.com/photos/tambako/494118044/" title="Roaring lion by Tambako the Jaguar, on Flickr"&gt;&lt;img src="http://farm1.static.flickr.com/193/494118044_a0439df4c9.jpg" alt="Roaring lion" height="375" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;&lt;br /&gt;I've always wished emacs could notify me of it's doings. For example the message function just pops up text in the minibuffer and is easy to miss, and impossible to see when the window is not in focus. So I was pleased when looking through the &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.emacswiki.org/cgi-bin/emacs/twit.el"&gt;twit.el&lt;/a&gt;&lt;span style="font-family:arial;"&gt; code to find out about todochiku, and emacs interface to Growl.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Download &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.growlforwindows.com/gfw/"&gt;Growl for windows&lt;/a&gt;&lt;span style="font-family:arial;"&gt; and set it up. Send yourself a test growl at the command prompt like this: &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;"C:/Progra~1/Growlf~1/growlnotify.exe" /T:"title" "message"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Once that's working you can send notifications from emacs. &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.emacswiki.org/emacs/ToDoChiKu"&gt;todochiku&lt;/a&gt;&lt;span style="font-family:arial;"&gt; is an emacs package for sending notifications to growl, snarl or whatever you have. In our case we have growl. Unfortunately the windows default is to use snarl, and there's no support for growl. I've made a few modifications to the original to get that working and uploaded the new file here. &lt;/span&gt;(Ideally I should make it so it searches both for windows and for growl or snarl being installed but for now the choice is made manually)&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: arial;" href="http://www.heyes-jones.com/todochiku.el"&gt;heyes-jones.com/todochiku.el&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Download the elisp file into a directory in your emacs load-path (or add it) and add the (require 'todochiku) command to your .emacs file. Reload emacs, or just hit &lt;span style="font-weight: bold;"&gt;C-x e&lt;/span&gt; after the (require command in your .emacs)&lt;br /&gt;&lt;br /&gt;&lt;div&gt;You will need (require 'cl) somewhere before this is loaded (.emacs perhaps)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Customize the variables for the program using M-x customize-group todochiku&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;You'll need to set the `todochiku command' to &lt;/span&gt;something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;"&gt;C:/Progra~1/Growlf~1/growlnotify.exe&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Use "Dir /x *" in a folder to find out what the 8 character name is.&lt;br /&gt;&lt;br /&gt;If you want icons that come with todochiku then download them from the todochiku wiki page and point to them with the variable `todochiku icons directory'. For example mine is set to:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;"&gt;~/localemacs/todochiku-icons&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally you can do a growl... try this&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;"&gt;(growl "Emacs" "Hello")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: arial;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nkGbjVeC3i4/SqnEPAOrP1I/AAAAAAAADFM/lxhiNQtcxfg/s1600-h/growl.png"&gt;&lt;img style="cursor: pointer; width: 304px; height: 320px;" src="http://3.bp.blogspot.com/_nkGbjVeC3i4/SqnEPAOrP1I/AAAAAAAADFM/lxhiNQtcxfg/s320/growl.png" alt="" id="BLOGGER_PHOTO_ID_5380046991909404498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There's also `todochiku-message' which let's you specify an icon. This can be an image filename, and url, or an icon symbol from the built in list of icons you can find by the variable `todochiku-icons'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-family:courier new;"&gt;(todochiku-message "Emacs" "You're growlingnow" 'social)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(todochiku-message "Emacs" "You're growlingnow" "http://www.growlforwindows.com/gfw/images/downloadlatest.gif")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(todochiku-message "Emacs" "You're growlingnow" &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;"c:/cygwin/home/Justin/localemacs/todochiku-icons/binary.png")&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;There's a command `todochiku-in' which will send you a notification from emacs in a set number of minutes.&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(todochiku-in "hello" 3)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;If you use twit.el you should find that todochiku automatically notifying you of tweets if you have called `show-recent-tweets'.&lt;br /&gt;&lt;br /&gt;It's very simple to use todochiku and growl so you should find all kinds of applications for this. Have fun!&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2647983504768597886?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2647983504768597886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2647983504768597886' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2647983504768597886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2647983504768597886'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/09/making-emacs-growl.html' title='Making emacs growl'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm1.static.flickr.com/193/494118044_a0439df4c9_t.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8584530707656079403</id><published>2009-09-08T14:12:00.001-07:00</published><updated>2009-09-08T14:12:54.886-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Directional window movement in emacs</title><content type='html'>One thing I sometimes miss about the text editor Brief, which I stopped using a decade ago, is being able to move between windows easily by pressing a function key and then an arrow key to switch to a window in that direction.&lt;br /&gt;&lt;br /&gt;In emacs I only knew how to move between windows using `other-window', mapped to &lt;span style="font-style: italic;"&gt;C-x o &lt;/span&gt;and that only cycles around the windows, and if you have a few windows open and possibly you're also editing the mini-buffer, that's quite a round trip.&lt;br /&gt;&lt;br /&gt;I just learned about `M-x windmove-default-keybindings', which binds a set of commands that do exactly the kind of directional movement I'm talking about (`windmove-right', `windmove-up' and so on) to the cursor keys (with shift key held).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8584530707656079403?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8584530707656079403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8584530707656079403' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8584530707656079403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8584530707656079403'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/09/directional-window-movement-in-emacs.html' title='Directional window movement in emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-7404340950619629013</id><published>2009-09-01T14:37:00.000-07:00</published><updated>2009-09-01T14:57:27.714-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Handful of emacs tips</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:lucida grande;"&gt;keep-lines&lt;br /&gt;flush-lines&lt;br /&gt;&lt;br /&gt;These handy functions prompt you for a regular expression and will either remove every line that does not contain that expression (keep) or remove the ones that do (flush&lt;/span&gt;&lt;span style="font-family:lucida grande;"&gt;).&lt;br /&gt;&lt;br /&gt;finder-list-keywords&lt;br /&gt;&lt;br /&gt;This function shows all the keywords used in the packages within emacs. In other words you can find a lot of stuff in emacs that you never knew was there.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nkGbjVeC3i4/Sp2Yo-V-6mI/AAAAAAAAC-o/ktl1yzdx57k/s1600-h/finder.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 341px;" src="http://1.bp.blogspot.com/_nkGbjVeC3i4/Sp2Yo-V-6mI/AAAAAAAAC-o/ktl1yzdx57k/s400/finder.png" alt="" id="BLOGGER_PHOTO_ID_5376621359847631458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:lucida grande;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-7404340950619629013?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/7404340950619629013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=7404340950619629013' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7404340950619629013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7404340950619629013'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/09/handful-of-emacs-tips.html' title='Handful of emacs tips'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nkGbjVeC3i4/Sp2Yo-V-6mI/AAAAAAAAC-o/ktl1yzdx57k/s72-c/finder.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1025737698734808846</id><published>2009-08-26T23:36:00.000-07:00</published><updated>2009-08-26T23:45:06.359-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs-lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='money'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='budget'/><title type='text'>Simple budget forecasts in emacs</title><content type='html'>&lt;a href="http://www.flickr.com/photos/amagill/3367543296/" title="Money by AMagill, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3600/3367543296_1470ef5247.jpg" width="350" alt="Money" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When I first moved from England to North America one of the things I found hard to get used to was getting paid every two weeks instead of monthly. This means that some of your bills are monthly, some are biweekly, and occasionally I had more or less money than I expected as they got out of sync.&lt;br /&gt;&lt;br /&gt;I've been using a simple elisp program I wrote to let you manage your upcoming bills, weekly budget items like groceries, and your regular income. It runs through a period of dates you supply, and a list of incomes and expenses, and produces a csv file and a buffer that contains the output of the forecast. It shows the highest and lowest balance of the period too, so you can spot if you will go over drawn, and also see peaks when it's a good time to move money to savings.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The code is hosted on google code as &lt;a href="http://code.google.com/p/emacs-easy-budget/"&gt;emacs-easy-budget&lt;/a&gt; and is also released as GPL v3. Hope somebody finds it useful.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1025737698734808846?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1025737698734808846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1025737698734808846' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1025737698734808846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1025737698734808846'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/08/simple-budget-forecasts-in-emacs.html' title='Simple budget forecasts in emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3600/3367543296_1470ef5247_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3475121921992898143</id><published>2009-06-17T11:41:00.000-07:00</published><updated>2009-06-17T11:44:01.366-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='stack overflow'/><category scheme='http://www.blogger.com/atom/ns#' term='geek'/><title type='text'>1337 on StackOverflow</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/Sjk5OqEilwI/AAAAAAAACck/KKPYdGdXBjM/s1600-h/leetstackoverflow.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 32px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/Sjk5OqEilwI/AAAAAAAACck/KKPYdGdXBjM/s200/leetstackoverflow.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5348368956453459714" /&gt;&lt;/a&gt;&lt;br /&gt;I noticed today that my StackOverflow reputation is 1337. What an incredibly geeky way to begin Wednesday!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3475121921992898143?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3475121921992898143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3475121921992898143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3475121921992898143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3475121921992898143'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/06/1337-on-stackoverflow.html' title='1337 on StackOverflow'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/Sjk5OqEilwI/AAAAAAAACck/KKPYdGdXBjM/s72-c/leetstackoverflow.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5959363046281937511</id><published>2009-05-27T10:35:00.000-07:00</published><updated>2009-05-27T10:38:48.273-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='modified'/><category scheme='http://www.blogger.com/atom/ns#' term='file search'/><category scheme='http://www.blogger.com/atom/ns#' term='time'/><title type='text'>Linux: Looking at files changed recently</title><content type='html'>This is really handy (on Linux and Cygwin) when you're working on a project that may not be in source control and you want to see what you changed recently. &lt;br /&gt;&lt;br /&gt;I made this blog post, when it seems a trivial use of find, because I don't think the man page covers it well. &lt;br /&gt;&lt;br /&gt;This command finds all files modified in the last 60 minutes:&lt;br /&gt;&lt;br /&gt;find . -type f -cmin -60&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5959363046281937511?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5959363046281937511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5959363046281937511' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5959363046281937511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5959363046281937511'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/linux-looking-at-files-changed-recently.html' title='Linux: Looking at files changed recently'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5144824078220087756</id><published>2009-05-14T16:48:00.000-07:00</published><updated>2009-05-14T16:51:25.869-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mingw32 link errors GetProcessMemoryInfo EnumProcesses'/><title type='text'>Linking MingW32 with psapi</title><content type='html'>Here's something I came across that didn't have a good answer when I googled. If you get link errors with MingW32 like:&lt;br /&gt;&lt;br /&gt;undefined reference to `GetProcessMemoryInfo@12' or &lt;br /&gt;c:/justinhj/mem.cpp:55: undefined reference to `EnumProcesses@12'&lt;br /&gt;&lt;br /&gt;Then you are not linking with the library psapi, and you need it. &lt;br /&gt;&lt;br /&gt;To do this just add -lpsapi to your command line. It needs to be last in the list of libraries too!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5144824078220087756?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5144824078220087756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5144824078220087756' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5144824078220087756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5144824078220087756'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/linking-mingw32-with-psapi.html' title='Linking MingW32 with psapi'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3500343950147124068</id><published>2009-05-14T16:36:00.000-07:00</published><updated>2009-05-19T19:10:44.999-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='compile'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Writing quick C++ programs in emacs without a makefile</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/SgyrtjhXGUI/AAAAAAAACS8/f4sO655etfc/s1600-h/cheetah.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 239px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/SgyrtjhXGUI/AAAAAAAACS8/f4sO655etfc/s320/cheetah.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5335828457644824898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/storm-crypt/"&gt;Cheetah by Storm Crypt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Often when programming in C++ (or many other languages) it's desirable to write a quick program, usually a console application, to test something quickly. Working in developer studio, it takes an amount of fiddling and clicking large enough that you may not want to bother.&lt;br /&gt;&lt;br /&gt;Working in emacs and MingW32 (or Microsoft's CL.exe) I can quickly create a CPP file, and then compile it. To compile a program though you need to either write a makefile, or build up a complex g++ command line. &lt;br /&gt;&lt;br /&gt;Rather than do either of those I make a helloworld.cpp file which can be built like this: &lt;br /&gt;&lt;br /&gt;g++ helloworld.cpp -g -o helloworld.exe&lt;br /&gt;&lt;br /&gt;So I hit &lt;br /&gt;&lt;br /&gt;M-x compile&lt;br /&gt;&lt;br /&gt;then type in the above to compile and link it. &lt;br /&gt;&lt;br /&gt;However there's a better way. You can add the compile command as the first line of the file as a file local variable. &lt;br /&gt;&lt;br /&gt;// -*- compile-command:"g++ helloworld.cpp -g -o helloworld.exe"; -*-&lt;br /&gt;&lt;br /&gt;Now I can hit the compile and it works right away, between sessions. No makefile or project settings in sight, and now there are minimal barriers involved in creating a simple test program beyond copy and pasting the file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3500343950147124068?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3500343950147124068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3500343950147124068' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3500343950147124068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3500343950147124068'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/writing-quick-c-programs-in-emacs.html' title='Writing quick C++ programs in emacs without a makefile'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/SgyrtjhXGUI/AAAAAAAACS8/f4sO655etfc/s72-c/cheetah.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5215613646239896457</id><published>2009-05-12T21:59:00.000-07:00</published><updated>2009-05-12T22:02:27.441-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mp3 flac convert lame'/><title type='text'>Converting flac to mp3</title><content type='html'>This is just a link to a great description of converting flac to mp3 files. There's a tonne of commercial and useless sites that try to answer this question&lt;br /&gt;&lt;br /&gt;So I thought I'd add another link to this one that actually works, and uses free software.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.afterdawn.com/guides/archive/how_to_convert_flac_files_to_mp3.cfm"&gt;http://www.afterdawn.com/guides/archive/how_to_convert_flac_files_to_mp3.cfm&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5215613646239896457?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5215613646239896457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5215613646239896457' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5215613646239896457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5215613646239896457'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/converting-flac-to-mp3.html' title='Converting flac to mp3'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8561702168887884887</id><published>2009-05-08T08:33:00.000-07:00</published><updated>2009-05-08T08:34:41.695-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs rename files'/><title type='text'>emacs: Renaming multiple files at once with a regular expression</title><content type='html'>M-x dired&lt;br /&gt;(navigate to the folder)&lt;br /&gt;M-x wdired-change-to-wdired-mode&lt;br /&gt;M-x replace-regexp&lt;br /&gt;(enter search and replace expressions)&lt;br /&gt;C-c C-c &lt;br /&gt;&lt;br /&gt;Which writes out the changes to the directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8561702168887884887?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8561702168887884887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8561702168887884887' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8561702168887884887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8561702168887884887'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/emacs-renaming-multiple-files-at-once.html' title='emacs: Renaming multiple files at once with a regular expression'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5188561538500548498</id><published>2009-05-07T09:08:00.000-07:00</published><updated>2009-05-19T11:17:24.112-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>emacs: Searching programming API's with webjump</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nkGbjVeC3i4/SgMKSJ9NvdI/AAAAAAAACSc/ZhXIZmFx3Jk/s1600-h/hideandseek.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 223px;" src="http://3.bp.blogspot.com/_nkGbjVeC3i4/SgMKSJ9NvdI/AAAAAAAACSc/ZhXIZmFx3Jk/s320/hideandseek.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5333117690763394514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Image by &lt;a href="http://www.flickr.com/photos/markybon/"&gt;MarkyBon&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;In a &lt;/span&gt;&lt;a href="http://justinsboringpage.blogspot.com/2009/02/search-reddit-flickr-and-google-from.html"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;previous post&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt; I outlined how to use webjump, a built in feature of emacs to quickly launch web pages in a browser, after querying the user for search phrases and so on.&lt;br /&gt;&lt;br /&gt;This describes how to simply setup webjump to search the API documentation for whatever framework you are using. The example will be Java's Platform documentation. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Find the base url you want to search. We will use google to only find things that begin with this. In the case of Javas documentation I'm going to search at &lt;/span&gt;&lt;a href="http://java.sun.com/javase/6/docs/api/"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;http://java.sun.com/javase/6/docs/api&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;/&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Set up the web jump code as below. The three arguments in square brackets are [ base url, normal search url prefix, search url post fix ]. You just need to replace the JAVA API part of my URL with the URL you are interested in.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;M-x webjump&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Type your query and hit enter&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Browser opens with search results&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;(require 'webjump)&lt;br /&gt;(global-set-key [f2] 'webjump)&lt;br /&gt;(setq webjump-sites&lt;br /&gt;(append '(&lt;br /&gt;("Java API" .&lt;br /&gt;[simple-query "www.google.com" "http://www.google.ca/search?hl=en&amp;amp;as_sitesearch=http://java.sun.com/javase/6/docs/api/&amp;amp;q=" ""])&lt;br /&gt;)&lt;br /&gt;      webjump-sample-sites))&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5188561538500548498?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5188561538500548498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5188561538500548498' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5188561538500548498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5188561538500548498'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/05/emacs-searching-programming-apis-with.html' title='emacs: Searching programming API&apos;s with webjump'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nkGbjVeC3i4/SgMKSJ9NvdI/AAAAAAAACSc/ZhXIZmFx3Jk/s72-c/hideandseek.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2739159345223074504</id><published>2009-04-15T10:49:00.001-07:00</published><updated>2009-06-03T09:27:22.374-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='elisp'/><category scheme='http://www.blogger.com/atom/ns#' term='mark files'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='dired'/><title type='text'>Running an elisp function on each marked file in a dired buffer</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/SiajYmJlKzI/AAAAAAAACYk/lUIZ4tMObYg/s1600-h/chaintool_florian.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/SiajYmJlKzI/AAAAAAAACYk/lUIZ4tMObYg/s200/chaintool_florian.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5343137650874592050" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;Chain Tool by &lt;/span&gt;&lt;a href="http://www.flickr.com/photos/fboyd/"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;Florian&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have some function, say some custom refactoring operation, you can call it from a dired buffer, and have it run on each marked file, using the code below. &lt;br /&gt;&lt;br /&gt;Go into a dired buffer, mark some files, and then do M-x and run your command. In this case it would be &lt;i&gt;test-for-each-dired-marked-file&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;;;; iterating over files in dired&lt;br /&gt;&lt;br /&gt;;;; usage example - for-each-dired-marked-file returns a filename and path&lt;br /&gt;;;; for each marked file, so this is what a function using it looks like&lt;br /&gt;(defun view-stuff(filename)&lt;br /&gt;"opens up the file and gets the length of it, then messages the result"&lt;br /&gt;(let (fpath fname mybuffer len)&lt;br /&gt;  (setq fpath filename)&lt;br /&gt;  (setq fname (file-name-nondirectory fpath))&lt;br /&gt;  (setq mybuffer (find-file fpath))&lt;br /&gt;  (setq len (buffer-size))&lt;br /&gt;  (kill-buffer mybuffer)&lt;br /&gt;  (message "Buffer length %d %s" len (buffer-file-name mybuffer))))&lt;br /&gt;&lt;br /&gt;; Usage example&lt;br /&gt;(defun test-for-each-dired-marked-file()&lt;br /&gt;(interactive)&lt;br /&gt;(for-each-dired-marked-file 'view-stuff))&lt;br /&gt;&lt;br /&gt;(defun for-each-dired-marked-file(fn)&lt;br /&gt;"Do stuff for each marked file, only works in dired window"&lt;br /&gt;(interactive)&lt;br /&gt;(if (eq major-mode 'dired-mode)&lt;br /&gt;   (let ((filenames (dired-get-marked-files)))&lt;br /&gt;     (mapcar fn filenames))&lt;br /&gt; (error (format "Not a Dired buffer \(%s\)" major-mode))))&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2739159345223074504?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2739159345223074504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2739159345223074504' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2739159345223074504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2739159345223074504'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/04/running-elisp-function-on-each-marked.html' title='Running an elisp function on each marked file in a dired buffer'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/SiajYmJlKzI/AAAAAAAACYk/lUIZ4tMObYg/s72-c/chaintool_florian.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-9072046395097548498</id><published>2009-04-02T11:51:00.000-07:00</published><updated>2009-04-02T11:56:10.102-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux cygwin secure file transfer'/><title type='text'>Securely copying files to another machine</title><content type='html'>Fast post about copying files between computers over a secure connection.&lt;br /&gt;&lt;br /&gt;Linux and Cygwin comes with scp, a secure version of cp.&lt;br /&gt;&lt;br /&gt;Usage... in this case I'm copying a file from my cygwin (putty) terminal to a remote machine.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;scp /cygdrive/c/Documents and Settings/myname/My Documents/interestingfile.txt usernameonmachine@1.2.3.3:/home/usernameonmachine/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;You should get a password prompt and see the transfer complete as follows.&lt;br /&gt;&lt;br /&gt;interestingfile.txt                               100%   34KB  34.3KB/s   00:00&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-9072046395097548498?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/9072046395097548498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=9072046395097548498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/9072046395097548498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/9072046395097548498'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/04/securely-copying-files-to-another.html' title='Securely copying files to another machine'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8333237791498294917</id><published>2009-03-18T08:46:00.000-07:00</published><updated>2009-03-18T08:50:23.411-07:00</updated><title type='text'>Vancouver game companies</title><content type='html'>I've copied this excellent list of Vancouver game companies from :&lt;br /&gt;&lt;br /&gt;&lt;a href="http://csciun1.mala.bc.ca:8080/%7Ewesselsd/gamedev/index.html"&gt;http://csciun1.mala.bc.ca:8080/~wesselsd/gamedev/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please not that the number of jobs for each one is constantly changing, and so will be only (roughly) correct at the time I posted this.&lt;br /&gt;&lt;br /&gt;   &lt;li&gt;&lt;a href="http://www.acronymonline.com/"&gt; Acronym Games&lt;/a&gt; (7 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.actionpantsinc.com/"&gt; Action Pants Inc &lt;/a&gt; (always recruiting multiple positions)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.airg.com/"&gt; AirG &lt;/a&gt; (2 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.atomicrobotgames.com/"&gt; Atomic Robot Games &lt;/a&gt; (always recruiting)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.backboneentertainment.com/"&gt; Backbone Entertainment/Foundation 9/Digital Eclipse &lt;/a&gt; (2 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.bardelentertainment.com/"&gt; Bardel Entertainment Inc. &lt;/a&gt; (3+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.bigsandwichgames.com/"&gt; BigSandwich Games &lt;/a&gt; (4+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.bluecastlegames.com/"&gt; Blue Castle Games &lt;/a&gt; (14 jobs + 3 co-op jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.credo-interactive.com/"&gt; Credo Interactive &lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.deepfriedentertainment.com/"&gt; Deep Fried Entertainment &lt;/a&gt; (8+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ea.com/"&gt; Electronic Arts Canada &lt;/a&gt; (21 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.gekidodesigns.com/"&gt; Gekido Design Group &lt;/a&gt; (3+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.hotdogday.com/"&gt; Hot Dog Day &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.hotheadgames.com/"&gt; HotHead Games &lt;/a&gt; (2 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.inlightentertainment.com/"&gt; InLight Entertainment (Victoria) &lt;/a&gt; (5+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.icgamesoft.com/"&gt; InterScape Creations &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ironcladgames.com/"&gt; IronClad Games&lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.iugome.com/"&gt; IUGO &lt;/a&gt; (2 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jarheadgames.com/"&gt; Jarhead Games &lt;/a&gt; (always recruiting)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jetblackgames.com/"&gt; JetBlack Games &lt;/a&gt; (1 job)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.justleapin.com/"&gt; Just Leap In &lt;/a&gt; (4+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.koolhausgames.com/"&gt; KoolHaus Games &lt;/a&gt; (10 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.lavamind.com/"&gt; LavaMind &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.lunny.com/"&gt; The Lunny Group &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.magellaninteractive.com/"&gt; Magellan Interactive &lt;/a&gt; (3 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.magnetargames.com/"&gt; Magnetar Games &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.nerdcorps.ca/"&gt; Nerd Corps Entertainment &lt;/a&gt; (7+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.nextlevelgames.com/"&gt; Next Level Games &lt;/a&gt; (4 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.nintendo.ca/"&gt; Nintendo of Canada &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.orangeviewgames.com/"&gt; Orangeview Games &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.piranha-games.com/"&gt; Piranha Games Inc. &lt;/a&gt; (always recruiting)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.propagandagames.go.com/"&gt; Propaganda Games &lt;/a&gt; (5 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.radical.ca/"&gt; Radical Entertainment &lt;/a&gt; (16 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.rainmaker.com/"&gt; Rainmaker &lt;/a&gt; (30+ jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.relic.com/"&gt; Relic Entertainment &lt;/a&gt; (12 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.rockstarvancouver.com/"&gt; Rockstar Vancouver &lt;/a&gt; (5 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.facegen.com/"&gt; Singular Inversions &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.slantsixgames.com/"&gt; Slant Six Games &lt;/a&gt; (6 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.smokingguninc.com/"&gt; Smoking Gun Interactive &lt;/a&gt; (5 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.threewavesoftware.com/"&gt; Threewave &lt;/a&gt; (8 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.trueview.net/"&gt; TrueView Rendering and Animation &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.unitedfrontgames.com/"&gt; United Front Games &lt;/a&gt; (3 jobs)&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.yamisoft.com/"&gt; Yamisoft Entertainment Inc. &lt;/a&gt;&lt;br /&gt;   &lt;/li&gt;&lt;li&gt;&lt;a href="http://www.yummy.net/"&gt; Yummy Interactive &lt;/a&gt; (1 job)&lt;/li&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8333237791498294917?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8333237791498294917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8333237791498294917' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8333237791498294917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8333237791498294917'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/03/vancouver-game-companies.html' title='Vancouver game companies'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-5815951488324447581</id><published>2009-03-09T10:06:00.000-07:00</published><updated>2010-05-10T11:54:44.249-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs source browsing tags win32 etags Emacs cygwin'/><title type='text'>Using tags in emacs on windows</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nkGbjVeC3i4/SbVQbc-LTaI/AAAAAAAACHk/hgWI49WsfaM/s1600-h/tags.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 200px;" src="http://4.bp.blogspot.com/_nkGbjVeC3i4/SbVQbc-LTaI/AAAAAAAACHk/hgWI49WsfaM/s200/tags.jpg" alt="" id="BLOGGER_PHOTO_ID_5311239768117038498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This requires you install the Gunwin32 tools or Cygwin, and describes how to build a tags table for the project you're working on, when using emacs to edit the source.&lt;br /&gt;&lt;br /&gt;First you want to generate a file containing all the source files you want to have tagged. Go to the root folder of your project.&lt;br /&gt;&lt;pre&gt;find . -regex ".*\(h$\|cpp$\)" &gt; files.txt&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family: arial;font-size:100%;" &gt;Next pass this to etags to generate the tags table.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;etags.exe - &lt; files.txt &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: arial;"&gt;Then when you're in emacs you need to visit the tags table, which will have been saved as TAGS.  M-x visit-tags-table  then browse to the folder where you made the TAGS file.  Now when you have the curser on some function you can type...  M-.  to go to a tag and  C-u M-.  to go to the next tag.  Once you're done, you can return to where you started with  M-*  Another useful function is  tags-apropos  Which will list all the tags matching a regex in a buffer.        &lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-5815951488324447581?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/5815951488324447581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=5815951488324447581' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5815951488324447581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/5815951488324447581'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/03/using-tags-in-emacs-on-windows.html' title='Using tags in emacs on windows'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nkGbjVeC3i4/SbVQbc-LTaI/AAAAAAAACHk/hgWI49WsfaM/s72-c/tags.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3608530477966491695</id><published>2009-02-20T10:31:00.000-08:00</published><updated>2009-03-25T09:05:12.372-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs smtp sending mail windows win32'/><title type='text'>Sending mail with emacs in Windows</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nkGbjVeC3i4/SZ76_EgKKwI/AAAAAAAACE8/pLWgnmo0Y40/s1600-h/pigeon.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: right; cursor: pointer; width: 120px; height: 200px;" src="http://3.bp.blogspot.com/_nkGbjVeC3i4/SZ76_EgKKwI/AAAAAAAACE8/pLWgnmo0Y40/s200/pigeon.jpg" alt="" id="BLOGGER_PHOTO_ID_5304953372536351490" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Thanks to a commenter in my earlier blog post for pointing me to this way of sending mail that actually does work:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.emacswiki.org/emacs/GnusMSMTP"&gt;http://www.emacswiki.org/emacs/GnusMSMTP&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You need to download msstp from sourceforge and install the exe in your path.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/msmtp/"&gt;http://sourceforge.net/projects/msmtp/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There is one change I needed to make to get this working. In the config file:&lt;br /&gt;&lt;br /&gt;msmtprc.txt&lt;br /&gt;&lt;br /&gt;You need to add a line&lt;br /&gt;&lt;br /&gt;from your.email@address.here&lt;br /&gt;&lt;br /&gt;Without that I was getting an error number and no email. If you run into a problem like that you can make sure MSSTP is running by trying it from the command line:&lt;br /&gt;&lt;br /&gt;msmtp -a yourname some@recipient.com&lt;br /&gt;&lt;br /&gt;Type some mail and hit Ctrl-Z and it should send correctly.&lt;br /&gt;&lt;br /&gt;Once that is working you can enter gnus within emacs, and send a mail using:&lt;br /&gt;&lt;br /&gt;M-x message-mail&lt;br /&gt;&lt;br /&gt;Fill out the fields and type C-c C-c and it should send correctly.&lt;br /&gt;&lt;br /&gt;A security issue with this is that it doesn't seem to work if you leave your password empty in the configuration file. From the command line it simply prompts you for your password and away you go, but from emacs it just hangs. So if you use this method you're taking the huge risk of having your password in a readable file on the hard drive.  I'll be trying to find a way around that before using this permanently.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3608530477966491695?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3608530477966491695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3608530477966491695' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3608530477966491695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3608530477966491695'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/sending-mail-with-emacs-in-windows.html' title='Sending mail with emacs in Windows'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nkGbjVeC3i4/SZ76_EgKKwI/AAAAAAAACE8/pLWgnmo0Y40/s72-c/pigeon.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1106913014461800146</id><published>2009-02-16T17:12:00.000-08:00</published><updated>2009-02-16T17:17:31.095-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++ a* a star cpp games'/><title type='text'>Who uses the A* code</title><content type='html'>I often wonder who uses the A* code. Sometimes people write to me to tell me they've used the code in their University assignments or just for fun, but has anyone used this in a project that I don't know about?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/a-star-algorithm-implementation/"&gt;My A* algorithm on google code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;During my time at Activision I worked on a code base that included some code from their game Gun, and was happy to find my code, verbatim included there too! &lt;br /&gt;&lt;br /&gt;Also, today, I downloaded a 2d game prototyping engine called Angel, from some EA guys. When I looked at how their path finding worked, I was surprised to see my code in there too! &lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/angel-engine/"&gt;http://code.google.com/p/angel-engine/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's cool that people are using this code. If you do use it in some commercial or interesting project, please let me know. A credit or thank you in your product would be nice too!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1106913014461800146?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1106913014461800146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1106913014461800146' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1106913014461800146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1106913014461800146'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/who-uses-a-code.html' title='Who uses the A* code'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1598145118141425524</id><published>2009-02-16T17:04:00.000-08:00</published><updated>2009-02-16T17:17:54.042-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++ astar a* game programming bugs'/><title type='text'>A* algorithm bug fixes</title><content type='html'>It's been a while since I checked the issues page on my A* algorithm google code project. So it turns out there's a possible memory leak and the Manhattan distance calculation in the findpath.cpp is wrong. I've investigated both of these and uploaded a fixed version.&lt;br /&gt;&lt;br /&gt;In the case of the memory leak, there is some code in my "fast simple allocator" which allocates some memory, assigns it to a temporary pointer, then converts it and stores it in a member variable. Apparently, this shows up in memory tracking software as a leak, even though the memory is released in the destructor, so I've changed the code so that the allocation and free is done with the same variable. &lt;br /&gt;&lt;br /&gt;The Manhattan distance refers to a simple heuristic for finding a path when you can only move horizontally and vertically through a grid. Like calculating how far you would have to walk in a city on a grid system, like NY, you simple count how many blocks along and how many blocks up you need to walk. Well I implemented this carelessly and forgot to make sure that I take the absolute value when calculating the difference between 'streets'. That's done now. &lt;br /&gt;&lt;br /&gt;You can download the latest version of the A* algorithm here...&lt;br /&gt;&lt;br /&gt;http://code.google.com/p/a-star-algorithm-implementation/downloads/list&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1598145118141425524?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1598145118141425524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1598145118141425524' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1598145118141425524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1598145118141425524'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/algorithm-bug-fixes.html' title='A* algorithm bug fixes'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8177538575446771997</id><published>2009-02-13T22:42:00.000-08:00</published><updated>2009-02-13T22:58:00.366-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs lispworks slime win32'/><title type='text'>Setting up lispworks personal</title><content type='html'>I've always used this excellent pair of blog posts by Bill Clementson to get lispworks personal working with emacs/slime on windows. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://bc.tech.coop/blog/040306.html"&gt;Configuring SLIME for 3 Win32 CL Implementations&lt;/a&gt;&lt;br /&gt;&lt;a href="http://bc.tech.coop/blog/040315.html"&gt;Using LispWorks Personal with Emacs/SLIME on Windows&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Having had the joy of a hard drive failure last week I had to reinstall everything, and I've found that with the latest CVS version of slime you need to change your ".slime.lisp" file to look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(load "/YOURPATHTOSLIME/slime/swank-loader.lisp")&lt;br /&gt;(swank-loader:init)&lt;br /&gt;(swank::create-server :port 4005)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So if your slime/lispworks personal setup stops working when you upgrade slime, hopefully you found your way here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8177538575446771997?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8177538575446771997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8177538575446771997' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8177538575446771997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8177538575446771997'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/setting-up-lispworks-personal.html' title='Setting up lispworks personal'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8122691330096066744</id><published>2009-02-13T22:07:00.000-08:00</published><updated>2009-02-13T22:33:45.386-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs web searches web jump'/><title type='text'>Searching Reddit, Flickr, and Google from emacs = Rad</title><content type='html'>I came across another brilliantly useful corner of emacs today.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.neilvandyke.org/webjump/"&gt;webjump&lt;/a&gt; by Neil Van Dyke is part of emacs and Xemacs, and gives you a way to assign memorable names to web site urls, and to build simple search queries. It then opens the website using emacs' built in browse-url function.&lt;br /&gt;&lt;br /&gt;Set up is easy. All you need to add something like this to .emacs:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(require 'webjump)&lt;br /&gt;(global-set-key [f2] 'webjump)&lt;br /&gt;(setq webjump-sites&lt;br /&gt;      (append '(&lt;br /&gt;  ("Reddit Search" .&lt;br /&gt;   [simple-query "www.reddit.com" "http://www.reddit.com/search?q=" ""])&lt;br /&gt;  ("Google Image Search" .&lt;br /&gt;   [simple-query "images.google.com" "images.google.com/images?hl=en&amp;q=" ""])&lt;br /&gt;  ("Flickr Search" .&lt;br /&gt;   [simple-query "www.flickr.com" "flickr.com/search/?q=" ""])&lt;br /&gt;  )&lt;br /&gt;       webjump-sample-sites))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The first line just makes sure the feature is loaded, and then I bind the webjump function to F2 in the second line. &lt;br /&gt;&lt;br /&gt;To use webjump, just press F2, and press TAB to expand the sample sites that are built in, and the ones we just added above. Type Flickr Search for example, and then you get a prompt for the search string. Once you enter that your browser should open with flickr showing the search. &lt;br /&gt;&lt;br /&gt;I've added Reddit, Flickr, and Google image search above, but it's easy to add your own as follows:&lt;br /&gt;&lt;br /&gt;Each entry in the jump list takes the form (name . url|builtin), where the simplest shortcut is just a name, url pair like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;("astar algorithm" . "http://www.heyes-jones.com/astar")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There are some builtin functions that you can use. For example simple-query lets you enter some text that will be inserted between two strings. The format is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;("Reddit Search" .&lt;br /&gt; [simple-query "www.reddit.com" "http://www.reddit.com/search?q=" ""])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When doing something more clever than an url you pass in a vector (hence the []'s), where the first argument is the function, the second is the default url (if the user doesn't enter anything, and the third and forth arguments are the prefix and the postfix wrapped around the users input to make the search work. In this case the last argument is the empty string. &lt;br /&gt;&lt;br /&gt;You can provide your own functions to do something really fancy if you need to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8122691330096066744?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8122691330096066744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8122691330096066744' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8122691330096066744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8122691330096066744'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/search-reddit-flickr-and-google-from.html' title='Searching Reddit, Flickr, and Google from emacs = Rad'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-140872619931223682</id><published>2009-02-07T22:51:00.000-08:00</published><updated>2009-02-07T23:04:41.309-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rss emacs xml parsing bbc news'/><title type='text'>Fun with RSS</title><content type='html'>Today I've been playing around with emacs, and one of the things I've wanted to write is something to grab a web page, do some manipluations to it and dump that to a buffer. &lt;br /&gt;&lt;br /&gt;So what I've got going is two things that are not quite joined up yet. Firstly grabbing some URL and sticking it in a buffer... &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun url-to-buffer(url)&lt;br /&gt;  (interactive "sEnter site url : ")&lt;br /&gt;  (let ((buffer (get-buffer-create "*url-to-buffer*")))&lt;br /&gt;    (shell-command (format "c:/coreutils/bin/wget.exe -q -O - %s" url) buffer)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see I'm using windows here, but as long as you have a path to wget this should work. I'm simply running wget and capturing the output to a buffer. &lt;br /&gt;&lt;br /&gt;So running that on BBC's news RSS feed, I then saved it to a file called bbc.xml.&lt;br /&gt;&lt;br /&gt;Since this is an XML file I can parse it without any effort using xml.el. Here is some code that walks through the items in the RSS file and prints them out in human readable format (ie: not XML) into a buffer. &lt;br /&gt;&lt;br /&gt;There is some helpful info about xml.el here&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.emacswiki.org/emacs/XmlParserExamples"&gt;http://www.emacswiki.org/emacs/XmlParserExamples&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which was neccesary to figure to figure out the syntax to grab the text from a tag. I wrote helper function to go from a node to the text for that node, since the syntax is quite verbose:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun get-item(tag node)&lt;br /&gt;  (let ((child-node (car (xml-get-children node tag))))&lt;br /&gt;    (car (xml-node-children child-node))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This lets you go from a tag name (eg title) and a node that you parsed from the xml file, to the item. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun parse-rss(filename)&lt;br /&gt;  (interactive "fRss file :")&lt;br /&gt;  (let ((parsed-xml &lt;br /&gt;  (xml-parse-file filename))&lt;br /&gt; (buffer&lt;br /&gt;  (get-buffer-create (format "%s-parsed.txt" filename))))&lt;br /&gt;    (goto-line 1 buffer)&lt;br /&gt;    (erase-buffer)&lt;br /&gt;    (let* ((rss (car parsed-xml))&lt;br /&gt;    (channel (xml-get-children rss 'channel))&lt;br /&gt;    (items (xml-get-children (car channel) 'item)))&lt;br /&gt;      (dolist (item items)&lt;br /&gt; (let ((title (get-item 'title item))&lt;br /&gt;       (description (get-item 'description item))&lt;br /&gt;       (date (get-item 'pubDate item)))&lt;br /&gt;   (insert (format "*%s*\n%s\n%s\n\n" title description date)))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;xml-parse-file is our one shot call to parse the xml file, which returns a nested lisp structure representing the xml document. I grab the channel, then grab any items within the channel and print out three items that I've grabbed from them, the title, description and date. &lt;br /&gt;&lt;br /&gt;So each item output looks like this:&lt;br /&gt;&lt;br /&gt;*Obama defends economic stimulus*&lt;br /&gt;The US president defends his economic stimulus plan as "absolutely necessary", and urges Congress to approve it quickly.&lt;br /&gt;Sat, 07 Feb 2009 22:23:20 GMT&lt;br /&gt;&lt;br /&gt;Note that if you want to read RSS feeds in emacs, look up the builtin function newsticker. All this information I'm writing about is really useful if you want to code up something custom though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-140872619931223682?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/140872619931223682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=140872619931223682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/140872619931223682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/140872619931223682'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/fun-with-rss.html' title='Fun with RSS'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3781339005307236974</id><published>2009-02-07T13:33:00.000-08:00</published><updated>2009-02-07T23:03:50.937-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs send mail smtp'/><title type='text'>Sending email via gmail in emacs</title><content type='html'>I got this working in linux, and it's fairly easy. I'm still trying to get it working on my win32 machines, and I'll post about that later if I get it working.&lt;br /&gt;&lt;br /&gt;This post has most of the details I needed:&lt;br /&gt;&lt;br /&gt;http://obfuscatedcode.wordpress.com/2007/04/26/configuring-emacs-for-gmails-smtp/&lt;br /&gt;&lt;br /&gt;So I put the following in my .emacs&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; install starttls from here (no need for patch)&lt;br /&gt;; http://josefsson.org/emacs-smtp-starttls.html&lt;br /&gt;&lt;br /&gt;(setq send-mail-function 'smtpmail-send-it&lt;br /&gt;   message-send-mail-function 'smtpmail-send-it&lt;br /&gt;   smtpmail-starttls-credentials&lt;br /&gt;   '(("smtp.gmail.com" 587 nil nil))&lt;br /&gt;   smtpmail-auth-credentials&lt;br /&gt;   (expand-file-name "~/.authinfo")&lt;br /&gt;   smtpmail-default-smtp-server "smtp.gmail.com"&lt;br /&gt;   smtpmail-smtp-server "smtp.gmail.com"&lt;br /&gt;   smtpmail-smtp-service 587&lt;br /&gt;   smtpmail-debug-info t&lt;br /&gt;   starttls-extra-arguments nil&lt;br /&gt;   smtpmail-warn-about-unknown-extensions t&lt;br /&gt;   starttls-use-gnutls nil)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And followed the instructions to make the .authinfo file containing:&lt;br /&gt;&lt;br /&gt;machine smtp.gmail.com login [your name]@gmail.com password [your password]&lt;br /&gt;&lt;br /&gt;And finally download, unzip, make and install startttls:&lt;br /&gt;&lt;br /&gt;http://josefsson.org/emacs-smtp-starttls.html&lt;br /&gt;&lt;br /&gt;You don't need to apply the patch there, it works without as far as I can tell.&lt;br /&gt;&lt;br /&gt;Finally you can create and send mail.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3781339005307236974?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3781339005307236974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3781339005307236974' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3781339005307236974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3781339005307236974'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/02/sending-email-via-gmail-in-emacs.html' title='Sending email via gmail in emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1821438704277709106</id><published>2009-01-23T14:23:00.000-08:00</published><updated>2009-01-23T14:26:28.741-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs perforce p4'/><title type='text'>Simple perforce checkout in emacs using elisp</title><content type='html'>I know there are all kinds of clever perforce modes, but I prefer to have a few common perforce actions that I write myself and can easily extend and customise as needed.&lt;br /&gt;&lt;br /&gt;For example this is all you need to checkout a file you are visiting.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun p4-checkout-buffer()&lt;br /&gt; "Check out the current buffer from perforce using a shell command line"&lt;br /&gt; (interactive)&lt;br /&gt; (shell-command (format "p4.exe edit %s" (buffer-file-name)))&lt;br /&gt; (toggle-read-only -1))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1821438704277709106?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1821438704277709106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1821438704277709106' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1821438704277709106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1821438704277709106'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/01/simple-perforce-checkout-in-emacs-using.html' title='Simple perforce checkout in emacs using elisp'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-6013800755026330923</id><published>2009-01-12T07:45:00.000-08:00</published><updated>2009-01-12T07:50:02.781-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='msdos win32 command line'/><title type='text'>Finding writable files in a directory in a windows command line</title><content type='html'>Simple thing, but if you want to find which files in a directory are writable, use this dos command ...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;dir /a-r-d /s /b&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;/a is to search for attributes. In this case r is read only and d is directory. The minus signs negate those attributes. So we're looking for writable files only. &lt;br /&gt;&lt;br /&gt;/s means recurse subdirectories&lt;br /&gt;&lt;br /&gt;/b means bare format. Path and filename only.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-6013800755026330923?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/6013800755026330923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=6013800755026330923' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6013800755026330923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/6013800755026330923'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/01/finding-writable-files-in-directory-in.html' title='Finding writable files in a directory in a windows command line'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-388194404855911098</id><published>2009-01-08T12:48:00.000-08:00</published><updated>2009-01-12T07:52:03.401-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs p4 perforce elisp'/><title type='text'>Who changed the line your working on last?</title><content type='html'>My team use Perforce for version control, and I recently wrote an implementation of  'blame', also known as 'praise'. When editing a file that is in Perforce, I can run p4-blame, and it will figure out the last change list that this file, and the line that point is on, was changed. It then opens a buffer containing that change list. This is often useful while working, and is so fast when accessed from the editor, it makes it trivial to do.&lt;br /&gt;&lt;br /&gt;First, I wanted it to open two buffers, one with the annotated file (the file you're working on with the change list number at the start of each line), and another with the changelist you're interested in. When running the command multiple times I want these buffers to be deleted. So I added a helper function that creates a named buffer, and if it exists already, makes sure it is empty.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun get-buffer-create-and-clear(name)&lt;br /&gt;  (interactive "sName: ")&lt;br /&gt;  (let ((buffer (get-buffer-create name)))&lt;br /&gt;    (goto-line 1 buffer)&lt;br /&gt;    (erase-buffer)&lt;br /&gt;    buffer))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok now for the blame code. As you can see, mostly what it's doing is called the P4 command line and passing the output to buffers. Firstly I call annotate to get the change list numbered lines. Then I go to that file and go to the same line that point was at. (number-at-point) returns that number. Finally I call p4 describe to get the changelist information.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun p4-blame()&lt;br /&gt;  "blame the current line of code... it seeks out the change list of the last person&lt;br /&gt;to change this line. The arguments to annotate, which dumps the source file with the &lt;br /&gt;change list number it was last altered in, are q (no header) i (follow branches) and&lt;br /&gt;c for change numbers rather than revision numbers."&lt;br /&gt;  (interactive)&lt;br /&gt;  (let* ((line (line-number-at-pos))&lt;br /&gt;  (source-file (buffer-file-name))&lt;br /&gt;  (annotate-buffer (get-buffer-create-and-clear "*p4-annotate*")))&lt;br /&gt;    (shell-command (format "p4.exe annotate -q -i -c %s" source-file) annotate-buffer)&lt;br /&gt;    (goto-line line annotate-buffer)&lt;br /&gt;    (let ((change-number (number-at-point)))&lt;br /&gt;      (if change-number&lt;br /&gt;   (let ((blame-buffer (get-buffer-create-and-clear "*p4-blame*")))&lt;br /&gt;     (shell-command (format "p4.exe describe %d" change-number) blame-buffer))&lt;br /&gt; (message "error: could not get change list number for line %d" line)))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The error detection is a bit sloppy here. I don't know how to figure out if the shell-command failed. But it's not a big deal because if you do this in a file that is not in P4 then it will simply print a message saying could not get change list. &lt;br /&gt;&lt;br /&gt;Ideally I could send the error output to a buffer, and then parse it to see if it's empty.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-388194404855911098?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/388194404855911098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=388194404855911098' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/388194404855911098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/388194404855911098'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2009/01/who-changed-line-your-working-on-last.html' title='Who changed the line your working on last?'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-1895669180559976238</id><published>2008-11-21T11:43:00.000-08:00</published><updated>2009-01-12T07:52:59.844-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='svn google code sourceforge source control'/><title type='text'>How to copy an SVN repository from sourceforge to google code</title><content type='html'>Subversion has a tool called &lt;a href="http://svnbook.red-bean.com/en/1.4/svn.ref.svnsync.html"&gt;SVNSYNC&lt;/a&gt;  to make it easy to sync from one repository to another. This is great when moving to a different web based server. In this example I'm copying a project I work on from Sourceforge to Google Code. Once done, the google code repository will be an exact mirror, including the complete change history.&lt;br /&gt;&lt;br /&gt;You also need to set the revision number of the repository to zero. Google code, predictably, makes this easy, by having a button on the source page to do it for you.&lt;br /&gt;&lt;br /&gt;You need to have your username and password for google code to do this. For the repository you're copying you don't. First you use the initial command to set things up for the copy, then use the sync command to do the actual copy. It does this one revision at a time and takes a while...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;svnsync init https://lispbuilder.googlecode.com/svn https://lispbuilder.svn.sourceforge.net/svnroot/lispbuilderProject&lt;br /&gt;svnsync --username YOURNAME --password YOURPASSWORD sync https://lispbuilder.googlecode.com/svn https://lispbuilder.svn.sourceforge.net/svnroot/lispbuilder&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-1895669180559976238?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/1895669180559976238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=1895669180559976238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1895669180559976238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/1895669180559976238'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/11/how-to-copy-svn-repository-from.html' title='How to copy an SVN repository from sourceforge to google code'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-4696422128723514955</id><published>2008-11-08T22:03:00.001-08:00</published><updated>2008-11-09T10:17:01.899-08:00</updated><title type='text'>Grabbing info from web pages</title><content type='html'>This is how you use wget to grab a web page to stdout ...&lt;br /&gt;&lt;br /&gt;wget -O - http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml&lt;br /&gt;&lt;br /&gt;Where -O species the output file, and the - specifies use stdout instead of a filename.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-4696422128723514955?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/4696422128723514955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=4696422128723514955' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4696422128723514955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/4696422128723514955'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/11/grabbing-info-from-web-pages.html' title='Grabbing info from web pages'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2796100524992614258</id><published>2008-05-27T17:25:00.000-07:00</published><updated>2008-05-27T17:31:19.283-07:00</updated><title type='text'>Using find and printf</title><content type='html'>This is basic stuff but I wanted to post it so I can find it when I search for it...&lt;br /&gt;&lt;br /&gt;How to find a file and print the name, path and date and time it was last accessed...&lt;br /&gt;&lt;br /&gt;Change filename to be the file you want, with optional wildcards. (Use -iname for case insensitive search).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;find . -name &lt;filename&gt; -printf "%p %AD %AH:%AM\n"&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2796100524992614258?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2796100524992614258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2796100524992614258' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2796100524992614258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2796100524992614258'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/05/using-find-and-printf.html' title='Using find and printf'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-393191312791773744</id><published>2008-05-13T11:45:00.000-07:00</published><updated>2009-01-12T07:54:08.235-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='msdos win32 command line batch files'/><title type='text'>Batch file tip ... %~dp0</title><content type='html'>Here's a nice blog post on this...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://weblogs.asp.net/lorenh/archive/2006/03/24/441004.aspx"&gt;Silly batch file tricks, redirecting stdout into an evironment variable and %~dp0&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But just for my own reference the cryptic looking character sequence resolves to the path to the batchfile you are running. &lt;br /&gt;&lt;br /&gt;So if you put the following in a batch file, no matter what directory you are in when you run it, it will print the directory the batch file is in, and do a directory listing.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;echo Batch file path is %~dp0&lt;br /&gt;dir %~dp0&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-393191312791773744?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/393191312791773744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=393191312791773744' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/393191312791773744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/393191312791773744'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/05/batch-file-tip-dp0.html' title='Batch file tip ... %~dp0'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-400969742091382750</id><published>2008-05-01T11:38:00.000-07:00</published><updated>2008-05-01T11:42:17.424-07:00</updated><title type='text'>Copying characters from the line above in emacs</title><content type='html'>The BBC microcomputer had a button called COPY, which when you pressed it would copy the character on the line above the cursor. This was quite handy, and I recently was waiting for a large amount of code to link, and thought I'd have a go at implementing it. &lt;br /&gt;&lt;br /&gt;There's not a lot to it in fact. This function just remembers the cursor position (using save-excursion) and then goes to the previous line, gets the character after the point, and finally after the save-excursion block I just insert the character.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun copy-char-above()&lt;br /&gt; "copy the character above point into the buffer"&lt;br /&gt; (interactive)&lt;br /&gt; (let (c)&lt;br /&gt;   (save-excursion&lt;br /&gt;     (previous-line)&lt;br /&gt;     (setq c (char-after)))&lt;br /&gt;   (insert (char-to-string c))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here I just assign the function to a key...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(global-set-key [f6] 'copy-char-above)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-400969742091382750?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/400969742091382750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=400969742091382750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/400969742091382750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/400969742091382750'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/05/copying-characters-from-line-above-in.html' title='Copying characters from the line above in emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2501944839386894200</id><published>2008-02-29T18:24:00.000-08:00</published><updated>2008-02-29T18:27:02.093-08:00</updated><title type='text'>Is it a leap year</title><content type='html'>Here's a bit of elisp code to find out...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun is-century-year(year)&lt;br /&gt;  (if (= (mod year 100) 0)&lt;br /&gt;      t&lt;br /&gt;    nil))&lt;br /&gt;&lt;br /&gt;(defun is-leap-year(year)&lt;br /&gt;  "leap year is century years divisible by 400, &lt;br /&gt;not other century years, otherwise anything evenly &lt;br /&gt;divisble by 4"&lt;br /&gt;  (if (is-century-year year) &lt;br /&gt;      (if (= 0 (mod year 400))&lt;br /&gt;   t&lt;br /&gt; nil)&lt;br /&gt;    (if (= 0 (mod year 4))&lt;br /&gt; t&lt;br /&gt;      nil)))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2501944839386894200?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2501944839386894200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2501944839386894200' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2501944839386894200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2501944839386894200'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/02/is-it-leap-year.html' title='Is it a leap year'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2382190268593974630</id><published>2008-01-29T14:42:00.000-08:00</published><updated>2008-01-29T14:43:41.320-08:00</updated><title type='text'>emacs - a simple search and replace function</title><content type='html'>This function is for emacs; it searchs for any sequence composed of spaces and tabs and replaces it with a single tab&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun space-and-tabs-to-tab()&lt;br /&gt;  (interactive)&lt;br /&gt;  (while (re-search-forward "[\t ]+" nil t)&lt;br /&gt;    (replace-match "\t" nil nil)))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2382190268593974630?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2382190268593974630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2382190268593974630' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2382190268593974630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2382190268593974630'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2008/01/emacs-simple-search-and-replace.html' title='emacs - a simple search and replace function'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3362163213750999415</id><published>2007-12-08T15:18:00.000-08:00</published><updated>2007-12-08T15:25:18.649-08:00</updated><title type='text'>emacs: how-many</title><content type='html'>Discovered another emacs command yesterday:&lt;br /&gt;&lt;br /&gt;how-many&lt;br /&gt;&lt;br /&gt;Returns the count of a regex following the point (cursor position).&lt;br /&gt;&lt;br /&gt;For example &lt;br /&gt;&lt;br /&gt;M-x how-many &lt;br /&gt;\b\w &lt;br /&gt;&lt;br /&gt;returns a word count from point to the end of the buffer.&lt;br /&gt;&lt;br /&gt;Nice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3362163213750999415?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3362163213750999415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3362163213750999415' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3362163213750999415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3362163213750999415'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/12/emacs-how-many.html' title='emacs: how-many'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2962431215723075681</id><published>2007-12-07T13:04:00.000-08:00</published><updated>2009-06-03T15:41:13.439-07:00</updated><title type='text'>C: Passing on variadic function arguments to another function</title><content type='html'>I needed to do this today, and it took me a while to google it, so here is complete sample showing how it's done:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// How to pass a variadic argument list to another function&lt;br /&gt;// Justin&lt;br /&gt;&lt;br /&gt;#include "iostream"&lt;br /&gt;#include "stdarg.h"&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;void debugMessageHelper(char *buffer, const char* format, va_list arglist)&lt;br /&gt;{&lt;br /&gt; vsprintf(buffer, format, arglist);&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;void debugMessage(char *buffer, const char* format, ...)&lt;br /&gt;{&lt;br /&gt; va_list arg;&lt;br /&gt; va_start(arg, format);&lt;br /&gt;&lt;br /&gt; debugMessageHelper(buffer, format, arg);&lt;br /&gt;&lt;br /&gt; va_end(arg);&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt; char testBuffer[128];&lt;br /&gt; &lt;br /&gt; debugMessage(testBuffer, "hello %s %u %-04.2f", "world", 21 33.122f);&lt;br /&gt;&lt;br /&gt; cout &lt;&lt; "\'" &lt;&lt; testBuffer &lt;&lt; "\'" &lt;&lt; endl;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2962431215723075681?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2962431215723075681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2962431215723075681' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2962431215723075681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2962431215723075681'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/12/c-passing-on-variadic-function.html' title='C: Passing on variadic function arguments to another function'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2568969843659079024</id><published>2007-10-24T09:50:00.001-07:00</published><updated>2007-10-24T09:50:39.075-07:00</updated><title type='text'>Ubuntu 7.10</title><content type='html'>With a new version of Ubuntu out (7.10) I decided to repeat the painful experience I put myself  through every couple of years to see if I want to use it as a windows replacement on the desktop.&lt;br /&gt;&lt;br /&gt;I've been pleasantly surprised this time. The install process was a bit of a monumental fuck up, but it turned out that my PC has been overheating for a while due to a dirty fan. Windows didn't seem to care. Linux kept shutting down, and I eventually found the system log that told me why it was shutting down, and the exact temperature that caused it. Nice.&lt;br /&gt;&lt;br /&gt;At least when linux fails it is usually able to tell you exactly whats going on.&lt;br /&gt;Installing the Nvidia drivers turned out to be a pain in the ass too. The simple procedure they give you to do it from the desktop just didn't work. I then tried Nvidia's simple shell script, which didn't work. And a day or so later I found something called Envy, which did work.&lt;br /&gt;&lt;br /&gt;Overall I had to be familiar with linux commands, logging in as root, and editing configuration scripts to get it to do what I needed. It's still a computer experts OS as far as I can tell. Although you can pay for phone support, I don't think they're anywhere near capturing the typical Best Buy PC owner.&lt;br /&gt;&lt;br /&gt;So far I can do nearly everything I need to in XP, but the user interface is both flashier, faster, and has the benefit of being linux.&lt;br /&gt;&lt;br /&gt;It's still likely I won't be able to fully ditch XP though. I can't chat with my webcam yet. The webcam works but  the chat software doesn't support it.&lt;br /&gt;&lt;br /&gt;I don't like the fonts, but I'm hoping I can configure that, I haven't spent time twiddling with it yet.&lt;br /&gt;&lt;br /&gt;Ubuntu is definitely getting there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2568969843659079024?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2568969843659079024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2568969843659079024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2568969843659079024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2568969843659079024'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/10/ubuntu-710.html' title='Ubuntu 7.10'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2294216644782730644</id><published>2007-10-24T09:00:00.000-07:00</published><updated>2007-10-24T09:02:13.489-07:00</updated><title type='text'>C and C++ function pointers</title><content type='html'>I came across a great page for C and C++ function pointers. It includes the syntax for how you do most things you would ever do with them. An ideal reference because I can never remember the syntax...&lt;br /&gt;&lt;a href="http://www.newty.de/fpt/fpt.html"&gt;&lt;br /&gt;http://www.newty.de/fpt/fpt.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2294216644782730644?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2294216644782730644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2294216644782730644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2294216644782730644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2294216644782730644'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/10/c-and-c-function-pointers.html' title='C and C++ function pointers'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-7437896327461290267</id><published>2007-10-09T10:44:00.000-07:00</published><updated>2007-10-09T11:13:13.949-07:00</updated><title type='text'>Avoiding Ten Common Game AI Mistakes</title><content type='html'>&lt;span style=";font-family:times new roman;font-size:100%;"  &gt;1) Moonwalking into walls or objects&lt;br /&gt;&lt;br /&gt;Often this is a symptom of the interface between the AI and the game world being too complex, and therefore hard to debug. Sometimes it can simply mean that you have no path finding in the game at all, but we will ignore that for now.&lt;br /&gt;&lt;br /&gt;Look for differences in the way that the animation moves and the way it queries the collision system. For example, the AI may do a ray cast to see if there is an object in front of it, but the character control system may  move a larger object such as a cylinder, which then collides with the world unexpectedly.&lt;br /&gt;&lt;br /&gt;Other problems may be that the general movement code does not handle the collision when it is detected resulting in continuous attempts to move when the physics and collision system will not allow it. Sometimes the movement code fails, switches to an idle state, which then immediately attempts to move again, see item 4 below.&lt;br /&gt;&lt;br /&gt;2) Turning "the long way around" to face a target&lt;br /&gt;&lt;br /&gt;For some reason this bug often survives until late in a project; sometimes it even ships! It seems like a simple thing to calculate... should I turn left or right to face a target.&lt;br /&gt;&lt;br /&gt;Typically people start out getting the X and Z distance to the target and figuring out that as an angle using atan2. Then they take the X and Z components of the facing vector to get that angle via the same route. Finally you just take the difference between those angles.&lt;br /&gt;&lt;br /&gt;What usually happens is that if you're not careful when manipulating these angles there are mistakes made when converting between radians of degrees, or when figuring out whether to turn left or right, or when wrapping angles around at 360 degrees.&lt;br /&gt;&lt;br /&gt;Let's look at a solution that avoids having to convert and do arithmetic with angles, which is where most of the bugs I see come from.&lt;br /&gt;&lt;br /&gt;Firstly take a dot product of the vector to your target and the characters facing direction (just the X and Z components). This gives you the cosine of the angle between the two vectors. Take an acos of that to get the angle in radians. What's nice about that compared to the atan2 route is that it immediately gives you the angle you want, the angle between the facing direction and the target position. You don't have to do anything more to make sure it's the shortest way around.&lt;br /&gt;&lt;br /&gt;Then we want to know whether to turn left or right. Again looking only at the X and Z vectors, we can simply figure out whether the target is to our left or right. First we need to get the 2d cross product of our facing direction. If the facing vector is (x,y,z), a vector at right angles to this in 2d is just (-z, x).&lt;br /&gt;&lt;br /&gt;If you then take the dot product of this and the vector to the target, the sign of that is whether you should turn left or right! Simple.&lt;br /&gt;&lt;br /&gt;3) All the enemies on screen doing the same idle animation in perfect synchronization&lt;br /&gt;&lt;br /&gt;This is a very common when a bunch of enemies get spawned at the same time, with the same behaviour and their animations end up perfectly synchronised. Also it happens when the AI's are all hit by some weapon at the same time.&lt;br /&gt;&lt;br /&gt;It looks lame, and there's a couple of ways to help this along with making a major impact on your engine. You can play animations at irregular speeds. Play the idle animations at variances of just a few percent, and they won't look wrong, and they will be out of sync with each other. Use sets of random animations as often as you can, especially looping ones. At a higher level you can also make sets of states behave differently. If you have a state machine which has random elements for choosing the next state, then use that to vary the AI's.&lt;br /&gt;&lt;br /&gt;4) Enemy behaving unpredictably&lt;br /&gt;&lt;br /&gt;However you set up your AI system it will always end up complicated. At it's worst AI code is a mass of "if X then do Y" type statements, and unless you manage it correctly you won't be able to understand what is going on.&lt;br /&gt;&lt;br /&gt;Firstly you need to abstract the state actions and state decisions as much as you can. Seperate concepts such as "doing an action" from "perceiving the world" and "deciding to do something". As much as you can allow the AI to be set up in the game data, not in the game code.&lt;br /&gt;&lt;br /&gt;Doing so also makes concurrency easier, since if you encapsulate all of your queries about the world, you can execute them in parallel with other game systems, then in a later stage of execution you get the deferred results of those queries and act on them.&lt;br /&gt;&lt;br /&gt;But the ultimate solution to unpredictability is debugging tools. You want to be able to store the last few states the AI was in, what transitions got him into that state, and what states it is considering transitioning to. If you can show this stuff on screen, at will, while the game is running, then you're golden. Spend lots of time on this kind of stuff, because I guarantee there will be a time near the end project when someone will come and stand behind you and ask you why something on the screen is doing X instead of Y. If you have no idea, then you're not doing job as an AI programmer.&lt;br /&gt;&lt;br /&gt;5) Enemy is vibrating, flipping rapidly between two animations&lt;br /&gt;&lt;br /&gt;This happens often in state machines. If you get a state A which transitions to state B, and then on the next update, state B transitions back to A again. Assuming, as often people do, the AI states also trigger animations, then you have the horrible flickering between the two first frames of each.&lt;br /&gt;&lt;br /&gt;Ulimately the AI designers can avoid state cycles by not making them, but there are bound to be some that slip through. At which point it, it would be nice to have some mechanism to avoid them. You could flag an error or warning when a state immediately returns to the previous state, or you could have a time within which you cannot return to the previous state.&lt;br /&gt;&lt;br /&gt;One nice way to handle this is to make the data about how long you should stay in a state explicit. For example, if an enemy is rolling along the floor then it makes sense that you cannot interrupt that action once it starts, so we have the concept of an interrupt time, before which you cannot break to a different state. Tying states to animations achieves this too, but I don't recommend a one-to-one match of animations to state for reasons that I will cover later.&lt;br /&gt;&lt;br /&gt;Having interrupt times that are at least 1/2 a second is a simple way to avoid state thrashing, but you still have to solve the problem at the design level.&lt;br /&gt;&lt;br /&gt;6) Irratic running on the spot and sudden direction changes.&lt;br /&gt;&lt;br /&gt;Have you ever seen AI's running to a point in the world, then when they get there they overshoot? Or maybe they just keep stopping and running again. Or maybe they spin on the spot.&lt;br /&gt;&lt;br /&gt;The problem here is nearly always to do with managing movement and distances to points. There are many ways to get this wrong. For example, if you use a bone or root node on a model as the absolute position of the character, then his distance from a point may vary over time as he animates. Meaning that you keep moving too far from the target point, triggering a new movement state.&lt;br /&gt;&lt;br /&gt;Another issue is how close do you have to be to the point to stop trying to move there? If it is 1cm then how accurate is your character movement system? can you move someone with an accuracy of 1cm? If not then you need to enlarge your arrival distance until it is large enough that you can guarantee accurate arrival.&lt;br /&gt;&lt;br /&gt;If you couple movement to animation you need to spend a lot of time thinking about where the character is, and a good way is to use a root node that is carefully animated to be well behaved. Then I recommend that you store the displacement of animations, so that you know exactly how far they will move the root node when played.&lt;br /&gt;&lt;br /&gt;For ultra slick AI's that walk or run to a point then do a smooth stop animation and end up exactly on the target, you just need to play your walk animation until you get to the point when the transition to stop animation would get you exactly to the target. The you need to play that animation at the right point. You also need to consider where the foot steps are. You can then determine whether to transition to a left or right footed stop.&lt;br /&gt;&lt;br /&gt;Finally, it's nice if you can manipulate your animations so that you can vary the distance covered by your walk cycle, just enough so that the transition to stop can be executed at a perfect boundary.&lt;br /&gt;&lt;br /&gt;If animation is just something you play in the background and doesn't affect your movement, then things are easier. It comes down to fixing the issues above as best you can, but you don't have to fix them, you will just get sliding and popping now and then. But you won't get the kind of animation driven movement problems that cause you to overshoot.&lt;br /&gt;&lt;br /&gt;One final issue is turning. Make sure your characters have a turn speed, that varies with running speed. You can turn on the spot when you're stationary, for example. When running your turning circle is limited.&lt;br /&gt;&lt;br /&gt;7) Enemy doing nothing at all&lt;br /&gt;&lt;br /&gt;This is pretty much a design level issue, but it's common enough to mention. Sometimes AI's are just dead. They have no idea what to do next and this looks pretty stupid.&lt;br /&gt;&lt;br /&gt;Usually this occurs when AI have no valid transition from an idle state. So have your designers think about things the AI should do if everything they typically think he should be able to do cannot be done.&lt;br /&gt;&lt;br /&gt;One possiblity is that the path finder is failing. Perhaps the AI spawned in an unreachable area by mistake, or was pushed there, or fell there. If your AI's can get into a situation where they cannot move, then perhaps have them animate now and then so they look puzzled, or are looking around wondering what to do.&lt;br /&gt;&lt;br /&gt;Look though transitions from idle and make sure that there is something interested there that can be transitioned to if everything else fails.&lt;br /&gt;&lt;br /&gt;This also comes down to good AI system debugging tools. If you can immediately bring up a display showing which transitions the dead entity is considering, you will be able to figure out what to do.&lt;br /&gt;&lt;br /&gt;8) Movement deadlocks (doors, bridges)&lt;br /&gt;&lt;br /&gt;Choke points happen in AI. Narrow corridors, doors, bridges, tunnels. Sometimes we are even clever enough to come up with a system for handling them. AI's that want to enter the choke point take a queue number, and they go through one by one for example.&lt;br /&gt;&lt;br /&gt;Whether you do something like that, or do nothing at all, there needs to be some way to avoid deadlock. One way to do that is by giving your AI's different priorities for movement, so that they can move AI's out of the way. Often a player is able to move AI's about, sometimes simply because he moves first.&lt;br /&gt;&lt;br /&gt;If you have a physics based engine for character movement this is easy, just set the mass to be greater on characters that you want to have the highest priority. Otherwise you'll probably have some kind of collision resolution system, and you need to feed in the priority from the AI into that.&lt;br /&gt;&lt;br /&gt;9) Using A* for everything&lt;br /&gt;&lt;br /&gt;I run a web site which teaches A*, and yet when I come to write a pathfinding or other search program I don't always use A*, and when I do I never do A* on a fine mesh or grid. Why? Because it uses a lot of memory and processing power that is totally unneccesary.&lt;br /&gt;&lt;br /&gt;Firstly if you're searching only small data sets, like an AI state graph, or a dozen or so path nodes in a room, you can use Dijkstra's algorithm, which is particularly effective when all the AI's in the room will path find to the same node, since the algorithm will fill out data for the whole network rather than just the start and end nodes. Sometimes even a breadthfirst search is enough.&lt;br /&gt;&lt;br /&gt;In general you want the path finding data to be as high level as possible whilst still allowing movement to all possible gameplay areas.&lt;br /&gt;&lt;br /&gt;One approach is hierarchical path finding, which really needs to work at engine level. If you divide your game world up into regions, buildings, floors and rooms, for example, an AI can path find at all those levels before finally pathfinding on a grid or mesh level inside the current room it is in.&lt;br /&gt;&lt;br /&gt;10) Being too clever&lt;br /&gt;&lt;br /&gt;Good AI is often based on quite simple systems. It almost always is built up using good tools and good design, rather than clever algorithms.&lt;br /&gt;&lt;br /&gt;Things to watch out for are learning algorithms, unless they are directly related to gameplay, which tend to make it hard to get the behaviour you want. I don't want to sound like I'm stifling innovation, but don't use a back propagating neural network when a simple table would do the job.&lt;br /&gt;&lt;br /&gt;At all times make the systems workings clear via debugging tools, and as best you can allow rapid iteration of AI changes, ideally allow real time changes while the game is running.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-7437896327461290267?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/7437896327461290267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=7437896327461290267' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7437896327461290267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7437896327461290267'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/10/avoiding-ten-common-game-ai-mistakes.html' title='Avoiding Ten Common Game AI Mistakes'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-2741852211389762610</id><published>2007-09-27T14:46:00.000-07:00</published><updated>2007-09-27T14:50:25.612-07:00</updated><title type='text'>11 Visual Studio tricks in Emacs</title><content type='html'>Recently I read the blog post &lt;a href="http://www.chinhdo.com/chinh/blog/20070920/top-11-visual-studio-2005-ide-tips-and-tricks-to-make-you-a-more-productive-developer/"&gt;"11 Visual Studio 2005 IDE Tips and Tricks to Make You a More Productive Developer"&lt;/a&gt; which has some neat tips indeed. I thought I would investigate which of the tips can be replicated in emacs, which are easier or more powerful in emacs and vice versa.&lt;br /&gt;&lt;br /&gt;I've been using Visual Studio for over 10 years though I'm certainly not a power user, and recently I only use it for building and occasional code editing. I do more editing in emacs. I'm not writing this post to prove that one is better than the other, it is more for the learning experience for myself, and hopefully somebody will find something interesting here.&lt;br /&gt;&lt;br /&gt;(1) Express Yourself with Regular Expressions&lt;br /&gt;&lt;br /&gt;The example is to convert&lt;br /&gt;&lt;br /&gt;    , last_name&lt;br /&gt;    , ssn&lt;br /&gt;    , employee_id&lt;br /&gt;&lt;br /&gt;into&lt;br /&gt;&lt;br /&gt;    + "last_name"&lt;br /&gt;    + "ssn"&lt;br /&gt;    + "employee_id"&lt;br /&gt;&lt;br /&gt;using a regex. Well, I'd probably record a keyboard macro to do that, but let's do the regex replace instead.&lt;br /&gt;&lt;br /&gt;The syntax of the regex is a little different in emacs, but the basic sequence looks like this:&lt;br /&gt;&lt;br /&gt;Alt-x replace-regexp&lt;br /&gt;\(, \)\(.*$\)&lt;br /&gt;, "\2"&lt;br /&gt;&lt;br /&gt;Notice you need slashes for the brackets to make the groups.&lt;br /&gt;&lt;br /&gt;Verdict: Visual Studio lets you use Regex's in script, and emacs lets you do it in elisp code... and they both have the functionality needed for the tip. Draw.&lt;br /&gt;&lt;br /&gt;(2) Take (Keyboard) Shortcuts&lt;br /&gt;&lt;br /&gt;This tip is to simply use keyboard shortcuts. Well in fact you won't get anywhere with emacs without using them. So this is kind of a mute point.&lt;br /&gt;&lt;br /&gt;But I'll list some random keyboard short cuts for completeness...&lt;br /&gt;&lt;br /&gt;Alt z runs zap-to-char, kills everything up until the character you enter.&lt;br /&gt;&lt;br /&gt;Alt . runs find-tag. Finds the next occurence of current tag in the tags table, for finding function and variable declarations for example.&lt;br /&gt;&lt;br /&gt;Ctrl U Alt . finds previous tag&lt;br /&gt;&lt;br /&gt;Ctrl &lt; goes to the start of a buffer&lt;br /&gt;&lt;br /&gt;Ctrl &gt; goes to the end&lt;br /&gt;&lt;br /&gt;Ctrl H m describes the current mode, which is handy if you just downloaded a new editing mode and you want to see what the keys are and so on&lt;br /&gt;&lt;br /&gt;Alt t runs transpose. You can flip two words around.&lt;br /&gt;&lt;br /&gt;Verdict: Another draw.&lt;br /&gt;&lt;br /&gt;(3) Make New Shortcuts&lt;br /&gt;&lt;br /&gt;This is straight forward in emacs...&lt;br /&gt;&lt;br /&gt;(global-set-key [M-f2] 'zap-to-char)&lt;br /&gt;&lt;br /&gt;... sets Alt-F2 to do zap-to-char&lt;br /&gt;&lt;br /&gt;You can override keys globally like that, or you can do local-set-key to change that key only for the current editing mode.&lt;br /&gt;&lt;br /&gt;Verdict: emacs and Visual Studio both allow remapping anything they can do to a key, and they both allow you to redefine a key differently for different modes. Another draw!&lt;br /&gt;&lt;br /&gt;(4) Use Code Snippets&lt;br /&gt;&lt;br /&gt;I wasn't aware of this feature for Visual Studio so I checked it out briefly. So it lets you dump out text, such as automatically creating empty for loops or adding set and get fields given a field name.&lt;br /&gt;&lt;br /&gt;Well in emacs there are abbreviations. So for example let's say I want for( to automatically expand to for(int i; i&lt;???; i++)&lt;br /&gt;then I can make an abreviation, by going into the mode I want this to be active, and typing&lt;br /&gt;&lt;br /&gt;Alt-x abbrev-mode (turn the mode on)&lt;br /&gt;Alt-X define-mode-abbrev (interactively add a new abbreviation for this mode)&lt;br /&gt;for&lt;br /&gt;for(int i; i&lt;???; i++)&lt;br /&gt;&lt;br /&gt;and now when I type for and space, it will expand automatically.&lt;br /&gt;&lt;br /&gt;If you don't want it to expand then you type Ctrl-Q before you complete the abbreviation.&lt;br /&gt;&lt;br /&gt;But snippets let you do more advanced stuff like take a field name and create the get, set fields. Well I would write elisp code for that kind of thing, or again use a keyboard macro.&lt;br /&gt;&lt;br /&gt;Abbreviations are nice and easy to use, but they don't have the power of snippets.&lt;br /&gt;&lt;br /&gt;Verdict: Visual Studio code snippets don't seem to map directly to emacs. In emacs you can use the more basic abbreviations, or roll your own solution for wrapping text in more dynamic ways.&lt;br /&gt;&lt;br /&gt;(5) State Your Preferences&lt;br /&gt;&lt;br /&gt;Not a lot to say here. emacs is fully configurable through the startup file .emacs, so you can do configure everything as you want it to be.&lt;br /&gt;&lt;br /&gt;Verdict: Draw.&lt;br /&gt;&lt;br /&gt;(6) "Attach to Process" to Start Debugging ASP.NET&lt;br /&gt;&lt;br /&gt;Emacs doesn't support windows debugging, of course, but you can use gdb to debug processes. So the same functionality would be :&lt;br /&gt;&lt;br /&gt;Alt-x gdb&lt;br /&gt;attach [process ID]&lt;br /&gt;&lt;br /&gt;Verdict: Draw.&lt;br /&gt;&lt;br /&gt;7) Stop Conditionally (Conditional Breakpoints)&lt;br /&gt;&lt;br /&gt;Again, this is a windows only thing... you can run gdb and type&lt;br /&gt;&lt;br /&gt;break [LOCATION]&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;condition [COND]&lt;br /&gt;&lt;br /&gt;to set up a conditional breakpoint.&lt;br /&gt;&lt;br /&gt;Verdict: Draw. You can't debug windows processes from emacs, and you can't debug linux processes from Windows, but both offer debugging from within the IDE.&lt;br /&gt;&lt;br /&gt;(8) Employ Task List Tokens&lt;br /&gt;&lt;br /&gt;This is an odd feature. By typing // TODO in C++ code, for example, you can view the TODO's in a task list window for that file.&lt;br /&gt;&lt;br /&gt;Emacs lets you do this with say the 'occur' function.&lt;br /&gt;&lt;br /&gt;Alt-X occur&lt;br /&gt;TODO&lt;br /&gt;&lt;br /&gt;Will give a list of lines containing TODO.&lt;br /&gt;&lt;br /&gt;You could make an elisp function to wrap this up into a task list function:&lt;br /&gt;&lt;br /&gt;(defun task-list()&lt;br /&gt;       (interactive)   &lt;br /&gt;       (occur "TODO"))   &lt;br /&gt;&lt;br /&gt;Verdict: Not much of a feature really, but yeah, another draw.&lt;br /&gt;&lt;br /&gt;(9)  Go Directly to Any File with the Find Combo Box&lt;br /&gt;&lt;br /&gt;I couldn't get this tip to work, but Alt-Shift O seems to be the one he is talking about. A very nice list of files, and you can quickly open a file by typing part of the filename.&lt;br /&gt;&lt;br /&gt;emacs doesn't include the files in your current project, so we don't have a direct comparison, but let's assume you have a root directory containing your source and you want to find files matching a regex:&lt;br /&gt;&lt;br /&gt;Alt-x find-dired&lt;br /&gt;d:\YourSourceFiles\&lt;br /&gt;-regex ".*SEARCHTEXT.*"&lt;br /&gt;&lt;br /&gt;This will open a dired window (like a file manager dialog box but lets you do lots more things to the files) containing the matching files.&lt;br /&gt;&lt;br /&gt;Verdict: emacs is a bit better than studio in that you can search using all the power of the unix find command, but it's more fiddly to use, and there's no equivalent to Studio managing all the files in each project. (That I know of).&lt;br /&gt;&lt;br /&gt;(10) Type Ahead (Incremental Search) in Lists&lt;br /&gt;&lt;br /&gt;So for example in Studio, do Ctrl-O and you get a file dialog. Typing letters gradually filters the available files until you get the one you want.&lt;br /&gt;&lt;br /&gt;Emacs has exactly the same thing.&lt;br /&gt;&lt;br /&gt;Ctrl-X Ctrl-F to visit a file for example (although this works with anything that asks you for a file.)&lt;br /&gt;&lt;br /&gt;Firstly you can use the buffer history to find files you opened and closed earlier, and also you can edit this, so if you just opened a .cpp file, you can change it to .h and load that easily.&lt;br /&gt;&lt;br /&gt;Secondly hitting tab will cycle through possible files based on what you typed so far, but also open a buffer with the current valid files, so you can switch and select from there.&lt;br /&gt;&lt;br /&gt;Finally, if you open the wrong file by mistake you can run 'find-alternate-file' and load a different file into the buffer you opened.&lt;br /&gt;&lt;br /&gt;Verdict: emacs wins by a nose. More flexibility.&lt;br /&gt;&lt;br /&gt;(11) Automate with Macros and Visual Studio Automation&lt;br /&gt;&lt;br /&gt;emacs also has very cool macro recording...&lt;br /&gt;&lt;br /&gt;Ctrl-X (   starts recording&lt;br /&gt;&lt;br /&gt;do your thing&lt;br /&gt;&lt;br /&gt;Ctrl-X )   ends recording&lt;br /&gt;&lt;br /&gt;Ctrl-X e   runs the macro&lt;br /&gt;&lt;br /&gt;If you make a useful macro that runs on one line, you can then run it multiple times:&lt;br /&gt;&lt;br /&gt;Ctrl-U 10 Ctrl-X e&lt;br /&gt;&lt;br /&gt;runs the macro 10 times for example.&lt;br /&gt;&lt;br /&gt;You can also edit the macro with edit-last-kbd-macro, which brings up an editor.&lt;br /&gt;&lt;br /&gt;Well that's it, I'm sure I've missed out a lot of emacs features, I've been using it for about 4 years and I know there is still a lot of stuff in there I haven't discovered!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-2741852211389762610?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/2741852211389762610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=2741852211389762610' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2741852211389762610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/2741852211389762610'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/09/11-visual-studio-tricks-in-emacs.html' title='11 Visual Studio tricks in Emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-7302558058541195918</id><published>2007-09-22T09:44:00.000-07:00</published><updated>2007-09-22T10:03:44.607-07:00</updated><title type='text'>Word numbers programming puzzle</title><content type='html'>Reading &lt;a href="http://www.itasoftware.com/careers/puzzles07.html"&gt;Reddit&lt;/a&gt; last week I came across an interesting programming puzzle.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.itasoftware.com/careers/puzzles07.html"&gt;http://www.itasoftware.com/careers/puzzles07.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I've written a straightforward Common Lisp solution which is pasted below. What is interesting about this problem, and what would make it a good interview question, is that coding up the basic solution as I have here only poses more problems.&lt;br /&gt;&lt;br /&gt;None of the Lisp environments I've tried have enough heap space to complete this problem, even though in terms of time complexity it is O(n). Judging by how long it takes to run on a few hundred thousand numbers, and then several million, it would take about 20 hours on my 2Ghz PC to solve for 1 billion numbers.&lt;br /&gt;&lt;br /&gt;Even if I used the file system to hold the numbers, assuming each number fits in 50 chars of text, 4 bytes for the value and a further 4 to hold the length of the string, that is still in the order of 50Gb. You would then need to sort that file a bit at a time in memory, using a merge sort, and finally do a linear run through the file until you get the 51,000,000,000nth number.&lt;br /&gt;&lt;br /&gt;Some clever folk have presented a more intelligent solution here...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://conway.rutgers.edu/%7Eccshan/wiki/blog/posts/WordNumbers1/"&gt;http://conway.rutgers.edu/~ccshan/wiki/blog/posts/WordNumbers1/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is my solution so far:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#|&lt;br /&gt; Word Numbers&lt;br /&gt;&lt;br /&gt;This is a partial solution to the problem found at http://www.itasoftware.com/careers/puzzles07.html&lt;br /&gt;by Justin Heyes-Jones&lt;br /&gt;&lt;br /&gt;I say partial because it does actually work, and if you had a lisp environment with enough memory, it would finish &lt;br /&gt;in about a day. But the real solution seems to be either to spot patterns so you don't have to generate and sort &lt;br /&gt;all 1 billion numbers, or to use the file system to cope with what your computer memory cannot. &lt;br /&gt;&lt;br /&gt; "If the integers from 1 to 999,999,999 are written as words, sorted alphabetically, and concatenated, what is the 51 billionth letter?"&lt;br /&gt;&lt;br /&gt;To be precise: if the integers from 1 to 999,999,999 are expressed in words&lt;br /&gt;(omitting spaces, 'and', and punctuation[1]), and sorted alphabetically so that the first six integers are&lt;br /&gt;&lt;br /&gt;    * eight&lt;br /&gt;    * eighteen&lt;br /&gt;    * eighteenmillion&lt;br /&gt;    * eighteenmillioneight&lt;br /&gt;    * eighteenmillioneighteen&lt;br /&gt;    * eighteenmillioneighteenthousand&lt;br /&gt;&lt;br /&gt;and the last is&lt;br /&gt;&lt;br /&gt;    * twothousandtwohundredtwo&lt;br /&gt;&lt;br /&gt;then reading top to bottom, left to right, the 28th letter completes the spelling of the integer "eighteenmillion".&lt;br /&gt;&lt;br /&gt;The 51 billionth letter also completes the spelling of an integer. Which one, and what is the sum of all the integers to that point?&lt;br /&gt;&lt;br /&gt;[1] For example, 911,610,034 is written "ninehundredelevenmillionsixhundredtenthousandthirtyfour"; 500,000,000 is written "fivehundredmillion"; 1,709 is written "onethousandsevenhundrednine".&lt;br /&gt;&lt;br /&gt;|#&lt;br /&gt;&lt;br /&gt;; (load (compile-file "wordnumbers.lisp"))&lt;br /&gt;; (solve 999999999 51000000000) ; unlikely to finish unless you have a massive memory heap &lt;br /&gt;; (solve 10 26) ; will work, but may not get you the job ;-)&lt;br /&gt;&lt;br /&gt;;;;; Utilities&lt;br /&gt;&lt;br /&gt;(defmacro with-string-words((str word) &amp;body body)&lt;br /&gt;  "Utility macro to iterate over a string and return each word (anything between spaces)"&lt;br /&gt;  `(do* ((start 0 (if end (1+ end) nil))&lt;br /&gt;         (end&lt;br /&gt;          (position #\Space ,str :start 0)&lt;br /&gt;          (if end (position #\Space ,str :start (1+ end)) nil))&lt;br /&gt;         (,word (subseq ,str start end) (if start (subseq ,str start end) nil)))&lt;br /&gt;       ((null start))&lt;br /&gt;     ,@body))&lt;br /&gt;&lt;br /&gt;;;;; Numbers are stores as the number in words, the length of this string and finally the numeric value&lt;br /&gt;&lt;br /&gt;(defun get-words(lst)&lt;br /&gt;  (first lst))&lt;br /&gt;&lt;br /&gt;(defun get-length(lst)&lt;br /&gt;  (second lst))&lt;br /&gt;&lt;br /&gt;(defun get-value(lst)&lt;br /&gt;  (third lst))&lt;br /&gt;&lt;br /&gt;(defun remove-and(str)&lt;br /&gt;  "remove occurences of 'and' from a string"&lt;br /&gt;  (let ((new-str (make-array 0 :element-type 'character :fill-pointer 0 :adjustable t)))&lt;br /&gt;    (with-string-words (str word)&lt;br /&gt;                (if (string/= "and" word)&lt;br /&gt;                    (and&lt;br /&gt;                     (setf new-str (concatenate 'string new-str word))&lt;br /&gt;                     (setf new-str (concatenate 'string new-str " ")))))&lt;br /&gt;    new-str))&lt;br /&gt;&lt;br /&gt;(defun char-space-or-hyphen-p(c)&lt;br /&gt;  (if (or (char= #\Space c) (char= #\- c))&lt;br /&gt;      t&lt;br /&gt;      nil))&lt;br /&gt;  &lt;br /&gt;(defun remove-spaces-and-hyphens(str)&lt;br /&gt;  "remove spaces and hyphens from a string"&lt;br /&gt;  (remove-if #'char-space-or-hyphen-p str))&lt;br /&gt;&lt;br /&gt;(defun get-number-as-words(n)&lt;br /&gt;  "Use common lisps built in English text number output"&lt;br /&gt;  (format nil "~r" n))&lt;br /&gt;&lt;br /&gt;(defun get-numbers-as-word-list(n)&lt;br /&gt;  "get the numbers from 1 to n and return as a list of strings and the lengths"&lt;br /&gt;  "of each string as a list of three items, words, length of word string and" &lt;br /&gt;  "actual numeric value"&lt;br /&gt;  (loop for n from 1 to n collect&lt;br /&gt;        (let* ((str (get-number-as-words n)) (len (length str)))&lt;br /&gt;          (list (convert-text str) len n))))&lt;br /&gt;&lt;br /&gt;(defun compare-word-and-len(a b)&lt;br /&gt;  "given a string, length pair compare on alphabetical order"&lt;br /&gt;  (string&lt; (get-words a) (get-words b)))&lt;br /&gt;&lt;br /&gt;(defun sort-number-word-list-alphabetically(lst)&lt;br /&gt;  (sort lst #'compare-word-and-len))&lt;br /&gt;&lt;br /&gt;(defun convert-text(str)&lt;br /&gt;  (remove-spaces-and-hyphens (remove-and str)))&lt;br /&gt;&lt;br /&gt;(defun get-number-from-letter-index(lst target-index)&lt;br /&gt;  (do&lt;br /&gt;   ((number 0 (1+ number))&lt;br /&gt;    (index 0 (+ index (get-length (nth number lst)))))&lt;br /&gt;   ((&gt; number (1- (length lst))))&lt;br /&gt;    (if (&lt;= target-index (+ index (get-length (nth number lst))))&lt;br /&gt;        (return-from get-number-from-letter-index number)))&lt;br /&gt;  nil)&lt;br /&gt;&lt;br /&gt;(defun sum-to-n(lst n)&lt;br /&gt;  (if (&gt;= n 0)&lt;br /&gt;      (+ (get-value (car lst))&lt;br /&gt;         (sum-to-n (cdr lst) (1- n)))&lt;br /&gt;      0))&lt;br /&gt;&lt;br /&gt;(defun solve(num n)&lt;br /&gt;  "Solve the problem for 'num' numbers, finding character position n"&lt;br /&gt;  (let ((lst&lt;br /&gt;         (sort-number-word-list-alphabetically&lt;br /&gt;          (get-numbers-as-word-list num))))&lt;br /&gt;    (format t "Made list~%")&lt;br /&gt;    (let ((number&lt;br /&gt;           (get-number-from-letter-index lst n)))&lt;br /&gt;      (format t "Found number~%")&lt;br /&gt;      (let ((value (get-value (nth number lst))))&lt;br /&gt;        (format t "Done.~%Number at character pos ~a is ~a. Sum to that number is ~a~%" n value (sum-to-n lst number))))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-7302558058541195918?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/7302558058541195918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=7302558058541195918' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7302558058541195918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/7302558058541195918'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/09/word-numbers-programming-puzzle.html' title='Word numbers programming puzzle'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-3090427255484728398</id><published>2007-09-12T13:30:00.000-07:00</published><updated>2007-09-12T13:35:24.944-07:00</updated><title type='text'>Commenting out a block of C++ in emacs</title><content type='html'>Here are couple more simple functions, used for commenting out a block of C++ code.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;c++-comment-line&lt;/span&gt; below simple inserts "//" at the start of a line&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;c++-comment&lt;/span&gt; region will take the current region and run the c++comment-line on each line.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun c++-comment-region()&lt;br /&gt; "Comment a region out"&lt;br /&gt; (interactive)&lt;br /&gt; (save-excursion&lt;br /&gt;   (save-restriction&lt;br /&gt;     (narrow-to-region (point) (mark))&lt;br /&gt;     (goto-char (point-min))&lt;br /&gt;     (while (&gt; (point-max) (point))&lt;br /&gt; (c++-comment-line)&lt;br /&gt; (forward-line)))))&lt;br /&gt;&lt;br /&gt;(defun c++-comment-line()&lt;br /&gt; "Comment a line of C++ out"&lt;br /&gt; (beginning-of-line)&lt;br /&gt; (insert "//"))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-3090427255484728398?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/3090427255484728398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=3090427255484728398' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3090427255484728398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/3090427255484728398'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/09/commenting-out-block-of-c-in-emacs.html' title='Commenting out a block of C++ in emacs'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8898140909915618671</id><published>2007-09-11T08:44:00.000-07:00</published><updated>2007-09-11T11:46:13.380-07:00</updated><title type='text'>Adding C++ class names to a function name</title><content type='html'>I use this elisp code to add a C++ class name to a line such as:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void getNameRawString(char *string);&lt;br /&gt;&lt;br /&gt;automatically becomes ...&lt;br /&gt;&lt;br /&gt;void SomeClassName::getNameRawString(char *string);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is useful as you can copy a bunch of class method definitions from a header file you've just created and then run this on each line to add the class names. &lt;br /&gt;&lt;br /&gt;First I wrote a utility function that finds the function name, which is presumed to be letters and underscores, following space and ended with a bracket. The function name includes the word probably because it might not work depending on your formatting, but you can twiddle the regex to get what you want. &lt;br /&gt;&lt;br /&gt;So as you can see this finds the match for the regex, which will place the point at the end of the search. Then I search backwards for a space which puts the point where we want to insert the class name and double colons...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun find-function-start-probably()&lt;br /&gt;  (interactive)&lt;br /&gt;  (re-search-forward " [*&amp;_a-zA-Z]+(")&lt;br /&gt;  (re-search-backward " ")&lt;br /&gt;  (forward-char)&lt;br /&gt;  (if (or&lt;br /&gt;       (char-equal (char-after) ?*)&lt;br /&gt;       (char-equal (char-after) ?&amp;))&lt;br /&gt;      (forward-char)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally the function below calls find-function-start-probably. It prompts for the class name, finds the function and inserts the text. The program automatically aborts if there is no match. You can override that behavior by passing arguments to re-search-forward.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun classname-add(classname)                                                                   &lt;br /&gt;    (interactive "sEnter class name: ")                                                           &lt;br /&gt;    (find-function-start-probably)                                                                &lt;br /&gt;    (insert classname)                                                                            &lt;br /&gt;    (insert "::")                                                                                 &lt;br /&gt;    (beginning-of-line)                                                                           &lt;br /&gt;    (forward-line)) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Improvements on the way:&lt;br /&gt;&lt;br /&gt;Multi-line version: do this over multiple lines&lt;br /&gt;&lt;br /&gt;Improvements unlikely but would be nice:&lt;br /&gt;&lt;br /&gt;Parse the header file more intelligently and create all the class function definitions with empty function bodies in a specified buffer&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8898140909915618671?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8898140909915618671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8898140909915618671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8898140909915618671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8898140909915618671'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/09/adding-c-class-names-to-function-name.html' title='Adding C++ class names to a function name'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4777243148323391813.post-8503690313313184615</id><published>2007-09-07T16:46:00.000-07:00</published><updated>2007-09-07T16:52:49.381-07:00</updated><title type='text'>Fixing up windows pathnames to use in cygwin</title><content type='html'>I use emacs within Cygwin, and often I want to paste a pathname from an explorer window into emacs and use it there. Unfortunately you have to edit it by hand before it will work.&lt;br /&gt;&lt;br /&gt;So for example a path like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;c:\code\haskell\cats\monkeys&lt;br /&gt;&lt;br /&gt;Needs to be converted to:&lt;br /&gt;&lt;br /&gt;/cygdrive/c/code/haskell/cats/monkeys&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The following interactive elisp function does that with the currently selected text:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defun win32-to-cygwin-path()&lt;br /&gt;  "Converts a win32 path into a cygwin happy one"&lt;br /&gt;  (interactive)&lt;br /&gt;  (save-excursion&lt;br /&gt;    (save-restriction&lt;br /&gt;      (narrow-to-region (point) (mark))&lt;br /&gt;      (goto-char (point-min))&lt;br /&gt;      (insert "/cygdrive/")&lt;br /&gt;      (goto-char (point-min))&lt;br /&gt;      (while (search-forward ":" nil t)&lt;br /&gt;        (replace-match "" nil t))&lt;br /&gt;      (while (search-forward "\\" nil t)&lt;br /&gt;        (replace-match "/" nil t)))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nothing much clever going on here, just two search and replaces for the slashes and to removed the colon, and I insert the cygdrive prefix.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4777243148323391813-8503690313313184615?l=justinsboringpage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://justinsboringpage.blogspot.com/feeds/8503690313313184615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4777243148323391813&amp;postID=8503690313313184615' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8503690313313184615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4777243148323391813/posts/default/8503690313313184615'/><link rel='alternate' type='text/html' href='http://justinsboringpage.blogspot.com/2007/09/fixing-up-windows-pathnames-to-use-in.html' title='Fixing up windows pathnames to use in cygwin'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry></feed>
