The problem with technical books.

Introduction

Technology books (especially programming books) are a required item for most software professionals and my office at work is littered with them. At any given time there are a dozen books that I may actively reference on a day-to-day basis for the projects that I’m working on. My main library, literally, is my home. I cycle books in and out of my house with the regularity of a public branch library; albeit one dedicated to technology. I have racks of books in my basement where they are shelved and ready to be used when needed. While not necessarily grouped and classified using structure of the Dewey Decimal System, it’s good enough for me.

If you’ve been around software long enough you’ve been exposed to the almost universal maxim regarding software — it almost never stops changing. Software changes and grows, sometimes organically, sometimes in rough and abrupt ways, but rarely does it stay constant. Nascent projects change so rapidly that any attempt to produce good documentation usually leads to those same documents being outdated before they are published. Luckily, maturity usually means a certain level of stability where documentation can be produced and consumed before a new version of the system is released and the documentation has to be updated. It becomes an infinite, but necessary loop.

At some point someone may write a book on the subject at which point in time the current state of system is not only captured, but actually printed and bound, effectively freezing the state of the system for all time. But if software is constantly evolving, doesn’t the material physically printed in these books become obsolete? Yes, and it’s a common problem that those of us who purchase technology books have come to accept. A technology book isn’t like most other books — it has a built in but hidden expiration date. Because almost all software invariably changes, the printed page being a physical immutable object can no longer accurately describe the current state of the system. Most readers of technology books learn this, and book publishers have grown smarter about it and started to identify the version of the software that the book applies to.

The Problem

At some point the printed material itself becomes more than outdated, it becomes obsolete. I have collected hundreds of technology books over the years. Some for work endeavors, others for personal learning, but all have served me well. Unlike non-technology focused books, I have to periodically purge my collection to avoid the issues described earlier. There may be someone who becomes interested in the lineage of a particular piece of software and therefore the book becomes a historical reference capturing the evolution of a piece of software. But for most of us, they simple become unusable and start collecting dust.

With book prices typically ranging between $30.00 and $70.00, purchasing something that’s going to be out of date in the near future may not be the best financial decision in the long run. Witness the prices for a used Java EJB book on Amazon.

amazon_ejb_ss

This particular title, is selling for $0.29 used. Anyone who purchased this book new and at list price has lost 99.99% of it’s original value. It’s understandable why. This particular book has been in print since late 2004. The subject matter is mature but now outdated. The value that this book provides is limited to anyone who must still use or support this older version and the audience will continue to shrink over time.  To be fair to the authors of the book, an updated version of this book has already been released that addresses the improvements to EJBs. The changes are sufficiently large enough to warrant re-purchasing the book again even if someone currently possesses the previous version.

After years of this, I think it’s getting wasteful. Both on my wallet and the amount of dead trees that I currently house in my personal library. For my technical collection, I have wished for a solution that avoids the dead tree and continual update syndrome for those of us who purchase technology books are subject to. I want authors to get paid, high quality material to continually be published, and I’m willing to re-purchase for documentation that contains significant changes or for new version. However, I also want to have access to updates and fixes to typographical and code examples. Printed material just can’t offer that and my books are usually marked up with errata found on the publishers or book’s web site. It’s not an optimal solution by any stretch of the imagination.

An Interim Solution

One interim solution that I have used for the last couple of years is Safari Books Online. Safari has multiple membership levels, and I subscribe to the one that gives unlimited access to the library for approximately $40.00 a month. So for about the price of one physical book, you get access to a dizzying array of technical books for the same cost. For me personally it’s worked well. Here’s an example of the book discussed earlier.

safari_ejb_ss

Safari allows me access to all versions of this book. As new editions are released, the updates are also released into the library satisfying my need for access to timely updates to typographical and code corrections. The interface gives a true print fidelity view as well so what appears on the screen is what the book actually looks like printed. Just as important, you can annotate, bookmark, and make notes. Additionally, as a bonus, you are also given tokens that can be redeemed to download chapters and/or entire books into PDF form and kept offline. Safari has a ton of features so it’s worth a look for someone who is purchasing books on a regular basis.

