Category Archives: Productivity

List of Favorite OS X Web Developer Apps

The following tools are either open source, shareware or freeware. For shareware, I will post freeware alternatives.DEVELOPMENT* JetBrains RubyMine (for Ruby and Rails development)

DEBUGGING
* Charles Proxy
* PHP xdebug with remote_enable = true

* SourceTree (if you use git)
* Cornerstone (if you use svn)

PRODUCTIVITY
* iTerm2
* Zshell with Oh My Zsh
* BetterSnapTool
* Mou (Markdown Editor)
* Tabs Outliner extension for Chrome

OTHER
* LittleSnitch
* Skitch
* Dropbox
* SuperDupr! or Time Machine
* RescueTime
* Solarized Theme (for shell, TextMate, etc.)

Remote repository hosting
* BitBucket.org
* GitHub.com
* GitLab.com

A dedicated IDE or Editor. Pimping Your IDE will be in another post. Here are my most used editors/workflows (not in any specific order. Usually the right one for the job.)

MacVim with solarized (light) BG but I’m constantly tweaking the colorscheme. Font is one of Anonymous, Source Code Pro, Consolas, Inconsolata, all patched for powerline (optional.)

I use NeoBundle to manage my vim packages. Here are my current bundles:

" After install, exec ~/.vim/bundle/vimproc, (n,g)make -f your_machines_makefile</pre>
NeoBundle 'Shougo/vimproc'
NeoBundle 'Shougo/vimshell'
NeoBundle 'kien/ctrlp.vim.git'
NeoBundle 'honza/writer.vim'
NeoBundle 'vim-ruby/vim-ruby'
NeoBundle 'plasticboy/vim-markdown'
NeoBundle 'juvenn/mustache.vim'
NeoBundle 'tpope/vim-rails'
NeoBundle 'tpope/vim-fugitive'
NeoBundle 'tpope/vim-unimpaired'
NeoBundle 'tpope/vim-abolish'
NeoBundle 'tpope/vim-surround'
NeoBundle 'tpope/vim-bundler'
NeoBundle 'tpope/vim-surround'
NeoBundle 'tpope/vim-characterize'
NeoBundle 'tpope/vim-haml'
NeoBundle 'tpope/vim-rake'
NeoBundle 'Lokaltog/vim-easymotion'
NeoBundle 'jeetsukumaran/vim-buffergator'
NeoBundle 'tilljoel/vim-automatic-ctags'
NeoBundle 'git://github.com/kchmck/vim-coffee-script.git'
NeoBundle 'altercation/vim-colors-solarized'
NeoBundle 'vim-scripts/Vim-R-plugin'
NeoBundle 'vim-scripts/R-MacOSX'
NeoBundle 'vim-scripts/vim-mou'
NeoBundle 'vim-scripts/ShowMarks'
NeoBundle 'vim-scripts/dbext.vim'
NeoBundle 'vim-scripts/Txtfmt-The-Vim-Highlighter'
NeoBundle 'vim-scripts/mru.vim'
NeoBundle 'vim-scripts/YankRing.vim'
NeoBundle 'majutsushi/tagbar'
NeoBundle 'mileszs/ack.vim'
NeoBundle 'ervandew/screen'
NeoBundle 'L9'
NeoBundle 'Gundo'
NeoBundle 'mattn/zencoding-vim'
NeoBundle 'scrooloose/nerdtree'
NeoBundle 'scrooloose/nerdcommenter'
NeoBundle 'jistr/vim-nerdtree-tabs'
NeoBundle 'nathanaelkane/vim-indent-guides'
NeoBundle 'git://git.wincent.com/command-t.git'
NeoBundle 'git://github.com/Lokaltog/vim-powerline.git'
NeoBundle 'http://svn.macports.org/repository/macports/contrib/mpvim/'
<pre>

Tmux + vim

Bulk Upload Images as Simple Products in Magento

The client has thousands of images, each of which is a (simple) product they want in Magento. Each image is named the associated product’s SKU number with a JPG extension. I began by using a recorded Batch script in Photoshop to resize all the images to reduce filesize and make the image more web-friendly.

