Friday, January 4, 2013

A simple method for using shared webhosting like Dreamhost to store git repositories

I wanted to set up some personal git repositories and don't want to pay the fee to github.com or another service to host the repository.  Fortunately it's possible to set up a repository behind any SSH account, such as on my web hosting account.  I've just gone through setting up a git repository on my Dreamhost account, and it is pretty straight-forward, but the steps are different from what's shown at the GIT book on git-scm.com.

The first step is to set up passwordless SSH access to your web hosting account or other SSH login.  The instructions at git-scm.com are pretty accurate in how to do this.  They're suggesting to set up a new account, named git, to store the repositories but I don't think that's necessary.  However, if the repository is to be shared between multiple people it should be set up on its own SSH login.

I created a directory 'git' in the home directory of my hosting account.  That directory is being used to store repositories.  Repositories are created as follows.

$ mkdir git
$ cd git
$ mkdir repository.git
$ cd repository.git
$ git --bare init

So far the steps are as shown on git-scm.com.  From here onward is where my steps differ from theirs.

On your laptop, type this:

$ git clone userName@server.host.dom.ain:git/repository.git

This creates a directory named 'repository' containing a clone of the empty repository just created above.

Now add files to the repository, for example:

$ cd repository
$ echo 'Hello, world!' >README.md
$ git add README.md
$ git commit -m 'initial commit'
$ git push

QED



Friday, August 3, 2012

How to connect a Google+ Page with a Blogger blog to extend your blogs branding into Google+

The "Google Plusification" of all of Google is proceeding slowly, and it seems likely that eventually Google+ will be a part of every Google property.  Google Blogger just added a new Google+ integration that's interesting, that gives you an option to associate a Google+ Page with your blog rather than associating it with your personal Google+ Profile.  You'd want to do this to help with better branding of your blog, and to separate your personal Google+ activities from the activities associated with your blog.

Suppose you have several blogs (as I do) that cover topics unrelated?  Should your personal activity stream be filled with all these unrelated postings?  Or should there be an activity stream on G+ that individually covers each blog separately.  That way your followers could subscribe to the page associated with your blog, rather than your personal page, and they'd receive updates solely with the blog they're interested in, without being bothered by the other unrelated stuff that you post.

How do you do this?  Let's take one of my blogs, Migrate From Drupal, and go through the steps.

The necessary requisite step is obviously to have a Google account which has a Google+ account.   It's possible to have a Google account and not have an associated Google+ account.  But obviously to associate a Google+ page with your blog, you must first have a Google+ account.  That's because Google+ pages act like a second identity on Google+.

First is you log into the Blogger dashboard, and navigate to the blog you wish to do this for.

Notice in the list of subsections on the let is a Google+ choice.  Click on that.

It's likely going to say this:
This blog is associated with your personal Google+ profile
Change the association to one of your Google+ pages using the box below. 
And

Associating your blog with your Google+ Profile or Page allows you to share your posts to the desired location.
If your Google+ page has already created Google+ Pages they'll be shown.  There are two ways to create a Google+ Page.

From within Blogger, the Google+ tab has a "Create my Page" button at the bottom of the page.  It's located below this nice graphic.


 The other way to create a Google+ page is, from your Google+ profile page, scroll down to the bottom where the "More ..." button is, hover over  the "...", and click on the Pages choice.  From that page you can create a new G+ Page.  Both methods get through to the same page on G+.

Here's a video about this feature



Basically, fill in the steps to create the page.  Enter the name of the page (e.g. the same as the name of your blog) as well as the URL for the blog.  It'll help if you already have an image available to serve as the profile image (250x250). 

The G+ Page acts as an identity on Google+ meaning you can browse around G+ as that Page, and interact with others as that Page, rather than browsing around and interacting as your own identity.  The page has its own Profile and About page, etc. 

The next thing to do is make sure that widgets from the G+ Page show up on the blog.

In the Layout area of the Blogger dashboard, click on the "Add a Gadget" choice and one of the featured items is "Google+ Badge."  Simply add that, and it'll do the correct thing, and add a "Follow" button onto your blog that's associated with the Google+ Page.

