I added rel="nofollow" support to the Blosxom writeback plugin. I use Doug Alcorn's version that supports a blacklist and emails me when a new comment/trackback is posted.
Only one small change was required. I simply modified the writeback plugin to
prepend all href attributes with rel="nofollow".
--- writeback.orig 2005-01-20 10:59:23.000000000 -0800
+++ writeback 2005-01-20 11:31:00.000000000 -0800
@@ -233,6 +233,7 @@
$writeback =~ s/\$writeback::(\w+)/$param{$1}/ge;
$writeback =~ s!mailto:([^\s<]+)!<a href="mailto:$1">$1</a>!g;
+ $writeback =~ s!\bhref\b!rel="nofollow" href!ig;
$writebacks .= $writeback;
$count++;
}
Updated: changed regex to match word boundaries around href.
Saleforce uses 15-character IDs as primary keys for every record. When retrieving an ID over the API, 18-character case-insensitive IDs are returned. Generally, this doesn't cause any problems because the 18-character version can be used anywhere the 15-character one is. One problem arises though when you are storing IDs in a text field. In this case, you may need to convert a 15-character ID into its 18-character version. Salesforce provides a description of how to perform this conversion.
Here is a PHP implementation of the algorithm.
function sf15to18($short) {
$chunks = str_split($short, 5);
$extra = '';
foreach ($chunks as $chunk) {
$chars = str_split($chunk, 1);
$bits = '';
foreach ($chars as $char) {
$bits .= (!is_numeric($char) && $char == strtoupper($char)) ? '1' : '0';
}
$map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345';
$extra .= substr($map, base_convert(strrev($bits), 2, 10), 1);
}
return $short . $extra;
}
tech » salesforce | Permanent Link
If you are trying to track multiple domains within the same Google Analytics or Urchin profile, make sure you are using the same tracking library on all sites. I was attempting to track a visitor from one site using urchin.js to another using ga.js, and I spent a few hours trying to figure out why it wasn't working.
It turns out that the cookie data is encoded differently in query string appended to the url of the site to which you are passing it. With urchin.js and __utmLinker(), the __utmz cookie is url-encoded, but not with ga.js and ._link(). Compare the two URLs below.
http://example.com/?__utma=1.1181041260.1202679736.1202679736.1202679736.1&__utmb=1&__utmc=1.0&__utmx=-&__utmz=1.1202680382.1.3.utmcsr%3DFake%2BSource%7Cutmccn%3Dbogus%7Cutmcmd%3Dclicky%2Bclicky&__utmv=-&__utmk=129628685 http://example.com/?__utma=1.1181041260.1202679736.1202679736.1202679736.1&__utmb=1.0&__utmc=1.0&__utmx=-&__utmz=1.1202680287.1.2.utmcsr=Fake%2BSource|utmccn=bogus|utmcmd=clicky%2Bclicky&__utmv=-&__utmk=54196648
The ga.js _initData() won't properly parse the __utmz data from the query string in the first example. I hope this saves someone else some time.
If you work with people, you have probably received meeting requests from MS Outlook/Exchange users. I used to add these to KOrganizer using korganizerIn, but I stopped using KOrganizer a long time ago, and I've been pretty happy using Google Calendar for a while. My goal was to add meeting requests to my Google Calendar. The OpenSync library provides the means for moving events between different calendar formats, and multisync-tools provide a command-line interface to the OpenSync library.
Install and configure multisync-tools.
# apt-get install multisync-tools opensync-plugin-google-calendar opensync-plugin-file $ mkdir ~/calendar $ echo "text/calendar;~/bin/addCalendarItem %s; needsterminal;" >> ~/.mailcap $ msynctool --addgroup file-google $ msynctool --addmember file-google file-sync $ msynctool --addmember file-google google-calendar $ msynctool --configure file-google 1
Change the contents of the <path> tag.<config><path>/home/dir/calendar</path><recursive>FALSE</recursive></config>$ msynctool --configure file-google 2
Replace USER@gmail.com with your Google username and PASSWORD with your password.
Create ~/bin/addCalendarItem:
#!/bin/sh echo loading $1; cp $1 `tempfile -d ~/calendar` msynctool --sync file-google 2> /dev/null
Now when you get a meeting request in mutt, you can view-attachments, then view-attach (<Return>) on the meeting.ics attachment, and the meeting will be added to your Google calendar. It's not perfect. No acceptance notifications are sent. If you view a meeting request multiple times, it will be added to the calendar multiple times. Sometimes the synchronization hangs, and when you try it again, it detects conflicts between what's in your calendar directory and your Google calendar, and you have to tell it which to keep.
If I ever get the motivation, I might write a script to just add events using the Google Calendar API since I don't really need two-way synchronization.
Thanks to Trond for getting me started.
I was recently asked to configure Exim to archive all mail sent and received by certain customers. Users authenticate to send mail using their email address so I used a domainlist to specify which domains' users should have their mail archived.
domainlist archive_domains = example.com
I created two routers
and a transport for handling the mail sent by authenticated users. The first
is a redirect
router which rewrites the recipient address to a special address containing
the sender's address, e.g. _!%#archive#%!_-user@example.com. This router has
the unseen option set so the message is routed to the original
recipient as usual. This doubles the number of recipients, but Exim discards
duplicates so the final recipients are the original recipients plus the
sender's archive copy. The second router strips the _!%#archive#%!_- prefix
and delivers to the message to the sender's archive mailbox using a special
transport.
These routers should probably be the first two since you don't want another router to accept delivery of the message first.
archive_by_sender_rewrite:
driver = redirect
condition = ${if and { {def:authenticated_id}{match_domain{${domain:$authenticated_id}}{+archive_domains}} }{yes}{no}}
data = _!%#archive#%!_-$authenticated_id
unseen
no_repeat_use
no_verify
archive_by_sender:
local_part_prefix = _!%#archive#%!_-
driver = accept
no_verify
transport=archive_by_sender
Because $authenticated_id is used to get the sender's address, you
should have server_set_id = $1 in your authenticators
so the variable gets set.
The router to archive recieved mail is pretty simple. It uses the
unseen option again to create a copy of the message, and like
archive_by_sender uses a separate transport to archive the
message. This router should be placed before any routers that accept mail for
the +archive_domains. If you use routers to discard or quarantine
spam, this one should be before those if you want to archive the spam received.
archive_by_recipient: driver = accept domains = +archive_domains unseen no_verify transport=archive_by_recipient
Here are the transports. The messages are written to maildir directories. Any missing directories will be created if Exim has permission to create them.
archive_by_sender: driver = appendfile maildir_format mode = 0600 mode_fail_narrower = false envelope_to_add = true return_path_add = true create_directory directory = /path/to/archive/$domain/$local_part/sent archive_by_recipient: driver = appendfile maildir_format mode = 0600 mode_fail_narrower = false envelope_to_add = true return_path_add = true create_directory directory = /path/to/archive/$domain/$local_part/received
If you don't have the default rule in your rcpt acl to reject local parts
contains %, !, etc., you should make sure you don't accept mail for the special
archive user address. Safeguarding against malicious users with shell access
is left as an exercise for the reader. (Hint: I would probably look at
$received_protocol.)
tech » mail | Permanent Link
Mat Balez predicts
the demise of Twitter. Twitter is
kind of a micro-blogging tool. You can post messages to Twitter over the web,
IM, and SMS. These messages are then sent to people in your social network,
again through IM, SMS, or the web (html or rss). The messages are limited to
140 characters, and are meant to keep your friends up to date about the
minutiae in your life.
Twitter has become quite popular, but Mat thinks it will fail pretty quickly because it offers no real value beyond the novelty and is too much work. I think the real reason Twitter is likely to fail is that it suffers from network effects that bend back on themselves. Like other networking sites like MySpace and LinkedIn, the service becomes more useful as more people use it. But with Twitter, beyond a certain level, it becomes too intrusive and therefore less useful. If you have a hundred friends posting every time they refill their coffee cup, you will be inundated with twitter spam (twam?). The novelty will turn annoyance.
Real Player 10 has a nicer interface than version 8, but the video quality sucks. It's very choppy. So I recommend sticking with RealPlayer 8 for now. Real doesn't make it very easy to find old versions of their software, but there they do make them available in their Legacy Software Archive. For some reason, the link to RealPlayer 8 for Linux isn't the latest version. The Debian realplayer installer package expects rp8_linux20_libc6_i386_cs2_rpm. Also available is a tarball of the RealVideo 9 Codecs for use with RealPlayer 8. These are needed to play some videos.
Looking at my web stats, I saw a few visitors from Google who were looking for information on how to get old messages onto a Blackberry. Since I didn't actually have that information, I'll add it here.
Suppose you have some old messages in your IMAP inbox which have been purged from your Blackberry because they are too old, and you would like to get them back so you can reply while on the subway. Just copy them from your inbox back to your inbox. You can do this in a single action with mutt--using save will copy the messages and delete the originals. But Thunderbird doesn't seem to allow you to create a copy of messages within a folder so you will have to move (copy and delete original) the messages to another folder, and then copy them back to your inbox.
The copies will then look like new messages to the Blackberry service, and your Blackberry will download them. If, within your non-mobile MUA, your sort your inbox by date or date-then-thread (mutt's threaded mode), your inbox should appear the same as before making the copies, but if you sort your messages in the order they exist in the IMAP store (including Thunderbird's threaded mode), the copies will appear at the end (or beginning, depending on your sorting direction) of your inbox.
tech » mail | Permanent Link
I recently bought a RAID
enclosure for my backup drives. One of the nice features is that it powers
down the drives and fans when there is no activity for five minutes.
I use burp for backing up my laptops. Burp has a timed backup mode, in which a client can connect to the server, and start a backup if it's been too long since its last backup. This allows, for example, wife to suspend her laptop whenever she wants. When it is running, burp will check with the server every 20 minutes whether it needs to be backed up. If she suspends it in the middle of a backup, it will resume during the next check.
I've configured burp to only allow backups outside of my normal working hours so I don't need to hear the drives grinding away while I'm at my desk. (Pulling myself away from my desk at night is the next challenge.)
The only problem with this configuration is that when a client connects, the backup directory is accessed to figure out whether to start a backup, causing the drives in my RAID enclosure to spin up. The solution was to not have burp touch the backup directory until it's starting a backup.
When a client connects, burp creates a lockfile. By default, this lockfile is
created in the backup directory, but there is an option to use a different
directory, client_lockdir. Set this in the server's burp.conf.
client_lockdir=/var/run/burp
The next change required is to have the timer script, which checks whether the
server should start a backup when the client asks, use a separate directory to
check the state of existing backups. First, enough data from the backup
directory needs to be copied to a separate directory each time a backup is
completed. To do this, I use the server_script_post option, which
runs a script each time a backup completes.
server_script_post=/etc/burp/update_state_dir
My update_state_dir
script copies the current symlinks and timestamp
files from the backup directory to a separate state directory. I updated
the timer script to check this state directory. Review all of the changes at
github.
In response to my questions about using Lua and
Lighttpd to serve up static blosxom pages, Tomas Carnecky sent me an email
with a better way to check for an empty query string within Lua, using "if
next(get) then return 1 end". Here's my new power-magnet.cml
-- if query string is empty and static file exists, serve static file
dr = request["DOCUMENT_ROOT"]
-- local f=assert(io.open(dr.."/debug.out","a"))
if next(get) then return 1 end
sn = request["SCRIPT_NAME"]
static = string.gsub(sn, '^/blog/(.*)$', '/static/%1')
if (file_isdir(dr .. static) and file_isreg(dr .. static .. "/index.html")) then
-- f:write("cache hit on directory\n")
output_include = { dr .. static .. "/index.html" }
return 0
elseif file_isreg(dr .. static) then
-- f:write("cache hit on file\n")
output_include = { dr .. static }
return 0
end
-- f:write("no cache hit\n")
return 1

The state is that great fiction by which everyone tries to live at the expense of everyone else. - Frederic Bastiat