The following Ruby script generates a Magento Product CSV file from JPG images in a directory. It is pasted as-is.

#!/bin/env ruby

require 'rubygems'
require 'csv'
require 'htmlentities'
require 'uri'


def main
    #Dir.glob("media/products/#{catname}/*").each_with_index do |imgpath, i|

    # Magento 1.7 CSV product headers
    csv_headers = '"store"	"websites"	"attribute_set"	"type"	"category_ids"	"sku"	"has_options"	"name"	"meta_title"	"meta_description"	"image"	"small_image"	"thumbnail"	"url_key"	"url_path"	"custom_design"	"page_layout"	"options_container"	"image_label"	"small_image_label"	"thumbnail_label"	"country_of_manufacture"	"msrp_enabled"	"msrp_display_actual_price_type"	"gift_message_available"	"price"	"special_price"	"weight"	"msrp"	"status"	"visibility"	"Featured"	"Deal"	"Hot"	"enable_googlecheckout"	"tax_class_id"	"is_recurring"	"description"	"short_description"	"meta_keyword"	"custom_layout_update"	"news_from_date"	"news_to_date"	"special_from_date"	"special_to_date"	"custom_design_from"	"custom_design_to"	"qty"	"min_qty"	"use_config_min_qty"	"is_qty_decimal"	"backorders"	"use_config_backorders"	"min_sale_qty"	"use_config_min_sale_qty"	"max_sale_qty"	"use_config_max_sale_qty"	"is_in_stock"	"low_stock_date"	"notify_stock_qty"	"use_config_notify_stock_qty"	"manage_stock"	"use_config_manage_stock"	"stock_status_changed_auto"	"use_config_qty_increments"	"qty_increments"	"use_config_enable_qty_inc"	"enable_qty_increments"	"is_decimal_divided"	"stock_status_changed_automatically"	"use_config_enable_qty_increments"	"product_name"	"store_id"	"product_type_id"	"product_status_changed"	"product_changed_websites"'

    path = "output.csv"
    open(path, 'w') { |f| f.puts csv_headers } 

    Dir.glob("*.JPG").each_with_index do |imgpath, i|
        image_name = File.basename(imgpath)
        image_url = "/#{image_name}"
        sku = image_name[0,image_name.size-4]
        name = sku
        desc_short = sku
        desc = sku
        csv = '"default"	"base"	"Default"	"simple"	"2"	"SKU"	"0"	"NAME"	"META_TITLE"	"META_DESC"	"IMAGE"	"IMAGE"	"IMAGE"	"url-key-SKU"	"url-key-SKU"	""	"No layout updates"	"Block after Info Column"	""	""	""	" "	"Use config"	"Use config"	"No"	"1.0000"	"China"	"1.0000"	""	"Enabled"	"Catalog, Search"	"0"	"0"	"0"	"Yes"	"None"	"No"	"LONG_DESC"	"SHORT_DESC"	"META_KEYWORDS"	""	""	""	""	""	""	""	"10000.0000"	"0.0000"	"1"	"0"	"0"	"1"	"1.0000"	"1"	"0.0000"	"1"	"1"	""	""	"1"	"0"	"1"	"0"	"1"	"0.0000"	"1"	"0"	"0"	"0"	"1"	"NAME"	"0"	"simple"	""	""'
        csv.gsub!('SKU', sku)
        csv.gsub!('NAME', name)
        csv.gsub!('LONG_DESC', desc)
        csv.gsub!('SHORT_DESC', desc_short)
        csv.gsub!('META_TITLE', sku)
        csv.gsub!('META_DESC', sku)
        csv.gsub!('META_KEYWORDS', sku)
        csv.gsub!('IMAGE', "#{image_url}")
        open(path, 'a') { |f| f.puts csv } 
    end

    p "Finished."
end

main


=begin

#require 'yaml'
#require 'hpricot'
#require 'tempfile'
#require 'mechanize'
#require 'open-uri'
#require 'highline/import'
#HighLine.track_eof = false

class Importer
  def initialize
    CSV.foreach('/Users/bluish/Desktop/export_ish.csv') do |row|
      p row.inspect
    end
    return
    
    CSV.open('/Users/bluish/Desktop/export_ish.csv', 'wb') do |csv|
      p 'injecting csv'
      csv << ['123', '', '456'] 
    end
  end