The "About Me" gadget for some reason doesn't associate itself with the G+ Page, but your G+ Account.

That's about it - I'm not finding anything like how Facebook Fan Pages can export a widget showing the membership of the Fan Page etc.  What I was hoping is for a widget that would show "social proof" (the number of followers), but G+ does not provide such a widget.


Friday, April 13, 2012

Monetizing your self-hosted wordpress blog with the Amazon Link plugin for Wordpress

The Amazon associate program is the grand-daddy of all affiliate programs.  That program began in the late 1990's (?1998?) with the idea that individual website owners could place links to products being sold by amazon.com, and earn a sales commission.  Today there are thousands of online stores with their own affiliate programs perhaps hoping to replicate Amazon's success that's in part due to finding a way to incentivize zillions of individual website owners to promote amazon.com as a place to buy stuff.

The point is that you, as a website owner, can help pay for your time to build your website by earning revenue from getting people to buy stuff from amazon.com.

It's a win-win arrangement where you are rewarded, and amazon.com is rewarded, and hopefully the people you send to amazon.com gains from buying a product they need.

The Amazon Link plugin for Wordpress helps you find products from amazon.com and insert product information into your posts.

Installation:  This is pretty simple because the module is part of the standard plugins available through the plugin panel in the wordpress dashboard.  Simply go to Plugins / Add New, type "Amazon Link" into the search process, then click on the install link, and then activate the plugin.  You've probably done this a few times already.

After installation an Amazon Link shows up in the Settings area.  There are some settings to make.

Link Text: This is default text on links ... out of the box it reads amazon.co.uk but maybe you want to use amazon.com instead?

Default Country: Again, out of the box it is United Kingdom, but you might want it to read United States instead?

AWS Public & Private Key: This is absolutely required.  The Amazon Link plugin accesses Amazon's product advertising data API, and requires a pair of security keys to use as credentials authenticating access to the API.  Unfortunately the plugin doesn't make it very clear what to do, and neither does Amazon make it easy to understand.

The plugin links you to http://aws.amazon.com/ but once you get there you're likely to scratch your head and say "now what?"  What you do is sign up for an account (it's free and doesn't cost anything).  Ignore most of what's on that site because the site is mostly about Amazon selling people on using this huge array of cloud computing services.  Amazon's primary intellectual property is the cloud computing infrastructure running the company's websites, and they rent out that infrastructure to other companies as well.  You might be interested in those other services, for for the moment please ignore it all.

What we need right now is the security credentials that Amazon will have already generated for your use.  In the upper right-hand-corner of the page is a "My Account" link, hover your mouse over it, and see the Security Credentials choice in the dropdown.  Click on that.  Part-way down the page is a box showing Access Credentials, one column is labeled Access Key ID, the other labeled Secret Access Key.  Simply copy/paste those keys into the AWS Public & Private Key boxes in the settings page.

Amazon Tracking ID Channels: This is also a very important thing, and if you do not change this the author of the module could be given all the credit for affiliate sales from your website.  Paste your amazon affiliate ID into the boxes.  If you haven't already signed up for the program, do so here:  Amazon Affiliate Program

USAGE: Once you've done these things usage is pretty simple.  At the bottom of the Add Post page is a new set of blocks letting you find products to paste into the post.  As you use this feature you notice that it simply pastes special tags into your posts.

Already have an ASIN for a product?  (ASIN's are Amazon's product ID codes, and the ASIN for a given product is shown on its product page)  That's the top area of the Add Amazon Link area .. paste the ASIN in, then enter Link Text, then choose a template.

Want to search for a product instead?  Use the next area.  Choose the product type, then enter search terms into either Author or Title boxes.  It then shows a number of candidate products.  Simply click the Insert button, and a tag gets entered.  Unfortunately the tag takes the default text and is a simple text link.

