• 22Jan

    At work I’m trying to set up an NFS mount on my desktop. Our servers mount a given directory on our filer as /auto. I want to do the same thing on my (Ubuntu) PC so that I don’t have to ssh to the server to do my development anymore. Our filer is (for the sake of this post) company-filer05.

    I want to access company-filer05/projects as /auto on my computer and company-filer05/company-linux-rhel4.0-x86-32 as /usr/company for access to things like perl (binaries and modules).

    I’m pretty new to network file sharing (NFS), so I’m trying to figure out how it all works. I found a lot of guides that worked a little bit, but nothing that worked for me completely. I should mention that my PC is behind the company firewall, so I didn’t have to deal with that. This is what I finally did to get it working.

    First, create the directory that will act as the mount point.

    Create the local directory you'll use to access the remote files.
    1
    sudo mkdir /auto

    Notes

    • I used sudo because I’m making the file at root /.
    • If you do not do this step, you will get this error when you try to execute the mounts:
      1
      mount error: can not change directory into mount target /auto

    Next, open your /etc/fstab file. I use vim, though you can use gedit or anything else, of course.

    Edit your /etc/fstab file.
    1
    sudo vim /etc/fstab

    The file should look something like this:

    A default /etc/fstab file.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # /etc/fstab: static file system information.
    #
    # <file system> <mount point>   <type>  <options>       <dump>  <pass>
    proc            /proc           proc    defaults        0       0
    # /dev/sda2
    UUID=0a3618da-0ebf-446e-a58e-56927ed6af3e /               ext3    defaults,errors=remount-ro,relatime 0       1
    # /dev/sda4
    UUID=e0712dd8-8e27-4498-934b-39db3d99821a /home           ext3    defaults,relatime        0       2
    # /dev/sda3
    UUID=23023707-e2a4-4cfc-867f-c08792e26873 /share          ext3    defaults,relatime        0       2
    # /dev/sda1
    UUID=46c1d2f4-b189-4b6e-9223-3d284ea4ab2e none            swap    sw              0       0
    /dev/hda        /media/cdrom0   udf,iso9660 user,noauto,exec 0       0
    /dev/fd0        /media/floppy0  auto    rw,user,noauto,exec 0       0

    Add the following line to the bottom (or anywhere, I guess) to mount company-filer05/projects as /auto:

    Set the up the mount map in /etc/fstab
    1
    2
    ### Mount /auto from rtp-filer04b.
    //company-filer05/projects/   /auto   cifs   credentials=/home/username/.smb_credentials,dir_mode=0777,file_mode=0777 0 0

    Save and close the file.

    Notes

    • I used sudo because this is a system file that I can’t edit without admin privileges.
    • Instead of cifs, use smb if that’s better for your setup. Search on Google for cifs vs. smb to find out more.
    • Note that we set the dir_mode and file_mode parameters. That acts as a mask to give us these permissions (0777) on all mounted files. Does anyone know how to make it give true, unmasked permissions?
    • Notice that we set a credentials file (credentials=/home/username/.smb_credentials). We haven’t created that, but we will in the next step. It will contain our username and password to access the filer.

    We’re almost done. Next, let’s create the credentials file that will hold our username and password to the filer. We do that instead of putting it into the fstab file so that our password isn’t just plainly visible to anyone. Replace “my_username” and “my_password” below with your username and password respectively, of course.

    Create the ~/.smb_credentials file that contains our filer username and password.
    1
    2
    3
    # Create the file.
    echo "username=my_username" >> .smb_credentials
    echo "password=my_password" >> .smb_credentials

    Your ~/.smb_credentials file should now look like this:

    A sample ~/.smb_credentials file.
    1
    2
    username=my_username
    password=my_password

    Almost done. Now all we have to do is mount the files. We’ll use the mount command with the -a (Mount all filesystems (of the given types) mentioned in fstab) option.

    Manually execute the system mounts.
    1
    sudo mount -a

    If everything worked, you won’t get any messages. To check if it worked, just go to the mount point and check if it now has the remote contents. You can do this for as many mount points as you like, of course.

    I do have one outstanding question myself: I don’t want the files to be masked with 0777 — or anything else. I would like to have them be whatever they really are on the server, but I don’t know how to do that. Does anyone else?

    Tags: , , , , , , ,

  • 12Jan

    Sometimes colorized diffs are a lot easier to read than the default diff output. Thankfully, Dave Ewart has written colordiff (http://colordiff.sourceforge.net/), a diff colorizer for the linux command line. It turns out it’s available in package repos for Debian and Ubuntu, and has been packaged for or ported to Gentoo, Fedora, Mac OS X, Lunar Linux, and FreeBSD.

    After you’ve installed it, you can just pipe diff output to it to colorize your diffs:

    1
    $ diff -u file.a file.b |colordiff

    Tags: , , , , , , ,

  • 08Jan

    The following is designed to test Geshi’s highlighting capabilities against Perl’s special variables and other magic. I’ve compiled a list of oddities here at the top. Have I missed anything?

    • $0 and $1 - $9 appear to be interpreted as comments rather than special variables.
    • <> default filehandle var appears to be ignored.
    • Almost all operators seems to be ignored … but ne, cmp, and, and or are highlighted.
    • Dereferencing seems only to work for arrays and hashes.
    • Heredoc is ignored (should be treated as a string delimeter).
    • $# “last element” sigil is ignored.
    • Referencing is ignored for all variable types. Matching on /(\\+[\\$@%&\*]\w+)/ should cause $1 to be seen as a ref (greedy matching) … (note that \\\\\\$foo is valid).
    • Subs and globs and file handles are ignored.
    • The => “comma alternate” operator should be interpreted as a comma, forcing the left-hand operand into string context. Matching on /[^'^"](\w+)\s+=>/ should cause $1 to be interpreted as a string.
    • Package namespaces are a little wierd. Perhaps matching on :: as a left-or-right sigil will help catch the first tier (as in line 76). Priority should be given to packages preceded by variable sigils, and the whole thing should be marked as a variable.
    • Most of the special variables are excluded. Generally they can be interpreted without a subsequent \w+ match. Some have special cases, like the @_ variable (sub arguments), which can be accessed via @_[$index].
    Some of Perl's magic, highlighted by Geshi
    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    ##########################################
    ### A Summary of what seemed problematic
    $foo eq $bar          ### currently ignored
    $foo ne $bar          ### currently kw1
    $foo cmp $bar         ### currently kw1
    $foo lt $bar          ### currently ignored
    $foo gt $bar          ### currently ignored
    $foo le $bar          ### currently ignored
    $foo ge $bar          ### currently ignored
    $foo xor $bar         ### currently ignored
    $foo ^ $bar           ### currently ignored
    $foo ^= $bar;         ### bitwise exclusive or assignment
    $foo x= $bar;         ### repetition assignment
    \$foo                 ### ref to a scalar
    \@foo                 ### ref to a array
    \%foo                 ### ref to a hash
    \*foo                 ### ref to a glob
    \&foo                 ### ref to a sub
    \\$foo                ### ref to a scalar ref
    \4                    ### ref to a read-only constant
    \\6                   ### ref to a ref to a read-only constant
    'foo is $bar now.'    ### Variables should NOT be highlighted
    “foo is $bar now.”    ### Variables should be highlighted
    `foo is $bar now.`    ### Variables should be highlighted
    /foo is $bar now./    ### Variables should be highlighted
    q(foo is $bar)        ### Variables should NOT be highlighted
    qq(foo is $bar)       ### variables should be highlighted
    qx(foo is $bar)       ### variables should be highlighted
    qr(foo is $bar)       ### variables should be highlighted
    qw(foo is $bar)       ### variables should NOT be highlighted
    <<BAR;
       foo is $bar now.
    BAR

    “foo is b${a}r now.”  ### ${a} should be a scalar variable.
    “foo is @bar now.”    ### @bar is interpolated, and should be highlighted.
    “foo $$bar{$fubar}”   ### accessing a dereferenced hash ref.
    “foo ${$bar{$fubar}}### ${...} should be a scalar with $bar{$fubar} interpolated.
    This::Is::My::Module         ### 'This' is ignored.
    This::Is::$My::Module        ### 'This' is ignored.
    $This::Is::My::Module::var   ### A package-level scalar
    @This::Is::My::Module::var   ### A package-level array
    %This::Is::My::Module::var   ### A package-level hash
    &This::Is::My::Module::var   ### A package-level sub
    *This::Is::My::Module::var   ### A package-level glob
    /$This::Is::My::Module::var  ### A package-level scalar re
    $foo = %!;                   ### %! is sy0.  Should be just a hash maybe?
    ARGV
    ARGVOUT
    use constant FOO =>$bar

    ##########################################
    ### More general
    $scalar              ### scalar
    @array               ### array
    %hash                ### hash
    *glob                ### glob
    &sub                 ### sub
    <filehandle>         ### file handle
    <$filehandle>        ### file handle as scalar
    @$foorray_ref        ### An array reference as a dereferenced list (copy)
    %$hash_ref           ### Same for a hash
    $$scalar_ref         ### Same for scalar
    &$code_ref           ### Same for code
    *$code_ref           ### Same for code
    $#array              ### The last element of an array
    $foo ne $bar;        ### not equal (string)
    $foo eq $bar;        ### equal (string)
    $foo = <<EOP;        ### heredoc (matches /<<\w+;/)
    $foo{$bar}           ### Hash access
    $foo{$bar}{$fubar}   ### Multi-level hash access
    $foo->bar            ### Object access
    $foo->bar->fubar     ### Multi-level hash access
    while(<>)            ### Reading a file
    $foo cmp $bar        ### ascii comparison
    $foo <=> $bar        ### numeric comparison (spaceship)
    \$foo                ### Reference to a scalar
    \@foo                ### Ref to an array
    \%foo                ### Ref to a hash
    \*foo                ### Ref to a glob
    \&foo                ### Ref to code
    \\$foo               ### Ref to a reference to a scalar
    $foo & $bar          ### bitwise and
    $foo | $bar          ### bitwise or
    $foo ? $bar : $fubar ### ternary conditional operation
    $foo . $bar          ### concatenation
    $foo <<= $bar        ### assignment bitwise shift left
    $foo >>= $bar        ### assignment bitwise shift right
    $foo |= $bar         ### assignment bitwise or
    $foo ||= $bar        ### assignment symbolic or
    $foo += $bar         ### assignment addition
    $foo &= $bar         ### assignment bitwise and
    $foo ^= $bar         ### assignment bitwise exclusive or
    $foo **= $bar        ### assignment exponentiation
    $foo &&= $bar        ### assignment logical and
    $foo .= $bar         ### assignment concatenation
    $foo %= $bar         ### assignment modulus
    $foo *= $bar         ### assignment multiple
    $foo -= $bar         ### assignment subtract
    $foo x= $bar         ### assignment repetition
    $foo /= $bar         ### assignment divide
    $foo = !!$bar        ### boolean interpretation (really two !s)
    $foo = 'bar'         ### uninterpolated string
    $foo = "bar"         ### interpolated string
    $foo = `bar`         ### system command execution
    ($foo and $bar)      ### logical and
    ($foo xor $bar)      ### logical exclusive or
    ($foo or $bar)       ### logical or
    $foo << $bar         ### bitshift
    $foo >> $bar         ### bitshift
    $foo++               ### increment after
    $foo--               ### decrement after
    ++$foo               ### increment before
    --$foo               ### decrement before
    $foo ** $bar         ### exponent
    $foo ~ $bar          ### bitwise not
    $foo x $bar          ### repetition operator
    if ($foo <  $bar)    ### less than (numbers)
    if ($foo >  $bar)    ### greater than (numbers)
    if ($foo <= $bar)    ### less than or equal to (numbers)
    if ($foo >= $bar)    ### greater than or equal to (numbers)
    if ($foo lt $bar)    ### less than (strings)
    if ($foo gt $bar)    ### greater than (strings)
    if ($foo le $bar)    ### less than or equal to (strings)
    if ($foo ge $bar)    ### greater than or equal to (strings)
    if ($foo ^ $bar)     ### bitwise exclusive or
    for ($foo .. $bar)   ### range operator
    &foo('a',$bar)       ### comma
    &foo(a=>$bar)        ### comma alternate (any list context)

    Package::Subpackage  ### Namespace delimiter
    $Pgk::level::scalar  ### package level scalar ($scalar in Pkg::level)
    @Pgk::level::array   ### package level array  ($foorray in Pkg::level)
    %Pgk::level::hash    ### package level hash   ($hash in Pkg::level)
    &Pgk::level::sub     ### package level sub    ($scalar in Pkg::level)
    *Pgk::level::glob    ### package level glob   ($scalar in Pkg::level)
    \4                   ### Ref to number (yeah, that's useful sometimes).
    $_                   ### The default or implicit variable.
    @_                   ### Subroutine parameters.
    $a                   ### sort comparison routine var (first value)
    $b                   ### sort comparison routine var (second value)
    $1 ... $9            ### Regexp parenthetical capture holders.
    $&                   ### Last successful match (degrades performance).
    $`                   ### Prematch for last successful match string (degrades performance).
    $'                   ### Postmatch for last successful match string (degrades performance).
    $+                   ### Last paren match.
    $^N                  ### Last closed paren match.
    @+                   ### Offsets of ends of successful submatches in scope.
    @-                   ### Offsets of starts of successful submatches in scope.
    $*                   ### Boolean for multi-line matching. Deprecated. Use /s and /m.
    $^R                  ### Last regexp (?{code}) result.
    $.                   ### Current line number (or record number) of most recent filehandle.
    $/                   ### Input record separator.
    $|                   ### Output autoflush. 1=autoflush, 0=default
    $,                   ### Output field separator (lists)
    $\                   ### Output record separator.
    $"                   ### Output list separator. (interpolated lists)
    $;                   ### Subscript separator. (Use a real multidimensional array instead.)
    $#                   ### Output format for printed numbers (deprecated).
    $%                   ### Page number for currently selected output channel.
    $=                   ### Current page length.
    $-                   ### Number of lines left on page.
    $~                   ### Format name.
    $^                   ### Name of top-of-page format.
    $:                   ### Format line break characters
    $^L                  ### Form feed (default "\f").
    $^A                  ### Format Accumulator
    $?                   ### Child error. Status code of most recent system call or pipe.
    $!                   ### Operating System Error. (What just went 'bang'?)
    %!                   ### Error number hash
    $^E                  ### Extended Operating System Error (Extra error explanation).
    $@                   ### Eval error.
    $$                   ### Process ID
    $<                   ### Real user id of process.
    $>                   ### Effective user id of process.
    $(                   ### Real group id of process.
    $)                   ### Effective group id of process.
    $0                   ### Program name.
    $^O                  ### Operating System name.
    $]                   ### Version and patch number of perl interpreter.
    $^C                  ### Current value of flag associated with -c switch.
    $^D                  ### Current value of debugging flags
    $^F                  ### Maximum file descriptor.
    $^I                  ### Value of the -i (inplace edit) switch.
    $^M                  ### Emergency Memory pool.
    $^P                  ### Internal variable for debugging support.
    $^R                  ### Last regexp (?{code}) result.
    $^S                  ### Exceptions being caught. (eval)
    $^T                  ### Base time of program start.
    $^V                  ### Perl version.
    $^W                  ### Status of -w switch
    $^X                  ### Perl executable name.
    ARGV                 ### Filehandle iterates over files from command line (see also <>).
    $ARGV                ### Name of current file when reading <>
    @ARGV                ### List of command line args.
    ARGVOUT              ### Output filehandle for -i switch
    @F                   ### Autosplit (-a mode) recipient.
    @INC                 ### List of library paths.
    %INC                 ### Keys are filenames, values are paths to modules included via use, require, or do.
    %ENV                 ### Hash containing current environment variables
    %SIG                 ### Signal handlers.
    $[                   ### Array and substr first element (Deprecated).
    $foo =~ /bar/;       ### regexp match
    $foo !~ /bar/;       ### regexp match inversion
    $$foo{$bar}          ### Dereferenced hash before accessing a value
    ${$foo{$bar}}        ### Disambiguated referencing.  Not sure if this is a failure...
    $_[$foo]             ### Accessing the ${foo}th argument in a sub.

    Tags: ,

  • 07Jan

    In a work project, I had to find the difference between two arrays bidirectionally. I didn’t just need to know which elements were not common, I had to know which were in one and not in the other.

    An inefficient — but conceptually straightforward — approach is to loop over the two arrays:

    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
    ### Create some storage arrays for results.
    my @foo_only;
    my @bar_only;

    ### For each element only in the foo array.
    foreach my $f (@foo) {
       ### Create a flag so we can track if it's found.
       $found = 0;

       ### Check our foo element against each of the bar elements.
       foreach my $b (@bar) {
          $found = 1 if ($f eq $b);
       }
       push (@foo_only,$f) if (not $found);
    }

    ### Do the reverse to find each element in the bar array only.
    foreach my $b (@bar) {
       ### Create a flag so we can track if it's found.
       $found = 0;

       ### Check our foo element against each of the bar elements.
       foreach my $f (@foo) {
          $found = 1 if ($b eq $f);
       }
       push (@bar_only,$f) if (not $found);
    }

    Ugly. One major problem with this is that you then have to invert the loop nesting and search @a against each element of @b to get the mirrored.

    That’s not very pretty, so after a bit of thought, I decided upon the following approach to the problem.

    Let’s assume I’m working with two arrays of numbers (though they can contain anything): (1,2,3,4,5) and (3,4,5,6,7). The overlap is (3,4,5) and the differences are (1,2) and (6,7).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ### Create our arrays.
    my @foo = (1, 2, 3, 4, 5);
    my @bar = (3, 4, 5, 6, 7);

    ### Create hash representations of these.
    my %foo_h = map {$_=>1} @foo;
    my %bar_h = map {$_=>1} @bar;

    ### Create some storage arrays so we can see where our
    ### differences lie.  We will have to do this with any
    ### scheme.
    my @foo_only;
    my @bar_only;

    ### Loop through the elements of @foo and @bar and record
    ### how things stand.
    map {
       push (@foo_only,$_) if ($foo_h{$_} and not $bar_h{$_});
       push (@bar_only,$_) if ($bar_h{$_} and not $foo_h{$_});
    } (@foo,@bar);

    Now @foo_only contains what’s in @foo and not in @bar and vice versa for @bar_only. The best part is that we only had to loop over each of our original arrays twice, and incurred the extra cost of only two hashes.

    Tags: ,

  • 06Jan

    The Bash shell has the terrific feature that as you traverse directories your pwd reflects the perceived path rather than your absolute path. That means that if you move across the file system through a symbolic link, you appear simply to have descended further into the current tree. In other words, Bash preserves the structural illusion offered by symbolic links.

    Most of the time that’s terrific! Sometimes you’ll want to be able to see where you “actually” are (such as using pwd to determine your absolute path from the disk root. Thankfully, both pwd and cd have a -P parameter that will puncture the illusion and reveal your true location. For example, let’s say you have this file structure:

    1
    2
    3
    4
    5
    ./bar/
    ./bar/foo/
    ./kung/
    ./kung/fu -> ../bar/foo
    /users/username/$

    Here, ./kung/fu links to ./bar/foo. Let’s move to ./kung/fu and take a look around.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /users/username/$ ls
    drwxr-xr-x  4 4.0K Jan  6 14:42 bar/
    drwxr-xr-x  2 4.0K Jan  6 14:43 kung/
    /users/username/$ cd kung
    /users/username/kung/$ ls
    drwxr-xr-x  2 4.0K Jan  6 14:42 fu/
    /users/username/kung/$ cd fu
    /users/username/kung/fu/$ pwd
    /users/username/kung/fu
    /users/username/kung/fu/$ pwd -P
    /users/username/bar/foo
    /users/username/kung/fu/$ cd -P ..
    /users/username/bar/$ pwd
    /users/username/bar
    /users/username/bar/$

    Look what happened in line 8 (after we cd fu in line 7): bash reports our current path as if the symbolic link were a local directory. By adding the -P option (line 10), we get to see our actual location — /users/username/bar/foo. If we had backed out of ./kung/fu using cd .. (rather than cd -P ..) we would have ended up back in ./kung. Instead, by using the -P argument, we told bash that we wanted to move around in the “real” disk structure, rather than in the illusory one created by links, so we ended up in /users/username/bar (line 13).

    Neat =)

    Tags: , , , ,

  • 06Jan

    Diomidis Spinellis, a Grecian researcher, has made a comparison along various lines of the Linux, FreeBSD, OpenSolaris, and Windows Research Kernel kernels in a paper called A Tale of Four Kernels. The abstract states that

    The FreeBSD, GNU/Linux, Solaris, and Windows operating systems have kernels that provide comparable facilities. Interestingly, their code bases share almost no common parts, while their development processes vary dramatically. We analyze the source code of the four systems by collecting metrics in the areas of file organization, code structure, code style, the use of the C preprocessor, and data organization. The aggregate results indicate that across various areas and many different metrics, four systems developed using wildly different processes score comparably. This allows us to posit that the structure and internal quality attributes of a working, non-trivial software artifact will represent first and foremost the engineering requirements of its construction, with the influence of process being marginal, if any.

    You can read the rest of the paper via the link above.

    Tags: , , ,

  • 05Jan

    It’s pretty hard for me to get used to Apple’s “lock-down” mentality. When I was young, my first computer was an Apple ][ Plus that my brother and I got in 1981. We loved it — we translated Choose Your Own Adventure! books into computer games (with graphics!) and even made up a few of our own adventure-sets. We got pretty good, playing classics like Zork and Stellar-7. We had that computer for quite a while, and in the mid-80s started to think about upgrading. The problem was, by the time we were ready, Mac had gone all AOL on us (of course, we didn’t frame it that way at the time) and had gone with a ridiculous graphical interface to broaden its appeal. So, we got a PC so we could use DOS and pretty much ran PC boxes since — mostly DOS and Windows, with an occasional foray into Linux.

    A couple of years ago, Mac made one of the best choices ever and switched to a NeXT based system for it’s newest operating system: OS X. That was pretty much all I needed to push me back towards mac — being a programmer and a command-line lover (yes, it is faster if you know what you’re doing), it now had everything I needed: graphics capabilities (Photoshop, Flash, etc. and 3D modeling) as well as command line for serious engine work (Perl development, etc.). I was ready.

    Finally, about 2 years ago, I got an iPod (and loved it). In addition to music, I used it as a spare hdd, and did everything I needed to. Great product. About 6 months later, I got my first mac (through my job). It’s a nice, 17″ Powerbook G4 — excellent computer. My main OS is Linux (Ubuntu) which I run on 3 machines at home and at work; I virtualize windows XP and Vista on two machines for work (because I have to do cross-platform testing), and now I use OS X natively on my Powerbook. I’ve had a few troubles with it here and there — mostly character differences between OS X’s underlying system and Linux — but it’s no big deal, just learning a new system.

    This past Christmas (’07) my excellent wife surprised me with an iPhone (I had been swooning over them for a while =). I must say, it is a superb device. It has excellent hardware, a smooth interface, and it does almost everything it should. It does have one major problem: It’s heavy into Apple’s lock-down mentality. Let me explain.

    I have no problem buying software. I don’t want to steal anyone’s work, I don’t want to rip anyone off. I don’t download music illegally — I buy it from iTunes if I want it (one of the main reasons an iPod and iPhone worked well for me). Everything’s happy-fun. I have a bunch of music from CDs and stuff from GarageBand, etc. The problem is, Apple wants to rule my computing with an iron fist. Everything has to be registered with everything else; I can’t whip out a program and stick it on my iPhone, I can’t read the spec and do something fun like make a little game for my little boy — I basically can’t do anything unless I want to participate in Apple’s philosophy of “the privilege of buying Apple.”

    Yesterday my Mac HDD freaked out. I tried to do everything I could to fix it, but it couldn’t be saved. In the end, I had to re-install Leopard (thankfully I had bought into a family pack!).

    Anyway, I thought, “It’s a good thing I have my iTunes music and my contacts and calendars on my iPhone! Go Apple!” The funny thing was that when I got everything re-installed and set up, and went to re-sync my phone, the only option available to me was to wipe my phone and sync to the new (empty) library. I could transfer my purchased songs, which is fine, but I couldn’t transfer my non-purchased songs. Anyway, I ended up searching for a very long time to find some free software that would let me mount the phone (to Windows, Linux, or Mac) and grab my stuff, but I couldn’t find anything legal and free. What a weird mentality switch from Linux! I ended up buying some nice software called MegaPhone from a company called ecamm (http://www.ecamm.com/mac/megaphone). It works really nicely and does exactly what it should (plus a bunch of extra stuff like the ability to edit my notes and such).

    Anyway, as a friend of mine pointed out, I wouldn’t have gotten into trouble if I hadn’t been counting on my iPhone as a backup. Really, though, I wouldn’t have gotten in trouble if I hadn’t been thinking with a freedom-based mindset. It’s very true, and not Apple’s “fault” — they have the right to have whatever mindset they like — but it’s a very strange one to me. I’m used to thinking in terms of mutual benefit, not … well, I guess I’d have to call it something like, “adversarial benevolence.” I mean really, Apple and users are poised as adversaries to each other; the users want certain things (such as the freedom to distribute apps freely) and Apple wants to see how little it can give and still retain users, as opposed to how much it can give and still retain partners. This dichotomy is key to understanding Apple — it’s got business partners and interests, and it needs users to maintain its goals in those relationships (profitability). It’s 180 degrees off of the mindset to which I’ve chosen to grow accustomed (FOSS, for example) which holds the relationship between provider and user as primary.

    C’est la vie; lesson learned. I am starting to lean ever more away from Apple. It’s like a smart, nice, pretty girl who spits and hits and smokes and curses: picking up coarseness and brutality because she can’t tell the difference between strength and force. You don’t mind occasional encounters, but you don’t really want a deep relationship until she gets a bit more wisdom and learns what’s really important.

    Tags: , , , , , ,

  • 05Jan

    If you have an array in perl but you don”t know how long it is, there’s a really fast way to get the last element. Use the special variable sigil $# to get the index of the last element of an array. Here’s a clear code example.

    Finding the last index of an array using $#
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ### Create an array.
    my @arr = ('a', 'b', 'c', 'd', 'e');
    ### $length is now 5
    my $length = scalar(@arr);
    ### $lastIndex is now 4
    my $lastIndex = $#arr;
    ### Get the last element of the array:  'e'
    my $el = $arr[$#arr];
    ### Get the fourth-to-last element:  'b'
    my $el = $arr[$#arr - 4];

    Now you know.

    Tags: , , ,

  • 05Jan

    I’ve got a .bashrc file that has some functions defined.  Every so often I need to do one of them on a list of files — that I can usually get out of find.  Sadly, if I want to run an alias myfunc on all the files in a dir (recursively), I can”t do it the intuitive way:

    1
    find . -type f -exec myfunc {} \;

    Since myfunc is a shell function, it’s not found anywhere in the execution path, and is therefore invisible to find.

    But there is a solution!  Instead, we can pipe the output of find through our shell, like so:

    1
    find . -type f | while read fn; do myfunc $fn; done

    Easy as pie.

    Tags: , , ,