end

class String
  def decode
    HTMLEntities.new(:expanded).decode(self)
  end

  def encode
    #HTMLEntities.new(:expanded).encode(self)
    URI::escape(self)
  end
end
 
def saveImage(remote_url, thumb_url, dir='./media/import')
  require 'open-uri'
    begin
        base = File.basename(remote_url)
        img = "#{dir}/#{base}"
        
        unless File.exist? img
          p img
          open(img, 'wb') do |file|
            file << open(remote_url).read
          end
        end 
        
        thumb =  "#{dir}/thumb-#{base}"
        unless File.exist? thumb
          p thumb
          open(thumb, 'wb') do |file|
            file << open(thumb_url).read
         end
        end
        
        p "GOT MEDIA"

    rescue
       p "FAILED to grab #{remote_url}"
       p "or #{thumb_url}"
       p 'Possible 404? continuing...'
    end
end           

=end



Learning to Program on Your Own

Learning how to code is like learning anything else – You have to do it. The hardest part is figuring out where to begin, and then you need some mechanism to show you that you’re making progress. The latter is important because it motivates you to keep going.

First, have a goal. I initially wanted to make AOL “punters” (apps that kicked other users offline) and malware. I found them interesting. Do you want to program games? websites? Facebook Apps? Apps for OS X?

Once you have the goal, do research on how those apps are made, particularly on the language used, APIs/libraries used, and so on.

When starting, you will be learning a lot of concepts that you will see no use for. If-then statements, variables, etc. You might understand the basic idea of what a variable is, but might wonder – why would I ever use this instead of putting the value in directly? At this stage, it’s important that you remain persistant and just go through the examples/exercises in your book (or those provided by your tutor). I noticed that most people will struggle through the first set of concepts, and then lose interest and quit after seeing that they aren’t doing anything interesting. One day, you’ll be doing something and everything will fall into place. An A-Ha moment.

You’re learning a bunch of stuff that doesn’t really connect with each other. How does printing “Hello World” to the screen eventually become a 3D game? How do I go from a console app to a window app? How does knowing what a variable or constant is translate to a web development project?

It’s a plateau — and I want to stress that this applies to almost anything, not just programming. You begin by learning a lot of stuff, very slowly making progress, and over time you begin to see that you kinda “know” what’s happening behind the scenes of the apps you’re using. After that, learning because easier and quicker. Getting to that level requires persistance.

My Turning Point – Stop Asking “What Should I Code?”

When I first began coding, I had the mentality that I had to “learn how to program” before “making app X” – This is logical but the way I structured in my head was important in impeding my progress. I divided learning how to program and making app X into two separate goals. It was a problem because it migrated me away from the goal of “making app X.” I began asking the wrong question – what should I code to learn how to program?

Instead, I should have been asking – what should I learn next, to reach my goal of making app X? I broke down app X into individual tasks, and then began learning how to do each one. For example, let’s say my goal is to program a game.

If I ask “what should I code to learn how to program?” I will spend a lot of time learning things I might not need anytime soon (or ever), I will get nowhere near reaching my goal, and will become unmotivated and quit before getting there. Instead, I would break down the game into individual tasks (this requires research) and work on learning each one.

Let’s see, I need to figure out how to make a window/draw things on screen. That becomes my new short term goal. I dig deeper and learn that I need to learn the Windows API. I learn that the Windows API is how one draws to the screen. But the Windows API is another thing I need to learn, so that becomes the immediate short term goal. Digging deeper, I realize that the Windows API is just a bunch of functions with some conventions that I need to memorize.

Now my goal is somewhat clearer. I begin reading about the Windows API, making different small apps to make sure I understand what I’m reading. Eventually I am able to draw a window and controls. Great. I still don’t have a game. What’s next? I need to draw graphics. I dig into how it’s done and learn that the Windows API provides a set of functions graphics. I’m familiar with the Win API and so I just begin learning the graphics lib. I make a few dozen apps drawing basic circles, loading bitmap images, etc. Now my goal of making a game is starting to take shape in my head. I can mentally structure how the game will be, minus a few concepts I might not have learned yet.