Recommendations:  It sounds like such a useful plug-in in the description, but in usage I don't quite grok why it's thought to be so good.  Yes, it helps you find and insert products from Amazon.  However, Amazon themselves makes that easy today.  As an affiliate program member, when you browse the Amazon website a toolbar is at the top of the page showing options that help you get HTML codes for affiliate links.

Another issue I have with it is the thing doesn't copy over any of the sales copy that Amazon can provide, nor price information, etc.  There is a feature letting you create templates, and the templates can copy over some information provided by Amazon.  But the user interface for using and creating templates is klunky.

I can't really recommend using this module.  I find it easy enough to browse around the Amazon website to get links that way.  Further, the link provided by Amazon is in HTML and does not require additional plugins on the website to use. 

The Amazon Link plugin lives on your website, and rather than generate HTML it generates a special tag, and for your website to continue displaying the right stuff (the amazon product link) the plugin must be installed.

Saturday, January 7, 2012

Implementing MySQL style AUTOINCREMENT in SQLite3

Yesterday I wrote about implementing the MySQL enum datatype in SQLite3, and while that exploration turned out to be pretty simple someone tweeted a followup talking about how I needed to cover the AUTOINCREMENT feature as well.  Studying my code I realized that indeed it would be necessary.  Fortunately this came out to be very simple, much simpler than was implementing the enum datatype.

To start this off let's review what the MySQL style auto_increment does.  A typical schema might include

CREATE TABLE geog (
  id int(11) NOT NULL auto_increment,
..
);

With this table definition you add items to your database with:

INSERT INTO geog(id, ..) VALUES(NULL, ..);

Basically the idea is when you supply NULL for the value of an auto_increment field, the database picks the next available value which will be one greater than the largest existing value.  This feature is useful for auto-generating unique keys for your data.

Unfortunately SQLite3 doesn't support this syntax.  And in the code I posted yesterday I skipped over the auto_increment feature by specifying this in the schema:

CREATE TABLE geog (
  id int(11) NOT NULL ,
..
);

This does not at all implement the auto_increment feature, instead it requires that values be provided for the id column.  The code running my website instead specifies NULL so that the database will provide a value for id.  If you think about it, it's difficult to implement this from the code running the site because there's a race condition in which you could write a query to get the current maximum value in the id column, then generate a new id value, but what if there are two requests underway at the same moment attempting to add rows to this table.  The two could be retrieving the maximum id value at the same time, generate the same next value for id, then both insert entries in the database with the same id value, which would erase its value as a unique identifier.  It's much better for the database to do this for us.