The problem with Safari is that it is a service. Once you stop paying, you lose everything. PDF’s you generate and have downloaded are yours, but everything else is gone. So far it hasn’t been an issue, but it’s something to be aware of. Finally, and this is a personal issue, I don’t really enjoy reading on a monitor. Usually with most technical books it’s done in a reference type mode so it’s usually not a continual three hour session but nevertheless it’s not very ergonomic.

Overall Safari is great. It deals with most of my issues about owning technical books. I still have to read them online, but for the price, my technical collection expanded a hundred-fold and I never have to donate a book again. As an interim solution I think it has worked well and I’ll continue to subscribe to Safari just for the unfettered access to a huge technical library. Still, what I really want is something that I can hold in my hand but has the power of Safari.

The Perfect Solution

What I really would like is for the publishers of technical books to always provide a version of the book that could be used with the latest eReaders like the Barnes & Noble Nook or the Amazon Kindle. If I could tote around one of those with a couple hundred technical eBooks, I’d be loving life. I wouldn’t know what to do with myself if I could get access to Safari using the eReader as an interface. The eBook concept, especially for technical books, is a great idea that is being offered more and more. They’re priced considerably less that the printed version, and I don’t have to deal with the disposal issues later.

I think we’re close enough that I purchased a Nook. The screen may be smallish for technical reading, but it’s a start and it has to be better than the monitor. It can hold an entire libraries worth of book and it’s portable. Only time will tell, but it’s a start. As a result, I think I’ll convert this article into a series about getting technical material on eReaders. As I progress I’ll continue the series. Happy eReading for all.

30. November 2009 by Jason
Categories: Personal | Leave a comment

Fix zimbra logrotate issues

If this error occurs on a host with Zimbra installed:

/etc/cron.daily/logrotate:
error: zimbra:64 unexpected text

It’s due to a typographical error in /etc/logrotate.d/zimbra that has not been fixed in the latest release (6.0.3.) The log rotate configuration file for Zimbra as delivered has a typographical error in the freshclam section.

1
2
3
4
5
6
7
8
9
10
11
12
/opt/zimbra/log/freshclam.log {
    daily
    missingok
    copytruncate
    notifempty    create 0660 zimbra zimbra
    postrotate
     kill -HUP `cat /opt/zimbra/log/freshclam.pid 2> /dev/null` 2> /dev/null || true
    endscript
    compress
    size 5000k
    rotate 7
}

On line five, the notifempty and create 0660 zimbra zimbra have been concatenated together. To fix, just move the create stanza to the next line like so.

1
2
3
4
5
6
7
8
9
10
11
12
13
/opt/zimbra/log/freshclam.log {
    daily
    missingok
    copytruncate
    notifempty    
    create 0660 zimbra zimbra
    postrotate
     kill -HUP `cat /opt/zimbra/log/freshclam.pid 2> /dev/null` 2> /dev/null || true
    endscript
    compress
    size 5000k
    rotate 7
}

Be aware that since this isn’t officially fixed from the folks at Zimbra, any updates applied after this change is made may revert this back to the original, broken behavior.

Enjoy.

24. November 2009 by Jason
Categories: Linux, UNIX | Tags: | Leave a comment

Fedora 12 on VirtualBox

Just a quick note that if you use the default VirtualBox settings during the “Create New Virtual Machine” wizard for a new install of Fedora 12, you’ll find that the .iso will boot to the live user screen, but when attempting to run the “Install to Hard Drive” installation routine, it’s runs for a second and then quits.

The problem is that the default memory settings in VirtualBox for fedora are insufficient. Reset the system base memory to a more appropriate 512MB and you’ll find the installation routine runs as expected.

Enjoy.

20. November 2009 by Jason
Categories: Virtualization | Tags: , | 7 comments

Fix Logwatch emails on Zimbra hosts

We’ve had an issue for a while where Logwatch emails are not getting through properly in Zimbra with Zimbra complaining about relay issues. While our migration to Zimbra will be the subject of another, much longer post, our last remaining issue looks to be finally resolved. Here’s what we found.

The solution was relatively simple:

[zimbra@zimbra ~]$ zmprov mcf zimbraMtaMyDestination 'localhost zimbra.subaquatic.net'

That allowed us to use the /etc/aliases file and forward logwatch emails destined for root to our mailbox of choice.

26. October 2009 by Jason
Categories: Linux, UNIX | Tags: , , , | Leave a comment