Persistence.

What Firefox’s Memory Leak Feature Taught Me About Life

(draft)

I’ve been using Firefox since the first public beta, and the one thing always on my wish list was fixing the sluggishness and unbelievable memory consumption (2 GB of RAM?) that results from keeping Firefox open for too long. This is still on my wish list today (almost 2010), and I know it’s unlikely to be fixed. In fact, I’ve realized that – Zen Moment – the ‘patch’ must come from within.

The Mozilla team claim it is a feature and not a bug. Firefox stores pages you’ve been to so that you can go back to them instantly upon hitting the “Back” button. This means that FF’s memory needs grow as you browse the net, and leaving a page doesn’t necessarily mean the page’s memory has been deallocated. It makes sense, but in practice it results in Firefox becoming unresponsive. You can go into about:config and edit hundreds of settings, but I’ve never had any success with any of them in any version of Firefox on any OS. Ever.

I probably don’t use Firefox like the majority of users, and certainly not like the developers intended. For one, I don’t close it. In fact, I’ve never voluntarily closed Firefox in my life (I don’t shut down). I purposely crash it and then re-open it so that it asks me to load up all my previously open tabs. This clears out some memory and restores responsiveness making Firefox useable again.

Why don’t I just close it? Because I usually have a minimum of 50 tabs open across several FF instances, and some of those tabs are actually those “Oops, this is embarrassing…” windows that let you choose what tabs to re-open when you re-run a crashed Firefox. That means some of the tabs hold the potential to open up dozens or even hundreds of more tabs.

I feel relieved when Firefox is unable to restore my tabs. Life starts anew.

I keep tabs open that I intend to go through (never!), and I keep different sets of windows/tabs open depending on what I’m doing. i.e., cooking tabs in one window, work tabs in another, research tabs in another, etc. But this isn’t restricted to Firefox. On my Linux desktop I have 2 displays and 8 virtual desktops, making that 16 workspaces, and they’re usually always full. Since I have the RAM/power to run this setup, it’s smooth… except for Firefox and most other browsers (not Chrome).

On this desktop I worked around the Firefox memory problem by creating multiple profiles and using different profiles for different tasks (one for work, one for multimedia, etc). This also allowed me to crash one without affecting the others. It’s a temporary and crude solution until Firefox natively supports multiple processes like Chrome (see Electrolysis.)

But while there are some workarounds, fixing the technical issue isn’t going to increase productivity much. Having more sites open will probably make things worse. The habit of putting things off for later is inherently the problem. Having many sites/apps open is normal only amongst abnormal people. There’s nothing ‘wrong’ with it, but I don’t feel it’s very efficient, even if it may seem so at the time.

I’m generally disorganized and severely ADD-ed, and so this issue doesn’t only exist digitally. My desk is just as messy as Firefox. I have pieces of paper, napkins and anything else I jotted down notes on. I have unopened snail mail, opened but unchecked mail, and mail that has been checked and separated into 2 piles, those that require a reply and those that are to be trashed. There’s books I’m reading (multiple), and always unsorted pages of ideas/diagrams/blueprints of things I’ll probably never get to.

I’m obviously spreading my attention span thin. Going back to Firefox, if there’s an important piece of news on a page buried beneath other sites, I subconsciously still have “must read that article” somewhere deep in my head. It probably doesn’t result in any noticeable effect on its own, but when multiplied by 100x, the decline in calmness becomes significant enough to kill productivity. It produces a weak feeling of anxiety or overwhelmingness.

Small Vim Shortcut for PHP Tags

The short tags in PHP have been deprecated as of 5.3.0. Short tags provided a shorter alternative to the annoying-to-type <?php and <?php echo. Instead, you could use <? and <?= respectively. This was great but it caused problems when working with XML files, and the short_tags option was disabled in the PHP config by default on some implementations.

To make life easier, I created this vim mapping that will expand <? to <?php and <?? to <?php echo. You may change the abbreviation as you see fit. Simply place this in your .vimrc

inoremap <??    <?php echo  ?><Left><Left><Left>
inoremap <?     <?php  ?><Left><Left><Left>