Fortunately the SQLite3 documentation has an answer for us (see http://www.sqlite.org/autoinc.html) that's ready to use, but with a different syntax than MySQL's implementation.  So much for SQL being a standard language, eh?

With SQLite3 you do this in your schema:

CREATE TABLE geog (
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- int(11) NOT NULL ,
..
);

It turns out that in SQLite3 there is a ROWID column on every table that actually could serve very well as a unique identifier for each row.  However adding a column as defined above aliases the ROWID column to be the one you name with the datatype INTEGER PRIMARY KEY AUTOINCREMENT.  The other thing you have to do is not declare a PRIMARY KEY in the table like so:

CREATE TABLE geog (
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- int(11) NOT NULL ,
..
--   PRIMARY KEY  (`id`) --  AUTOINCREMENT,
..
);

That is, here I've commented out the PRIMARY KEY declaration, because id is already declared to be a PRIMARY KEY and SQLite3 doesn't like having two PRIMARY KEY specifications.

So, that's nice, but how do you use it?

sqlite> insert into geog(id, continent, country, state, city, url) values  (1, 'Georgia', '', '', '', '');
SQL error: foreign-key violation: geog.continent
sqlite> insert into geog(id, continent, country, state, city, url) values  (1, 'Asia', '', '', '', '');
sqlite> insert into geog(id, continent, country, state, city, url) values  (NULL, 'Asia', 'Japan', '', '', '');
sqlite> insert into geog(id, continent, country, state, city, url) values  (NULL, 'Asia', 'Japan', 'Tokyo', '', '');
sqlite> insert into geog(id, continent, country, state, city, url) values  (NULL, 'Asia', 'Japan', 'Tokyo', 'Tokyo', '');
sqlite> .dump geog
BEGIN TRANSACTION;
CREATE TABLE geog (
  id INTEGER PRIMARY KEY AUTOINCREMENT, -- int(11) NOT NULL ,
  continent text, --  enum('North America','South America','Central America','Carribean','Atlantic','Europe (West)','Europe (East)','Africa','Middle East','South Asia','East Asia','Asia','Pacific','Australia') NOT NULL ,
  country char(255) NOT NULL default '',
  state char(255) NOT NULL default '',
  city char(255) NOT NULL default '',
  url char(255) default NULL
--   PRIMARY KEY  (`id`) --  AUTOINCREMENT,
--   KEY `byContinent` (`continent`),
--   KEY `byCountry` (`country`),
--   KEY `byState` (`state`),
--   KEY `byCity` (`city`),
--   KEY `geogurl` (`url`)
);
INSERT INTO "geog" VALUES(1,'Asia','','','','');
INSERT INTO "geog" VALUES(2,'Asia','Japan','','','');
INSERT INTO "geog" VALUES(3,'Asia','Japan','Tokyo','','');
INSERT INTO "geog" VALUES(4,'Asia','Japan','Tokyo','Tokyo','');
CREATE TRIGGER ContinentTrigger BEFORE INSERT ON geog FOR EACH ROW
WHEN (SELECT COUNT(*) FROM geogContinents WHERE  continentName = new.continent) = 0 BEGIN
   SELECT RAISE(rollback, 'foreign-key violation: geog.continent');
END;
COMMIT;

The first insert command demonstrates that the trigger still works to limit the continent names to the values stored in geogContinents.  The following insert's demonstrate using NULL to autogenerate id values, and then we dump the table showing the values that the database now contains.

The behavior is exactly what the code in my site expects.



Friday, January 6, 2012

Converting a MySQL enum for use in SQLite3

I've got a database & website I want to move from using MySQL to using SQLite3.  Well, I think I want to use SQLite3.  Their document saying what sorts of uses make sense for SQLite3 are directly in line with my website, and I do want to remove some of the load off of my MySQL server so that it can have  cycles free for more important purposes.

However I've run into a couple troubles converting the schema so that it fits within SQLite3's limited SQL support.  Turns out that it doesn't support some column types and indexes.  And that the SQL produced by mysqldump contains some MySQLisms which SQLite3 just doesn't understand.

One of the details is that SQLite3 doesn't support enum's.  Sigh.  Here's one of my table definitions only slightly cleaned up from mysqldump:

DROP TABLE IF EXISTS geog;
 SET @saved_cs_client     = @@character_set_client;
 SET character_set_client = utf8;
CREATE TABLE geog (
  id int(11) NOT NULL ,
  continent  enum('North America','South America','Central America','Carribean','Atlantic','Europe (West)','Europe (East)','Africa','Middle East','South Asia','East Asia','Asia','Pacific','Australia') NOT NULL ,
  country char(255) NOT NULL default '',
  state char(255) NOT NULL default '',
  city char(255) NOT NULL default '',
  url char(255) default NULL,
  PRIMARY KEY  (`id`)  AUTOINCREMENT,
   KEY `byContinent` (`continent`),
   KEY `byCountry` (`country`),
   KEY `byState` (`state`),
   KEY `byCity` (`city`),
   KEY `geogurl` (`url`)
) ENGINE=MyISAM AUTO_INCREMENT=9643 DEFAULT CHARSET=latin1 PACK_KEYS=1;
SET character_set_client = @saved_cs_client;

This table is meant to contain a list of geographic locations and I chose to use an enum to store the continent names.  There are several things in this which SQLite3 barfs on when you run it like so:

$ sqlite3 -init geog.sql geog.db
-- Loading resources from geog.sql
SQL error near line 3: near "SET": syntax error
SQL error near line 4: near "SET": syntax error
SQL error near line 5: near "'North America'": syntax error
SQL error near line 19: near "SET": syntax error
SQLite version 3.5.9
Enter ".help" for instructions
sqlite>

Most of the SET statements simply don't work so we'll comment them out in a minute.  The thing which stuck out was the "syntax error" on North America.  Took awhile to work out what that meant, had to dig through the SQLite3 documentation to learn that their type system is somewhat, um, interesting.

They have this concept of "type affinity" which means that the stored value is only loosely associated with the type name in the SQL of the table definition.  One particular thing is that enum is not one of the recognized data types.  Which leaves you with the task of mimicing the enum column type in some other way.

Basically an enum column is a text column constrained to a specific set of values.  I like the enum syntax because it's nice and concise and declarative.  But .. pragmatically .. there are several ways to implement constraints.  For example your code surrounding the database can enforce the constraint, but then you have to make sure all accesses to the database is through that code because that's the only way to enforce the constraint.

Fortunately I found a discussion of using triggers to enforce constraints and came up with this:-

DROP TABLE IF EXISTS geog;
-- SET @saved_cs_client     = @@character_set_client;
-- SET character_set_client = utf8;
CREATE TABLE geog (
  id int(11) NOT NULL ,
  continent text, --  enum('North America','South America','Central America','Carribean','Atlantic','Europe (West)','Europe (East)','Africa','Middle East','South Asia','East Asia','Asia','Pacific','Australia') NOT NULL ,
  country char(255) NOT NULL default '',
  state char(255) NOT NULL default '',
  city char(255) NOT NULL default '',
  url char(255) default NULL,
  PRIMARY KEY  (`id`) --  AUTOINCREMENT,
--   KEY `byContinent` (`continent`),
--   KEY `byCountry` (`country`),
--   KEY `byState` (`state`),
--   KEY `byCity` (`city`),
--   KEY `geogurl` (`url`)
);  -- ENGINE=MyISAM AUTO_INCREMENT=9643 DEFAULT CHARSET=latin1 PACK_KEYS=1;
--SET character_set_client = @saved_cs_client;

DROP TABLE IF EXISTS geogContinents;
CREATE TABLE geogContinents (
  continentName text
);

CREATE TRIGGER ContinentTrigger BEFORE INSERT ON geog FOR EACH ROW
WHEN (SELECT COUNT(*) FROM geogContinents WHERE  continentName = new.continent) = 0 BEGIN
   SELECT RAISE(rollback, 'foreign-key violation: geog.continent');
END;

insert into geogContinents values ('North America');
insert into geogContinents values ('South America');
insert into geogContinents values ('Central America');
insert into geogContinents values ('Carribean');
insert into geogContinents values ('Atlantic');
insert into geogContinents values ('Europe (West)');
insert into geogContinents values ('Europe (East)');
insert into geogContinents values ('Africa');
insert into geogContinents values ('Middle East');
insert into geogContinents values ('South Asia');
insert into geogContinents values ('East Asia');
insert into geogContinents values ('Asia');
insert into geogContinents values ('Pacific');
insert into geogContinents values ('Australia');

First off, notice that I commented out a bunch of stuff because SQLite3 doesn't recognize SET or KEY statements, or AUTOINCREMENT, or some other stuff.

The other thing is to change the definition of continent to text, add a new table geogContinents to hold the continent names, and a trigger to enforce the constraint that continent names can only be those named in the geogContinents table.

Now with this table definition you can initialize the database:-

$ sqlite3 -init geog2.sql geog2.db
-- Loading resources from geog2.sql
SQLite version 3.5.9
Enter ".help" for instructions
sqlite>

Then with an initialized database see that the constraints are enforced:-

$ sqlite3 geog2.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> .tables
geog            geogContinents
sqlite> insert into geog values (1, 'Georgia', '', '', '', '');
SQL error: foreign-key violation: geog.continent
sqlite> insert into geog values (1, 'Asia', '', '', '', '');
sqlite> 



http://old.nabble.com/enum-in-SQLite-td2223029.html




Sunday, December 11, 2011

Google's new 2-step verification process, and using it with 3rd party applications (like MarsEdit)

Did you turn on 2-step verification recently in your gmail account, and then see MarsEdit stop working, and groan "NOW WHAT"?  That's what I did recently, and fortunately there is a simple way to get 2-step verification to work with applications.  The issue is that most (all?) applications do not know how to do the 2-step verification process and instead fail to log you in.  By "application" I mean a non-browser application, like MarsEdit or Picasa, or I suppose some websites that do authentication against your Google Account might also fail to work.

Google in their infinite wisdom has published a video describing the new verification process, the issue with applications, and the procedure to resolve the problem.

Let's walk through the steps.

First you go to your Google Account Settings page.  In gmail (currently) if you click on your email address in the upper toolbar, it drops down a menu-thingy that includes the phrase "Account Settings".

On the Account Settings page there are links on the Overview tab - a) 2-step verification, b) Authorizing Applications & Sites