Easy ways to convert a man page

I typically author UNIX man pages for projects a couple of times a year. When I do, the next request I usually receive is to provide a hard copy of the man page as well. Depending on the system, there are a litany of ways to convert a man page into something print ready. Here’s a few:
Continue Reading →

13. August 2009 by Jason
Categories: Document Processing, UNIX | Tags: , , | Leave a comment

Find supported LDAP syntaxes in OpenLdap

To lookup the supported syntaxes in OpenLdap, issue this command:

ldapsearch -x -s base -b "cn=subschema" ldapsyntaxes

Should end up with output like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
[root@ldap schema]# ldapsearch  -x -s base -b "cn=subschema" ldapsyntaxes
# extended LDIF
#
# LDAPv3
# base <cn=subschema> with scope baseObject
# filter: (objectclass=*)
# requesting: ldapsyntaxes 
#
 
# Subschema
dn: cn=Subschema
ldapSyntaxes: ( 1.3.6.1.1.16.1 DESC 'UUID' )
ldapSyntaxes: ( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )
ldapSyntaxes: ( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' X-BIN
 ARY-TRANSFER-REQUIRED 'TRUE' X-NOT-HUMAN-READABLE 'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' X-NOT-HUMAN-READABLE
  'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number
 ' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )
ldapSyntaxes: ( 1.2.36.79672281.1.5.0 DESC 'RDN' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' X-BINARY
 -TRANSFER-REQUIRED 'TRUE' X-NOT-HUMAN-READABLE 'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' X-BINARY-
 TRANSFER-REQUIRED 'TRUE' X-NOT-HUMAN-READABLE 'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' X-BINARY-TRANS
 FER-REQUIRED 'TRUE' X-NOT-HUMAN-READABLE 'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' X-NOT-HUMAN-READABL
 E 'TRUE' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' X-NOT-HUMAN-READABLE
  'TRUE' )
 
# search result
search: 2
result: 0 Success
 
# numResponses: 2
# numEntries: 1

15. July 2009 by Jason
Categories: Development | Tags: , | 1 comment

Keep JUnit TestCases from Cobertura Instrumentation

To keep your Cobertura code coverage reports accurate, don’t forget to exclude any JUnit TestCases during instrumentation.

Example:

1
2
3
4
5
6
<cobertura-instrument todir="${cobertura.inst.classes}" datafile="${cobertura.datafile}">
    <fileset dir="${build}">
      <include name="**/*.class"/>
      <exclude name="**/*Test*.class"/>
    </fileset>
</cobertura-instrument>

Here’s one of my full Cobertura target’s that contains the above example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<target name="cobertura" depends="compile">
    <property name="cobertura.home" value="/opt/cobertura-1.9.1"/>
    <property name="cobertura.datafile" value="${build}/cobertura.ser"/>
    <property name="cobertura.inst.classes" value="${build}/instrumented-classes"/>
    <property name="cobertura.coverage" value="${reports}/coverage"/>
 
    <!-- Cleanup an previous runs -->
    <delete dir="${cobertura.coverage}"/>
    <delete dir="${cobertura.inst.classes}"/>
    <delete file="${cobertura.datafile}"/>
 
    <path id="cobertura.classpath">
        <fileset dir="${cobertura.home}">
            <include name="cobertura.jar"/>
            <include name="lib/**/*.jar"/>
        </fileset>
    </path>
    <taskdef classpathref="cobertura.classpath" resource="tasks.properties"/>
 
    <cobertura-instrument todir="${cobertura.inst.classes}" datafile="${cobertura.datafile}">
        <fileset dir="${build}">
            <include name="**/*.class"/>
	    <exclude name="**/*Test*.class"/>
        </fileset>
    </cobertura-instrument>
 
    <junit showoutput="true" printsummary="withOutAndErr" fork="true" forkmode="once" failureproperty="test.failed">
        <classpath refid="cobertura.classpath" />
        <sysproperty key="net.sourceforge.cobertura.datafile" file="${cobertura.datafile}" />
 
        <classpath location="${cobertura.inst.classes}" />
        <classpath location="${build}"/>
        <batchtest todir="${reports}/junit/">
          <fileset dir="${src}">
            <include name="**/*Test*.java"/>
          </fileset>
        </batchtest>
    </junit>
 
    <cobertura-report srcdir="${src}" destdir="${cobertura.coverage}" datafile="${cobertura.datafile}"/>
</target>

16. April 2009 by Jason
Categories: Java | Tags: | Leave a comment

Installing Citrix XenServer 5.0 with acpi issues

Like my other post related to getting CentOS installed on an HP dc5800, Citrix XenServer also balks on this host. There’s a technote to get you past some of the issues, but it doesn’t completely fix the issue in 5.0.

The doc cover says it covers up to XenServer 4.1, but works for 5.0 with some adjustments. The condensed and revised version is:

  1. While booting off of the CD/DVD, hit escape to stop the timer, and select F2
  2. At the boot prompt, type menu.c32
  3. Move to the install line and hit the tab button to bring up the boot stanza.
  4. After /boot/xen.gz insert no-real-mode acpi=off and hit enter
  5. Boot process should continue and you install away.
  6. However, this doesn’t fix the problem from re-occuring after installation (this is where the document diverges drastically.)
  7. With the installation CD/DVD out of the machine, boot the machine and at the boot: prompt, again type menu.c32
  8. Select the xe boot option and hit tab to edit the boot stanza.
  9. After /boot/xen.gz, add acpi=off again and hit enter. XenServer should now start up properly.
  10. To permanently resolve the issue, with XenServer up and running, cursor down to Local Command Shell
  11. From the shell, cd /boot and backup the extlinux.conf file.
  12. vi extlinux.conf and re-add the acpi=off directly after /boot/xen.gz for each entry
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    label xe
      # XenServer
      kernel mboot.c32
      append /boot/xen.gz acpi=off om0_mem=752M lowmem_emergency_pool=16M crashkernel=64M@32M console=/dev/null vga=mode-0x0311 --- /boot/vmlinuz-2.6-xen root=LABEL=root-vodjnbjv ro quiet vga=785 splash --- /boot/initrd-2.6-xen.img
     
    label fallback
      # XenServer (Xen 3.2.1 / Linux 2.6.18-92.1.10.el5.xs5.0.0.426.647xen)
      kernel mboot.c32
      append /boot/xen-3.2.1.gz acpi=off dom0_mem=752M lowmem_emergency_pool=16M crashkernel=64M@32M --- /boot/vmlinuz-2.6.18-92.1.10.el5.xs5.0.0.426.647xen root=LABEL=root-vodjnbjv ro console=tty0 --- /boot/initrd-2.6.18-92.1.10.el5.xs5.0.0.426.647xen.img
  13. Exit out of the shell and reboot.

XenServer 5.0 should now startup without any issues.

07. April 2009 by Jason
Categories: Virtualization | Tags: | Leave a comment

Getting Cisco VPN software to work on a Windows guest running in VirtualBox

Problem: Cisco VPN client running on a Windows XP guest in VirtualBox is unable to connect. Each attempt to connect is met with the same result — it won’t connect and endlessly asks for re-authentication.

Answer: After some googling, I made a snapshot of the guest (just in case), and changed the guest configuration from using the default NAT setup to having it bridge directly to my network. Bring the guest back up and attempt the VPN connection again and lo’ and behold, it works. The why/hows are still unknown, but at least it works.

09. March 2009 by Jason
Categories: Virtualization | Tags: , | Leave a comment

New Netbackup RMAN job issue?

Ever run into issues with a NetBackup RMAN job failing for what seems no reason? Do your logs look something like below?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RMAN-03009: failure of backup command on t1 channel at 02/26/2009 16:31:05
ORA-19513: failed to identify sequential file
ORA-27206: requested file not found in media management catalog
continuing other job steps, job failed will not be re-run
channel t1: starting full datafile backupset
channel t1: specifying datafile(s) in backupset
including current control file in backupset
channel t1: starting piece 1 at 26-FEB-09
released channel: t1
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03009: failure of backup command on t1 channel at 02/26/2009 16:32:11
ORA-19513: failed to identify sequential file
ORA-27206: requested file not found in media management catalog

To fix it, make sure that the CLIENT_NAME in /usr/openv/netbackup/bp.conf matches (including the case) the client name entered in the NetBackup policy.

04. March 2009 by Jason
Categories: UNIX | Leave a comment

← Older posts

Newer posts →