Re-open vim or type use :source ~/.vimrc to reload the config. Now just type <? or <?? in insert mode.

Bash Tips for Power Users

Every Geek site needs an obligatory Bash Tips post

Copy Files Securely Between Two Machines

I used to always forget the syntax for this, until I realized that the syntax is exactly like the standard cp command. In fact, you can copy files like you normally would using scp, on your local machine. The following are equivalent:

$ cp file file.orig
$ scp file file.orig

Where they differ is, scp lets you copy files over a network, through SSH. Here’s an example:

$ scp contents.txt silver@ssh.domain.com:/tmp

This will copy local file contents.txt to /tmp on the remote machine ssh.domain.com, as user silver. Here are some more examples:

$ scp draft.pdf ssh.domain.com:

(copy draft.pdf to my home dir on remote machine. username is implied to be the same locally and remotely.)

$ scp swine.jpg rex@ssh.domain.com

(read: This will copy swine.jpg to local machine as a file named rex@ssh.domain.com. To make it go remote, append a : to the address, like above)

scp supports, among other things, compression (-C) and recursive copying of directories (-r).

$ scp -rC code/ ssh.domain.com:/archive/code_02032009

Trying to copy to a directory you don’t have permission to (/usr etc) will fail.

Don’t Get Lost Jumping To and Fro Between Directories

You can use cd - to jump to the previous (NOT parent) dir. For example:

kiwi@localhost: ~ $ cd /usr/local/share
kiwi@localhost: /usr/local/share $ cd -
/home/kiwi
kiwi@localhost: ~ $ cd -
/usr/local/share
kiwi@localhost: /usr/local/share $

Another way is using pushd/popd – A Last In First Out (LIFO) stack of dirs.

kiwi@localhost: ~ $ pushd /usr/local/share/
/usr/local/share ~

pushd is like cd but keeps note of the current dir before cd’ing into a new one. The stack of dirs is listed every time you invoke pushd (the “/usr/local/share ~” output you see above.)

kiwi@localhost: /usr/local/share $ pushd /
/ /usr/local/share ~

Stack is ordered left to right, latest push first. If we pop the first dir off:

kiwi@localhost: / $ popd
/usr/local/share /tmp ~
kiwi@localhost: /usr/local/share $

We’re back in the share dir. We can keep popping until there’s nothing left (throws an error):

kiwi@localhost: /usr/local/share $ popd
/tmp ~
kiwi@localhost: /tmp $ pushd /lib
/lib /tmp ~
kiwi@localhost: /lib $ popd
/tmp ~
kiwi@localhost: /tmp $ popd
~
kiwi@localhost: ~ $ popd
bash: popd: directory stack empty

Working with Long Lines

No need for more Bash shortcut cheat sheets, but here are some useful ones to help you work with long lines.

You can jump to the start & end of a line using CTRL+a & CTRL+e respectively. Example (* is the cursor):

kiwi@localhost: ~ $ echo al the ducks are swimming in the w*

and you want to fix the first word. You can hop to the beginning of the line with CTRL+a:

kiwi@localhost: ~ $ *echo al the ducks are swimming in the w

and now you can jump to the end of the misspelled word “al” using CTRL+Right twice to correct it:

kiwi@localhost: ~ $ echo all*the ducks are swimming in the w

Now ctrl+e to jump to the end of line:

kiwi@localhost: ~ $ echo all the ducks are swimming in the w*

Instead of backspacing every character, use ALT+Backspace to backspace entire words. You can also delete all or part of a line using CTRL+u combo. It deletes everything before the cursor. Likewise, CTRL+k wipes out everything after the cursor. I’ve developed a habit of using CTRL+e CTRL+k to delete lines.

Bash has a lot of ALT commands that let you move and manipulate words. ALT+l and ALT+u will make a word in front of the cursor lowercase or uppercase, for example. A neat one I don’t think I ever used is ALT+\ It pulls everything after the cursor left to the first non-whitespace character. Here’s an example, * is the cursor:

BEFORE:

$ my     spacebar is    *sticky

AFTER (ALT+\):

$ my     spacebar issticky

