tag:blogger.com,1999:blog-194637832024-03-13T14:23:51.548-07:00Chuck's BlogChuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.comBlogger61125tag:blogger.com,1999:blog-19463783.post-59795870048159791362024-02-22T00:49:00.000-08:002024-02-22T00:49:06.798-08:00switch_root PID 1<p>I am developing an initramfs with a custom init. For dev/test purposes I am spawning a bash shell at the end of the init startup sequence (but before the <span style="font-family: courier;">switch_root</span> would normally happen) so I can work on complex parts of the boot process without doing a lot of build iteration.<br /></p><p>I thought I had everything working, and did a test run - "<span style="font-family: courier;">exec switch_root /sysroot /sbin/init"</span>. That got me a nice kernel panic, the kind you get when init exits. Which is precisely what happens when you fork <span style="font-family: courier;">/bin/bash</span> at the end of your init and <span style="font-family: courier;">exec switch_root</span> from the forked shell.</p><p>The init process is PID 1 and the forked bash shell is... not PID 1. Attempting a <span style="font-family: courier;">switch_root</span> from any process other than one running as PID 1 will not work.<br /></p><p>The solution was to <span style="font-family: courier;">exec /bin/bash</span> at the end of init so that the new shell becomes PID 1. Once I am happy with the way things work, I can get rid of the shell call and replace it with <span style="font-family: courier;">exec switch_root /sysroot /sbin/init</span>. </p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-40010816296035779602024-01-30T00:59:00.000-08:002024-01-30T00:59:46.354-08:00Failed to connect to bus: No medium found<p>If you are trying to run a <span style="font-family: courier;">systemctl --user</span> command as a non root user and getting "<span style="font-family: courier;">Failed to connect to bus: No medium found</span>" this is probably because a few things are out of place.</p><p>First make sure you have linger turned on "<span style="font-family: courier;">sudo loginctl enable-linger $USER</span>". This ensures that your services will hang around when you are not logged in.</p><p>Next, use the <span style="font-family: courier;">env</span> command to make sure you have <span style="font-family: courier;">XDG_SESSION_ID</span> and <span style="font-family: courier;">XDG_RUNTIME_DIR</span> defined in your environment. If you do not see them, then you probably did not do a proper login. My guess is that you logged in as a different user and use the <span style="font-family: courier;">su</span> command to change to your current user.</p><p>In that case, you pretty much have two choices.</p><ol style="text-align: left;"><li>You can define XDG_RUNTIME_DIR manually with the following command: <span style="font-family: courier;">export XDG_RUNTIME_DIR=/run/user/$(id -u $USER)</span></li><li>Log out and ssh back in directly as the desired user. This should trigger the PAM module that sets up the correct session variables.<br /></li></ol>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-41536363000699981892024-01-27T23:04:00.000-08:002024-01-27T23:04:58.240-08:00Fair and Honest Discourse<p>What follows are my personal rules and general philosophy for engaging in discourse. All of this information is tentative and will change in response to better information.<br /></p><ul style="text-align: left;"><li>The purpose of discourse is to discard incorrect ideas.</li><li>I am a better person when I hold fewer incorrect ideas.</li><li>Discourse on a particular idea shall stop when:</li><ul><li>requested.<br /></li><li>it becomes unproductive. <br /></li><li>everyone involved finds that they are in agreement. <br /></li></ul><li>Discourse that stops without general agreement is evidence of incomplete understanding. <br /></li><li>General agreement is not evidence of the correctness of an idea.</li><li>Without the consent of those it affects, sensitive information shall be excluded from discourse.<br /></li><li>A single piece of evidence is sufficient to disprove an idea.<br /></li><li>An idea that has not been disproved must account for all relevant existing evidence.<br /></li><li>An idea can never be proven to zero uncertainty.</li><li>Honest participation requires fair and full treatment of all proffered evidence.<br /></li><li>One who discards an idea should graciously acknowledge the act. <br /></li><li>One who discards an idea should credit the person who provided the evidence. <br /></li><li>Goal posts can be moved as long as one clearly acknowledges their prior insufficiency.</li><li>The validity of a claim is not affected by its source.</li><li>The burden of proof is on the person making the claim. <br /></li><li>Extraordinary claims require extraordinary evidence.</li><li>That which can be claimed without evidence can be discarded without evidence. <br /></li></ul>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-63990490699248939722024-01-15T22:24:00.000-08:002024-01-15T22:24:32.079-08:00Furnace Maintenance<p><b><u>Disclaimer: Do your own research! This information worked for me, but it may not be suitable for you. I am not responsible for anything that goes wrong when using this information.</u></b><br /></p><p>This information applies to the following residential furnaces:</p><p>Carrier 58MVB, 58MVC, or 58MVP<br />Bryant: 355AAV, 355BAV, 355CAV, 355MAV<br />Payne: PG9UAA</p><p>All part numbers in the description below are current as of the date of this post. Manufacturers have a tendency to update part numbers, so do your research. The <a href="https://www.carrierenterprise.com">Carrier Enterprise</a> site seems to be a good source of information, but unless you are an approved vendor you only have access to a minimal amount of information.<br /></p><p>If your furnace is making a lot of grinding noises, your draft inducer assembly is probably going bad and needs to be replaced. This is an expensive part, but it is a small fraction of the cost of a new furnace and the replacement is something a reasonably handy homeowner can do on their own. The current draft inducer part number is 340793-762.</p><p>You will also need to ensure you have the correct pressure switch. If you have an old draft inducer assembly, your pressure switch will not fit on the new assembly and you will need to get a new one. If you have a 40,000 BTU/Hr furnace, you are going to need part number HK06NB025. For all other furnaces, you will need part number HK06NB023.</p><p>These pressure switches can be mounted to the bracket that comes with the 340793-762 draft inducer assembly, but you will need to find a few screws to make it happen. There are plenty of mount points on the pressure switch bodies, just be sure your screws are not so long that they pierce the plastic body of the pressure switch.<br /></p><p>While undertaking this repair, it is important to check that the <a href="https://www.amazon.com/gp/product/B00QW2UBHW">condensate trap</a> and the hoses leading in to it are draining reliably. If any of these are plugged, condensation will back up and damage internal components of your furnace.</p><p>You might also find that some of your hoses are in bad shape. Part number 319873-715 is the hose that connects to the pressure switch (it has a pink label), and part number 319873-714 (green label) is the hose that connects to the condensate trap.</p><p>You should be able to find maintenance, troubleshooting, and installation manuals online. They will help a great deal when undertaking a repair like this.</p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-1487471440524964422023-05-20T03:02:00.003-07:002023-05-20T03:04:47.783-07:00LVM - Restoring Files and Directories<p>If you run an AWS EC2 instance you can set up a policy that takes regular snapshots. For disaster recovery, it is pretty simple to convert a snapshot to a volume and attach it to your EC2 instance in place of the previously failed volume. It gets a little more complicated if you are trying to restore individual files or directories that are contained within logical volumes.<br /></p><p>The first step is to convert your most recent snapshot into a volume and attach it to your EC2 instance. In general you should do this while your EC2 instance is running in order to avoid any confusion at startup. You should see a reference to the new volume in your kernel ring buffer shortly after it is attached. </p><p style="text-align: left;">Because the volume group on your new volume has the same name and UUID as the volume group that is currently in use, you will not be able to restore files just yet. You will need to use the <span style="font-family: courier;">vgimportclone </span>command to update the volume group name and UUID.</p><p style="margin-left: 40px; text-align: left;"><span style="font-family: courier;"># vgimportclone <devicename></span></p><p style="text-align: left;">Use the <span style="font-family: courier;">vgdisplay</span> command to list your volume groups. You should now see a new volume group in the output which will need to be activated with the <span style="font-family: courier;">vgchange</span> command. This should cause device nodes to show up in the <span style="font-family: courier;">/dev/mapper</span> directory.</p><p style="text-align: left;">If you have used the xfs filesystem format on your logical volumes, your filesystems will have identical UUIDs to the ones currently mounted. There are ways of updating the xfs UUID, or you can pass the <span style="font-family: courier;">-o nouuid</span> argument to the mount command.</p><p style="text-align: left;">Once you are done restoring files, unmount the volumes, deactivate the volume group with the <span style="font-family: courier;">vgchange</span> command, detach the volume from your EC2 instance, and delete it.<br /></p><p><br /></p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-36166971118028482392022-01-19T03:16:00.003-08:002022-01-19T22:24:49.992-08:00Quick and Dirty Function to get Rounded Up Log2<p> Here is a quick and dirty C/C++ function to return the rounded up log base 2 of any integer.
</p><p><b><span style="font-family: courier;">
int ceil_log_base_2(int value) {<br />
int ones = 0;<br />
int shifts = 0;<br />
while (value > 0) {<br />
shifts++;<br />
if (1 & value)<br />
ones++;<br />
value = value >> 1;<br />
}<br />
return --shifts + (ones > 1 ? 1 : 0);<br />
}</span></b> </p>
<p>My buddy Rob jumped in and spun this one x86 assembly style:<br /></p>
<p><b><span style="font-family: courier;">
int __builtin_popcount (unsigned int x);<br />
int __builtin_clz (unsigned int x);<br />
<br />int rob_ceil_log_base_2 (int value) {<br />
return ((sizeof(int) * 8) - __builtin_clz (value)) +<br />
(__builtin_popcount(value) > 1 ? 1 : 0) - 1;<br />
}</span></b></p>
<p>And if you prefer inline, Rob has you covered there too:<br /></p>
<p><b><span style="font-family: courier;">
int __builtin_popcount (unsigned int x);<br />
int __builtin_clz (unsigned int x);<br />
#define rob_ceil_log_base_2(value) (int) (sizeof(value) * 8) - \
__builtin_clz (value) + (__builtin_popcount(value) > 1 ? 0 : -1)<br />
</span></b></p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-73423036856480633772021-02-21T20:20:00.000-08:002021-02-21T20:20:31.029-08:00Bootable Linux Sparse Virtual Disk Images<p>The following recipe will get you a bootable <a href="https://en.wikipedia.org/wiki/Sparse_file" rel="nofollow" target="_blank">sparse</a> disk image that is 20GB in size, but only takes up a minimal amount of disk space (about 4.5MB to start). This process is suitable for creating disk images for Linux virtual machines.</p><p>First step is to create your sparse file:</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">truncate example.img --size 20G</span></b><br /></p><p>This sets the size to about <a href="https://en.wikipedia.org/wiki/Byte#Multiple-byte_units" rel="nofollow" target="_blank">20 gigabytes</a>, but in reality it is not taking up any space:</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># ls --size --block-size=1 example.img</span></b><b><span style="font-family: courier;"><b><span style="font-family: courier;"> <br /></span></b></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"><b><span style="font-family: courier;">0 example.img</span></b></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># stat --format='%s' example.img<br /><br />21474836480</span></b></p><p>Since you probably want to install a <a href="https://en.wikipedia.org/wiki/GRUB" rel="nofollow" target="_blank">bootloader</a> in order to make this a bootable image, we are going to need a <a href="https://en.wikipedia.org/wiki/GUID_Partition_Table" rel="nofollow" target="_blank">partition table</a>. I prefer the <a href="https://en.wikipedia.org/wiki/GNU_Parted" rel="nofollow" target="_blank">parted</a> command for this over our old friend <a href="https://en.wikipedia.org/wiki/Fdisk">fdisk</a>, since parted is a bit easier to script. <br /></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># parted example.img mklabel gpt</span></b></p><p>This creates a <a href="https://en.wikipedia.org/wiki/GUID_Partition_Table" rel="nofollow" target="_blank">GPT</a> partition table in the first 2048 sectors of the image file. The default partition type is <a href="https://en.wikipedia.org/wiki/Master_boot_record" rel="nofollow" target="_blank">MBR</a>, which is fine if you plan on staying under 2TB, and do not mind dealing with extended and logical partitions. I see little to be lost by using GPT, since it part of <a href="https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface" rel="nofollow" target="_blank">UEFI</a>, and is backward compatible with legacy <a href="https://en.wikipedia.org/wiki/BIOS" rel="nofollow" target="_blank">BIOS</a> type systems.</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># parted example.img print</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">Model: (file)<br />Disk /tmp/example.img: 21.5GB<br />Sector size (logical/physical): 512B/512B<br />Partition Table: gpt<br />Disk Flags: <br /><br />Number Start End Size File system Name Flags</span></b><br /></p><p>Checking on the size, we see that our image file takes up about 40 kbytes, despite still appearing to be 20 gigabytes in size.<br /></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># ls --size --block-size=1 example.img</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">40960 example.img</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"><b><span style="font-family: courier;"># stat --format='%s' example.img<br /><br />21474836480</span></b> </span></b> </p><p>Now we can add a partition. In this case I am only going to create one partition that uses all of the available space and I am going to give it the name "vm-root" to avoid confusion later.<br /></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># parted example.img mkpart primary 0% 100%</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># parted example.img name 1 vm-root <br /></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># parted example.img print</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">Model: (file)<br />Disk /tmp/example.img: 21.5GB<br />Sector size (logical/physical): 512B/512B<br />Partition Table: gpt<br />Disk Flags: <br /><br />Number Start End Size File system Name Flags<br /> 1 1049kB 21.5GB 21.5GB vm-root</span></b><br /></p><p>Now we format the partition; I generally use <a href="https://en.wikipedia.org/wiki/Ext4" rel="nofollow" target="_blank">ext4</a> these days. There is a fairly significant limitation to the ext4 mkfs tooling that forces us to use loopback devices at this point.</p><p>It was my hope that mkfs would figure out the partition size on its own, or perhaps let me specify it as an argument. But all attempts to do that caused mkfs to overrun the partition boundaries and break the backup GPT partition table.</p><p>When you specify <b><span style="font-family: courier;">fs-size</span></b> to the mkfs.ext4 command, what you are specifying is the usable space you want, not the actual size of the available volume. The mkfs.ext4 command gets the volume size from the kernel's block layer, and then juggles a lot of complex logic to figure out how much space needs to be burned for meta information like superblocks and inode tables.</p><p>I probably could have figured out the math for the fs-size argument and formatted the image file partition directly, but there are too many variables to make me feel like that is a good use of my time. That being said, it would be of nice if the mkfs tooling got a virtual image mode that either allowed you to specify the device size, or detected the partition size from the partition table.<br /></p><p>We need to bind our image file and partition to a loopback device:</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">DEV=$(losetup --show --find --partscan example.img)</span></b></p><p> And now we can format our new partition:</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># mkfs.ext4 -F ${DEV}p1</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">mke2fs 1.45.6 (20-Mar-2020)<br />/dev/loop0p1 contains a ext4 file system<br /> created on Sun Feb 21 19:32:16 2021<br />Discarding device blocks: done <br />Creating filesystem with 5242368 4k blocks and 1310720 inodes<br />Filesystem UUID: ede5cf4d-f7f6-4747-8c7a-28d794f92b92<br />Superblock backups stored on blocks: <br /> 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, <br /> 4096000<br /><br />Allocating group tables: done <br />Writing inode tables: done <br />Creating journal (32768 blocks): done<br />Writing superblocks and filesystem accounting information: done</span></b></p><p> Another size check shows that we are now up to about 4.5 megabytes.<br /></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># ls --size --block-size=1 example.img</span></b><b><span style="font-family: courier;"><b><span style="font-family: courier;"> <br /></span></b></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"><b><span style="font-family: courier;">4505600 example.img</span></b></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"><b><span style="font-family: courier;"># stat --format='%s' example.img</span></b></span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"><b><span style="font-family: courier;">21474836480 <br /></span></b></span></b></p><p>Pretty good so far. Now we can mount our new volume and take a look around.</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># mkdir img-mp</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># mount ${DEV}p1 img-mp</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># df img-mp</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;">Filesystem 1K-blocks Used Available Use% Mounted on<br />/dev/loop0p1 20509264 45080 19399328 1% /tmp/img/img-mp</span></b></p><p style="text-align: left;">And now for the cleanup:</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># umount ${DEV}p1</span></b></p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># losetup -d ${DEV}</span></b><br /></p><p style="text-align: left;">To make this a bootable image, mount your volume again and copy the Linux OS file tree of your choice into the mounted volume. Then use the grub-install command to install the boot loader.</p><p style="margin-left: 40px; text-align: left;"><b><span style="font-family: courier;"># grub-install --modules=part_gpt --root-directory /tmp/img/img-mp ${DEV}</span></b></p><p style="text-align: left;">Since this is a sparse image, it will grow larger as more data is written to it until you hit the size limit, but it will not get smaller when data is deleted.</p><p style="text-align: left;">The simplest way to compact this image is to use the <a href="https://frippery.org/uml/index.html" rel="nofollow" target="_blank">zerofree</a> command to zero out the empty space, and then use your VM hypervisor's tools to do the rest, such as <a href="https://libguestfs.org/virt-sparsify.1.html" rel="nofollow" target="_blank">virt-sparsify</a> or <b><span style="font-family: courier;">VirtualBox modifymedium ${FILENAME} --compact</span></b>.<br /></p><p style="text-align: left;"><br /></p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-12750010413582755032021-02-09T19:29:00.009-08:002021-02-09T20:30:55.089-08:00Bash-ism to Display Last Command in xterm Title Bar<p>I got frustrated at the lack of support for displaying the last command entered in the xterm title bar when I bounced around from host to host, so I came up with a bash-ism to remedy the problem. <br /><br />Add these to your .bashrc file on any hosts that this matters to you. I suspect there is a cleaner implementation but all of the command escaping was getting too complicated, so I broke it up into two separate functions.<br /></p><p>This only works with versions of bash with PS0 support (bash 4.4 or higher) and I have only tested it using the macOS Terminal.app. It seems to work exactly as expected in <a href="https://www.gnu.org/software/screen/" rel="nofollow" target="_blank">screen</a> sessions too, which is a nice bonus.<br /></p><p>Fixes welcomed and appreciated, particularly those that make this work on earlier versions of bash. Just leave a comment or @ me on twitter.</p><p> <br /></p><p style="margin-left: 80px; text-align: left;"><b><span style="font-family: courier;">settitle() {<br /> [[ -z $1 ]] && return<br /> case ${TERM} in<br /> xterm*) echo -n -e "\033]0;$1\007";;<br /> esac<br />}<br /><br />lastcmd() {<br /> echo $(fc -l -1 -1 | sed -e 's/\s*[0-9]*\s*//');<br />}<br /><br />export PS0='$(settitle "$(lastcmd)")'</span></b></p><p style="text-align: left;"> </p><p style="text-align: left;">Note: macOS does not deliver with bash 4.4 (yet?), so you should make sure to leave the "Active process name" setting checked in your Terminal.app to get this information locally. These are the settings that I am using.<br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-mzUjPWlk9_w/YCNhOPLaT1I/AAAAAAAABec/4cZube8mXIwVLdSY4E8drn9dwjd-6X7-wCNcBGAsYHQ/Screen%2BShot%2B2021-02-09%2Bat%2B8.28.34%2BPM.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="386" data-original-width="878" height="141" src="https://lh3.googleusercontent.com/-mzUjPWlk9_w/YCNhOPLaT1I/AAAAAAAABec/4cZube8mXIwVLdSY4E8drn9dwjd-6X7-wCNcBGAsYHQ/Screen%2BShot%2B2021-02-09%2Bat%2B8.28.34%2BPM.png" width="320" /></a></div><br /><br /><br /><br /><br /><p></p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-8065298816020699972021-01-30T21:35:00.003-08:002021-01-30T21:47:11.777-08:00EdgeRouter Failover Configuration with Partial IPv6<p>I am in that fortunate first world situation to have two Internet connections wired to my humble abode. One is fast, and the other is pretty slow by modern standards. I considered getting rid of the slow connection, but I got a killer lifetime deal on the price, so it hardly seems worth getting rid of it.</p><p>My <a href="https://www.ui.com/edgemax/edgerouter-poe/" rel="nofollow" target="_blank">EdgeRouter</a> supports failover so I figured I would take advantage of the second Internet connection and add a some redundancy to my home network. I wanted to bias things in favor of the faster connection, so it was important to ensure that I was only on the slower connection whenever the faster connection was unavailable. The faster connection also supports IPv6, which I wanted to retain as much as possible.<br /></p><p>The basic failover configuration is simple enough that you can use one of the build-in Wizards in the EdgeMAX web UI to set it up. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-cpIARODc1Ks/YBYl7_GrkdI/AAAAAAAABco/5EgNQl6A1holozjZaYvrU3wmWV7iLgqqwCNcBGAsYHQ/s658/Screen%2BShot%2B2021-01-30%2Bat%2B7.36.44%2BPM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="356" data-original-width="658" src="https://1.bp.blogspot.com/-cpIARODc1Ks/YBYl7_GrkdI/AAAAAAAABco/5EgNQl6A1holozjZaYvrU3wmWV7iLgqqwCNcBGAsYHQ/s320/Screen%2BShot%2B2021-01-30%2Bat%2B7.36.44%2BPM.png" width="320" /></a></div> <p></p><p>To ensure that the secondary connection only stands-in when the primary connection is unavailable, simply check this box:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Myu_5XldkU4/YBYm8UPCgcI/AAAAAAAABcw/hA5VfeV8_LwUGqVu1JQLRHvJaMDpkE9OwCNcBGAsYHQ/s1304/Screen%2BShot%2B2021-01-30%2Bat%2B7.37.57%2BPM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="1304" height="198" src="https://1.bp.blogspot.com/-Myu_5XldkU4/YBYm8UPCgcI/AAAAAAAABcw/hA5VfeV8_LwUGqVu1JQLRHvJaMDpkE9OwCNcBGAsYHQ/w417-h198/Screen%2BShot%2B2021-01-30%2Bat%2B7.37.57%2BPM.png" width="417" /></a></div><p></p><p>In the EdgeOS config, this sets a failover priority value of 100 on the eth0 interface (the fast connection) and 60 on the eth1 interface (the slow connection). Your mileage may vary, but my experimentation showed that it only took six seconds to fail over to the slow connection, and about 40 seconds to fail back to the fast connection.</p><p>This particular configuration is quick and easy, but it omits IPv6, so that part requires some hand tweaking and a few compromises in my situation.<br /></p><p>The intention behind IPv6 is that everything on the Internet gets a unique address. In contrast, IPv4 simply does not have enough addresses to go around, so the normal approach is to use a <a href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol" rel="nofollow" target="_blank">DHCP</a> server to hand out <a href="https://tools.ietf.org/html/rfc1918" rel="nofollow" target="_blank">RFC 1918</a> addresses to stuff inside of your private network.<br /></p><p>Supporting IPv6 is great for the health of the Internet, but it complicates things when you want to set your SOHO network up for redundancy. When you failover, your alternate ISP does not recognize the IPv6 address range assigned to all of your devices, so everything stops communicating until each device updates their IPv6 address. In contrast, private IPv4 assignments are typically <a href="https://en.wikipedia.org/wiki/Network_address_translation" rel="nofollow" target="_blank">translated at your firewall</a>, so nothing is required on the client side when you failover.</p><p>To fix this problem with IPv6 we have a few tools at our disposal <a href="https://en.wikipedia.org/wiki/IPv6-to-IPv6_Network_Prefix_Translation" rel="nofollow" target="_blank">NPTv6</a>, <a href="https://tools.ietf.org/id/draft-mrw-nat66-00.html" rel="nofollow" target="_blank">NAT66</a>, and <a href="https://en.wikipedia.org/wiki/Unique_local_address" rel="nofollow" target="_blank">ULA</a>. I agree with many other voices on the Internet that NAT66 is a fundamentally broken hack and should not be used. There are privacy concerns with NPTv6, but <a href="https://tools.ietf.org/html/rfc4941" rel="nofollow" target="_blank">RFC 4941</a> seems to address most (all?) of them. ULA solves the problem that RFC 1918 solves with private addresses, and is probably not a significant factor in any SOHO failover design like this.</p><p>If I had two connections that supported IPv6, I would probably figure out how to get NPTv6 working, but since I only have one, I really just need to accept a minor compromise. If I choose to support IPv6, I have to accept that I will not have any IPv6 support during a failover. I have no problem with this compromise because we are still in the IPv6 <a href="https://www.google.com/intl/en/ipv6/statistics.html#tab=ipv6-adoption" rel="nofollow" target="_blank">transition phase</a> and virtually everything is available via IPv4. I expect that applications sending traffic over an IPv6 interface will more or less transparently start using the IPv4 interface.<br /></p><p>To add IPv6 support to the EdgeOS failover configuration, you can manually add the following sections to support an IPv6 firewall and a DHCPv6 prefix designation.</p><p>The firewall configuration (which goes into the firewall section) should look something like this:</p><p><span style="font-family: courier;"> ipv6-name WANv6_IN {<br /> default-action drop<br /> description "WAN inbound traffic forwarded to LAN"<br /> enable-default-log<br /> rule 10 {<br /> action accept<br /> description "Allow established/related sessions"<br /> state {<br /> established enable<br /> related enable<br /> }<br /> }<br /> rule 20 {<br /> action drop<br /> description "Drop invalid state"<br /> state {<br /> invalid enable<br /> }<br /> }<br /> }<br /> ipv6-name WANv6_LOCAL {<br /> default-action drop<br /> description "WAN inbound traffic to the router"<br /> enable-default-log<br /> rule 10 {<br /> action accept<br /> description "Allow established/related sessions"<br /> state {<br /> established enable<br /> related enable<br /> }<br /> }<br /> rule 20 {<br /> action drop<br /> description "Drop invalid state"<br /> state {<br /> invalid enable<br /> }<br /> }<br /> rule 30 {<br /> action accept<br /> description "Allow IPv6 icmp"<br /> protocol ipv6-icmp<br /> }<br /> rule 40 {<br /> action accept<br /> description "allow dhcpv6"<br /> destination {<br /> port 546<br /> }<br /> protocol udp<br /> source {<br /> port 547<br /> }<br /> }<br /> }</span></p><p> And this gets added to the eth0 interface configuration: </p><p><span style="font-family: courier;"> dhcpv6-pd {<br /> pd 0 {<br /> interface eth1 {<br /> host-address ::1<br /> prefix-id :1<br /> service slaac<br /> }<br /> interface switch0 {<br /> host-address ::1<br /> prefix-id :2<br /> service slaac<br /> }<br /> prefix-length /60<br /> }<br /> rapid-commit enable<br /> }</span><br /></p><p>Important Note: The /60 prefix length is provider specific. If you cannot get an IPv6 grant from your provider, you may need to change this value. <br /></p><p>And finally, be sure to add the new IPv6 firewall labels to your eth0 interface firewall configuration to bring it all together:</p><p><span style="font-family: courier;"> firewall {<br /> in {<br /> ipv6-name WANv6_IN<br /> name WAN_IN<br /> }<br /> local {<br /> ipv6-name WANv6_LOCAL<br /> name WAN_LOCAL<br /> }<br /> }</span></p><p>Load that configuration back to EdgeOS and you should be all set after a reboot.<br /></p>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-79082045214237281372019-10-20T17:00:00.001-07:002020-01-13T19:45:51.031-08:00MSTest Unit Tests on Visual Studio 2019 for MacThere are several unit test options available in Visual Studio 2019, but the decision to use MSTest for a particular project was out of my hands, so this post covers getting MSTest unit tests working on Visual Studio 2019 for Mac.<br />
<br />
The first step is to make sure you are using Visual Studio, and not confusing it with Visual Studio Code. The Visual Studio icon looks like this:<br />
<br />
<div style="text-align: center;">
<a href="http://1.bp.blogspot.com/-UWzHwMCuZt0/Xh0gEPT5qMI/AAAAAAAABQI/kTvx3n64tUwgzS4gHM-rL56KPVj7AOaPgCK4BGAYYCw/s1600/Screen%2BShot%2B2020-01-13%2Bat%2B5.45.00%2BPM.png" imageanchor="1"><img border="0" height="200" src="https://1.bp.blogspot.com/-UWzHwMCuZt0/Xh0gEPT5qMI/AAAAAAAABQI/kTvx3n64tUwgzS4gHM-rL56KPVj7AOaPgCK4BGAYYCw/s200/Screen%2BShot%2B2020-01-13%2Bat%2B5.45.00%2BPM.png" width="146" /></a> </div>
<br />
<br />
And the Visual Studio Code icon looks like this:<br />
<br />
<div style="text-align: center;">
<a href="http://2.bp.blogspot.com/-_yuOGv3xId4/Xh0gL75X0QI/AAAAAAAABQQ/G_h2RbBKc40j1zlkBaWmgpfeCzrasWjiwCK4BGAYYCw/s1600/Screen%2BShot%2B2020-01-13%2Bat%2B5.44.42%2BPM.png" imageanchor="1"><img border="0" height="200" src="https://2.bp.blogspot.com/-_yuOGv3xId4/Xh0gL75X0QI/AAAAAAAABQQ/G_h2RbBKc40j1zlkBaWmgpfeCzrasWjiwCK4BGAYYCw/s200/Screen%2BShot%2B2020-01-13%2Bat%2B5.44.42%2BPM.png" width="163" /></a> </div>
<br />
These instructions apply to Visual Studio (for Mac), not Visual Studio Code.<br />
<br />
If you want to download a pre-loaded solution with a working example of an MSTest unit
test, feel free to clone <a href="https://github.com/chuckwolber/VisualStudioMSTestExample" target="_blank">this GitHub repository</a> and make any necessary
changes. Replace the C# files with yours as needed (or just copy and paste contents). All of the Assert class methods can be <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.assert?view=mstest-net-1.2.0" target="_blank">found here</a>; they are necessary to write other forms of unit test functions.<br />
<br />
<b>Important Note:</b> If you clone the above repository, but have never added all of the NuGet testing plugins, the project will probably fail to build. The resolution is to follow the first half of the instructions below to install all of the necessary NuGet packages. <br />
<br />
<h2>
To update an existing project... </h2>
If you run into trouble, it might help to clone the example repository above and compare your solution with mine.<br />
<br />
Some guidance instructs you to create a separate sub-project under your project's solution to contain the unit test code. I suspect those instructions work properly for Visual Studio running on Windows, but there seem to be namespace issues in Visual Studio for Mac that prevents that approach from working correctly.<br />
<br />
The solution is to apply all of the following instructions to the solution that your source files are stored in and not create a separate sub-project to contain the unit tests.<br />
<br />
Add the proper unit test packages via NuGet.<span style="font-family: "courier new" , "courier" , monospace;"><b> <ctrl>-click Dependencies</b></span> and select <span style="font-family: "courier new" , "courier" , monospace;"><b>Manage NuGet Packages...</b></span><br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://1.bp.blogspot.com/-QSzWPeFQPi4/XazsMq566oI/AAAAAAAABNo/nzozkHoE1ocUEWqg13orYq3BWuzTxoKNACNcBGAsYHQ/s1600/Screen%2BShot%2B2019-10-20%2Bat%2B4.22.08%2BPM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="600" height="121" src="https://1.bp.blogspot.com/-QSzWPeFQPi4/XazsMq566oI/AAAAAAAABNo/nzozkHoE1ocUEWqg13orYq3BWuzTxoKNACNcBGAsYHQ/s320/Screen%2BShot%2B2019-10-20%2Bat%2B4.22.08%2BPM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You should see a screen similar to this one:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-PJUbWKuCqO4/XaztW38T3xI/AAAAAAAABNw/CGblegVYaH46tmbE9Rrnh6zgZFz9fOnBQCNcBGAsYHQ/s1600/Screen%2BShot%2B2019-10-20%2Bat%2B4.23.46%2BPM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1048" data-original-width="1600" height="209" src="https://1.bp.blogspot.com/-PJUbWKuCqO4/XaztW38T3xI/AAAAAAAABNw/CGblegVYaH46tmbE9Rrnh6zgZFz9fOnBQCNcBGAsYHQ/s320/Screen%2BShot%2B2019-10-20%2Bat%2B4.23.46%2BPM.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Use the search box in the upper right of that screen to find and add the following three packages:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;"><b>Microsoft.NET.Test.Sdk</b></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;"><b>MSTest.TestAdapter</b></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;"><b>MSTest.TestFramework</b></span></li>
</ul>
<div>
<br />
Once you have added these packages, your solution will probably be broken with the following build message:</div>
<div>
<br /></div>
<div class="p1">
<span class="s1" style="color: lime; font-family: "courier new" , "courier" , monospace;"><b style="background-color: black;">error CS0017: Program has more than one entry point defined. Compile with /main to specify the type that contains the entry point.</b></span></div>
<div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; color: #b42419; background-color: #000000}
span.s1 {font-variant-ligatures: no-common-ligatures}
</style>
</div>
<div class="separator" style="clear: both;">
</div>
<div>
<br /></div>
<div>
Many thanks to <a href="https://andrewlock.net/" target="_blank">Andrew Lock</a> for <a href="https://andrewlock.net/fixing-the-error-program-has-more-than-one-entry-point-defined-for-console-apps-containing-xunit-tests/" target="_blank">solving this one</a>. His solution is geared towards xUnit, but it works in this case as well.<br />
<br />
You should really read his incredibly detailed rundown; I did, and I learned a lot. But if you are short on time, the TL;DR is to add the following line of XML to any <span style="font-family: "courier new" , "courier" , monospace;"><b><PropertyGroup> </b></span>section of your project's <span style="font-family: "courier new" , "courier" , monospace;"><b>.csproj</b></span> file:<br />
<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; color: #00ff00; background-color: #000000}
span.s1 {font-variant-ligatures: no-common-ligatures}
</style>
<br />
<div style="text-align: center;">
<span style="font-family: "courier new" , "courier" , monospace;"><b><GenerateProgramFile>false</GenerateProgramFile>
</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<br />
<div style="text-align: left;">
<br />
And finally, to actually run the unit tests, select "<b><span style="font-family: "courier new" , "courier" , monospace;">Run Unit Tests</span></b>" from the "<b><span style="font-family: "courier new" , "courier" , monospace;">Run</span></b>" menu.<br />
<br />
<div style="text-align: center;">
<a href="http://1.bp.blogspot.com/-OnghRO9tkyo/Xh0tPiHfNuI/AAAAAAAABQg/j9hWPsD6r-I3j_2t72X8TAfJ_9z_DYzVwCK4BGAYYCw/s1600/Screen%2BShot%2B2020-01-13%2Bat%2B6.52.27%2BPM.png" imageanchor="1"><img border="0" height="320" src="https://1.bp.blogspot.com/-OnghRO9tkyo/Xh0tPiHfNuI/AAAAAAAABQg/j9hWPsD6r-I3j_2t72X8TAfJ_9z_DYzVwCK4BGAYYCw/s320/Screen%2BShot%2B2020-01-13%2Bat%2B6.52.27%2BPM.png" width="171" /> </a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
After you run the unit tests for the first time, you should have a button like this at the bottom of your IDE:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="http://4.bp.blogspot.com/-6cdl6U48Omw/Xh0tciMKlqI/AAAAAAAABQo/450VDegW0AwgyIE0WE_BFKHvNqmTTAomACK4BGAYYCw/s1600/Screen%2BShot%2B2020-01-13%2Bat%2B6.53.40%2BPM.png" imageanchor="1"><img border="0" height="60" src="https://4.bp.blogspot.com/-6cdl6U48Omw/Xh0tciMKlqI/AAAAAAAABQo/450VDegW0AwgyIE0WE_BFKHvNqmTTAomACK4BGAYYCw/s320/Screen%2BShot%2B2020-01-13%2Bat%2B6.53.40%2BPM.png" width="320" /></a> </div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Click "<b><span style="font-family: "courier new" , "courier" , monospace;">Test Results</span></b>" to display the test results browser and debug any test failures.</div>
</div>
</div>
</div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-24845448011567554432018-03-08T16:59:00.002-08:002018-03-08T23:16:11.308-08:00Chasing a (possible) udev issue...I have been chasing, what might possibly be, a problem in <a href="https://github.com/systemd/systemd" target="_blank">udev</a>, and am using this blog post as a gathering point for evidence.<br />
<br />
Because there is so little to be found on this issue, it is almost certainly a configuration issue in my own environment. Otherwise the Internet would be full of people seeing the same problems.<br />
<br />
I also cannot guarantee that all of this evidence is related, nor can I be 100% certain that it is actually due to a problem with udev. All I can say for certain is that the evidence seems to be pointing towards an issue with device nodes not being created when they should be. Since udev is responsible for managing device nodes, it seems reasonable to start considering that udev may be at fault somehow.<br />
<br />
<br />
First some background information. I am maintaining my own <a href="https://www.yoctoproject.org/" target="_blank">yocto based</a> Linux distribution, currently working from the <a href="https://wiki.yoctoproject.org/wiki/Releases" target="_blank">Pyro branch</a>.<br />
<br />
<ul>
<li>bash version - 4.3.47(1) (x86_64)</li>
<li>LVM version information:</li>
<ul>
<li>LVM Version: 2.02.166(2) (2016-09-26)</li>
<li>Library Version: 1.02.135 (2016-09-26)</li>
<li>Driver Version: 4.31.0</li>
</ul>
<li>udev version 232</li>
</ul>
<div>
<h3>
</h3>
<h3>
The first problem...</h3>
</div>
<div>
When I attempt to create a new logical volume:</div>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>root@server:~# lvcreate -L1M -ntest.data vg00</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>Rounding up size to full physical extent 4.00 MiB</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>/dev/vg00/test.data: not found: device not cleared</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>Aborting. Failed to wipe start of new LV.</b></span></blockquote>
When you create a new logical volume with <span style="font-family: "courier new" , "courier" , monospace;"><b>lvcreate</b></span>, the first 4KiB needs to be zeroed out to avoid a potential hang when mounting the volume. It appears as if the device file (<span style="font-family: "courier new" , "courier" , monospace;"><b>/dev/vg00/test.data</b></span>) is not being created in time for the remaining <span style="font-family: "courier new" , "courier" , monospace;"><b>lvcreate</b></span> tasks to finish. The workaround is to use the <span style="font-family: "courier new" , "courier" , monospace;"><b>-Zn</b></span> argument to <span style="font-family: "courier new" , "courier" , monospace;"><b>lvcreate</b></span> and then do a manual zeroing with the <span style="font-family: "courier new" , "courier" , monospace;"><b>dd</b></span> command, like the following:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>root@server:~# lvcreate -Zn -L1M -ntest.data vg00</b></span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;"><b>Rounding up size to full physical extent 4.00 MiB</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>WARNING: Logical volume vg00/test.data is not zeroed.</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>Logical volume "test.data" created.</b></span></blockquote>
<blockquote class="tr_bq">
<b style="font-family: "courier new", courier, monospace;">root@server:~# dd if=/dev/zero of=/dev/vg00/test.data bs=512 count=8</b></blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier";"><b>8+0 records in</b></span><br />
<span style="font-family: "courier new" , "courier";"><b>8+0 records out</b></span><br />
<span style="font-family: "courier new" , "courier";"><b>4096 bytes (4.1kB, 4.0 KiB) copied,
0.00415683 s, 985 kB/s</b></span></blockquote>
<div>
<h3>
</h3>
<h3>
The second problem...</h3>
This one happens when I attempt to use <a href="http://tldp.org/LDP/abs/html/process-sub.html" target="_blank">bash process substitution</a>. What I expect to see is something like the following:<br />
<blockquote class="tr_bq">
<b style="font-family: "courier new", courier, monospace;">root@server:~# echo <(true)</b><br />
<b style="font-family: "courier new", courier, monospace;">/dev/fd/63</b></blockquote>
What I actually see is the following:<br />
<blockquote class="tr_bq">
<b style="font-family: "courier new", courier, monospace;">root@server:~# echo <(true)</b><br />
<b style="font-family: "courier new", courier, monospace;">-sh: syntax error near unexpected token `('</b></blockquote>
The characters are absolutely identical in both cases - I have copied and pasted them in every way I know how. I have also tried the same command in a multitude of bash interpreters of various versions and it always works as expected.<br />
<br />
Because bash process substitution depends on device nodes being created on the fly, this seems like it would be related to the LVM problem above.<br />
<h3>
</h3>
<h3>
Conclusions...</h3>
As I mentioned at the top, I am not 100% certain that this is all related, but it seems pretty suspicious. Two instances that rely on device files to be created on the fly, both seem to fail. Conversely, the boot process, which creates a lot of device nodes, seems to work just fine. I am also not able to find any smoking guns (or even faint whiffs) in the logs.<br />
<br />
More to come...</div>
<div>
<br /></div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-29595729070952868152016-03-26T14:58:00.001-07:002016-03-26T14:58:08.960-07:00Converting global temperature change to energy...TL;DR: Over the last 100 years, every 41 days the amount of energy we generated in 2013 gets "stuck" in the atmosphere.<br />
<br />
The details...<br />
<br />
I like reading <a href="http://cliffmass.blogspot.com/" target="_blank">Cliff Mass' blog</a> because he takes such an even handed approach to the science of climate change. He is very careful with his assertions and <a href="http://cliffmass.blogspot.com/2014/02/why-does-seattle-times-and-other-media.html" target="_blank">takes on media outlets</a> for being too sensational about what the data does and does not say.<br />
<br />
A <a href="http://cliffmass.blogspot.com/2016/03/the-golden-rule-of-climate-extremes.html" target="_blank">recent post of his</a> did a fantastic job of putting the affect of climate change into context with natural variability. The punchline is that climate change only enhances what is <b><u>already natural variability</u></b>. If it was going to be hot, it will be just a little bit hotter. If it was going to be cold, it will be slightly less cold. If you were going to get a hurricane, it will be a bit more energetic. And so on...<br />
<br />
Or to put it in different terms, you cannot blame anything directly on climate change. If you are experiencing it, it was probably going to happen whether or not humans were on the Earth. You are just going to have a more intense experience.<br />
<br />
So I applied some High School level math to figure out exactly what that means...<br />
<br />
<a href="https://en.wikipedia.org/wiki/Atmosphere_of_Earth" target="_blank">Mass of the Earth's Atmosphere:</a> 5x10<sup>18</sup> kg<br />
<a href="http://wattsupwiththat.com/2011/04/06/energy-content-the-heat-is-on-atmosphere-vs-ocean/" target="_blank">Average atmospheric specific heat:</a> 1005 j/kg/K<br />
<a href="http://cliffmass.blogspot.com/2016/03/the-golden-rule-of-climate-extremes.html" target="_blank">Current average temperature change:</a> About 1 degree Kelvin (which is the same as 1 degree Celsius)<br />
<a href="https://en.wikipedia.org/wiki/World_energy_consumption" target="_blank">Global yearly energy generation in 2013:</a> 5.67x10<sup>20</sup> joules<br />
<br />
Note: I assume energy consumption is equivalent to energy generation. While they may not be exactly equal in reality, it is certainly true that consumption could not be less than generation. I am also using 2013 energy consumption numbers. The numbers are most certainly higher in 2016.<br />
<br />
So given the basic heat equation: Q = mcΔT<br />
<br />
Q = Joules of energy required to cause a temperature change.<br />
m = Mass (in kilograms) of the matter you are heating up.<br />
c = A constant representing how difficult it is to change the temperature of the matter.<br />
ΔT = The actual temperature change.<br />
<br />
Using the above numbers we get:<br />
<br />
Q = 5x10<sup>18</sup> kg * 1005 j/kg/K * 1 = 5.025x10<sup>21</sup> joules<br />
<br />
So that means it takes 5.025x10<sup>21</sup><sup> </sup>joules of energy to raise the average temperature of the Earth one degree Celsius. But 5.025x10<sup>21</sup><sup> </sup>joules is a really big number that is hard to put into terms that anyone can understand, so let us look at how this compares to how much energy we actually <b>generate</b> on the Earth...<br />
<br />
As I mentioned above, in 2013 we generated about 5.67x10<sup>20</sup> joules of energy. If we divide the amount of energy it took to raise the atmosphere by 1 degree Celsius, by the amount of energy we generated in 2013, we get:<br />
<br />
5.025x10<sup>21</sup> joules / 5.67x10<sup>20 </sup>joules = 8.86<br />
<br />
So this means we have 8.86 times the energy we generated in 2013 currently trapped in the atmosphere. But this number is still not very interesting because it says nothing about the rate at which this is happening.<br />
<br />
The industrial era has been going on for about 100 years now which is about 36,525 days. In that amount of time, we have managed to alter the atmosphere so that 8.86 times the 2013 energy generating capacity of the earth is stuck in it.<br />
<br />
Averaging over that 36,525 days:<br />
<br />
5.025x10<sup>21</sup> joules / 36,525 days = 1.38x10<sup>17</sup> joules stuck in the atmosphere per day<br />
<br />
Which means that the atmosphere has been retaining an average of 1.38x10<sup>17 </sup>joules of energy every single day.<br /><br />So how does that compare to the 2013 energy generating capacity?<br /><br />1.38x10<sup>17 </sup>joules per day / 5.67x10<sup>20</sup> joules in 2013 = 0.00024 * 100% = 0.024% of energy generated in 2013<br />
<br />
So that means, <b><u>for every single day</u></b> in the last 100 years, the atmosphere has retained about 0.024% of the equivalent of the 2013 energy generating capacity. Or to flip that around, every 41 days the amount of energy we generated in 2013 gets "stuck" in the atmosphere.<br />Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-48328824721457839202014-12-03T00:07:00.001-08:002015-03-16T13:48:22.685-07:00IRONMAN Arizona Trip Report Part II<span class="s1">[Note: I wrote this mostly as a reminder for myself, but I think it might be helpful to other triathletes as well. I recognize that it may seem overly detailed, but triathlons are complicated affairs that require some trial and error to get right</span>.]<br />
<br />
This is part II of my IRONMAN Arizona 2014 trip report. It concerns all the stuff that happened on race day. The details leading up to race day can be found in <a href="http://chuckwolber.blogspot.com/2014/12/ironman-arizona-trip-report-part-i.html" target="_blank">Part I</a>.<br />
<br />
I was up by 0400hrs on Sunday morning. Actually, I was up a bit before that but I did not feel tired at all, nor was I really that nervous. This is an endurance event, not a test of skill, so there is really nothing to be nervous about. I think my body was just readying itself for the task ahead.<br />
<br />
The first order of business was to follow my usual morning routine. One of the golden rules of triathlon is to never do anything out of the ordinary before a race, so I still took a shower even though I was about to go swimming and then sweat for another 12 hours. I finished up by putting on the heart rate monitor, tri-suit, timing chip, and finally my street clothes.<br />
<br />
I hung out in the hotel room for a bit reading the news and checking the weather. I was disappointed to discover that the winds on the race course were expected to be 25 knots after being nearly dead calm for the last few weeks. It was only after the race that I found that that this was a gross under-prediction. The actual winds were a sustained 40 knots, gusting to ludicrous speeds...<br />
<br />
I was down at the hotel breakfast by about 0500hrs. I had a little coffee and a bowl of cereal, but that was about all I could get down. I would have loved to be able to send a thousand calorie breakfast down the pipe for some insurance, but it was just not possible. Fueling in an IRONMAN is called the "fourth discipline" for a reason - it is very difficult to get right. No one has the kind of built in reserves to last an entire race, and your digestive system is carefully evolved to come to a screaming halt during athletic endeavors. You have to take on calories as you go and stay ahead of the reaper, but you have to be careful about how you do it. I saw more than a few athletes "praying to the dusty ground" during this race. I was not too worried about the slim breakfast though because I had a well tested fueling plan for the race.<br />
<br />
I was back at the hotel room at 0515hrs to pick up my Orange and Black special needs bags, as well as my Green "morning clothes" bag. I put all of my swim gear in my Green bag the night before, and planned on swapping it all out for my morning clothes once I got suited up for the swim. The wife and I jumped into the rental car and made it close enough to the starting line by 0530hrs. She took the obligatory "before" picture, gave me a kiss, and then headed back to the hotel to get the boy up. <br />
<br />
I walked among the rapidly growing crowd of athletes as we made our way into the transition area for final race preparations. The first order of business was to drop off my Orange and Black special needs bags. Then I made my way back to the Red and Blue transition bags. I added some hydration to each, and put my <a href="http://www.myathletelive.com/" target="_blank">athlete tracker</a> into the Blue bike transition bag. Finally, I put my bike computer on my bike, and then got suited up for the swim. <br />
<br />
I should probably expand on my swim "uniform". I wear a <a href="http://www.tyr.com/shop/mens-hurricane-wetsuit-category-3.html" target="_blank">Tyr Hurricane Cat 3</a> wetsuit in size Large, a <a href="http://www.tyr.com/shop/wrinkle-free-silicone-swim-cap.html" target="_blank">Tyr wrinkle free</a> swim cap, then my goggles, and then the required IRONMAN swim cap. Sandwiching your goggles between two swim caps is a great way to keep them from being knocked off during the mass swim, and also affords you a bit more head insulation. I also wear some silicone ear plugs to prevent from getting dizzy during the swim. I am not normally prone to inner ear issues when I swim, but on rare occasions strange stuff happens.<br />
<br />
After packing all of my morning clothes into my Green bag, I handed it over to one of the morning clothes bag volunteers and then headed over to the long lineup of athletes waiting to get into the water. The actual swim start is about 200 metres from the swim entrance, so you have a nice non competitive warm-up swim to the start line.<br />
<br />
The pro-men entered the water first and started their race at 0645hrs. The pro-women enter second, and start their race five minutes later. While all of that was going on, the race volunteers do their best to get over 3000 age group athletes in the water as quickly as possible. Whether you are in the water or not, your race starts at 0700hrs so there is a lot of effort to keep that line moving. The line looked incredibly long, but I am pretty sure everyone was in the water on time. <br />
<br />
I figure I was somewhere in the first third of age groupers waiting to get into the water. Tempe Town Lake was a lot lower this year so they had to continuously warn people to be careful when they got in the water. Despite that, somehow the top of my left foot scraped the bottom and I lost a nice chunk of skin - none of which I felt at the time, probably thanks to the adrenaline...<br />
<br />
The water was not nearly as cold as I remember it being at the practice swim, but I did require a few minutes to acclimate before I felt comfortable putting my face in and swimming normally. The race officials told us the temperature was about 68F, which felt about right to me. I took my time making my way to the starting line, occasionally looking back and waving to the spectators on the bridges above. All things considered, it was the perfect warmup. <br />
<br />
I took a spot about 20 metres back from the starting line on the far left side, closest to the buoys. This has the advantage of swimming the shortest distance, while still being far enough back that you do not get mowed over by faster swimmers. I treaded water while Mike "The Voice of IRONMAN" Reilly got the crowd excited. A few minutes before the starting gun, they played the Star Spangled Banner, which ended with a roaring crowd and more than a few athletes yelling "Play Ball!".<br />
<br />
Once the gun went off it was down to business. I am not a fast swimmer, so my plan was to draft as much as possible and make it out of the water sometime between 1:20 and 1:30. The early parts of the swim reminded me of what it would probably be like to be a member of a zombie horde. You really cannot see or hear much, and everyone just stumbles along more or less in the same direction.<br />
<br />
In general I just plodded along doing my best to keep clear water in front of me and sighting from one buoy to the next. I forgot to make a count of the buoys before the swim started, so I settled into a sustainable groove and kept following the yellow buoys until that <b><u>gorgeous</u></b> red turnaround buoy appeared in the distance. The way back is easier to swim because the field of swimmers is a lot more spread out and you can judge your remaining distance by sighting the two bridges just before the swim exit.<br />
<br />
As for complications, I barely ran into any at all. Until you get past the turn buoy, the big struggle is to find clear water and avoid athletes who suddenly stop. If you feel like you need to stop during a mass swim, please turn backwards to face oncoming traffic. Most swimmers are more focused on buoy sighting, so there is little chance that they will see you in time. <br />
<br />
Other than that, the other big thing to watch out for is swimmers who converge into you. Shortly after the start you are more or less in a pod of people going about the same speed, but not exactly the same direction. The challenge is to "de-couple" once you find yourself converging with another swimmer. Your strokes tend to become synchronized and you have to work at making sure there is enough spacing between you. If there is clear water, you can adjust pretty easily. Otherwise you just have to accept that you are going to bump into someone a few times while you get things sorted out. Most people are cooperative and do their best to make room, although a small minority seemed to want to hold their line at all costs.<br />
<br />
All told I got hit in the face twice, and had a few additional bumps here and there. Otherwise everything was fine. I heard some stories of people taking a foot to the face, but none of them appeared to have suffered any real injury. Another athlete told me stories of people swimming over the top of him, but nothing like that happened to me. The best way to avoid anything like that is to be realistic about your swimming abilities and start a bit further back than you think you should.<br />
<br />
As you cross under the two bridges near the end of the swim, you can really hear Mike Reilly and the crowds cheering the athletes on. The crowd noise and the image of the swim exit as you round that last corner were really motivating and it made that last leg of the swim a lot of fun. I have to admit that I was a little sad for that part of the race to be over - and trust me, I am no big fan of swimming.<br />
<br />
Since the water was so low this year, the bottom step of the swim exit was above the water level. This required some effort to actually get out of the water. The idea was to put your back to the exit and hoist yourself up into a sitting position on the bottom step. Then you twist around, and use the rail to pull yourself to your feet. A volunteer is there to help, but I was surprisingly stable getting out of the water and did not need any help.<br />
<br />
The first order of business was to raise my goggles to my forehead and strip my wetsuit down to my waist in one graceful motion - all while walk-running with a large pack of athletes who are doing more or less the same thing. Next you encounter the wetsuit strippers who have you lay down so they can get the rest of you out of your wetsuit in about 3.5 nanoseconds.<br />
<br />
Once I had my wetsuit off, I made my way over to the changing tent while stripping off my swim caps, goggles, and ear plugs. I passed by the Blue bike transition bag area, yelled out my number and my bike transition bag magically appeared in my hand courtesy of a very helpful volunteer. Since I finished the swim in 1:25, the most average time imaginable, it was prime time in the changing tent.<br />
<br />
I managed to find an open chair, and used it to hold my swim gear while I rummaged through my bag for my bike gear. Contrary to what you would imagine, you really do not need a towel in T1. You may be a bit wet, but it dries off incredibly fast, and even putting on socks is not that hard by the time you get to the changing tent. The only issue I encountered was all of the dried grass that sticks to your feet - I was still picking it out of my luggage after we got home. For that reason alone, I will probably bring a small towel next time to get the gunk off of my feet before I put my socks on.<br />
<br />
Some of the athletes were doing a full change of clothes, I opted to remain in my tri-suit for the bike - which turned out to be a good idea. Once I was ready to ride, I stuffed my swim gear into my Blue bike bag, handed it off to a volunteer, and then went over to the Sunscreen volunteers to get all of my pasty white Irish skin covered. From there I headed over to my numbered bike location, shoved my cleat covers into my saddle bag, and walked my bike out of the transition area and to the bicycle mount line.<br />
<br />
Once I crossed the bicycle mount line, I was officially out of T1 and on to the bike portion of the race. My target speed of 18.8 mph has me through the bike course in just under 6 hours and leaves me with plenty of "juice" to run the marathon. On a flat course with relatively calm winds, this translates to around 175 watts, well under 80% of my FTP (Functional Threshold Power) of 267 watts. If I went all out, I could probably do the course in under five hours, but I would have absolutely nothing left for the run.<br />
<br />
Like my old Chief Engineer used to say, no plan withstands first contact with the enemy. The winds turned out to be a sustained 40 knot headwind on the climbing portion of the course. I later found out that they were the strongest in the 11 year history of the race. This makes it all the more amazing that someone broke the course record this year - two time Olympian, Brent McMahon finished in 7 hours 55 minutes!<br />
<br />
Despite the wind I was still able to complete the first lap exactly on schedule. I took stock of my situation after that, and realized there was no way I was going to have anything left if I kept the same pace for the remaining two laps. I dialed it down quite a bit and did my best to make up time on the downwind side of the course. I lost 15 minutes on the second lap and 30 minutes on the third lap. I think I could have done better, but after my complete meltdown on the run at IRONMAN St. George, I was trying to be as cautious as possible.<br />
<br />
Another issue on the bike was my fueling plan. Originally it called for a mix of Honey Stinger gels and mixed nuts - something I had tested throughout my training. Unfortunately my stomach completely shut down just after the beginning of the ride, and I had to abandon all forms of solid food and stick to gels (one every ten miles). This was not nearly enough calories to get me through the race, but it was better than nothing. I put a can of Red Bull in my special needs bag and downed it during my second lap and that helped immensely. About five minutes after drinking it the world got brighter and AC/DC poured forth from the skies! I have a lot of work to do on my fueling plan for next year, but I am fairly certain that more Red Bull will be part of it.<br />
<br />
One thing I did get right was to not waste any weight carrying my own hydration. The volunteers have stations set up every ten miles with a variety of drinks and food, including water bottles with pop tops that fit perfectly in your bike cage.<br />
<br />
As I got closer to the bike leg finish, I was quite ready to get off the bike. A tri-suit does not have the usual amount of padding, and riding in a hunched over "semi-aero" position takes its toll after a while. Aside from the positioning issues, I came into the bike transition feeling really good. About a mile out I started loosening my shoes, and by the dismount line I was able to pull my feet out and leave the shoes attached to the pedals. A volunteer took my bike while I trotted over to the run transition bag area. I yelled out my number, a volunteer handed me my bag, and I was on my way into the changing tent once again.<br />
<br />
The changing tent was still chaotic, but not nearly as much as during the T1 transition. I found a seat and got to work switching out my bike gear for my run gear. Instead of doing the Marathon in my tri-suit, I opted to change into traditional running gear. It took me an extra few minutes, but it added a lot of comfort to a very long run. Also, in future races I may try doing the bike ride without any socks. I do not believe the socks helped me at all, and I ended up changing into a new pair for the run.<br />
<br />
I noticed in the changing tent that my right eye was very cloudy. I thought my contact lens had gotten "gunked" up, but my right eye was still cloudy after removing the lens that night. I have no idea what it was, but the cloudiness was gone when I woke up the next morning.<br />
<br />
Once I was ready to go I stuffed all of my bike gear into my run transition bag, handed it off to a volunteer, and hit the sunblock station. I should note that I was surprised at how little the sun seemed to affect me until I noticed a very red silver dollar sized area on my back the day after the race. The sunblock applicators missed a small spot and I had a very ominous demonstration of just how bad I would have been burned had I not been so diligent about being covered.<br />
<br />
Looking back at IRONMAN St. George 70.3 in May, 2013, I remember feeling like death when I left T2. 13.1 miles seemed like a lot at the time, but I was incredibly grateful to not have a whole marathon ahead of me. Much of my training since then has focused on making sure that never happens again. I learned to budget my energy on the bike better, and I did a lot of bike to run training to get used to the feel of running after a bike ride. It seemed to pay off this time because I felt amazing once I started running. Truth be told, I felt like I had not even ridden a bike at all. Granted, this feeling did not last very long, but I felt very happy knowing that I had made some major progress on one of my biggest problems.<br />
<br />
My first mile was a respectable 9:17, and the next six averaged just over ten. From there my average settled in at 12:32 per mile. This was actually a slower overall pace than IRONMAN St. George, but the distances were much longer and I felt a lot better. All things considered, I feel like it was a major improvement. For comparison, when running fresh, I can easily lay down 8 minute miles for a half marathon, and I just did my first ever sub-20 minute 5k.<br />
<br />
Once again my digestive system completely shut down, and I was not able to take anything in but water. This happened shortly after the first mile, and did not let up for the next five miles. I felt certain that I was going to puke a few times during that period, especially after forcing myself to down a gel at mile three, but nothing happened and the feeling slowly passed.<br />
<br />
I have no idea why all of these digestive issues happened to me, but I will be looking into it as part of my 2015 training plan. After the sixth mile, I started drinking watered down Coke with some ice in it at every aid station, and added cups of warm chicken broth once they started making them available after sundown. My body tolerated all of that quite well. Ultimately my performance is going to be limited if I do not solve this fueling problem...<br />
<br />
I managed to run the first six miles, only walking briefly through the aid stations. After mile seven my quads really started to hurt and my walk through the aid stations took longer and longer. By mile 15 I met up with another racer who was going my speed, and we started a pattern of walking a quarter mile and running three quarters of a mile. It was painful, but doable. We also had some great conversations that did a lot for our mental focus.<br />
<br />
By mile 24 you can really hear Mike Reilly and the crowds in the distance. We hit the last aid station at mile 25 and did a little extra walking so we could hit the finish strong. At the last 0.2 miles, the road bends to the right and goes up a slight incline. This is where the crowds start to line up, and they get thicker and thicker as you enter the finish area. As we approached the corner I felt like it was time to put what energy I had left into the final run to the finish. I thought my running partner was going to come with me, but as I picked up speed, he wished me well. I told him I would see him at the finish line and took off. It felt good to pick up speed like that, but I knew I could not sustain it for very long.<br />
<br />
The finish was an absolute blur. All I remember seeing through my cloudy vision was a lot of flashes and the approximate location of the finish line. I vaguely remember hearing my name called and the title of IRONMAN conferred on me by Mike Reilly, as well as the cheering crowd noise in the background. I also remembered to not touch my Garmin watch until well after I crossed the finish line. They warn you about this in the race packet. Apparently a lot of athletes cross the finish line with their head down and their hand pressing buttons on their watch. It makes for a terrible picture as you cross the finish line.<br />
<br />
As soon as I crossed the finish line I stopped running and nearly fell over. One of the volunteer catchers grabbed me and held me upright while another volunteer removed my timing chip and gave me a foil blanket. My catcher walked me over to get my finisher medal, hat, and t-shirt, and then took me to the picture station to get my finisher picture taken. Finally, she brought me over to the food tent, put me in a chair, and got me some of the best tasting cold pizza in the whole freaking world. Right next to the food tent was a free massage area, which I took full advantage of. I am not sure if it was the 13+ hour effort, or the magic hands on my masseuse, but that massage felt amazing. <br />
<br />
Other than finding it hard to walk, the only real issue after finishing was that I could not regulate my own body temperature. I am not sure what I would have done without that foil blanket.<br />
<br />
The whole area from the finish chute on back to the rest area is for athletes only, so the wife and the boy had to greet me from the fence. I was really happy to see them, but could barely get out of the chair to give them a hug. It turns out they had already gotten my bike out of the transition area and turned it in to the TriBike Transport people. They also picked up my transition bags and were ready to go as soon as I was rested enough to walk out of there. Since they ended up parking a mile away from the finish line, we took a bike taxi to the rental car. Normally I would never pay for something like that, but this time it was worth every penny - plus the guy had some killer tunes playing on his sound system.<br />
<br />
We got back to the hotel where I had a nice soak in the tub to wash the stink off, and then hit the sack feeling very satisfied. I lounged around the hotel the whole next day while the wife and boy went to do some college campus tours and check out Sedona. I was really sore for the next few days, but by the second day after the race, I felt good enough to race the boy up several flights of stairs - which I won quite handily.<br />
<br />
I want to save the final words in this post for the amazing volunteers. At every station and situation, the volunteers were well trained, highly enthusiastic, and ready to help in any way possible. I did not suffer a moment of confusion, or unnecessary discomfort thanks to them. They did their best to energetically support all of the athletes from sunrise to long after sunset and I have nothing but effusive praise for them. I wish all of the volunteers the very best and give them my sincere thanks for their time and energy!
<br />
<br />
<u>Swim Gear</u>
<br />
<ul>
<li>Body Glide (Makes it easier to get into the wetsuit)</li>
<li>Wetsuit</li>
<li>Base swim cap</li>
<li>Goggles</li>
<li>Top swim cap</li>
<li>Defogger (I never ended up using this because my goggles were still fairly new)</li>
<li>Ear plugs</li>
<li>Garmin 910xt</li>
</ul>
<br />
<br />
<u>Blue Bag (T1 - Swim to Bike)</u>
<br />
<ul>
<li>220 Calorie bottle of Ensure (Ended up drinking this)</li>
<li>Can of Red Bull (Cannot remember if I drank this)</li>
<li>Water bottle with plain water in it (Took a few swings of this)</li>
<li>Chamois Butt'r (I used tons of this in the morning, so none was needed)</li>
<li>Mole skin (I used this for a spot on my foot that tends to chafe a lot)</li>
<li>Socks (I wore these, but may not do so again at the next race)</li>
<li>Bike shoes</li>
<li>Helmet</li>
<li>Sunglasses</li>
<li>Athlete Tracker</li>
</ul>
<br />
<br />
<u>Orange Bag (Bike Special Needs)</u>
<br />
<ul>
<li>Red Bull (I ended up drinking this)</li>
<li>Snickers (Never ate it)</li>
<li>Chamois Butt'r</li>
<li>Fruit snacks (Never ate 'em)</li>
<li>Moleskins (Did not need them)</li>
</ul>
<br />
<br />
<u>Red Bag (T2 - Bike to Run)</u>
<br />
<ul>
<li>Amphipod with mixed nuts (Did not end up using this)</li>
<li>Fuel belt with race number and 10x Honey Stingers (Only used one Honey Stinger)</li>
<li>Small towel (Used to clear sweat out of my eyes; only needed it once on the run)</li>
<li>Chamois Butt'r</li>
<li>Socks (Definitely used these)</li>
<li>Moleskin (Had to re-apply because the first one came off with my bike socks)</li>
<li>Running Shoes</li>
<li>White running cap (Very helpful in all conditions)</li>
<li>Bottle of water (Took a few swigs from this)</li>
<li>Running shorts and tech shirt (Changed into these in the changing tent)</li>
<li>Tube of salt pills and some chewable Pepto (Took all of it)</li>
</ul>
<br />
<br />
<u>Black Bag (Run Special Needs - I never used any of this)</u>
<br />
<ul>
<li>Tube of salt pills and some chewable Pepto</li>
<li>Moleskins</li>
<li>Chamois Butt'r</li>
<li>Pro Bar</li>
<li>Red Bull</li>
<li>Snickers</li>
<li>Beef Jerkey</li>
<li>Fruit Snacks</li>
</ul>
<br />
<br />
<u>Other stuff I packed in my giant duffle bag...</u>
<br />
<ul>
<li>Bicycle Pump (Came in very handy)</li>
<li>Garmin 910xt charger</li>
<li>Garmin 800 (So I could read my stats on the bike without looking at my watch)</li>
<li>Garmin 800 charger</li>
<li>Pedal Wrench (Did not need it)</li>
<li>Cassette Socket (Did not need it)</li>
<li>Torque Wrench (Used it, but could have left it at home)</li>
<li>Socket Set (Used it, but could have left it at home)</li>
<li>Crank Tightener (Did not need it)</li>
<li>Chain link tool (Did not need it)</li>
<li>Precision driver set (Handy for changing batteries in the hear rate monitor, etc)</li>
<li>Scissors (Surprisingly handy)</li>
<li>Bike mounted fuel pouch (Very handy for storing gel wrappers, and solid food)</li>
<li>4x Bike bottles (I used three of these)</li>
<li>Spare CR2032 batteries (I did not need any, but was glad to have them)</li>
<li>2x Spare tubes (Thankfully did not need these)</li>
<li>Di2 charger (Did not need it)</li>
<li>Electrical Tape (Fantastically useful for mounting gels to bike top tube)</li>
<li>Clear plastic tape (I forget why I had this...)</li>
<li>Safety pins (Very useful for double securing race chip)</li>
<li>Sunblock (I should have used more of this, I got a light sunburn on Thursday...)</li>
</ul>
<div>
<br /></div>
<div>
And last but not least, my official race results:</div>
<div>
<br /></div>
<div>
<u><b>Swim</b></u></div>
<div>
<ul>
<li>Distance: 2.4 miles</li>
<li>Split Time: 1:25:26</li>
<li>Race Time: 1:25:26</li>
<li>Pace: 2:12/100m</li>
<li>Division Rank: 238 of 502</li>
<li>Gender Rank: 1112 of 2270</li>
<li>Overall Rank: 1427 of 3202</li>
</ul>
<div>
<u style="font-weight: bold;"><br /></u>
<u style="font-weight: bold;">T1</u><span style="font-weight: bold;">:</span> 00:08:32</div>
<div>
<b><u><br /></u></b></div>
<div>
<b><u><br /></u></b>
<b><u>Bike</u></b></div>
</div>
<div>
<ul>
<li>Distance: 112 miles</li>
<li>Split Time: 06:41:31</li>
<li>Race Time: 08:15:29</li>
<li>Pace: 16.74 mph</li>
<li>Division Rank: 246 of 502</li>
<li>Gender Rank: 1098 of 2270</li>
<li>Overall Rank: 1366 of 3202</li>
</ul>
<div>
<b><u><br /></u></b>
<b><u>T2</u>:</b> 00:07:49</div>
</div>
<div>
<br /></div>
<div>
<b><u><br /></u></b>
<b><u>Run</u></b></div>
<div>
<ul>
<li>Distance: 26.2 miles</li>
<li>Split Time: 05:24:09</li>
<li>Race Time: 13:47:27</li>
<li>Pace: 12:22/mi</li>
<li>Division Rank: 244 of 502</li>
<li>Gender Rank: 1062 of 2270</li>
<li>Overall Rank: 1358 of 3202</li>
</ul>
<div>
<br /></div>
<b><u>Finisher Breakdown</u></b><ul>
<li>2390 finishers out of 3202 signed up.</li>
<li>1696 male finishers out of 2270 signed up.</li>
<li>378 male 40-44 finishers out of 502 signed up.</li>
<li>2639 registered participants started the race.</li>
<li>563 registered participants had a DNS (Did Not Start)</li>
<li>241 registered participants had a DNF (Did Not Finish)</li>
<li>8 registered participants had a DQ (Disqualified)</li>
</ul>
<div>
<b><br /></b></div>
<div>
<b><u>My Overall Percentiles</u></b></div>
</div>
<div>
<ul>
<li>Male 40-44: 51st percentile (registrants), 35th percentile (finishers)</li>
<li>Male: 53rd percentile (registrants), 37th percentile (finishers)</li>
<li>Overall: 57th percentile (registrants), 43rd percentile (finishers)</li>
</ul>
</div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-57678626966742239782014-12-02T23:37:00.000-08:002014-12-03T00:18:32.533-08:00IRONMAN Arizona Trip Report Part I<div class="p1">
<span class="s1">[Note: I wrote this mostly as a reminder for myself, but I think it might be helpful to other triathletes as well. I recognize that it may seem overly detailed, but triathlons are complicated affairs that require some trial and error to get right</span>.]<br />
<span class="s1"><br />I participated in IRONMAN Arizona 2014 on Sunday, November 16, and </span>this is Part I of my trip report. If you are bored by detailed rundowns of packet pickup, and practice swims, you can jump directly to <a href="http://chuckwolber.blogspot.com/2014/12/ironman-arizona-trip-report-part-ii.html" target="_blank">Part II</a> for the race day action.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">This trip really started back in November of 2013. IRONMAN Arizona is so popular </span>that the only way to ensure a spot is to volunteer for a race. This gives you the right to register on-site Monday after the race. The lineup for volunteer registration seemed to start around 0300hrs for a 0800hrs registration. I got in line around 0430hrs and, despite being pretty far back, had no trouble getting a spot on the 2014 roster.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">After volunteers, the general public can register onsite, and finally </span>registration is opened online. In 2014, I heard that online registration ended five minutes after it opened. I just checked on the 2015 race and there was no online registration. The race filled up from onsite registration alone! If you are willing to pay double ($1,450), at the time of this writing there are some IRONMAN Foundation slots still open for the 2015 race.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">One of the benefits of getting into the race is the right to sign up for the </span>next year's race during packet pickup. If you plan to do this race multiple times, it is a real benefit. I have some specific goals in mind that are going to take a few years to reach, so it was worth it for me to invest in the volunteer trip.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">Volunteering for the previous year's race also had some benefits that </span>went way beyond assuring a spot. If you have never done a long course (140.6) triathlon before, it really helps to watch how things go at the event before participating. It was also useful to get to know the town of Tempe as well. All of that made for significantly less stress when I did the race this year.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">This year's race schedule started on Thursday. You could arrive as late as </span>Friday, but there is so much to do prior to one of these races that arriving on Friday might make things uncomfortably busy. I wanted arrive even before Thursday to get better acclimated to the desert environment, but work and other responsibilities did not allow for it.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">My plane landed around noon on Thursday and by 1300hrs I had my rental car and </span>was on my way to Tempe Beach Park. By 1330hrs I was parked in downtown Tempe (downtown Tempe has tons of parking), and headed into the registration tent to pick up my race packet.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">The first step was to show my driver's license. In return I got a card with my </span>race number printed on it, a liability waiver, and a medical release waiver. I went to a table in the back corner to read the waivers and then sign and date both. The medical release waiver permits IRONMAN to release medical information to your family if something happens to you during the race, and the liability waiver is the standard legalese to remind you that you race at your own risk.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">Once read and signed, you go to the second table to turn in your forms and </span>receive your wristband. Your wristband is your ticket to all of the athlete areas - and trust me, security is pretty tight, they will check it a lot. It has your athlete number printed on it, and it cannot be removed without destroying it.</div>
<div class="p1">
</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">After receiving your wristband, you are directed to the packet pickup table. </span>You hand them the race number card that you got at the first table, and in return you get your race envelope with your race stickers, your race bib, and your colored swim cap (green for males, pink for females, white for IRONMAN Foundation racers, and I believe grey for pros). A volunteer writes your number on your swim cap, answers any questions you may have, and then directs you to the next table to pick up some SWAG.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">I passed on most of the SWAG because none of it looked that interesting to me - I have no use for </span>posters and flashy brochures. I did pick up some spiffy baggage tags though. They are made of very durable plastic and come in handy when you want a nice label for your luggage.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">The last table in the registration tent is the timing chip. They check the race </span>number on your wristband and then program that into a chip. You can verify they have the right race number programmed into the chip because your name shows up on the computer screen when you hear that satisfying *beep* that signifies your chip is ready to go. The chip comes with an ankle holder that attaches via velcro. Despite being bulletproof and virtually impossible to fall off, purely out of paranoia, I weave a safety pin into both sides of the velcro. I also wear the chip facing the inside of my leg, out of concern that it may clip something if it is on the outside.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">After completing the registration tent, they direct you to the merchandising </span>tent to pick up your backpack and athlete bags. While it is possible that they do it this way to get you into the merchandising tent, judging by how crowded the registration tent is, it seems more likely that they simply ran out of room. I took a break before I went over to the merchandising tent to listen to the remainder of the mandatory athlete meeting.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">The athlete meeting goes over a lot of what is in the athlete manual (published </span>on the website), other details that may not be obvious, and they take questions from the athletes. I have done shorter triathlons and I always find these meetings useful, so I made it a point to attend. I ended up missing the first quarter of the meeting while I was in the registration tent, so I attended a repeat meeting on Saturday.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">Back at the merchandising tent, I picked up my backpack and athlete bags. The </span>backpack is a rather nice gift, and the athlete bags are part of your equipment to complete the race. Each bag is a different color and serves a different purpose.</div>
<div class="p2">
<ul>
<li>Green - Morning Clothes</li>
<li>Blue - Bike Gear</li>
<li>Red - Run Gear</li>
<li>Orange - Bike Special Needs</li>
<li>Black - Run Special Needs</li>
</ul>
<br /></div>
<div class="p1">
<span class="s1">Most of that should be self explanatory, but I will briefly go over each one. </span>All of the stuff you will need in T1 (transition from swim to bike) goes in the blue bag. All of the stuff you need in T2 (transition from bike to run) goes in the red bag. Your street clothes that you wear to the race in the morning go into the green bag. If you need anything to help you through the bike or the run, you can put those in the orange and black special needs bags. The special needs bags are made available to athletes at a designated location on the bike and run courses. I ended up using my bike special needs bag, but not my run special needs bag. I have placed a list of the contents of all my bags, and what worked and did not work, at the bottom of the Part II post.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">Now that I was all checked in, my last stop was to the TriBike Transport tent </span>to pick up my bike. This is my second event with TriBike Transport, and I have nothing but praise for them. They save me a *TON* of trouble by making sure my bike gets to the event and back safely. The alternative is to buy an expensive bike box, disassemble my bike, pack it in the box, pay extra to check it on the airplane, and hope that it arrives in one piece. TriBike has a vested interest in getting bikes to events without so much as a scratch on them. And the best part is that I get to hand my bike back to them, all sticky and nasty, right after the event. A few days later I get an email when it arrives back in Seattle.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">At this point, I grabbed some dinner at an outdoor pub, loaded everything up </span>into my rental car, and checked into my hotel.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">I spent nearly all of Friday unpacking and organizing my race gear. Once I got </span>things squared away, I filled my gear bags to get them ready for gear check-in on Saturday. This was also the time I spent mentally going over my race plan to make sure I was not missing anything. I am not sure how other people do this, but it took up a fair bit of space in the hotel room to accomplish this whole process.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">Saturday was the practice swim and gear check-in. It is illegal to swim in </span>Tempe Town Lake unless you have a permit, so the practice swim was the only time to "test the waters". I treated it just like the actual event swim and wore my wetsuit. They also require you to wear your racing chip so they can chip you in and out of the water. The line to get into the swim was pretty long, so I recommend getting there closer to when it opens. The practice swim course was an 800 metre version of the actual event swim. They gave you the option of swimming all or part of it, or perhaps even going further. I opted to just swim the practice course, which took me about 20 minutes and ultimately registered 0.63 miles on my Garmin watch. The water felt surprisingly cold, even though it was tested to be 68F. I guess I am too used to swimming in the 80F water at my local pool.</div>
<div class="p2">
<span class="s1"></span><br /></div>
<div class="p1">
<span class="s1">The practice swim had an athlete gear storage area just outside of the swim </span>entry. There was no privacy, just a fenced off area with stakes in the ground marking athlete number ranges. As long as you wore your bathing suit under your street clothes, you could change into your wetsuit right there and drop off your gear in your numbered area. When your practice swim is over you do the reverse. I also opted to hang my wetsuit on the fence so that it would dry in the sun. By the time I picked it up after gear check-in, it was nearly completely dry.</div>
<div class="p2">
<span class="s1"><br /></span></div>
<div class="p2">
<span class="s1">I took my swim gear (minus the wetsuit) back to the car and traded them for my </span>bike, run gear bag, and bike gear bag. Overall the check-in process was extremely straightforward. I rolled my bike into the T1 transition area, found my race number and racked my bike on the bike holder. I then went over to the bike and run gear bag areas and placed my bag near the section that contained my race number. I have to admit that their race numbering was a bit hard to read, but they had volunteers helping us get our bags in the right place. After gear check-in closed the volunteers did a thorough check to ensure the bags were in the right order.<br />
<br /></div>
<div class="p1">
<span class="s1">I ended Saturday's activities by attending the last athlete meeting to pick up </span>whatever I missed in the first athlete meeting.<br /><br />Continue on to <a href="http://chuckwolber.blogspot.com/2014/12/ironman-arizona-trip-report-part-ii.html" target="_blank">part II</a>...</div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-90158107450417086312014-11-02T22:27:00.000-08:002014-11-05T17:29:09.397-08:00Purple Stride 5KThe boy and I ran the Purple Strider 5K today. It was a great race for a great cause!<br />
<br />
I managed to nail a personal best time of 19:53, and the boy came in at around 24:30.Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-77393609905644801012014-09-14T22:08:00.002-07:002017-11-26T14:42:57.723-08:00Another Sprint TriathlonThe boy and I did another Sprint triathlon today. This one was a 0.5 mile swim, 11 mile bike, and 2.8 mile run. As usual, the boy smoked me on the swim, but I managed to catch up to him on the bike at the 2.3 mile point. Here are the results (out of 123 finishers):<br />
<br />
The Boy:<br />
<ul>
<li>Place Overall: 37</li>
<li>Overall Time: 1:22:43</li>
<li>Division Place: 1</li>
<li>Swim Rank / Time: 14 / 00:13:52</li>
<li>T1: 2:59</li>
<li>Bike Rank / Time: 66 / 00:38:57</li>
<li>T2: ??</li>
<li>Run Rank / Time: 80 / 00:26:54</li>
</ul>
<br />
<div>
<br /></div>
<div>
Me:</div>
<ul>
<li>Place Overall: 11</li>
<li>Overall Time: 1:14:54</li>
<li>Division Place: 3</li>
<li>Swim Rank / Time: 33 / 00:15:38</li>
<li>T1: 2:52</li>
<li>Bike Rank / Time: 10 / 00:32:17</li>
<li>T2: 1:31</li>
<li>Run Rank / Time: 29 / 00:22:36</li>
</ul>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-1869133894881996772014-06-28T21:52:00.000-07:002017-11-26T14:43:23.527-08:00Sprint Triathlon<span style="font-family: "arial" , "helvetica" , sans-serif;">The Boy and I did a sprint triathlon today (0.25 mile swim, 14 mile bike, 3.1 mile run). He smoked me on the swim, but I cleaned up on the rest. Here are our results (out of 154 finishers):</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The Boy</span><span style="font-family: "arial" , "helvetica" , sans-serif;">: </span></div>
<div>
<ul><span style="font-family: "arial" , "helvetica" , sans-serif;">
<li>Place Overall: 103 </li>
<li>Division Place: 3rd (15-19) </li>
<li>Swim Rank/Time: 18 / 0:06:38.0 </li>
<li>T1: 0:02:15.6 </li>
<li>Bike Rank / Time / Speed: 101 / 0:49:07.2 / 17.1MPH </li>
<li>T2: 0:01:06.8 </li>
<li>Run Rank / Time / Speed: 126 / 0:28:28.6 / 9:11/M </li>
<li>Overall Time: 1:27:36.2</li>
</span></ul>
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span>
<br />
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">
Me: </span><br />
<ul><span style="font-family: "arial" , "helvetica" , sans-serif;">
<li>Place Overall: 38 </li>
<li>Division Place: 7th (40-44) </li>
<li>Swim Rank/Time: 79 / 0:08:36.4 </li>
<li>T1: 0:01:21.7 </li>
<li>Bike Rank / Time / Speed: 31 / 0:39:15.1 / 21.4MPH </li>
<li>T2: 0:01:07.3 </li>
<li>Run Rank / Time / Speed: 61 / 0:23:11.4 7:29/M </li>
<li>Overall Time: 1:13:31.9</li>
</span></ul>
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span></div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-63503666040679101282014-06-28T20:49:00.003-07:002015-07-02T12:36:21.817-07:00Downloading FIT files manually from a Garmin 910xt<span style="font-family: Arial, Helvetica, sans-serif;">When Garmin switched from their ANT agent to Garmin Express, the first version(s) of Garmin Express would not save the FIT files on your machine after it sync'd with Garmin Connect. The switch from the ANT agent to Garmin Express also broke connectivity with Strava and any other website that relied on the Garmin web browser plugin.<br /><br /> The workaround was (is) to upload FIT files directly to any site that got their plugin connectivity broken. Since the FIT files were deleted with earlier versions of Garmin Express, they could not be found to upload (catch-22). The fix is to extract the files manually with the </span><span style="font-family: Arial, Helvetica, sans-serif;">Garmin-Forerunner-610-Extractor </span><span style="font-family: Arial, Helvetica, sans-serif;">tool - yes, it works on the Garmin 910xt despite the name.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /> Here are detailed instructions for installing and running the manual extraction tool on an Apple machine running OSX Mavericks or later (and probably Linux). I have no idea how to do this on a win-tel machine. Also note that this how I personally got things working. Your mileage may vary, and I am not responsible for any problems that arise out of the use of these instructions. If you have problems, feel free to post a detailed explanation of what went wrong, and I will try to help.<br /><br />In your web browser go to <a href="http://www.libusb.org/">http://www.libusb.org/</a> and click on the link to "Download the latest release tarball" of libusb (Currently <a href="http://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-1.0.18/libusb-1.0.18.tar.bz2">libusb-1.0.18</a>).</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">[Note: A few people have missed the capital "D" in "Development" and "Documents". The OS X HFS+ filesystem is case sensitive, so you must be sure to get the case correct.]</span><br />
<div>
<ol><span style="font-family: Arial, Helvetica, sans-serif;">
<li>Open the terminal (You can find this by opening the finder and selecting "Applications" and then "Utilities". Double click on "Terminal"). </li>
<li>Type the following command in the Terminal: mkdir -p ~/Documents/Development && cd ~/Documents/Development </li>
<li>Type the following command in the Terminal: git clone https://github.com/Tigge/Garmin-Forerunner-610-Extractor </li>
<li>Type the following command in the Terminal: cd ~/Documents/Development/Garmin-Forerunner-610-Extractor/ </li>
<li>Type the following command in the Terminal: sudo easy_install pyusb </li>
<li>Type the following command in the Terminal: cp ~/Downloads/libusb* ~/Documents/Development/Garmin-Forerunner-610-Extractor/ </li>
<li>Type the following command in the Terminal: tar -zxvf libusb-* </li>
<li>Type the following command in the Terminal: cd libusb* </li>
<li>Type the following command in the Terminal: ./configure && make && sudo make install </li>
<li>Type the following command in the Terminal: cd .. </li>
<li>Turn on your Garmin device. Once it is fully started, plug in your ANT USB stick. </li>
<li>Type the following command in the Terminal: sudo python ~/Documents/Development/Garmin-Forerunner-610-Extractor/garmin.py </li>
<li>If this is the first time you have done this, your Garmin 910xt should ask if you want to pair with the Garmin Extractor device. Select "Yes" with the arrow button and press the "Enter" button. </li>
<li>The FIT files will now start downloading (including those that Garmin Express and the ANT Agent will not download). </li>
<li>When the download is complete, you can find them in ~/.config/garmin-extractor/$NUMBER/activities ($NUMBER is unique to your device, it should be the only numbered directory in ~/.config/garmin-extractor). This is the directory you will select files from when you need to upload them to sites like Strava. </li>
</span></ol>
<span style="font-family: Arial, Helvetica, sans-serif;">Repeat steps 1, and 12 - 16 for subsequent extractions.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Update:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">When running step 12, if you get an error similar to the following, it is probably because you have some other program accessing the ANT USB stick, like Garmin Express, or the old ANT Agent. Simply shut down the program in question, reinsert the ANT USB stick, and attempt step 12 again.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Driver available: [<class 0x10d53d8d8="" ant.base.driver.usb2driver="" at="">, <class 0x10d53d940="" ant.base.driver.usb3driver="" at="">]</class></class></span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> - Using: ant.base.driver.USB2Driver</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Traceback (most recent call last):</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "garmin.py", line 336, in main</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> g = Garmin(options.upload)</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "garmin.py", line 137, in __init__</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Application.__init__(self)</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "/Users/chuckwolber/Documents/Development/Garmin-Forerunner-610-Extractor/ant/fs/manager.py", line 82, in __init__</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> self._node = Node()</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "/Users/chuckwolber/Documents/Development/Garmin-Forerunner-610-Extractor/ant/easy/node.py", line 48, in __init__</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> self.ant = Ant()</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "/Users/chuckwolber/Documents/Development/Garmin-Forerunner-610-Extractor/ant/base/ant.py", line 59, in __init__</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> self._driver.open()</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "/Users/chuckwolber/Documents/Development/Garmin-Forerunner-610-Extractor/ant/base/driver.py", line 180, in open</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> dev.set_configuration()</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "build/bdist.macosx-10.9-intel/egg/usb/core.py", line 559, in set_configuration</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> self._ctx.managed_set_configuration(self, configuration)</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "build/bdist.macosx-10.9-intel/egg/usb/core.py", line 92, in managed_set_configuration</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> self.backend.set_configuration(self.handle, cfg.bConfigurationValue)</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "build/bdist.macosx-10.9-intel/egg/usb/backend/libusb1.py", line 741, in set_configuration</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> _check(self.lib.libusb_set_configuration(dev_handle.handle, config_value))</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> File "build/bdist.macosx-10.9-intel/egg/usb/backend/libusb1.py", line 571, in _check</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> raise USBError(_str_error[ret], ret, _libusb_errno[ret])</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">USBError: [Errno 19] No such device (it may have been disconnected)</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Interrupted: [Errno 19] No such device (it may have been disconnected)</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Update 20Nov2014:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I tested this with a Garmin FR60 and it worked great.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Update 02Jul2015:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">If you get the following, error or something like it:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">can't open file '/Users/Aaron/documents/development/garmin-forerunner-610-extractor/garmin.py': [Errno 2] No such file or directory</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">You probably neglected to capitalize the "D" in Documents and/or the "D" in Development. Look through the execution path carefully for "Documents" and "Development" and make sure you capitalize the "D".</span></div>
Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com18tag:blogger.com,1999:blog-19463783.post-85190841087876634022013-11-28T11:30:00.000-08:002013-11-28T11:36:37.237-08:00Juniper Network Connect and Mac OSI run a Macbook Pro to do a lot of my software development. When I work from home I have to connect to the company VPN to push code updates to the repository server - which is done with the Juniper Network Connect client. Occasionally the VPN client will connect and then disconnect after five seconds with a message that begins with, "Your computer's routing table has changed...". There is some discussion of this on the 'tubes, but no one seems to have a solution in hand. I managed to solve it on my own.<br />
<br />
The error message is correct, something is updating my machine's routing tables after the VPN connection is made. The simplest way to figure out what is doing this is to start killing processes until the VPN connection starts working - which you do with the "Activity Monitor" application (Macintosh HD -> Applications -> Utilities -> Activity Monitor).<br />
<br />
After some experimentation, it appears as if VMWare Fusion may be the culprit. I say "may" because I ended up killing several other processes at the same time, so I cannot be certain that VMWare Fusion was the right one. However, in reading forum posts from others who have had this problem, VMWare Fusion seems to pop up quite often during the discussion.<br />
<br />
Also, two other issues of note:<br />
<br />
Running the VPN client from within a VMWare instance seems to work all of the time. Even when this is happening within the base Mac OS.<br />
<br />
YMMV, but I usually have really messed up DNS settings once the VPN client disconnects. This can be solved by issuing the following two commands in the terminal:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">sudo launchctl unload /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span><span style="font-family: 'Courier New', Courier, monospace;">sudo launchctl load /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist</span>Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-91139580992856547262013-10-01T23:08:00.000-07:002013-10-01T23:08:51.680-07:00Chrome AnnoyanceI am writing some code that involves the use of embedded Jetty 9 (Jetty as a POJO). To start with, I was doing some basic testing with a handler that would print a message to the console and then do a Thread.sleep(10000). The idea was to get it sleep long enough for me to kick off a bunch of requests (web browser tabs to start, eventually graduating to a curl script) to see how well Jetty 9 handled simultaneous requests.<br />
<br />
No matter what I seemed to do, I could not get my code to respond to simultaneous requests. The requests always seemed to pass through serially. To make things worse, I just happened to be doing this development on a Windows 7 machine - which makes it pretty much impossible to sniff traffic on the localhost interface (yes, I know there are some possible ways to do that, but they are unreliable). So I was working in the blind and nothing seemed to be working...<br />
<br />
Finally I managed to find the answer <a href="http://comments.gmane.org/gmane.comp.java.jetty.support/15194" target="_blank">here</a>. The problem was not my code, it was the Chrome Browser. Apparently you cannot open the same URL on multiple tabs at the same time. I fired up Firefox (pun intended) and everything worked like a champ.<br />
<br />
So ah... What is the deal Google?Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-58378794759334046652013-09-19T23:29:00.000-07:002013-09-19T23:39:40.278-07:00PRP TherapyI was diagnosed with a split tear in my left Peroneal Brevis. My guess is that it was an old Soccer injury that got lit up by all of the training. My options were surgery, or something a bit newer called PRP Therapy. Surgery was the least preferable because it leaves me unable to train for six months. PRP - which stands for Platelet Rich Plasma, enables the body to heal the split on its own. It is about 70% effective and is far less invasive, enabling me to get back to training in weeks rather than months.<br />
<br />
The key problem with Tendons is that they have limited blood flow, which makes repair unlikely when damage exceeds certain limits. The lack of blood flow means that injuries do not get the benefit of the rich set of growth factors found in blood Platelets. PRP fixes that problem by injecting your own blood Platelets into the damaged area. The Platelets rapidly differentiate into growth factors that build a Collagen matrix. That Collagen matrix goes through a bunch of changes from one type of Collagen to another, eventually leaving you with a fully repaired Tendon.<br />
<br />
In practice, PRP is pretty simple stuff. They draw a small vial of your blood and spin it down in a centrifuge. The bottom layer is all of your red and white blood cells, and the top layer is a yellowish substance that contains all of the Platelets and other stuff that your body uses to heal itself on a regular basis. When they showed me my vial of centrifuged blood, it appeared as if nearly half of the vial was Platelet "goo". The doctor mixed some of the Platelet solution with Calcium Carbonate fluid, to prevent clotting, and then injected it into the split. She was guided to the split by a Sonogram (made by Sonosite - that apparently costs $60,000). <br />
<br />
Interestingly, the doctor was able to clearly see the injury with the sonogram, which made me wonder why I had to get an MRI for this injury in the first place. She told me that it was because the Sonogram device was very expensive, and it takes a lot of skill to use it in this manner. But she also agreed that things probably needed to change simply from a cost standpoint. An MRI costs $2000 ($1000 with insurance discounts), and a Sonogram is only about $150. She also indicated that they are training all of their new Fellows to diagnose injuries with a Sonogram.<br />
<br />
I had the injection today, and am now in an air cast boot for the next two weeks while the first phase of healing happens. I will not lie, the injection stung a little. They used Lidocaine at the injection site, but I later found out that Lidocaine can inhibit the Platelet action, so they do not anesthetize the Tendon itself. Normally the only painful part of most procedures is the initial stick of Lidocaine. The secondary sting took me by surprise. Had I known it was coming I would have been able to ignore it - it really was not that bad.<br />
<br />
Once the first phase of healing is complete, the next phase involves swimming, or light bike riding, in addition to the normal daily walking around. The second phase is supposed to last about two weeks and helps the collagen matrix go from a disorganized bunch of new cells, to a carefully aligned set of cells that will eventually heal into full fledged tendon material. At the four week point I can ease back into some cardio work with the Elliptical, and then the doctor sees me again at the six week point. If all goes well, I should be able to ease back into running after six or so weeks.<br />
<br />
Not exactly the way I wanted to spend the Fall, but it sure does beat being out of commission for six months...<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-Wxp8N1xB4y8/Ujvpr5DsOII/AAAAAAAAAio/hU0XaD8phk0/s1600/IMAG0110.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://2.bp.blogspot.com/-Wxp8N1xB4y8/Ujvpr5DsOII/AAAAAAAAAio/hU0XaD8phk0/s320/IMAG0110.jpg" width="181" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Air cast boot being inspected by Cisco...</td></tr>
</tbody></table>
<br />
<br />Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-32712831264426832332012-06-17T14:01:00.000-07:002012-06-17T14:01:41.120-07:00Dura Ace Di2 - Failure to DownshiftIf you have a Dura Ace Di2 electronic shifter and you find that it cannot shift the rear cassette to a larger gear (downshift), you might have forgotten to put your rear wheel back on in the same gear in which it was taken off. The Dura Ace Di2 rear cassette electronic shifter does not appear to sense its position. My guess is that it has absolute locations for shift positions, and you can confuse it by putting the derailleur back on at a different position.<br />
<br />
But wait! If you return your wheel to a different gear it <b><u>should</u></b> automatically find the gear it was previously on, simply because the derailleur is in that position. For whatever reason, that may not always be the case with the Dura Ace Di2 electronic shifting system. I have had it happen both ways. Sometimes the chain moves to the right place on the rear cassette, sometimes it does not.<br />
<br />
In my case, I solved this by removing the rear wheel and shifting all the way to the outermost gear. When I put the wheel back on, I made sure that the chain was on the outermost gear.Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-17332904965840906282011-12-15T21:58:00.000-08:002011-12-15T21:58:26.212-08:00Thank you Mr. HitchensIn October of 2011 I attended the <a href="http://www.texasfreethoughtconvention.com/" target="_blank">Texas Freethought Convention</a> and got to see <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Christopher_Hitchens" target="_blank">Christopher Hitchens</a> receive the Richard Dawkins Award. During the question and answer period an eight year old girl asked Christopher what authors she should be reading. Christopher considered it for a moment and then told the girl that he would meet her in the hallway after the talk and give her a list. True to his word Christopher met the girl in the hallway and gave her his undivided attention. What follows are the pictures I took of Christopher talking with the young girl. The pictures were taken with my HTC EVO 8 megapixel cellphone camera.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-ZvUNQD_QwDU/TurdCaGsMoI/AAAAAAAAAZ0/rWJ-HYgcDec/s1600/IMAG0165.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://2.bp.blogspot.com/-ZvUNQD_QwDU/TurdCaGsMoI/AAAAAAAAAZ0/rWJ-HYgcDec/s320/IMAG0165.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-Ov_t57qo7ew/TurdGlifxsI/AAAAAAAAAZ8/jAzVD9oKkJg/s1600/IMAG0166.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://2.bp.blogspot.com/-Ov_t57qo7ew/TurdGlifxsI/AAAAAAAAAZ8/jAzVD9oKkJg/s320/IMAG0166.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-WRz1ObOCRMU/TurdLBVV15I/AAAAAAAAAaE/Yc1_lqtrsb8/s1600/IMAG0167.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-WRz1ObOCRMU/TurdLBVV15I/AAAAAAAAAaE/Yc1_lqtrsb8/s320/IMAG0167.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-7cF_BeknB60/TurdPYJ5DOI/AAAAAAAAAaM/-touoAohILA/s1600/IMAG0168.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-7cF_BeknB60/TurdPYJ5DOI/AAAAAAAAAaM/-touoAohILA/s320/IMAG0168.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-m3usiW8N0pU/TurdTx29-vI/AAAAAAAAAaU/yZNDTucBA3E/s1600/IMAG0169.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://1.bp.blogspot.com/-m3usiW8N0pU/TurdTx29-vI/AAAAAAAAAaU/yZNDTucBA3E/s320/IMAG0169.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-PGyBQgCHNIM/TurdYdR_G4I/AAAAAAAAAac/p27ft25BAtE/s1600/IMAG0170.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://2.bp.blogspot.com/-PGyBQgCHNIM/TurdYdR_G4I/AAAAAAAAAac/p27ft25BAtE/s320/IMAG0170.jpg" width="191" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-IAe88Mw9fbk/Turdbziho8I/AAAAAAAAAak/CBN52JGfCh8/s1600/IMAG0171.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-IAe88Mw9fbk/Turdbziho8I/AAAAAAAAAak/CBN52JGfCh8/s320/IMAG0171.jpg" width="191" /></a></div>
<br />
<br />
<br />Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-77736873070389329782011-10-06T09:34:00.000-07:002011-10-06T09:47:54.697-07:00Benefits of Exercise... Need more proof?I like to do the timed race up the <a href="http://www.bigclimb.org/">Columbia Tower in Seattle</a>. In the 2008 I did it in 13:28.25 and 2009 my time was 12:55.55. Both were done without any training and each time I knew that I could have done better. I missed the 2010 race altogether.<br />
<br />
Sometime in September of 2010 I started training for the 2011 race. I managed to shave 30 seconds off of my 2009 time with only a few months of training and decided to push it even harder for the 2012 race. I also picked up a <a href="http://www.garmin.com/FR60">heart rate monitor</a> a few months ago in order to get a more detailed understanding of how my body was responding.<br />
<br />
As your aerobic capacity increases, your heart gets physically bigger and is able to pump more blood during every cycle. This causes your RHR (Resting Heart Rate) to slow down, which is a good way to track your progress. I got my heart rate monitor on 17Aug2011 and strapped it on for the night while I was sleeping. I added a daily run to my training and strapped on the monitor again last night (05Oct2011) to check my progress.<br />
<br />
The results speak for themselves - the blue graph is my August data and the pink represents the current state of affairs. <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-T46zRbkFCLI/To3UHzTb-_I/AAAAAAAAANI/H7kqylIHJCY/s1600/heartrate_comparison.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="http://2.bp.blogspot.com/-T46zRbkFCLI/To3UHzTb-_I/AAAAAAAAANI/H7kqylIHJCY/s400/heartrate_comparison.JPG" width="400" /></a></div>
<div style="text-align: center;">
(Click to embiggen...)</div>
<br />
From a subjective standpoint, I feel a lot calmer and more relaxed. The little things do not bug me as much as they used to, and on nights where I cannot get in enough sleep, I feel perfectly fine the next day.<br />
<br />
To be sure, the data is not perfect (you are not perfectly at rest while sleeping) and last night could have been an anomaly. I will continue to track this on a monthly basis and see if a true trend is developing. I like what I see so far though.Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0tag:blogger.com,1999:blog-19463783.post-73383557293710477852011-09-19T16:09:00.000-07:002017-11-26T14:38:15.335-08:00A lot of good that did...Then: "I, Rick Perry, Governor of Texas, under the authority vested in me by the Constitution and Statutes of the State of Texas, do hereby proclaim the three-day period from Friday, April 22, 2011, to Sunday, April 24, 2011, as Days of Prayer for Rain in the State of Texas."<br />
<br />
Now: "In the past seven days Texas Forest Service has responded to 176 fires for 126,844 acres."<br />
<br />
<br />Chuck Wolberhttp://www.blogger.com/profile/08724990719580309488noreply@blogger.com0