You can enable 2-step verification from the first of those links.  The benefit of 2-step verification is an added layer of security, where you get additionally verified through an SMS message sent to your cell phone.  I'm not entirely convinced this will always work as intended because for example what happens when you're traveling outside your country and maybe don't have roaming access with your normal cell phone to the local cell phone network?  Or what if you leave your cell phone at home, and need to authenticate while you're away?  In any case the verification, when your cell phone is handy, works well, because a message pops up on your phone right away with a number that you type into the entry box and you can go your merry way.

As noted this doesn't work for Applications like MarsEdit, and that's where the second link comes in.  Here you can revoke existing access grants but the important part for our immediate needs is the lower part of the page where there's a heading reading Application-Specific Passwords.

What you do is enter an Application Name, click the button, and it tells you a gobbledygook string that's the password for that application.  Google knows enough about the gobbledygook that it can recognize the application and all will be well.  The good news is you only have to do this once per application.

It's really pretty simple and it just works.

 

Monday, November 28, 2011

Posting nicely formatted code snippets on blogger blogs, using <pre> and the SyntaxHighlighter javascript library

In the past I've done my blogging on Drupal and enjoyed the contributed modules for generating syntax highlighting on code snippets.  Now that I'm moving to Blogger one issue was how to best present code snippets on the blog.  After some searching I've found a suitable method using a browser-side JavaScript library (Syntax Highlighter), and customizing the blogger theme with a small bit of code.