Avoid Retyping Commands & Arguments

ESC + . is very useful. Escape followed by a period will output the argument you sent to your last Bash command. Command calls themselves are outputted if they were invoked without any arguments (popd, ls, etc).

Example, unzipping a file and moving the archive to /tmp:

$ unzip archive-with-a-long-ambiguous-name-03092009-5960-1.2.5.zip
$ mv archive-with-a-long-ambiguous-name-03092009-5960-1.2.5.zip /tmp

In the mv command, the archive name was outputted by pressing ESC+. (full command being mv (ESC+.) /tmp) There was no need to type the long archive name twice.

The argument is taken from your bash history. You can keep invoking ESC+. to cycle back through all your recent command arguments. (history -c to clear)

Try not to forget this; You’ll naturally find plenty of uses for it.

Another way to avoid re-typing commands is CTRL+R. It will initiate a search of your command history. Begin typing, and watch Bash try to complete your command from previous ones you entered.

Command Getting Too Big? Send it to your Editor

Sometimes you begin writing what you think will be a simple command, only to realize that it has grown too complex for the command line, and you wish you were in your text editor.

First make sure your default editor is set. This is either in $EDITOR (export EDITOR=/usr/local/bin/vim) or elsewhere depending on the distro.

Use “fc” to open the last executed command in your editor:

ls -paul --sort=size
... ls output ...
fc

Now the ls line will be open in your editor. But what if you hadn’t executed the command yet? No problem. You’re sending off an email, but quickly realize that the command line isn’t ideal for everything:

echo -e "Dear Santa, \n\n\tIt has become evident that your fat ass is contributing to Global Warming, primarily due to the large quantity of coal you distribute annually. We hereby

No matter where you are on the line, hit CTRL+x, CTRL+e to invoke your editor, which now contains what you were typing on the cmd line.

I always find myself wanting to finish a command in vim, but unwilling to type the first few lines over, especially when I’m trying to write a for loop or any ugly multiline Bash code.

IMPORTANT: Whatever you type in your editor is executed automatically after you quit the editor.
Continue reading Bash Tips for Power Users

How to Block AIM’s Annoying ‘AOL System Msg’ in Pidgin

The following plugin for Pidgin will block the incredibly annoying and useless notifications from AOLSystemMsg on AIM.

“AOL System Msg: Your screen name (mrEman) is now signed into AOL(R) Instant Messenger (TM) in 2 locations. Click here for more information.”

To use, paste code in file, save file as blockaolsystemmsg.pl in ~/.purple/plugins/ and then open (or re-open) Pidgin and go to Tools -> Plugins (or press CTRL+U), and enable “Block AOLSystemMsg.” That should be it!

If you’re having any trouble, try going to Help -> Debug to open up Pidgin’s debug console.

#!/usr/bin/perl
# BlockAOLSystemMsg plugin tested on Pidgin 2.5.5. Put in ~/.purple/plugins/ and enable
use Purple;
our $target = 'AOL System Msg'; # case-insensitive
our $plugin_name = 'Block AOLSystemMsg'; 

%PLUGIN_INFO = (
  perl_api_version => 2,
  name => $plugin_name,
  version => "0.1",
  summary => "Blocks the screen name 'AOL System Msg'",
  description => "Ignore annoying 'your SN has signed on at 2 locations' AIM message",
  author => "Isam ",
  url => "http://biodegradablegeek.com",
  load => "plugin_load",
  unload => "plugin_unload"
);

sub loginfo { Purple::Debug::info($plugin_name, " @_\n"); }
sub minimize {
  my $r = lc($_[0]);
  $r =~ s/ //g;
  return $r;
}

sub plugin_init { return %PLUGIN_INFO; }

sub plugin_load {
  my $plugin = shift;
  $target = minimize($target);
  loginfo("Sight set on '$target'");
  Purple::Signal::connect(Purple::Conversations::get_handle(),
                          'receiving-im-msg', $plugin, \&callback, '');
}

sub plugin_unload {
  my $plugin = shift;
  loginfo('Block AOLSystemMsg Unloaded.');
}

