tag:blogger.com,1999:blog-20204441338108332672024-03-04T22:15:22.169-06:00grinding gierVarious notes about things that come up during the course of a day.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.comBlogger25125tag:blogger.com,1999:blog-2020444133810833267.post-53492236668799724212019-01-21T19:12:00.000-06:002019-01-21T19:13:32.008-06:00this is a test test test paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-37662724030968827982016-05-23T20:09:00.003-05:002016-05-23T20:10:50.868-05:00Duplicate function definition in PythonI discovered that Python will happily allow two functions with the same signature to be declared in the same file without any warning. The second function will just replace the first one. It seems like this should give a compile error or warning, but maybe there are some use cases where it would be useful to redefine/override a function based on a condition, so the compiler can't determine whether the duplicate function definition is valid.<br />
<br />
<a href="https://www.pylint.org/">pylint</a> will provide a "function-redefined" error if it detects a duplicate function, so it seems this is not a generally good practice.<br />
<br />paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-48699415749630700972012-02-02T11:42:00.000-06:002012-02-02T11:42:27.937-06:00Add custom application launcher in Fedora 16/Gnome 3The application launchers that appear when you bring up the <a href="http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/16.0/html/User_Guide/chap-User_Guide-Tour_of_the_GNOME_desktop.html#sect-User_Guide-_The_GNOME_desktop_-_The_Activities_Overview_">Activities Overview</a> when pressing the windows button, can be customized by adding or modifying <a href="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html">desktop entry</a> files.<br />
<br />
There are two places where you can add new desktop entry files depending on whether the launcher icon should be available for all users or only a single user. <br />
<br />
For example, to create a launcher for the eclipse IDE:<br />
<br />
Global (all users) -<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/usr/share/applications/eclipse.desktop</span><br />
<br />
Local (single user) -<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">/home/myusername/.local/share/applications/eclipse.desktop</span><br />
<br />
Assuming that eclipse is installed to /opt/eclipse, the eclipse.desktop file would look something like this:<br />
<blockquote>[Desktop Entry]<br />
Name=eclipse<br />
Type=Application<br />
Categories=Development<br />
Exec=/opt/eclipse/eclipse<br />
Icon=/opt/eclipse/icon.xpm<br />
Terminal=false</blockquote><br />
Hope this helps!paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-3163655513263674362011-11-22T14:27:00.000-06:002011-11-22T14:27:09.116-06:00Signed and UnsignedHere are some quick scripts to sign every jar in a directory, and then unsign every jar.<br />
<br />
Sign<br />
<br />
<code>find . -name "*.jar" -exec jarsigner -keystore /path/to/your/key -storepass yourpassword '{}' yourkeystorename \;</code><br />
<br />
Unsign<br />
<br />
<code>find . -type f -iname '*.jar' -exec zip -d '{}' META-INF/*.{SF,RSA} \;</code>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-38413332986059890412011-04-19T10:48:00.002-05:002011-04-19T10:53:29.615-05:00Http Proxy ServerHow does an HTTP proxy server work? I learned a little about this recently while trying to implement one using Apache, mod_python, and Python. HTTP is a relatively simple protocol. A connection is opened to a server, and a request in the form of a string is sent. For example, to get a web page, you just send a simple get request and wait for the web page (or an error code) to be sent back to you.<br />
<br />
<code>GET /path/to/file/index.html HTTP/1.0</code><br />
<br />
However, there is no server information in this request, so how does a proxy server know what you want? After you configure your browser or other client to use a proxy, the client opens a connection to the proxy server for each request, and sends a slightly different get request for each page.<br />
<br />
<code>GET http://someserver:80/path/to/file/index.html HTTP/1.0</code><br />
<br />
Notice that this get request includes the full URL (including the server and port). This tells the proxy server which server contains the actual content. So the proxy server connects to the specified server, and pipes the appropriate content back to you. <br />
<br />
The problem I face is that I need a way to track groups of requests coming from a particular client process. For example, let's say the user has two browsers and I want a separate log file containing all the downloads made by each browser. I can't track by IP address (they are the same), I can't track by modification to the URL since most client apps don't support adding information other than the servername and port. So this leaves the authentication mechanism. Each browser will need to send a unique username, and that username will be used to track which client is making the request. For now, that's the solution I'm going with.<br />
<br />
For more information, there is a nice introduction to HTTP here:<br />
<a href="http://www.jmarshall.com/easy/http/">http://www.jmarshall.com/easy/http/</a><br />
And for even more details, look at RFC 2616<br />
<a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http://www.w3.org/Protocols/rfc2616/rfc2616.html</a><br />
<br>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-90551617864212605402011-02-03T15:19:00.003-06:002011-02-03T15:42:25.135-06:00Extend TestCase and use annotations in JUnit 4JUnit 3 required that test classes extend, directly or indirectly, the class junit.framework.TestCase, and that each test method begin with the word "test". In contrast, JUnit 4 uses @Test annotations for each test method and does not require the test class to extend junit.framework.TestCase. But what if we have some JUnit 3 and some JUnit 4 tests? JUnit 4 automatically treats classes that extend TestCase as a JUnit 3 test, and therefore ignores the @Test notation. So let's say there is a class like the following.<br /><pre><br /> public class MyTests extends TestCase<br /> {<br /> @Test<br /> public testOne()<br /> {<br /> //do stuff<br /> }<br /><br /> @Test<br /> public anotherTest()<br /> {<br /> //do stuff<br /> }<br /> }<br /></pre><br />Using JUnit 4, it would appear that both these tests are run, but actually only the first one runs. Why? Because the class extends TestCase, so JUnit 4 will handle this class using a JUnit 3 compatibility mode. This means that the @Test tag is ignored and the method names are examined for the pattern "test*". This can be fixed in two ways. The first is by removing "extends TestCase". This will cause JUnit 4 to run the test in normal mode instead of backwards compat mode.<br /><br />The second option is to use a class annotation to force the class to be treated as a JUnit 4 test case. It looks like this:<br /><pre><br /> @RunWith(JUnit4.class)<br /> public class MyTests extends TestCase<br /> {<br /> ...<br /> }<br /></pre><br />This forces JUnit 4 to locate tests using annotations instead of using the older method name convention.<br /><br />The solution using @RunWith was found in the <a href="http://tech.dir.groups.yahoo.com/group/junit/message/21472">JUnit yahoo group</a>.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com2tag:blogger.com,1999:blog-2020444133810833267.post-69124195212218965252010-02-26T14:00:00.002-06:002010-02-26T14:06:02.080-06:00No %%Pages: comment in header!After being able to print successfully for several months, I got this error message today while printing from my laptop with Fedora 10: "No %%Pages: comment in header!". I have no idea what it means, but after searching around there was a simple fix for me. From the printer properties GUI I noticed that the "Print Test Page" button was disabled. In the policies tab the printer state "enabled" box was unchecked. I checked the box to re-enable the printer, and voila, I was able to print again.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-6065806831310756792010-02-15T11:10:00.002-06:002010-02-15T11:21:06.879-06:00MojoFailureException vs. MojoExecutionExceptionThere are two types of wrapper exceptions commonly used in Maven plugins, the MojoFailureException and MojoExecutionException. It's not obvious which one is the correct one to use, so here is a simple explanation. A MojoExecutionException typically means that an unexpected and unrecoverable error happened while running the plugin. This would be something like a NullPointerException or other RuntimeException that the plugin developer did not expect and/or can not handle. It's basically a plugin crash.<br /><br />A MojoFailureException means that there was a problem in the build which the plugin detected, and the plugin is now notifying you of that failure. This would be something like a Java source file that couldn't compile. The build can not continue, but the plugin is still working normally.<br /><br />More information can be found in the <a href="http://www.sonatype.com/books/mvnref-book/reference/writing-plugins-sect-failure.html">Sonatype Maven book</a>.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-11985652546939424642010-01-06T17:31:00.002-06:002010-01-06T17:33:52.421-06:00Perl multiline search/replaceQuick perl program to do a multi-line search and replace.<br /><blockquote><br />open(INPUT,"<$ARGV[0]") or die;<br />$/ = "%%\n";<br /><br />$theFile=<INPUT>;<br />#print $theFile;<br />close(INPUT);<br /><br />#$theFile =~ s# \<optional\>true\<\/optional\>\n##ig ;<br />$theFile =~ s# \<\/dependency\># \<optional\>true\<\/optional\>\n \<\/dependency\>#ig;<br /><br />open(OUTPUT,">$ARGV[1]") or die;<br />print(OUTPUT $theFile);<br />close(OUTPUT);<br /><br /></blockquote>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-40370553284735566552009-12-03T16:46:00.004-06:002010-02-26T14:10:57.108-06:00Rsync with central Maven repositoryFor reference here is the rsync command to copy files from the central Maven repository.<br /><br /><blockquote>rsync -v -t -l -r mirrors.ibiblio.org::maven2/subdir /local/path<br /></blockquote>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-85026785306090419542009-11-22T17:17:00.002-06:002009-11-22T17:29:40.133-06:00XUbuntu 9.10I have an old Fujitsu laptop (pentium 3, 256 MB RAM, 20 GB disk) that has gone through a few iterations of various linux distributions. I used XUbuntu 7.04 for a while and it was ok, but it was just too slow. The tricky part is that it has an old Cisco Aironet 360 wireless adapter which only works with a 2.4 kernel (or at least I thought this was the case). I tried out Damn Small Linux, and it's great for what it does, but for my laptop I couldn't get the wireless card or the touchpad working. I tried out various combinations of older versions of Fedora and Ubuntu, but they were always either painfully slow or unable to handle the old wireless card. Fedora 12 was unbearably slow.<br /><br />I didn't think a recent version of XUbuntu would work, because in the past I was only able to get the wireless working when using a 2.4 kernel. But I'm really glad I gave it a try anyway, because it works! XUbuntu 9.10 was able to find and configure everything on the laptop right away, including my old wireless card. The install process is improved since previous versions, the boot time is faster, and the gnome interface seems more responsive all around.<br /><br />Big thanks to the XUbuntu guys for all their work on this. Now I have an extra working laptop again!paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-55103580008024670602009-07-24T09:35:00.003-05:002009-07-24T09:43:14.614-05:00Ant refid resolution 1.5, 1.6, 1.7I noticed some behaviour changes in Ant related to refids. In Ant 1.5.x a fileset refid has to be defined before being used. So for example if I define a fileset in target "a" and then call target "b" which uses the refid, the build will fail because target "a" was never run and never set up the refid.<br /><br />This behaviour changed in Ant 1.6.x, so that Ant tries to be more intelligent and automatically searches for refids that are defined in the build, but not necessarily run. So in the above example, Ant silently succeeds and the refid is found in target "a" even though that target was never actually called. This seems like strange behaviour to me, because it's not well documented and seems like it could produce some tricky bugs. I guess the Ant developers also thought this behaviour was not ideal because in Ant 1.7 the same automatic refid resolution works but now produces a warning. I briefly tried to track down some discussion related to this in the ant developer mailing list archives, but I was unsuccessful in finding anything.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-3078535474385021142009-07-14T10:23:00.002-05:002009-07-14T10:44:38.186-05:00Recursive GreppingI recently had some need to search for certain text within files in a directory. This works with eclipse, but sometimes it can be slow and a bit limited in options. So I turned to good old grep. I wanted to exclude certain directory patterns from the search, but the problem I ran into was that the version of grep packaged with Fedora 10 and available in the yum repository is an older version (2.5.1) and does not include the "--exclude-dir" option. So I had to grab a recent copy of the <a href="http://www.gnu.org/software/grep/">source</a>. I then did a <span style="font-family: courier new;">./configure, make, make install</span> and I was good to go with version 2.5.4. The last tricky part for me was how to match multiple filename patterns using GLOB. Here is an example of the final command:<br /><br /><span style="font-family: courier new;">grep -R "apache.commons." . --include={*.xml,*.ent} --exclude-dir="output"</span>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-46441440557101735102009-06-29T13:49:00.015-05:002009-06-30T13:32:21.484-05:00Making a Sasuke (Ninja Warrior) Cliff HangerAfter watching the show Ninja Warrior on G4 for a couple years, I finally decided to build my own Ninja obstacle. I thought about what obstacle might be reasonable in effort and cost to build by myself (and with a little help from my friends) and eventually decided on a Cliff Hanger. This is one of the most well known obstacles from the show and probably one of the easiest to build.<br /><br />Here is a video of my friend practicing on the (almost) finished cliffhanger. Sorry for the low quality:<br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dz_sHqYc3B32GuiB3ev6d6zARxw_o4HfRPvaZMoMojGajZnnxtFmndwr7R1BGBiZPGQ5IDOCnmBNDQ_IM5eaw' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br />At this point, I hadn't put the higher ledges on yet, and keep in mind that I purposely built this to be low enough for my 5 year old son to use.<br /><br />I'm not at all experienced building stuff like this, and there are probably other people out there like me who might want to build there own Sasuke training equipment but aren't sure how difficult it is. So I'll try to give as detailed instructions as possible for anyone that wants to build something like this themselves. The total cost of the project was about $100, and in general I'm pretty happy with the way it came out although there are a few minor things I would change if I could do it again.<br /><br /><h3>Equipment and Materials</h3><br /><span style="font-weight: bold;">Equipment</span><br /><ul><li>Drill - Power drill with 1/4 inch wood drill bit.</li><li>Power Saw - It's possible to have all the cuts done at Home depot or wherever you buy the wood, but it requires some extra up front planning.</li><li>Power Sander - This is not absolutely necessary, but it comes in handy for sanding rough spots and fitting some of the pieces together.<br /></li><li>2 clamps - I didn't use any clamps but they would have been useful when drilling holes for some of the parts.</li><li>A sawhorse or other item to temporarily bear weight - This is another area where I improvised and just used whatever I had within reach to temporarily prop up the structure while building.</li><li>A step ladder.<br /></li></ul><span style="font-weight: bold;">Materials</span><br /><ul><li>4x8 foot 1/2 inch thick plywood - 1 @ $15 each<br /></li><li>8 foot long 2x4 standard studs - 10 @ $2 each</li><li>1/4" thick 3-1/2" long galvanized bolts with washer and nut - 8 @ .50$ each</li><li>1/4" thick 2-1/2" long galvanized bolts with washer and nut - 10 @ .50$ each</li><li>Size 12 wood screws 2-1/2" long - 1 box @ $10<br /></li><li>4 Small metal L-shaped brackets for attaching two 2x4 wood studs at a 90 degree angle. And 4 nails or screws for each bracket.<br /></li><li>Outdoor paint (optional) - 1 gallon buck @ 25$</li><li>4' long 2x2 (optional) - 2 @ $2<br /></li></ul>Before you rush out to Home Depot, you may want to think about how large (tall and wide) you want to structure to be. The cliffhanger that I built is a little low for most adults, but the lowest level is just right for my 5 year old. He is about 1-2 feet off the ground when hanging on it, so if/when he falls, he doesn't drop too far. The higher levels are out of my reach (I'm 5'11") when standing on the ground, but when hanging from them, the lower parts of the structure block your body from swinging forward. So it doesn't feel exactly like the real thing, but I don't mind because I don't plan on going to Mount Midoriyama any time soon.<br /><br />So an alternate construction plan for adults only use would be to buy 10' long 2x4s instead of 8' long. This would make the whole thing a bit taller without any need to change the design. Another option would be to use a plywood that is 10' by 4'. This will give a little more lateral distance and probably feel a little closer to the real thing.<br /><br /><h3>Getting the materials</h3>I bought most of the stuff at Home Depot over several trips as I figured out what I needed. If you have a pickup truck or a friend with a pickup, then you shouldn't have any problem bringing the stuff home. I had to tie the plywood to the top of my minivan which was a pain but it worked.<br /><br />The plywood is pretty heavy and you should have someone help you when bringing it home. You may want to cut a 6" strip of wood off the bottom of the plywood. This will make the bottom of the plywood a little higher (for more swinging room) and this piece can be used across the bottom for extra support.<br /><br />When you buy the wood you can have them make some cuts for you to save time. There are 4 upright posts and two base pieces as you can see from the picture. These don't need to be cut.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKNczmJgAb38ZpCLHZ-NUyEMO390DcFrfESqc2KFtgN5S1Ummd2k7pxuQnwRJ2jMvOt650K6doJ9n4Qp_yPuzX6Yi7KeOGwccx6VMiiTaJq1LKtWyaY2tpQ8W0jW-0J3qhWS_0BITUNuk/s1600-h/00067.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKNczmJgAb38ZpCLHZ-NUyEMO390DcFrfESqc2KFtgN5S1Ummd2k7pxuQnwRJ2jMvOt650K6doJ9n4Qp_yPuzX6Yi7KeOGwccx6VMiiTaJq1LKtWyaY2tpQ8W0jW-0J3qhWS_0BITUNuk/s320/00067.jpg" alt="" id="BLOGGER_PHOTO_ID_5352840370859657554" border="0" /></a><br />The diagonal pieces that prevent it from tipping forward or back are just 2x4s that were cut in half. So these can easily be cut before bringing them home.<br /><br />The stopper pieces that are attached to the upright posts and the base are just 6" long pieces of 2x4. Home Depot wouldn't cut shorter than 1 foot, so I had 4 1' pieces cut, and then I cut each one in half at home to make 8 6" pieces.<br /><br />The ledges used to hang on are just random lengths and can be configured however you like (different lengths, angles, etc). You should probably wait until the end of construction to make all the cuts for the ledges because you have a lot of options here.<br /><br />I used 6 1/4" galvinized (prevents corrosion) bolts 3-1/2" long to attach the upright posts to the plywood backboard. Three on each side basically evenly spaced. These seem to hold very well so I wouldn't really change anything here. When you buy the bolts, just put a 1/4" inch washer and nut on each bolt and then you know you will have the right amount of each.<br /><br />I used size 12 2-1/2" wood screws in various places. For example to hold the stoppers to the upright posts and the base posts.<br /><br />To attach the ledges to the plywood, I used 2" long 1/4" thick bolts. How many you will need really depends on how you configure the ledges. In the material list I put 10 because this should be enough to get you started.<br /><br />I spent some time sanding and painting before actually putting everything together in the hopes that my cliffhanger would last against the weather a bit longer. I've seen a couple of rains so far, and it's easy to see how the non-painted parts soak in the water. I recommend buying some outdoor paint if you are not on a strict time/cost budget. Painting was one of the more time consuming parts of the project but if you want your cliffhanger to last for more than 1 year, it's probably necessary.<br /><br />One last thing to note about the materials, my measurements were not exact. So don't worry if your cuts are not perfect, especially if you have an electric sander.<br /><br /><h3>Construction</h3><span style="font-weight: bold;"><br />Step 1 - Sanding, Painting, Cutting.</span><br /><br />The first thing I did was sanded and painted the pieces I had. Looking back, I probably didn't need to sand everything, but just removing the really rough spots is probably a good idea. I painted many of the pieces before assembling. Another option would be to just paint the whole thing after it's constructed. Painting at the beginning probably makes it a little better sealed against the elements, but it's more time consuming this way.<br /><br />As I mentioned in the materials section, you will need 8 6" pieces of 2x4 that can be used as stoppers to hold the diagonal support pieces in place. If you couldn't get these cut when you bough the wood, you will want to cut them now.<br /><br /><span style="font-weight: bold;">Step 2 - Assemble the upright posts.</span><br /><br />Lay the plywood onto two 2x4s. Line up the outside edges of the plywood with the 2x4s and then you can drill 1/4" holes for the 3-1/2" bolts. I made three evenly spaced holes for the bolts to go through two 2x4s and the plywood. This photo shows one of the bolts that holds the plywood and upright supports together.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr9elmcX51Up3z3d8psSipIKTzNn3Yv_jcwj2Cyw46DQ8xgbLD3cAGHQ5EZcWF8XMnnNGg5hDfBlkRfRv0nKpm4Ejb_Xuctls-9AEfi3Q5T0StFZP3JQYCPX69SUQe5fKc5hwNqvPUeRA/s1600-h/00092.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjr9elmcX51Up3z3d8psSipIKTzNn3Yv_jcwj2Cyw46DQ8xgbLD3cAGHQ5EZcWF8XMnnNGg5hDfBlkRfRv0nKpm4Ejb_Xuctls-9AEfi3Q5T0StFZP3JQYCPX69SUQe5fKc5hwNqvPUeRA/s320/00092.jpg" alt="" id="BLOGGER_PHOTO_ID_5352855882127034770" border="0" /></a><br />For extra support and to better hold things in place I recommend taking a small piece of the plywood or another 1/2" wide shim and put it between the two upright 2x4s at the bottom. Then bolt them together with the remaining two 3-1/2" bolts. This will help hold the 2x4s in place because they tend to warp.<br /><br />Next, attach the small 6" 2x4s to the base pieces. I used 2 2-1/2" screws and that seems to work ok.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpolZB-oyfLsqlanyHEi9thuVCp3CpNv3bzSTIg0k1qHFVFY1125k3uhDgbPES_SzMe884n18F4X-uwaaPem27vYr0utEOIi3Sf6LK_ctxqFA-TETtZoPlcCHO8Rm_Ud6nEt-tnriqXPI/s1600-h/00089.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpolZB-oyfLsqlanyHEi9thuVCp3CpNv3bzSTIg0k1qHFVFY1125k3uhDgbPES_SzMe884n18F4X-uwaaPem27vYr0utEOIi3Sf6LK_ctxqFA-TETtZoPlcCHO8Rm_Ud6nEt-tnriqXPI/s320/00089.jpg" alt="" id="BLOGGER_PHOTO_ID_5352857648644544962" border="0" /></a><br /><br /><span style="font-weight: bold;">Step 3 - Attach base to the upright posts.</span><br /><br />You will probably need help from a friend for this part, because the cliffhanger is already getting heavy at this point. Prop the lower part of the upright posts at about a 30 degree angle. If you have a couple of sawhorses that would be good, or find a small table stepladder or something else you can use. Line up the base 2x4 so that the center is leaning against the bottom of the upright posts. Drill a thin hole and screw in the base pieces from the bottom so that they are attached to the upright posts.<br /><br />This next part is <span style="font-weight: bold;">important</span>. You should take some small metal L-shaped brackets and use them to hold together the base piece with the upright posts. I didn't do this and it caused me some problems/breakage when I tried to lift the structure upright.<br /><br />This picture shows that I didn't have the 1/2" shim or the metal L-shaped brackets, and this was the one part of my design that I really made a mistake. Because it didn't hold together well during contruction, and we had to do some fixing afterwards.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg96aTlkZpic6baNjEdwG-n1FmIBbUKJWD8fDK1_1WSy1Enzfgm3o6UxGBJWAqTSnDmrKeP4qKEPcwRNpWzYXFV2AJI5zPlHqRWR761g_ft7YEu3fXmv7hJwa1QK6oxide-4gRa8P7IhS0/s1600-h/00090.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg96aTlkZpic6baNjEdwG-n1FmIBbUKJWD8fDK1_1WSy1Enzfgm3o6UxGBJWAqTSnDmrKeP4qKEPcwRNpWzYXFV2AJI5zPlHqRWR761g_ft7YEu3fXmv7hJwa1QK6oxide-4gRa8P7IhS0/s320/00090.jpg" alt="" id="BLOGGER_PHOTO_ID_5352861664296157858" border="0" /></a><br /><br /><span style="font-weight: bold;">Step 4 - Fit the diagonal support pieces.</span><br /><br />After you attach the metal brackets, next you'll want to attach two 6" stoppers to the upright posts, and then fit the diagonal support pieces into them. Measure approximately where they will line up, and then make it a little shorter so that you can sand the diagonal pieces until they fit.<br /><br />You only need to attach the diagonal supports on one side of the cliffhanger, just the part that is currently on the bottom. These are necessary, so that the base doesn't break off of the main posts when you lift the structure upright.<br /><br />After attaching the diagonal posts on one side, you will need a friend to help push the structure upright, and then hold it up until you attach the second set of diagonal support pieces. With an electric sander you can sand the corners of the diagonal 2x4 to a point so that it fits nicely into the corner made by the stopper.<br /><br /><span style="font-weight: bold;">Step 5 - Attach ledges and decorate.</span><br /><br />The last step is to attach the ledge pieces using the 2" bolts. This step is pretty straight forward. Just get on a step ladder and drill a hole through the 2x4 or 2x2 and bolt it on.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFwK7SUU__YTjHvlXZP2t1IZiofIkD5z4piqqVJAbAo5a-uuLmq_qVF5Q9uVaqZ3pLsrBVJ_RovjjaeKjIWn8kZ3zN8dkNnRmSXru7faAl40v3e1Mq1s_GNAyJn2C2BgfnybA9DJBr_TY/s1600-h/00094.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFwK7SUU__YTjHvlXZP2t1IZiofIkD5z4piqqVJAbAo5a-uuLmq_qVF5Q9uVaqZ3pLsrBVJ_RovjjaeKjIWn8kZ3zN8dkNnRmSXru7faAl40v3e1Mq1s_GNAyJn2C2BgfnybA9DJBr_TY/s320/00094.jpg" alt="" id="BLOGGER_PHOTO_ID_5352859551741779490" border="0" /></a><br />And of course you can add a little decoration to the back just for fun.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuqsad-HG_Zok_w9vvgmHLLVknziT5nvbTqrFyuCzooJYckfdVK3dnKYI-cbnT60PAoMT_WB75UXzT1g25IzsMg4D82nCFlBajmICLdg4OMp_cqoKZfTvIKV9958qsaW7ircNebKTGgsA/s1600-h/00093.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuqsad-HG_Zok_w9vvgmHLLVknziT5nvbTqrFyuCzooJYckfdVK3dnKYI-cbnT60PAoMT_WB75UXzT1g25IzsMg4D82nCFlBajmICLdg4OMp_cqoKZfTvIKV9958qsaW7ircNebKTGgsA/s320/00093.jpg" alt="" id="BLOGGER_PHOTO_ID_5352859640992748034" border="0" /></a>Please let me know if you have any question about this project. If you build your own cliffhanger I would love to hear about it the comments section and provide some pictures!paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com1tag:blogger.com,1999:blog-2020444133810833267.post-79800444266652895702009-05-29T13:20:00.002-05:002009-05-29T13:42:03.806-05:00JPackage NonsenseI've never understood the purpose of the <a href="http://www.jpackage.org/">JPackage</a> project. As a Java developer one would think I would be in their target audience, but it really doesn't solve any problems for me, and causes many inconveniences. The goal of the project is to package java projects up into nice little upgradable rpms, but I think the java and rpm worlds are really just incompatible. I use Fedora (currently version 10) for my main development environment and I've tried using the prepackaged version of things like eclipse, but it never seems to work as well as the downloadable version.<br /><br />Just today I was having problems with an Ant build using ant version 1.6.5 (I currently have 3 different versions of Ant installed for testing). I'm getting errors with 1.6.5 that I haven't seen before about missing task definitions. So I run "ant -version" to make sure I'm pointing to the right installation and it returns version 1.7.1. That's weird! So I double check my path "which ant" and check "$ANT_HOME", both are pointing to ant 1.6.5. I end up tracking down that the ant startup script is looking for a file called "/etc/ant.conf" to use as a global configuration file. I don't remember editing this file, but I do remember past experiences with jpackage rpms that do weird stuff to my java applications. Sure enough this configuration came from an rpm and is now breaking my default ant installation.<br /><br />So the only way to fix this is to either remove the file from "/etc/ant.conf" but the next yum update will probably just put it back and break things again. Or I can hand modify my ant 1.6.5 startup script to not check for this file (very ugly).<br /><br />I decided to remove the ant rpm "yum remove ant". This fixed my ant installation, but I'll have to watch out for this in the future in case the ant rpm accidentally gets installed again.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-2223566113892235512009-03-26T11:07:00.005-05:002009-04-30T11:11:56.638-05:00Jar Manifest Attribute NamesI probably should have known this before, but I discovered today that a "." character is invalid for a jar manifest attribute <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Name-Value%20pairs%20and%20Sections">name</a>. The attribute name is limited to:<br /><br />{A-Z} | {a-z} | {0-9} | - | _ <br /><br />I tried using an attribute name of "java.version" in my jar manifest and the jar was created by the Maven build without any problem, but when the jar was used as a dependency of another project, then I got a warning about an invalid name.<br /><br />The maven jar plugin and maybe assembly plugin should probably do some regex validation while creating the jar to at least give a warning. Otherwise maven will happily create a jar with invalid manifest and you may not discover this error until it starts causing some problems in other projects. I created a <a href="http://jira.codehaus.org/browse/MSHARED-99">Jira Issue</a> about this.<br /><br>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-24250761128323160662009-01-28T11:31:00.001-06:002009-01-28T12:16:57.732-06:00Restore a deleted file from subversion.If you want to restore a deleted file from svn there are a few ways to do it, and some work better than others.<br /><br />The <a href="http://svnbook.red-bean.com/en/1.0/ch04s04.html#svn-ch-4-sect-4.3">subversion book</a> gives the basic info for restoring a file using either <span style="font-family:courier new;">merge</span> or <span style="font-family:courier new;">copy</span>. However, the method used in the example for copy didn't work for me. So let's say you delete a file "Stuff.java" in revision 100. Then you would want to restore the file, using the previous revision, into the current working directory like this.<br /><br /><span style="font-family:courier new;">svn copy -r 99 http://svn.mycompany.org/repos/myproject/Stuff.java Stuff.java</span><br /><br />My svn server didn't seem to handle the revision option correctly, and kept telling me that the file didn't exist. So an alternative syntax looks like this:<br /><br /><span style="font-family:courier new;">svn copy http://svn.mycompany.org/repos/myproject/Stuff.java@99 Stuff.java</span><br /><br />This second syntax, which I didn't see mentioned in the svn book, worked like a charm for me.<br /><br />If you don't know in which revision the file was deleted, you can use <span style="font-family:courier new;">svn log</span> in the directory to see a history of file changes.<br /><br />After you copy the deleted file, you are not quite finished. You'll still have to commit your changes. So something like <span style="font-family: courier new;">svn commit -m "Restore file Stuff.java"</span> will finish the job.<br /><br /><br>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-3566754826704284542009-01-12T14:05:00.000-06:002009-01-28T11:29:36.714-06:00RPM for Pidgin msn pecanApparently Microsoft changed something on the MSN Messenger servers today, and this was causing <a href="https://bugs.launchpad.net/ubuntu/+source/pidgin/+bug/316252">problems</a> for many people using Pidgin. One workaround is to use the modified msn plugin from <a href="http://code.google.com/p/msn-pecan/">google</a>. But I couldn't find any Fedora rpms for this. So I decided to make one.<br /><br />The rpm for Fedora 10 is <a href="http://paulgier.googlepages.com/pidgin-msn-pecan-0.0.17-1.fc10.i386.rpm">here</a>.<br />And the source rpm is <a href="http://paulgier.googlepages.com/pidgin-msn-pecan-0.0.17-1.fc10.src.rpm">here</a>.<br /><br>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-16912379394311745572008-12-18T12:18:00.002-06:002009-02-05T12:20:04.715-06:00The fogIt was a beautiful foggy day today, so I decided to take a few pictures on the way to work.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ3cmC_PfSpeTmLXtzZS7Ay4mtZdbR2KbIgMYnp2SiM9WuCHFamaGc1ZEhpEbvddpOo_1d2TTNbUC5s6-Ad_uCIs9BU4SaHzsPfEaqgYeBckJbn4Nm0jDvGqYlfRSHUXerfQv-8OaZGHM/s1600-h/00002.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ3cmC_PfSpeTmLXtzZS7Ay4mtZdbR2KbIgMYnp2SiM9WuCHFamaGc1ZEhpEbvddpOo_1d2TTNbUC5s6-Ad_uCIs9BU4SaHzsPfEaqgYeBckJbn4Nm0jDvGqYlfRSHUXerfQv-8OaZGHM/s320/00002.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5299379626712634658" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3jazO3lC3r-Kr4TVYZg7s7V8SDunx-B8aPg3vmGk4119r-i7V-K2dT71OvU4SOZeEjX0PJcwoFj5AZxzfCWBYqvU8am6AQ16d6M9ZfH305hyphenhyphenIvzi3teHzcAXGHHCPqPB6Idgqado8DpA/s1600-h/00001.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3jazO3lC3r-Kr4TVYZg7s7V8SDunx-B8aPg3vmGk4119r-i7V-K2dT71OvU4SOZeEjX0PJcwoFj5AZxzfCWBYqvU8am6AQ16d6M9ZfH305hyphenhyphenIvzi3teHzcAXGHHCPqPB6Idgqado8DpA/s320/00001.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5299379628125934082" /></a>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-52241141648465780422008-08-14T11:26:00.000-05:002008-08-14T11:35:34.862-05:00Recursively remove .svn directoriesIt seems I regularly need to remove all the .svn directories from a directory structure. It would be nice if this function to disconnect a directory structure was built into svn, but since it is not, I usually use this command from the root of the project directory structure:<br /><br /><span style="font-family: courier new;">rm -rf `find . -name .svn`</span>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-89938715902062243172008-06-05T09:36:00.000-05:002008-08-14T11:30:45.968-05:00You talk better than you foolOne of my favorite Simpson's quotes:<br /><br /><blockquote>Bart: You're going down, Homer. I'm gonna fool you!<br />Homer: You talk better than you fool.<br />Bart: I'll fool you up real nice.<br />Homer: You couldn't fool your mother on the foolingest day of your life if you had an electrified fooling machine.</blockquote>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-89019584699394287712008-03-21T10:01:00.000-05:002008-03-21T10:05:35.063-05:00Finding stuff in jarsMy coworker gave me a nice command to use when looking for certain classes in a set of jar files. This will recursively process each jar file in the current directory, and list the contents in search_jars.txt<br /><br /><span style="font-size:100%;"><span style="font-size:85%;"><span style="font-family: courier new;">find . -name \*jar -exec unzip -l {} \; > search_jars.txt</span></span><br /><br />Then you can look in search_jars to find out where class files or other stuff is coming from.<br /><br /></span>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-5372050554519840462008-02-12T15:21:00.000-06:002008-03-23T20:21:13.872-05:00Setting local maven repositoryMaven has a convenient property that can be used to set the location of the local maven repository. It can be passed as a parameter using the "-D" option.<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;">mvn -Dmaven.repo.local=/home/path/to/local/repo install</span></span>paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-20418730882421676642008-01-15T13:27:00.000-06:002008-01-15T13:56:32.554-06:00Accented Characters in LinuxI normally use Fedora for my day to day work, and I wanted to be able to type accented characters, specifically French accent marks like in the words "très" and "ça va". It took me a good bit of searching before I found an easy way to do this so I thought I could share the information here.<br /><br />I found this page on <a href="http://wiki.linuxquestions.org/wiki/Accented_Characters">Accented_Characters</a>, but the "Alt Gr" didn't seem to work for me. Eventually I found a hint on the ubuntu forums and was able to find the Fedora equivalent. <br /><br />So here is the solution (using Fedora 7):<br /><br />Go to System -> Preferences -> Hardware -> Keyboard, select the Layout Options tab, expand "Compose key position" and choose your preference (I chose the right Alt-key). This seems to make the compose key into the "Alt Gr" key on the other page I found.<br /><br />So now things like (Alt + `, e) will give me è. Have a look at the <a href="http://en.wikipedia.org/wiki/Compose_key">wikipedia</a> entry for additional information on using the compose key.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0tag:blogger.com,1999:blog-2020444133810833267.post-55803369379266866012007-05-10T14:14:00.000-05:002007-05-10T14:17:33.247-05:00First PostMy last name is gier, this is a site where I post stuff I'm thinking about, the end.paulhttp://www.blogger.com/profile/01596450968333983497noreply@blogger.com0