Let's first start with the problem statement.

We want "code" generally to be presented with a fixed-width font if only so we have good control over indentation on code snippets.  It would be nice to automatically highlight certain things in different colors to make it easier to read the code.  It'll also be extremely useful if code snippets automatically scroll along the horizontal axis, because code snippets are often wide.

The first step is to use the <pre> tag, and to customize your theme a little bit.  Using that tag automatically, generally, takes care of forcing a fixed-width font, so we can add one small bit of CSS to make enable scrollbars for <pre> tag content.

In the Blogger dashboard, navigate to the blog you want to enable this on, then head to the template section of that blog's dashboard.  The currently selected theme will be shown at the top, so click the Customize button.  Blogger will ask you to confirm you want to modify the template.

There's a consideration to make before you take this step.  Blogger doesn't do a good job with customized templates.  You're plopped into a screen where to edit the HTML/CSS/etc code of the template, and there's no attempt to separate out the kind of additions we're about to make so that you can easily switch to another template.  You'll have to record somewhere the modifications you make, so that if you later switch templates you can re-apply the changes to that new template.

Now that you're editing the template go into the <HEAD> section of the template and insert this bit of code:

<style>
pre {
  overflow-x: scroll;
}
</style>

What this does is tell the browser to add a horizontal scrollbar to <pre> tags.

We could stop at this point, and just recommend putting code snippets within <pre> tags.  In a moment we'll go on to add the Syntax Highlighter library to make this prettier, but let's first ponder a little problem.  The <pre> tags do nothing to hide other tags from being interpreted.  Putting HTML tags within <pre> tags may cause those tags to be interpreted by the browser and it's safer to encode the tags to hide them from the browser.  It's not just tags, because often we'll have less-than signs ('<') and other special characters in code snippets that the browsers might try to interpret.