sub callback {
  my ($acc, $sender, $msg, $flags) = @_;
  if (minimize($sender) eq $target) {
    loginfo("(BLOCKED) <$sender> $msg");
    return 1
  };
}

update: Fixed the botched code. Thanks.

4 Do-It-Yourself Whiteboard Alternatives

post_it_note_wall
Whiteboards are as useful as they are overpriced. I built one using tileboard (the thing they use in bathrooms), and I highly recommend making/buying one. It took me awhile to find tileboard in my area. In case anyone has the same problem, here are 4 alternatives I considered:

They are not in any specific order.

Glass or Plexiglas

Anything Expo markers can write on may be used as a board surface. This means a piece of glass, or acrylic glass (Plexiglas), placed over a bright white surface it (i.e., a wall or table). Glass actually works pretty well in terms of eligibility and clean up, but it’s heavy, has sharp edges and cannot be drilled into (easily). It’s also not cheap.

Plexiglas works well, but I heard some dry erase Expo markers have problems coming off. Research this before trying Plexiglas. Never use Acetone to clean Plexiglas (or any plastic).

Plexiglas might be a hassle to cut. Sawing at a high speed, be it power or manual, might cause the edge to melt and stick back together between each cut. It’s usually cut underwater ( don’t try putting a power saw in your bathtub).

What I did was use a regular hack saw, and had my friend shoot the area I was sawing with a water gun to cool it between each cut. A water gun.

Both glass and plexiglass have the advantage of letting you make overlays (assuming they are translucent). You can put anything behind this board, as opposed to having an all white surface. Some examples I’ve seen are adding templates like a blank calendar or checklist behind the glass.

If you put some work into it, this can be a nice, cheap setup.

Chalkboard or Chalkpaper

Chalkboards are cheaper than whiteboards, and even cheaper if you go the DIY route and make one using chalk paper. Chalk paper is basically a rough surface you can buy in rolls, which can be written on using standard chalk. Which means.. hopscotch in the office!

Chalkboards have great contrast, and chalk is dirt cheap compared to dry/wet erase markers (unless you steal those from your local college). The problem, and it’s a big one, is chalk dust. Chalk dust in a small room or office make this route unacceptable for most people. There is “anti-dust” / dust-free chalk, but dust can still be a problem if you don’t have good ventilation.
Continue reading 4 Do-It-Yourself Whiteboard Alternatives

I Can’t Live Without My vim Config

I have updated the vim page with my vimrc/gvimrc configs. Instead of repeating myself, I will quote some parts of the page ..

More details and the vim config itself here

I recommend turning backups on if you have them off. I personally hate having the ~ files all over my OS, so I keep them along with the .swp files in 1 backup dir in ~/.vim/

The programming language skeleton stuff will detect what files you are editing and change options in vim by inheriting the specified files which I put in ~/.vim/skeletons and ~/.vim/inherit.

The skeletons are automatically inserted in new files that vim is aware of. For example, in my own config, I have ~/.vim/inherit/c which has all the usual includes and int main() code. When I make a new C file (“gvim hello.c”), the new file begins with the skeleton code already present. Neat huh?

The inherit files can be used to set specific options for each language. This can mean different bindings, whitespace options, themes, etc depending on what language you’re working with, automatically.

See the vim page

What options have helped you the most?

How to Maintain Static Sites with Git & Jekyll

Static sites in this context just means non-database driven sites. Your static site can be an elaborate PHP script or just a few markup and image files. For this I am using Jekyll – A neat Ruby gem that makes your static sites dynamic. It lets you create layouts and embed custom variables in your HTML (this is a “prototype” of the site).

Jekyll tackles all the nuisances involved in creating static pages (I used to add just enough PHP to make a layout). It works by running your prototype through some parsers and outputs plain static HTML/XML (RSS feeds) etc. It’s perfect for lightweight sites that would be impractical on WordPress, like a few static pages of information, landing pages, portfolio/resume pages, and parked domains.

Git takes care of keeping your development (local) and production (remote) environments synced. Git might be a little confusing if you’re learning it with the mindset that it works like Subversion.

I’ll update this post when the guide is done. For now, the following will assume you’re familiar with Jekyll (or at least have an empty file in the prototype directory) and git. This Bash script simplifies creating the remote git repository:

** please read through the code and make sure you know what this does, and what you’re doing. As of now, this is bias towards my own Apache/vhost setup. It’s trivial to edit for your specific needs. You’re using this at your own risk.

(direct link – repogen.sh)

#!/bin/sh
# 
# 04/01/2009 | http://biodegradablegeek.com | GPL 
# 
# You should be in site (NOT public) root (be in same dir as public/ log/ etc)
# proto/ is created and will house the jekyll prototype
# public/ will be the generated static site
# the public/ folder will be REMOVED and regenerated on every push
# 

if [ -z "$1" ]; then
  echo "Usage: ./repogen.sh domain.comn"
  exit
fi

# optional. will make it easier to copy/paste cmd to clone repo 
SSHURL="ssh.domain.com"
URL="$1"

echo "** creating tmp repo"
mkdir proto
cd proto
git init 
touch INITIAL
git add INITIAL
git commit -a -m "Initial Commit"

echo "** creating bare repo"
cd ..
git clone --bare proto proto.git
mv proto proto.old
git clone proto.git
rm -rf proto.old

echo "** generating hook"
HOOK=proto.git/hooks/post-update

mv $HOOK /tmp
echo '#!/bin/sh' &gt;&gt; $HOOK
echo '# To enable this hook, make this file executable by "chmod +x post-update".' &gt;&gt; $HOOK
echo '#exec git-update-server-info' &gt;&gt; $HOOK
echo '' &gt;&gt; $HOOK
echo '' &gt;&gt; $HOOK
echo 'URL='"$URL" &gt;&gt; $HOOK
echo 'PROTO="/home/$USER/www/$URL/proto"' &gt;&gt; $HOOK
echo 'PUBLIC="/home/$USER/www/$URL/public"' &gt;&gt; $HOOK
echo  '' &gt;&gt; $HOOK
echo 'export GIT_DIR="$PROTO/.git"' &gt;&gt; $HOOK
echo 'pushd $PROTO &gt; /dev/null' &gt;&gt; $HOOK
echo 'git pull' &gt;&gt; $HOOK
echo 'popd &gt; /dev/null' &gt;&gt; $HOOK
echo '' &gt;&gt; $HOOK
echo "echo -----------------------------" &gt;&gt; $HOOK
echo "echo '** Pushing changes to '$URL" &gt;&gt; $HOOK
echo "echo '** Moving current public to /tmp'" &gt;&gt; $HOOK
echo 'mv "$PUBLIC" "/tmp/'$URL'public-`date '+%m%d%Y'`"' &gt;&gt; $HOOK
echo 'echo "** Generating new public"' &gt;&gt; $HOOK
echo 'jekyll "$PROTO" "$PUBLIC"' &gt;&gt; $HOOK

echo "** enabling hook"
chmod a+x $HOOK 

echo "** clone repo on local machina. example:"
echo "git clone ssh://$USER@$SSHURL/~$USER/www/$SSHURL/proto.git"

Usage

Your site structure might be different. repogen.sh is made by pasting the above code in a new file, and then chmod a+x to make it executable. This should be done on the remote server.

cd www/domain.com/
ls
public/ private/ log/ cgi-bin/

./repogen.sh domain.com

Now on your local machine, clone the new repo, move your files in, and push:

git clone ssh://[username]@ssh.domain.com/~[username]/www/domain.com/proto.git
cd proto/
cat "hello, world" &gt; index.htm
git add index.htm
git commit -a -m 'first local commit'
git push

After you push your changes, the post-update hook will delete the public/ directory (the root of the site). This dir and its contents are automatically generated and will get wiped out on EVERY push. Keep this in mind. All your changes and content should reside in proto/.

The proto/ repo will pull in the new changes, and then Jekyll will be invoked to generate the updated site in public/ from the prototype.

Should you need to edit it, the post-update hook is in the bare git repo (proto.git/hooks/)

Thanks to the authors in the posts below for sharing ideas. I first read this git method on dmiessler’s site.

Resources:
dmiessler.com – using git to maintain static pages
toroid.org – using git to manage a web site
Jekyll @ GitHub
git info
more git info