What's needed is a tool to encode a block of text using HTML entities (e.g. &lt; is the HTML entity for the less-than character).  One such tool is:  http://accessify.com/tools-and-wizards/developer-tools/quick-escape/.  If you're hip to Node.js you could also take a look at this:  https://github.com/pvorb/node-esc.  There's a whole field of knowledge about this which you can yahoogle with "escape HTML".  For now it might be enough to manually go through your code to replace less-than characters with &lt; ..?

Note that the Syntax Highlighter library we're about to install offers another method other than using <pre> tags.  That library also lets you put text inside <script> tags but I recommend against this because it doesn't degrade well.  What if the JavaScript files we're about to install become unavailable?  What if your reader's browser is configured to reject JavaScript?  What..if..what..if..?  Basically, if you just use <pre> tags with the CSS above and encode the text well, you'll have nice basic support for code snippets and no need to do anything else.  The Syntax Highlighter library gives useful additional features, but if it becomes unavailable we can just delete the <script> tags referencing the library and still have working code snippets, albeit without syntax highlighting.

Now let's look at the Syntax Highlighter library.  It's a self-contained fully featured JavaScript library for highlighting code snippets.  The JavaScript executes in the browser, so we have to place the JavaScript files somewhere and add code to the template to reference the files.

The website has some installation instructions that I found less that useful.  Here's the way I've installed it.

First, download the source from the github repository:  https://github.com/alexgorbatchev/SyntaxHighlighter

As of this writing the source repository contains two directories of importance (the other directories can be ignored):  scripts, styles

Those two directories must be uploaded to a web server so that we can add <script> and <link> tags to the template referencing the files.  The <script> and <link> tags will bring in both the JavaScript library, and the CSS used by the library, to implement syntax highlighting.

In my case I have web server space I'm renting from a hosting company, and I simply set up a sub-domain over there to house the files.  You can see the details by viewing the source code of this page - but I ask you to not use my copy of the files.  The Syntax Highlighter author also is hosting the files on his own Amazon S3 account, but he says it's costing him quite a bit of bandwidth fees from an Amazon S3 account.  I would avoid using his files because he might eventually tire of paying for this bandwidth cost.  Blogger unfortunately doesn't let us upload files to be used by the theme.

In any case once you have the files somewhere (or even if you're referencing them off Alex Gorbatchev's site) add <script> and <link> tags to the <head> section of your template.

The script tags start with this:

 <script type="text/javascript" src="<URL leading to >/scripts/shCore.js"></script> 

The bit marked "URL leading to" is the URL of the place you're storing the scripts and styles files.  For every file in the scripts directory add a similar tag.

Next reference the style-sheets using a tag like this:

 <link href="<URL leading to>/styles/shCore.css" rel="stylesheet" type="text/css" /> 

To make this clear, wherever you end up hosting the Syntax Highlighter library copy both the scripts and styles directories to that web hosting location. For every file in the styles directory add a similar tag.

There are enough JavaScript and CSS files in Syntax Highlighter that it's possible to trip across a bug in Internet Explorer where it silently fails if there are more than 30 or so style sheet files.  The problem occurs with Internet Explorer 6 and hopefully that is a decreasing problem as the old WinXP machines get retired out of existence.  In any case if you want to accommodate this problem an alternative solution is:-

<style type="text/css">
@import "<URL leading to>/styles/shCore.css";
// repeat once for each file in styles directory
</style> 

This way the impact is one style-sheet rather than the slew of them which come with Syntax Highlighter.

With these files set up we now use it by adding a class to the <pre> tags.  The class added to a <pre> tag indicate which coding language is being used so that Syntax Highlighter can do its job.  For example:

<pre class="brush:js">
function foo()
{
}
</pre>

I think the "brush:" part of the class is meant to invoke the idea of painting the syntax with the desired colors, while the part after the colon is a tag describing the brush to use.  The list of brushes are on Alex Gorbatchev's website.