tag:blogger.com,1999:blog-69052254023854831552024-03-13T21:16:20.878+00:00Trumphurst Technical NotesTechy notes for Linux, Windows and AndroidNikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.comBlogger31125tag:blogger.com,1999:blog-6905225402385483155.post-2492539004347360422018-05-27T17:50:00.001+01:002018-06-06T19:57:56.460+01:00Making an A frame for a Sailfish 18I saw some pictures of the aluminium angle A frames on Marika and Brown Owl, and decided to try to make one, in order to make raising the mast quicker, safer and easier.<br />
<br />
<div style="text-align: center;">
A frame ready to hoist mast:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw_wAK1W9_C1YqQHkeoLoWnZyjjj_MQOB4Zgna-KRYZspkLY8yzj4qvRY0qZJeucdDb83cBnfWE9rxJoRkm5OxL4-vcKvY2TTGwx9PHWbNE_5qguZy43REfw9fdUPx_1QRzBoTVHA15Qg/s1600/IMG_2782.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw_wAK1W9_C1YqQHkeoLoWnZyjjj_MQOB4Zgna-KRYZspkLY8yzj4qvRY0qZJeucdDb83cBnfWE9rxJoRkm5OxL4-vcKvY2TTGwx9PHWbNE_5qguZy43REfw9fdUPx_1QRzBoTVHA15Qg/s320/IMG_2782.JPG" width="320" /></a></div>
<br />
The frame itself is made from 25mm aluminium angle, 3mm thick. The brackets are cut from 75mm x 3mm angle, and the bit at the bow that fits over the existing bow fitting is 4" x 1/4" angle.<br />
<br />
The bracket fits under the back mounting of the pulpit. Unlike the other versions, I made the brackets to be as near in line fore and aft as possible.<br />
<br />
<div style="text-align: center;">
Photos of one of the brackets loose on the deck, from different angles:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHahqIchg3c6wFDmcKoi_Cs-EVeYc0CxipN5_HCoRsQ93VsQBGNCoF7QToRYTsBjAkpBa27MtOBnBCLVxn916y3ZOacCf4rCuifZwzRQTqT6BNCmKxAX3RmCHDbqWqUV1yvs8K1NCNC1g/s1600/IMG_2729.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHahqIchg3c6wFDmcKoi_Cs-EVeYc0CxipN5_HCoRsQ93VsQBGNCoF7QToRYTsBjAkpBa27MtOBnBCLVxn916y3ZOacCf4rCuifZwzRQTqT6BNCmKxAX3RmCHDbqWqUV1yvs8K1NCNC1g/s320/IMG_2729.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYUu60sDWK27N2QRpTedW4YVudm5JQVaEYiVGXRe2wJ7pICIers9u8XTiR1K-Ldv6dAbyvk0XzqL_hioCdjWFB5ZywOgeobFJGHIQocqTaaXFFrymO-ibJq6pc8q74MU5BlGt4JDkHjAU/s1600/IMG_2730.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYUu60sDWK27N2QRpTedW4YVudm5JQVaEYiVGXRe2wJ7pICIers9u8XTiR1K-Ldv6dAbyvk0XzqL_hioCdjWFB5ZywOgeobFJGHIQocqTaaXFFrymO-ibJq6pc8q74MU5BlGt4JDkHjAU/s320/IMG_2730.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrMHGj-JekOwwW8C10IyX1tRXI6829H-Cz5eb2-fFtr2umegoDAkI9dWYM5pLaUWLJvsdNNUk0ELG567m6EoVZiSsGf35vP869e72rl5B231SHvy-mhH2rQE3PBYXk7VJQhXkmv-_YyiQ/s1600/IMG_2731.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrMHGj-JekOwwW8C10IyX1tRXI6829H-Cz5eb2-fFtr2umegoDAkI9dWYM5pLaUWLJvsdNNUk0ELG567m6EoVZiSsGf35vP869e72rl5B231SHvy-mhH2rQE3PBYXk7VJQhXkmv-_YyiQ/s320/IMG_2731.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
The starboard bracket after fitting:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKRGLXiOCHjwiBkv-mX7Yau4voxboRlSch3aa37Pd7iGQrl_ZwSilk2TADxoMFm9IPqN6nEKc7wB1_uZXdLIXI6vk679ijsw1unsEXtPPbadcipUJJownZJnqQZ5eT0qp7LxNqohJp_Os/s1600/IMG_2732.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKRGLXiOCHjwiBkv-mX7Yau4voxboRlSch3aa37Pd7iGQrl_ZwSilk2TADxoMFm9IPqN6nEKc7wB1_uZXdLIXI6vk679ijsw1unsEXtPPbadcipUJJownZJnqQZ5eT0qp7LxNqohJp_Os/s320/IMG_2732.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVyji73UtA-RgIePNhyphenhyphenea4F9Omcyizy1z8jkLTBKwI38kW91oNPfZPAR9vbZOeB0_X8-AVJcM5gQ9NnYGek1TJEmmSzDuwxsre6gPKIQUsFgaKRUn5ikwxQryPfo-SyKCHlmEjsmtpTjc/s1600/IMG_2733.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVyji73UtA-RgIePNhyphenhyphenea4F9Omcyizy1z8jkLTBKwI38kW91oNPfZPAR9vbZOeB0_X8-AVJcM5gQ9NnYGek1TJEmmSzDuwxsre6gPKIQUsFgaKRUn5ikwxQryPfo-SyKCHlmEjsmtpTjc/s320/IMG_2733.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDb5Zpd_WWfn2w65xdzgVjE_CprtJEPkLlKdpqIs6g3LLEaROIyJGugJ9d23P41uosJ0dWwKYGHLkrzrFu05oDFzjod0nNDkAluT3mc-1V8QRMuOqqF3c362w1jpKsXZ2PfTH_lay1ceI/s1600/IMG_2734.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDb5Zpd_WWfn2w65xdzgVjE_CprtJEPkLlKdpqIs6g3LLEaROIyJGugJ9d23P41uosJ0dWwKYGHLkrzrFu05oDFzjod0nNDkAluT3mc-1V8QRMuOqqF3c362w1jpKsXZ2PfTH_lay1ceI/s320/IMG_2734.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Notice how the frame angle iron has been bent in a vice, so that it is parallel to the bracket - otherwise a lot of slop has to be left in the fixing bolt to allow the frame to rotate. This was arrived at late in the process - I should probably have bent it a bit more, so the fixing bolt could have been shorter.<br />
<br />
There is another, smaller bend in the middle of the frame, to make it clear the pulpit easily.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
The part that fits over the existing bow fitting:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnvT9_7lqKJk6wnDMV5Pho2eB2cI_BDpEbQP1ToslQbSsTh4mDRaTe2zp77SQwOE2v4rhICSTVKg3unleZYzBBgGZJaL4Q-5pvt54YRSNmgVJz2-KccPywmh_XPX3ehHgk3ykTL7zYUxo/s1600/IMG_2787.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnvT9_7lqKJk6wnDMV5Pho2eB2cI_BDpEbQP1ToslQbSsTh4mDRaTe2zp77SQwOE2v4rhICSTVKg3unleZYzBBgGZJaL4Q-5pvt54YRSNmgVJz2-KccPywmh_XPX3ehHgk3ykTL7zYUxo/s320/IMG_2787.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-qkF8h1LHZW83p9PHbX9bDhdjrXzZ0gyEDXIqdBogVze_LRANO0Ukrzm9JDvHRo2VEf_0s56zWxFAhSi46u642ywWNuPPiQhnxERvx21dIUiJzda7fGFCpVWv3ulN81gKd-DRpTLjVM4/s1600/IMG_2788.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-qkF8h1LHZW83p9PHbX9bDhdjrXzZ0gyEDXIqdBogVze_LRANO0Ukrzm9JDvHRo2VEf_0s56zWxFAhSi46u642ywWNuPPiQhnxERvx21dIUiJzda7fGFCpVWv3ulN81gKd-DRpTLjVM4/s320/IMG_2788.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I used 2 pieces of 4" angle - I initially tried to use 3", but it wasn't tall enough. With 4" it completely covers the bow fitting, and extends the full width of the bow, even on the port side (which is larger, because the existing bow fitting is offset to the starboard side).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I made it stick out at the front so I could move the existing bow roller onto the new fitting (although I think I will get a wider roller at some point, as I find the anchor line jumps off the roller onto the nuts). </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_sYZoax5mqHvMNAiaXebhbKNUSp0DLs_BrV_dZ8DEZbvRHCqqoN5t1_qUUI943vCUIPqLGtvMI_svwV6IbTuZ3D07CfMOH4-GL797QWfEtf0ME93lsBFD7pvOIu5FG0cx9cDA3dGtJCE/s1600/IMG_2785.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_sYZoax5mqHvMNAiaXebhbKNUSp0DLs_BrV_dZ8DEZbvRHCqqoN5t1_qUUI943vCUIPqLGtvMI_svwV6IbTuZ3D07CfMOH4-GL797QWfEtf0ME93lsBFD7pvOIu5FG0cx9cDA3dGtJCE/s320/IMG_2785.JPG" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSLHJkUnb7bewBOjEzXELVJAhIgM71SpZ0JBP5RWWjMBoJoWcKL01joCPP2jsb3PuNi9TsIJ3Lm_599BKaR2y4EtHtqnp_aUsVzNuXIR8TQbmnq4cTb_a7_yxZTNx4YXFbFK8sO0GhLm0/s1600/IMG_2786.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSLHJkUnb7bewBOjEzXELVJAhIgM71SpZ0JBP5RWWjMBoJoWcKL01joCPP2jsb3PuNi9TsIJ3Lm_599BKaR2y4EtHtqnp_aUsVzNuXIR8TQbmnq4cTb_a7_yxZTNx4YXFbFK8sO0GhLm0/s320/IMG_2786.JPG" width="240" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I used 3 10mm stainless bolts with nuts to space the sides apart, as this allows for adjustment to make it a perfect fit. I did try aluminium tubing as spacers, but found it too difficult to get them exactly the right length. The other bolts are 1 for the bow roller, 1 for the forestay attachment, 1 for the top pulleys, and 1 to hold the top pulley spacers </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I use a drop pin through the existing holes in the bow fitting to fix the frame in the down position. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
The pulley system:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk1a2HAsLCuhA03QdehmFq9tQNdxULbYUt3n-FyheK4FbVMJj9NmaGdSKGywLE7vSsIq7q7EEaqqjHb4PK3y7PijTod3_I9Vpg9Fo8xteNJIGqEO9LmO4r6I8yGhzF6shFvvLXaPUjNsY/s1600/IMG_2784.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk1a2HAsLCuhA03QdehmFq9tQNdxULbYUt3n-FyheK4FbVMJj9NmaGdSKGywLE7vSsIq7q7EEaqqjHb4PK3y7PijTod3_I9Vpg9Fo8xteNJIGqEO9LmO4r6I8yGhzF6shFvvLXaPUjNsY/s320/IMG_2784.JPG" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyLF0TllNnHDlHYyK4g-cYmb3ixbBqfjSgNdAUOy3CYubnd5G1KAYBLHlLtV8CVBeL3gFVQe5ShsBNjqvRnWfMGnEMgpD1nPpjIyQ74PQg5OvpVKjPoWOcCi3ulR8DBqzmLSBh8TxqmBM/s1600/IMG_2783.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyLF0TllNnHDlHYyK4g-cYmb3ixbBqfjSgNdAUOy3CYubnd5G1KAYBLHlLtV8CVBeL3gFVQe5ShsBNjqvRnWfMGnEMgpD1nPpjIyQ74PQg5OvpVKjPoWOcCi3ulR8DBqzmLSBh8TxqmBM/s320/IMG_2783.JPG" width="240" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
I bought the pulley wheels on eBay - there is a vendor who obviously makes them any size to order. The lower pulley replaces the old bow roller. Offcuts of aluminium act as spacers, and stop the line jumping off the wheels. The right most bit of rope is the fixed end, and covers a nut which holds the axle bolt in place. The head of the bolt has been cut off, so it does not stick out either side of the old bow fitting. I cut a screwdriver slot in it instead, so I could hold it steady while tightening the nut against the bow fitting.<br />
<br />
<div style="text-align: center;">
Triangle holding mast steadying line:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEillMJQY8DC3aTgxrFMYjUa_ucHK1T2cLktypmC7HTGlkvc1dznDJ-2tIO5MfjKj_u9HLz5_pNnf8-kFoMp1dDnr_0ZaBtkhbEK5BlO8vw2bL9N6O8sysDEE2kcuHyQQ9GpgOt5FRZb7Fc/s1600/IMG_20180606_124209.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEillMJQY8DC3aTgxrFMYjUa_ucHK1T2cLktypmC7HTGlkvc1dznDJ-2tIO5MfjKj_u9HLz5_pNnf8-kFoMp1dDnr_0ZaBtkhbEK5BlO8vw2bL9N6O8sysDEE2kcuHyQQ9GpgOt5FRZb7Fc/s320/IMG_20180606_124209.jpg" width="320" /></a></div>
<br />
<br />
In addition to the teak block I have put under the tabernacle (so the mast can sit horizontal without cracking the hatch), I have added a couple of triangles of aluminium fixed to the cabin top handrail. These hold shackles which line up exactly with the drop pin which holds the mast in the tabernacle. Pre-stretched 6mm halyard line goes from these to the mast to hold it steady while raising and lowering. Because it's line rather than wire, it does allow the mast to move from side to side a little, but it can't fall sideways. I leave these lines, and the stays, connected all the time.<br />
<br />
I also re-routed the jib furling line through a pulley and fairlead attached to the A frame, so the length doesn't change when the mast goes up and down.<br />
<br />
I keep the foot of the forestay permanently attached to the A frame, so raising the mast only involves rolling it back, attaching the top of the forestay, rolling it back some more (which pulls the A frame to the position shown in the photo), attaching the foot, pulling the A frame raising line (helping the mast up a bit with the other hand to start with), cleating it off, and inserting the drop pin in the bow fitting. Oh, and tightening the stays.<br />
<br />
The combination of the A frame, replacing a couple of shackles with clip shackles, and replacing the bolt which used to hold the mast foot with a drop pin, has cut time to launch by about 10-15 minutes.<br />
<br />
If you have a Sailfish, or are thinking of buying one, can I heartily recommend the <a href="https://sites.google.com/site/sailfishwebproject/" target="_blank">Sailfish Association</a>. A great bunch of people, with a website, forum and Facebook page full of helpful advice.<br />
<br />
<br />Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-28404601932565329412018-01-19T18:23:00.003+00:002018-01-19T18:23:39.583+00:00Showing progress of BackupPC backup while it is happeningI have just finished upgrading my central linux gateway box from ClearOs 6 to 7. I took the opportunity to do a complete rebuild, and evaluate what apps I run on it.<br />
<br />
I discovered BackupPC is a free option in the ClearOs Marketplace, so decided to try it, as the application I used before, CrashPlan, is no longer free.<br />
<br />
It is quite handy, once you have understood how to configure it. I now have it set up to backup the gateway box itself, plus all my PCs. It keeps 3 weeks backups of essential files on a twice-daily basis, so I should be able to recover any version of any file for any day up to 3 weeks ago.<br />
<br />
While setting it up, I wanted to monitor the progress of my initial backups, to make sure they were doing what I wanted. Unfortunately, BackupPC does not support this out of the box. The backup log is kept in a compressed file, in a slightly non-standard format.<br />
<br />
However, with the aid of a little research, I found the file was just missing the gzip header, so was able to devise a shell script which would show me the log output (almost) as it happened.<br />
<br />
Here is the script - call it with the name of the host being backed up, and it will tail the log file continuously.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#! /bin/bash</span><br />
<span style="font-family: Courier New, Courier, monospace;"># Show progress of BackupPC backup</span><br />
<span style="font-family: Courier New, Courier, monospace;">cd /var/lib/BackupPC/pc/$1</span><br />
<span style="font-family: Courier New, Courier, monospace;">(printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" ; tail -f -c+0 XferLOG.z) | gzip -dc | tail -f</span><br />
<div>
<br /></div>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-88226675411485818622017-10-25T13:55:00.000+01:002017-10-25T13:55:55.735+01:00Xamarin cross platform apps for phones, etc.I am starting to develop an app to run on phones and tablets, and, as I am familiar with C#, I decided to try Xamarin.<br />
<br />
It is an excellent environment, but full of pitfalls for the unwary.<br />
<br />
I installed Xamarin as part of Visual Studio 2017 Community Edition (which is free).<br />
<br />
Unfortunately creating a new Xamarin project leaves you with a pile of NuGet packages, many of which are out of date, and some of which are installed in multiple versions.<br />
<br />
Attempting to run the automatic update on all of them results in a cryptic error message.<br />
<br />
<i>You are trying to install this package into a project that targets 'MonoAndroid,Version=v7.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. </i><br />
<br />
It appears that the versions of the Android NuGet packages you have to use depend on the version of the Android SDK you are targeting. Plus, as supplied, VS 2017 does not include an Android SDK which matches the latest NuGet packages.<br />
<br />
There are 2 answers.<br />
<br />
Either:<br />
<br />
Upgrade your Visual Studio to the latest version, then go into Tools/Android/SDK Manager and update everything. Exit (it has probably updated itself) and re-enter. Repeat until all is up to date. Then make sure you have downloaded the latest SDK Platform. (You need to have all the SDK platforms between your Minimum Android Version and your Target Android Version, apparently.) Finally, adjust your Target Android Platform in your Android project properties, Application and Android Manifest tags, to the latest version. I understand it is best to select a specific version, rather than "Use latest".<br />
<br />
Or:<br />
<br />
Find the version of the SDK you are targeting, and upgrade all the Android packages individually by hand to the same major version number.
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-9939041455206362162015-07-22T18:14:00.001+01:002015-07-22T18:14:46.786+01:00Setting up ClearOS as a Google Cloud Print server<p>I have ClearOs 6 running 24/7 as my main Internet-facing router, providing firewalling and routing for my LAN.</p>
<p>I also have a number of Android devices, and it has always annoyed me that Google Cloud Printing seemed to require a Windows PC switched on.</p>
<p>Some Googling revealed that a Linux CUPS server can be made to share its printers with Google Cloud Print. so I decided to try to set this up.</p>
<p>First, I installed the Advanced Print Server into ClearOs, from its Marketplace (it's free).</p>
<p>Then I set up my printer by following the instructions.</p>
<p>Then I logged on to the server as root, using putty.</p>
<p>I downloaded cloudprint from <a href="https://github.com/armooo/cloudprint" target="_blank">https://github.com/armooo/cloudprint</a>, and unzipped it to /usr/share/cloudprint.</p>
<p>I installed the packages it needs (mostly worked out by trial and error)</p>
<p style="font-family: Courier New, Courier, monospace;">yum install python python-pip gcc python-devel cups-devel</p>
<p style="font-family: Courier New, Courier, monospace;">pip install pycups argparse cloudprint[daemon]</p>
<p style="font-family: Courier New, Courier, monospace;">pip install --upgrade cloudprint[daemon]</p>
<p style="font-family: Courier New, Courier, monospace;">cloudprint</p>
<p>(The square brackets are typed in as shown - they aren't code for an optional argument.)</p>
<p>This gave me a url to put into a web browser to add the printer to my Google Cloud.</p>
<p>In order to have this run automatically, in daemon mode, at startup, I added</p>
<p style="font-family: Courier New, Courier, monospace;"></p>
<p style="font-family: Courier New, Courier, monospace;">cloudprint -d</p>
<p>to <span style="font-family: Courier New, Courier, monospace;">/etc/rc.d/rc.local </span></p>
<p>That was pretty much it (aside from all the messing about finding out what was needed). Note that I did not do everything in one go, the way I have documented it, just installed each bit I needed when I found out what I had didn't work.</p>
<p>Hope this helps anyone else wanting to do it</p>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com2tag:blogger.com,1999:blog-6905225402385483155.post-25889013032679904622015-07-09T15:51:00.001+01:002015-11-09T16:58:41.236+00:00<p>My accounting software is now available for download at <a href="http://www.trumphurst.com/accounts.php" target="_blank">http://www.trumphurst.com/accounts.php</a>.</p>
<p>It is now Open Source on <a href="https://github.com/nikkilocke/AccountServer" target="_blank">GitHub</a>.</p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-79108718858652798562015-06-18T18:54:00.001+01:002015-06-18T18:54:16.028+01:00Free Accounting SoftwareI have continued to work on my accounting software, while using it in my business and for my personal accounts (in separate databases).<br />
<br />
I have added a number of new functions:<br />
<br />
<ul>
<li>Import statements from QIF files</li>
<li>Copy and paste statement data from bank web pages</li>
<li>Investments (shares, unit trusts, etc.)</li>
<li>Import data from Quicken</li>
</ul>
<div>
I'm really keen to get some more beta testers - anyone running Windows or Linux want to try a free small business accounting or personal package to run on their own computer, but which they can access from any computer, phone or tablet?</div>
<div>
<br /></div>
<div>
<br /></div>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-55271326337039368472015-04-09T09:59:00.000+01:002015-04-09T09:59:55.076+01:00Quick Books replacementI knew it was a while since I had posted anything on here, but I didn't realize how long! Comes of being too busy, I guess.<br />
<br />
In my small business, I have been using Quick Books for years. Although when I started the business I had been working for an accounting software company, I still chose Quick books because it was simple and easy to use - no remembering obscure account codes or customer numbers, everything works by name.<br />
<br />
Since upgrading to Windows 8, Quick Books has become significantly less functional - none of the pages that use the Internet Explorer web control work any more - they just come out blank. However, it is no longer possible to upgrade or buy Quick books - you have to subscribe to a web service instead.<br />
<br />
Doing this was just not worthwhile for a small business like mine, so I had a look at alternatives. Unfortunately, none of the alternatives I could find would import my existing Quick Books data.
As I know a lot about accounting software, and figured there would be lots of people in the same position as me, I decided I should write my own.<br />
<br />
I have just completed a beta test version, which has the following features:
<br />
<br />
<ul>
<li>Imports data exported from Quick Books. Journals are exported using a Quick Books report. The only limitation is that all sub-accounts must have unique names, as Quick Books does not distinguish between sub-accounts and main accounts in its journal report.</li>
<li>Does all the basic accounting tasks:</li>
<ul>
<li>Sales invoices, credit notes, payments</li>
<li>Customer maintenance</li>
<li>Product maintenance</li>
<li>Optional Days:Hours:Minutes or Hours:Minutes units on product quantities, to make life easier for people like me who do hourly billing.</li>
<li>Purchase invoices, credit notes and payments</li>
<li>Supplier maintenance</li>
<li>VAT</li>
<li>Banking, cheques, deposits, transfers, reconcile</li>
<li>Name maintenance</li>
<li>Accounting, journals, VAT return</li>
<li>Reminders</li>
<li>Memorised transactions</li>
<li>Import (from Quick Books, CSV or tab delimited files)</li>
<li>Data integrity check</li>
<li>Backup and restore data to json format</li>
<li>Audit trail shows details of every transaction added/deleted or changed</li>
<li>Payment history shows details of how each payment is allocated to invoices.</li>
</ul>
<li>Provides helpful features like Quick Books:</li>
<ul>
<li>Names (Customer, Supplier, Cheque payee, etc.) all either selected from drop-down lists, or use auto-complete (type part of a name, and choose the full name from a drop-down list).</li>
<li>Choosing an existing name for a payment, cheque, journal, etc. automatically populates the form with whatever values were used last time.</li>
</ul>
<li>Uses either SQLite or MySQL database (set in a configuration file)</li>
<li>Runs as a Web Server (on port set in configuration file), so can be accessed by any web browser (Chrome recommended for best usability). Tablet and phone friendly, so you can use it from anywhere with access to the computer running the server.</li>
<li>Runs on Windows or Linux (uses Mono on Linux, .Net on Windows).</li>
<li>Customisable - the user interface is all in HTML/CSS/Javascript, so if you understand these you can customise the user interface however you like.</li>
</ul>
<br />
<ul></ul>
<br />
<div>
I am therefore looking for people who would like to beta test the software. You get a free copy of the software, along with updates as bugs are identified and fixed. You also get free support via email during the beta test programme. Add a comment here, or contact me via my web site <a href="http://www.trumphurst.com/" target="_blank">http://www.trumphurst.com</a>.<br /></div>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-46780433154100546562013-03-19T19:01:00.001+00:002013-03-19T19:09:31.579+00:000x8024402c the proxy server or target server names can't be resolved with Microsoft Security Essentials<p>I found the above error on a Windows XP machine, when trying to update the virus definitions.</p>
I checked the Internet Explorer proxy settings - automatically determine was not checked, and there was no proxy setting.<br />
<p>I also ran <b>proxycfg -d</b>, just to make sure.</p>
<p>This still didn't fix it.</p>
<p>In the end, I ran <a href="http://www.wireshark.org/">wireshark</a> during the update attempt. I discovered that, despite the proxy settings being turned off, MSE was still querying the dns for host name <b>wpad</b>, and downloading the proxy setting script from <b>http://wpad/wpad.dat</b>. </p>
<p>Which would have been fine, except that I had a stray CNAME record for wpad in my local DNS, that pointed to my local webserver, that had a stray <b>wpad.dat</b> file in it, which set the proxy to a machine that no longer exists!</p>
<p>What was worse, the stray entry only existed in one of the two DNS servers on my network, so the problem was intermittent, depending on which DNS server Windows used for the query.</p>
<p>Once I deleted the stray DNS entry, and removed the <b>wpad.dat</b> file from my web server, it all started working.</p>
<p>The moral of the story is, if you experience the same problem, try typing <b>http://wpad/wpad.dat</b> into your web browser, and see if you get a file. If you do, open it with a text editor, and it will show you what proxy settings MSE will decide to use (even if you have told it not to)!</p>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-23965886285334444262013-01-03T17:17:00.001+00:002013-01-07T14:39:26.244+00:00Windows Vista Media Centre Program Guide disappeared on 1 Jan 2013I have had a Windows Media Centre almost since they were first invented. When I bought it, it ran Windows XP, but I "upgraded" it to Vista when Vista came out. (Although Vista had many problems, the Media Centre part was better than the XP version.)
<p>
On 1st Jan 2013, the program guide suddenly stopped working. It claimed it had downloaded the guide, but every program had "No data available" on it.
<p>
After some research on the 'Net, I discovered that the UK TV guide was downloaded from Broadcasting Data Services, and that Microsoft's agreement with them appeared to expire on 31 December 2012!
<p>
I spent a whole day investigating what to do about this. Microsoft were no help at all. I considered upgrading to Windows 8, but the Microsoft free offer of a Media Centre registration key via email doesn't work (at least, I had no reply to the request I sent a week ago).
<p>
The only obvious solution I found on the net was to use a separate program to extract the guide information from the broadcast EPG, and put it into Media Centre. To that end, I installed a program called <a href="https://sourceforge.net/projects/epgcollector/" target="_blank">EPG Collector</a> from SourceForge, installed it, and got it working. Except that it couldn't put the data into Media Centre, with the error message "Could not load file or assembly 'mcepg, Version=6.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'".
<p>
Further research, and a posting to the <a href="https://sourceforge.net/projects/epgcollector/forums/forum/1125946/topic/6546061/index/page/1" target="_blank">relevant forum</a>, suggested I install something called the Microsoft TV Pack, an upgrade to Media Centre - this does not seem to be available from Microsoft, but I found it at <a href="http://digiex.net/guides-reviews/guides-tutorials/media-guides/699-windows-media-center-tv-pack-2008-download-installation-guide.html" target="_blank">http://digiex.net/guides-reviews/guides-tutorials/media-guides/699-windows-media-center-tv-pack-2008-download-installation-guide.html</a>. I downloaded it, and the PlayReady PC Runtime (also from Microsoft, and linked from the same page), and installed them both.
<p>
I restarted the PC, and Media Centre - all my TV settings had gone! (This is normal, I think, as TV Pack is a major upgrade.) I went into the option to set up TV, and it appeared to hang at the point where it should have downloaded the guide. I panicked, and did some more research - others had the same problem, but none of their solutions seemed to work. So I started it again, and left it overnight.
<p>
In the morning, success! It had probably abandoned the download, and continued - it had scanned the available TV channels, and I was able to proceed (after another delay while it tried to download guide information again).
<p>
I then laboriously went through all the channels (some of which had got guide information from somewhere, and some hadn't). I pressed the "i" button while the cursor was on a channel name in the guide, and chose "Edit Channel" (this is a new option, which only appears after you have installed TV Pack). This gave me the option to renumber the channel (for some reason Al Jazeera had joined BBC2 on channel 2!), and to set up listings for the channel. In most cases, there was an option to "Use listings from broadcaster" - which I assume gets the listings from the broadcast signal, just as a Freeview TV would. There were a few obscure channels where this was not an option, but I left those alone (I wasn't interested in any of them, and most had too weak a signal to actually get a picture).
<p>
I now have a full guide, and I am hoping I will not need to use EPG Collector after all. I have lost all my series recording settings, but they were about due for a clear out anyway.Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com3tag:blogger.com,1999:blog-6905225402385483155.post-31794785476399112102012-12-28T15:59:00.000+00:002012-12-28T16:09:05.122+00:00Making a cheap concertina blind using greenhouse shading<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9xu-HZcpWTTgxKN2ElRE9jqITIMITxBZzoe-NU41WvjioIQqp2ztVPa6Mj6BB93wqML4QbgP1GPiPloHyZWbhHpAQOWhw3Bz9bBk1ybBNu6F8i3Mkw4sjpawabBzqw0Ob84-Yo-a7sCE/s1600/IMG_20121228_121505.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9xu-HZcpWTTgxKN2ElRE9jqITIMITxBZzoe-NU41WvjioIQqp2ztVPa6Mj6BB93wqML4QbgP1GPiPloHyZWbhHpAQOWhw3Bz9bBk1ybBNu6F8i3Mkw4sjpawabBzqw0Ob84-Yo-a7sCE/s320/IMG_20121228_121505.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Vertical blind, half open</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoIBBH2JLh24wO3onLSjLHJCsO1-4fv8b3qxW5VlOafSonQT1mygS_D8wNRSuZcgVUUMLtYD5S2PkpL4XHYwHaoV2XPD7rTKXZRs0B0oUpd0MTSbYmf14i1XlNgKL-l4OlWtOsWaRFMy0/s1600/IMG_20121228_121546.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoIBBH2JLh24wO3onLSjLHJCsO1-4fv8b3qxW5VlOafSonQT1mygS_D8wNRSuZcgVUUMLtYD5S2PkpL4XHYwHaoV2XPD7rTKXZRs0B0oUpd0MTSbYmf14i1XlNgKL-l4OlWtOsWaRFMy0/s320/IMG_20121228_121546.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Roof blinds - 1 closed, 1 open</td></tr>
</tbody></table>
<br />
For Christmas, I wanted to give my wife a set of greenhouse shading blinds for her new greenhouse.<br />
<br />
However, when I priced them up, the cost was going to be over £500. I decided to make some instead.<br />
<br />
Turns out they are not difficult to do, and, as I could find no instructions on the Web, I decided to write up how to do it here on this blog.<br />
<br />
The blinds shown here can be used vertically (as in the picture above), or horizontally (on the roof). In either case the moving rail (white in the picture) always stays parallel to the top and bottom rails, due to the guide lines threaded through it.<br />
<br />
The blinds can easily be opened and closed by pulling or pushing either end of the moving rail, and will stay in any position.<br />
<h2>
</h2>
<h2>
Materials</h2>
<div>
<ul>
<li>Greenhouse shade netting</li>
<li>Strimmer line</li>
<li>Plastic electrical conduit, oval section</li>
<li>Wood strips (about 1" x 1" - 25cm x 25cm)</li>
<li>Rust proof screws (brass or stainless steel)</li>
</ul>
<h2>
Method</h2>
</div>
<div>
First measure the area to be covered. I suggest making the blinds no wider than about 4 ft (120 cm), as the electrical conduit which forms the handle to open and close the blind bends if you use longer lengths.</div>
<div>
Cut the shade netting to the width to be covered, and about one and a quarter times the length.</div>
<div>
<br /></div>
<h3>
Pleating the blind</h3>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTGgR3qL3-GAqvJ5FNyCW5_Spdmu6cdSgu9MeOPr6Y-Z8Bh-x8UzITKOImK823riZ-8pFUd6guw_hILklsC0kBYVlLmD5seV6I3N-pgp0ThAgLqM9aPDl25xG-rV13AFbzUsBl1L3AhAo/s1600/IMG_20121228_112425.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTGgR3qL3-GAqvJ5FNyCW5_Spdmu6cdSgu9MeOPr6Y-Z8Bh-x8UzITKOImK823riZ-8pFUd6guw_hILklsC0kBYVlLmD5seV6I3N-pgp0ThAgLqM9aPDl25xG-rV13AFbzUsBl1L3AhAo/s320/IMG_20121228_112425.jpg" width="240" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Using a ruler to guide the pleating</td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Using an iron on the appropriate setting for your material (nylon for shade netting - not too hot, or it will melt), fold over about an inch of one end of the blind, and iron the fold in.<br />
<br />
I used a long metal ruler about an inch wide to help me get the folds straight and the correct width.<br />
<br />
Fold and iron again, and repeat until you have pleated the full length of the blind.<br />
<br />
I found the weight of the material hanging off the ironing board tended to pull the pleats out, so I used some weights (a couple of square bottles of water in the picture) to stop this happening.<br />
<br />
Obviously you will have to unfold earlier pleats as you go, otherwise the material gets too thick and difficult to handle.<br />
<br />
The pleats do not have to be totally accurate, but it is important to make sure they are reasonable square to the edges of the material (and that the material is cut squarely).<br />
<br />
When you have finished, gather the pleats up carefully (I found starting from the middle was easiest), and tie with some pieces of string to hold them in place. Make sure the edges are all squared up.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
Make the mechanism</h3>
<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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD4t-w8JtKoNXUKo6TNkwK-3Vs1ZXsOotSwNVB0FSqsDEWTRmLryvr4lsF7gblQDv2TnVjYYPbndVJRghvX3dL0WzhsS4h4yg0OT5Dmn_m8XWPcYtB0AxGE8O2ufeTtCnuR170NlFJb8Y/s1600/IMG_20121228_114138.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD4t-w8JtKoNXUKo6TNkwK-3Vs1ZXsOotSwNVB0FSqsDEWTRmLryvr4lsF7gblQDv2TnVjYYPbndVJRghvX3dL0WzhsS4h4yg0OT5Dmn_m8XWPcYtB0AxGE8O2ufeTtCnuR170NlFJb8Y/s320/IMG_20121228_114138.jpg" width="240" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Pleated blind with top rail threaded</td></tr>
</tbody></table>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
Cut 2 pieces of the wood the same width as the blind, and 1 piece of the electrical conduit.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_8ECcEYRUWAN-Td1m5ROHrpTKKa1PGOuIiMlDSTa9DZMV0chxYJcDRe3Ite0R_q_MfIz7KiJ57qqrfGWfuv_NnY8fK6OECTpO-zG8NJ-KG3rSPvrMECjjS7eHrp93eV8iMvFiEv0axwU/s1600/Drilling.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="80" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_8ECcEYRUWAN-Td1m5ROHrpTKKa1PGOuIiMlDSTa9DZMV0chxYJcDRe3Ite0R_q_MfIz7KiJ57qqrfGWfuv_NnY8fK6OECTpO-zG8NJ-KG3rSPvrMECjjS7eHrp93eV8iMvFiEv0axwU/s320/Drilling.png" width="320" /></a></div>
<br />
Drill holes for the strimmer cord - one close to each end, and one in the middle. The holes in the 2 pieces of wood and the conduit should all line up. Also drill diagonal holes in the ends of each piece of wood as shown.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
Thread the blind</h3>
<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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNIZH6dTm9YR6U8JVI4mvBS8VTb1rgRCJD_StTxZOOHFjILEGGltY_gURdEM57uG3cHx_f64ZKFjHOs2ph9xiSjnLa8l9-FATWbIoeGnCpRNqpPdjez023E-G41eDBFTC5rPPnqTeuw3Q/s1600/Threading.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNIZH6dTm9YR6U8JVI4mvBS8VTb1rgRCJD_StTxZOOHFjILEGGltY_gURdEM57uG3cHx_f64ZKFjHOs2ph9xiSjnLa8l9-FATWbIoeGnCpRNqpPdjez023E-G41eDBFTC5rPPnqTeuw3Q/s320/Threading.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Threading diagram</td></tr>
</tbody></table>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
The 3 main strimmer lines should be a little longer than the drop of the blind (enough to allow plenty for knots, and a bit extra for adjustment). The 2 guide lines (the ones that go through the conduit) should be longer by the length of the conduit - best to allow a bit more for adjustment, as these lines should not be as tight as the main lines.<br />
<br />
First thread the two guide lines though the length of the conduit. Then thread the 3 main strimmer lines through the top wooden rail, the blind, the conduit and the bottom rail as shown. Tie figure eight knots in the ends.<br />
<br />
Thread the ends of the guide lines though the diagonal holes - notice that one line goes from top left, through the conduit, and down to bottom right, and the other vice versa. Again, tie them off with figure eight knots.<br />
Now fasten the blind to the top rail (I used a staple gun), and to the conduit (I used gaffer/duck/duct tape).<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjENigG1p3e1qH5Ndo7Ibss4y1V6eiBs89MeHlohbgHasOm__zVjLherQJxT_hQpu37TQG0fqJ6hOYNxxJHeqkbHJomuaaCW8m5LHNQhZLJWSrvmEkalcNym8eVeA0VSklPERVqM3RkoUs/s1600/IMG_20121228_114407.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjENigG1p3e1qH5Ndo7Ibss4y1V6eiBs89MeHlohbgHasOm__zVjLherQJxT_hQpu37TQG0fqJ6hOYNxxJHeqkbHJomuaaCW8m5LHNQhZLJWSrvmEkalcNym8eVeA0VSklPERVqM3RkoUs/s320/IMG_20121228_114407.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Detail showing guide line (blue) threaded in top rail and conduit</td></tr>
</tbody></table>
<br />
<h3>
Fit</h3>
<div>
Drill holes in the top and bottom rails for the fitting screws - the placing depends on what you are screwing them to. Fasten the top rail in place, and hold the bottom rail where it is to go. Adjust the length of the main lines so they will be quite tight (a little stretched) when the bottom rail is in place. Temporarily fasten the bottom rail, ready to adjust the guide lines. For horizontal blinds the guide lines can be quite loose, but for vertical blinds, they must be tight enough so the blind does not close under its own weight. Once you have measured and tested, undo the bottom rail and tie the knots to make the lines the right length. Professionally made blinds do not use knots, they have a small piece of metal tube with a grub screw, so you can pull the right length of line through the tube, and tighten the screw.</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<br /></div>
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com1tag:blogger.com,1999:blog-6905225402385483155.post-54811576476932901992012-10-03T16:18:00.001+01:002015-04-27T11:52:22.676+01:00Using reCAPTCHA from C++I wanted to add reCAPTCHA to some old C++ CGI code, but I couldn't find a reCAPTCHA library for C++. Neither could a few other people I saw looking.
So I wrote the following code, which I am happy to share:
<br />
<pre>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <curl/curl.h>
static ostringstream curl_result;
/* curl write callback, to fill tidy's input buffer... */
uint write_cb(char *in, uint size, uint nmemb, void *out)
{
int r = size * nmemb;
in[r] = '\0';
curl_result << in;
return(r);
}
static bool recaptcha_check_answer(const char *private_key, const char *remoteip,
const char *challenge, const char *response, std::string &error) {
if (!remoteip || !*remoteip) {
error = "For security reasons, you must pass the remote ip to reCAPTCHA";
return false;
}
//discard spam submissions
if (!challenge || !*challenge || !response || !*response) {
error = "Captcha challenge or response missing";
return false;
}
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
if(curl_global_init(CURL_GLOBAL_SSL)) {
error = "Error initialising curl library";
return false;
}
curl = curl_easy_init();
if(!curl) {
error = "Error initialising curl library";
return false;
}
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "privatekey",
CURLFORM_COPYCONTENTS, private_key,
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "remoteip",
CURLFORM_COPYCONTENTS, remoteip,
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "challenge",
CURLFORM_COPYCONTENTS, challenge,
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "response",
CURLFORM_COPYCONTENTS, response,
CURLFORM_END);
const char *surl = "https://api-verify.recaptcha.net/verify";
curl_easy_setopt(curl, CURLOPT_URL, surl);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
#ifdef SKIP_HOSTNAME_VERFICATION
/*
* If the site you're connecting to uses a different host name that what
* they have mentioned in their server certificate's commonName (or
* subjectAltName) fields, libcurl will refuse to connect. You can skip
* this check, but this will make the connection less secure.
*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
if(res && res != CURLE_RECV_ERROR)
{
std::ostringstream err;
err << "Error " << res << " contacting captcha server";
error = err.str();
return false;
}
std::string resp = curl_result.str();
std::string::size_type pos = resp.find("\n");
std::string part1 = pos == std::string::npos ? resp : resp.substr(0, pos);
if(part1 == "true")
return true;
error = pos == std::string::npos ? "Unknown captcha error" : "Captcha error:" + resp.substr(pos);
return false;
}
</pre>
This code relies on the <a href="http://curl.haxx.se/">curl</a> library to handle the communication with the reCAPTCHA server.
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com5tag:blogger.com,1999:blog-6905225402385483155.post-22334725711745306692012-09-06T13:39:00.000+01:002012-09-06T13:54:07.813+01:00Using the word breaker from Microsoft SQL Server 2005 in a stand-alone C# program<br />
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
I have been writing a program which will query a full text search index on Microsoft SQL Server 2005. The data being indexed are large blobs of text (multiple lines).</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
I need to extract only those lines of text which contain the search words for display with the results.</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
Full Text Search uses a word breaker (IWordBreaker COM interface) and stemmer (IStemmer COM interface) to break the indexed text into words, and to enable matching of alternate word forms (e.g. "welcome" will also match "welcomes", "welcomed" and "welcoming").</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
I therefore need to use the Sql Server word breaker and stemmer to determine if each line of text from the blob matches the search string, as I believe the standard word breaker and stemmer in Windows search uses a different algorithm.</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
I thought if I copied the two dlls (infosoft and langwrbk) from a SQL Server installation to the machine on which I am running my program, and ran regsvr32 on them, they would be installed in the registry, and I would be able to use them. Unfortunately, this does not work, as regsvr32 does not add any information to the registry.</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
I therefore needed to load the COM components in the dlls "by hand". I started with <a href="http://gist.github.com/1568627">John Jeffery's code</a> to load COM components by hand. Once I had got over some 32-bit/64-bit problems (your DLL has to match the bit size of your calling code), it worked.</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
Here is the <a href="http://www.linqpad.net/">LinqPad</a> script I used to test the two interfaces, in case someone else needs to do the same thing:</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<br /></div>
<pre>
const string SqlServerDllFolder = @"C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn";
static LibraryModule langwrbk = LibraryModule.LoadModule(Path.Combine(SqlServerDllFolder, "LangWrbk.dll"));
static LibraryModule infosoft = LibraryModule.LoadModule(Path.Combine(SqlServerDllFolder, "infosoft.dll"));
static Guid stemmer = new Guid("D99F7670-7F1A-11CE-BE57-00AA0051FE20");
static Guid breaker = new Guid("173C97E2-AEBE-437C-9445-01B237ABF2F6");
void Main()
{
WordBreaker breaker = new WordBreaker();
string search;
while((search = Util.ReadLine("Query string:").Trim()) != "") {
Console.WriteLine("Original text:" + search);
foreach (string word in breaker.Search(search)) {
Console.WriteLine(word);
}
}
}
// COM Interface to Microsoft word breaker and stemmer
[Flags]
public enum WORDREP_BREAK_TYPE {
WORDREP_BREAK_EOW = 0,
WORDREP_BREAK_EOS = 1,
WORDREP_BREAK_EOP = 2,
WORDREP_BREAK_EOC = 3
}
[ComImport]
[Guid("CC907054-C058-101A-B554-08002B33B0E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IWordSink {
void PutWord([MarshalAs(UnmanagedType.U4)] int cwc,
[MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf,
[MarshalAs(UnmanagedType.U4)] int cwcSrcLen,
[MarshalAs(UnmanagedType.U4)] int cwcSrcPos);
void PutAltWord([MarshalAs(UnmanagedType.U4)] int cwc,
[MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf,
[MarshalAs(UnmanagedType.U4)] int cwcSrcLen,
[MarshalAs(UnmanagedType.U4)] int cwcSrcPos);
void StartAltPhrase();
void EndAltPhrase();
void PutBreak(WORDREP_BREAK_TYPE breakType);
}
[ComImport]
[Guid("CC906FF0-C058-101A-B554-08002B33B0E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPhraseSink {
void PutSmallPhrase([MarshalAs(UnmanagedType.LPWStr)] string pwcNoun,
[MarshalAs(UnmanagedType.U4)] int cwcNoun,
[MarshalAs(UnmanagedType.LPWStr)] string pwcModifier,
[MarshalAs(UnmanagedType.U4)] int cwcModifier,
[MarshalAs(UnmanagedType.U4)] int ulAttachmentType);
void PutPhrase([MarshalAs(UnmanagedType.LPWStr)] string pwcPhrase,
[MarshalAs(UnmanagedType.U4)] int cwcPhrase);
}
[ComImport]
[Guid("fe77c330-7f42-11ce-be57-00aa0051fe20")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IWordFormSink {
void PutAltWord([MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf, [MarshalAs(UnmanagedType.U4)] int cwc);
void PutWord([MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf, [MarshalAs(UnmanagedType.U4)] int cwc);
}
[StructLayout(LayoutKind.Sequential)]
public struct TEXT_SOURCE {
[MarshalAs(UnmanagedType.FunctionPtr)]
public delFillTextBuffer pfnFillTextBuffer;
[MarshalAs(UnmanagedType.LPWStr)]
public string awcBuffer;
[MarshalAs(UnmanagedType.U4)]
public int iEnd;
[MarshalAs(UnmanagedType.U4)]
public int iCur;
}
// used to fill the buffer for TEXT_SOURCE
public delegate uint delFillTextBuffer([MarshalAs(UnmanagedType.Struct)]
ref TEXT_SOURCE pTextSource);
[ComImport]
[Guid("D53552C8-77E3-101A-B552-08002B33B0E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IWordBreaker {
void Init([MarshalAs(UnmanagedType.Bool)] bool fQuery,
[MarshalAs(UnmanagedType.U4)] int maxTokenSize,
[MarshalAs(UnmanagedType.Bool)] out bool pfLicense);
void BreakText([MarshalAs(UnmanagedType.Struct)] ref TEXT_SOURCE pTextSource,
[MarshalAs(UnmanagedType.Interface)] IWordSink pWordSink,
[MarshalAs(UnmanagedType.Interface)] IPhraseSink pPhraseSink);
void GetLicenseToUse([MarshalAs(UnmanagedType.LPWStr)] out string ppwcsLicense);
}
[ComImport]
[Guid("EFBAF140-7F42-11CE-BE57-00AA0051FE20")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStemmer {
void Init([MarshalAs(UnmanagedType.U4)] int ulMaxTokenSize, [MarshalAs(UnmanagedType.Bool)] out bool pfLicense);
void GenerateWordForms([MarshalAs(UnmanagedType.LPWStr)] string pwcInBuf,
[MarshalAs(UnmanagedType.U4)] int cwc,
[MarshalAs(UnmanagedType.Interface)] IWordFormSink pStemSink);
void GetLicenseToUse([MarshalAs(UnmanagedType.LPWStr)] out string ppwcsLicense);
}
// Word breaker to break a line of text into words, stem them,
// and return a HashSet of all the words and stems
public class WordBreaker : IWordSink, IWordFormSink {
IWordBreaker wordBreaker;
HashSet<string> words; // Words to search for
IStemmer istm;
public WordBreaker() {
wordBreaker = (IWordBreaker)ComHelper.CreateInstance(langwrbk, breaker);
bool pfLicense = true;
wordBreaker.Init(true, 1000, out pfLicense);
istm = (IStemmer)ComHelper.CreateInstance(infosoft, stemmer);
pfLicense = true;
istm.Init(1000, out pfLicense);
}
public HashSet<string> Search(string text) {
words = new HashSet<string>();
TEXT_SOURCE pTextSource = new TEXT_SOURCE();
pTextSource.pfnFillTextBuffer = new delFillTextBuffer(pfnFillTextBuffer);
pTextSource.awcBuffer = text.ToLower();
pTextSource.iCur = 0;
pTextSource.iEnd = text.Length;
wordBreaker.BreakText(ref pTextSource, (IWordSink)this, null);
return words;
}
#region IWordFormSink Members
public void PutAltWord(string pwcInBuf, int cwc) {
words.Add(pwcInBuf.Substring(0, cwc));
}
public void PutWord(string pwcInBuf, int cwc) {
words.Add(pwcInBuf.Substring(0, cwc));
}
#endregion
#region IWordSink Members
public void PutWord(int cwc, string pwcInBuf, int cwcSrcLen, int cwcSrcPos) {
istm.GenerateWordForms(pwcInBuf.Substring(0, cwc), cwc, this);
}
public void PutAltWord(int cwc, string pwcInBuf, int cwcSrcLen, int cwcSrcPos) {
}
public void StartAltPhrase() {
}
public void EndAltPhrase() {
}
public void PutBreak(WORDREP_BREAK_TYPE breakType) {
}
#endregion
}
static uint pfnFillTextBuffer(ref TEXT_SOURCE pTextSource) {
// return WBREAK_E_END_OF_TEXT
return 0x80041780;
}
// Code from https://gist.github.com/1568627
// By John Jeffery
static class ComHelper
{
private delegate int DllGetClassObject(ref Guid clsid, ref Guid iid, [Out, MarshalAs(UnmanagedType.Interface)] out IClassFactory classFactory);
public static object CreateInstance(LibraryModule libraryModule, Guid clsid)
{
var classFactory = GetClassFactory(libraryModule, clsid);
var iid = new Guid("00000000-0000-0000-C000-000000000046"); // IUnknown
object obj;
classFactory.CreateInstance(null, ref iid, out obj);
return obj;
}
static IClassFactory GetClassFactory(LibraryModule libraryModule, Guid clsid)
{
IntPtr ptr = libraryModule.GetProcAddress("DllGetClassObject");
var callback = (DllGetClassObject) Marshal.GetDelegateForFunctionPointer(ptr, typeof (DllGetClassObject));
var classFactoryIid = new Guid("00000001-0000-0000-c000-000000000046");
IClassFactory classFactory;
var hresult = callback(ref clsid, ref classFactoryIid, out classFactory);
if (hresult != 0)
{
throw new Win32Exception(hresult, "Cannot create class factory");
}
return classFactory;
}
}
[Guid("00000001-0000-0000-c000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
interface IClassFactory
{
void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObject);
void LockServer(bool fLock);
}
class LibraryModule : IDisposable
{
private readonly IntPtr _handle;
private readonly string _filePath;
private static class Win32
{
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string lpFileName);
}
public static LibraryModule LoadModule(string filePath)
{
var libraryModule = new LibraryModule(Win32.LoadLibrary(filePath), filePath);
if (libraryModule._handle == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, "Cannot load library: " + filePath);
}
return libraryModule;
}
private LibraryModule(IntPtr handle, string filePath)
{
_filePath = filePath;
_handle = handle;
}
~LibraryModule()
{
if (_handle != IntPtr.Zero)
{
Win32.FreeLibrary(_handle);
}
}
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
Win32.FreeLibrary(_handle);
}
GC.SuppressFinalize(this);
}
public IntPtr GetProcAddress(string name)
{
IntPtr ptr = Win32.GetProcAddress(_handle, "DllGetClassObject");
if (ptr == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
string message = string.Format("Cannot find proc {0} in {1}", name, _filePath);
throw new Win32Exception(error, message);
}
return ptr;
}
public string FilePath
{
get { return _filePath; }
}
}
</pre>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-60569353285018525022012-04-23T12:29:00.000+01:002013-01-03T16:49:10.376+00:00Naerok 12" bandsaw manualI recently inherited a workshop containing a Naerok 12" bandsaw, and went looking on the Internet for a manual. Although I found manuals for similar saws, I couldn't find one for this model.<br />
<br />
However, when tidying the workshop, I found the real manual! In order to help anyone else with the same model of bandsaw, I have uploaded a scan of the manual to <a href="http://www.trumphurst.com/naerok.zip">http://www.trumphurst.com/naerok.zip</a>.<br />
<br />
<br />Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-21491533116932521702011-11-07T11:32:00.000+00:002013-04-15T19:34:39.444+01:00ACS AET62 Fingerprint Reader and C#<p>I'm currently trying to interface to an ACS AET62 Fingerprint Reader from C#. The reader comes with an SDK, along with what appear to be extensive example applications. However, the applications contain bugs which the documentation does not help to resolve. I thought I would record the bugs I have found, and how I have resolved them.<br />
</p>
<p>ABSEnroll has a ref int parameter which is returned as a pointer to an ABS_BIR structure. This is declared in the provided BSTypes.cs file as containing a header followed by 2560 bytes of data. Unfortunately, this is not correct - it contains a header followed by <u>up to</u> 2560 bytes of data. The actual length of the whole structure (including the header) is contained in the first uint Length member of the structure.<br />
</p>
<p>This kind of <i>variable length structure</i> is quite common in C++, but there is no built-in way to marshal it correctly in C#.</p>
<p>The code provided in the SDK just calls Marshal.PtrToStructure on it - this will run off the end of the allocated memory, and assign garbage to the last (should be unused) bytes of the ABS_BIR structure. That's sort of OK in a 32-bit operating system (it is unlikely to try to access memory that doesn't exist), but in a 64-bit one with properly protected memory, it may well throw an exception.</p>
<p>The correct way to marshal the structure is in two parts - first marshal the header part with Marshal.PtrToStructure, then allocate the data byte array to the length therein (first subtracting the length of the header itself), and use Marshal.Copy to copy the remainder.</p>
<pre>
ppEnrolledTemplate = new BSTypes.ABS_BIR();
BSTypes.ABS_BIR_HEADER hdr = (BSTypes.ABS_BIR_HEADER) Marshal.PtrToStructure(ptr, typeof(BSTypes.ABS_BIR_HEADER));
ppEnrolledTemplate.Header = hdr;
int hdrlen = Marshal.SizeOf(hdr);
int bodylen = (int)(hdr.Length - hdrlen);
ppEnrolledTemplate.Data = new byte[bodylen];
Marshal.Copy(new IntPtr(tset + hdrlen), ppEnrolledTemplate.Data, 0, bodylen);
</pre>
<p>ABSVerify takes a reference to an IntPtr which is represented in C++ as **ABS_BIR - it is supposed to be an array of pointers to ABS_BIR. The example code provided just passed one ABS_BIR - it used Marshal to allocate a chunk of global memory and marshal the structure into it. The resulting IntPtr was passed as the ref parameter. This is all very fine if you only want to verify a single fingerprint, but if you want to determine which of a list of fingerprints is being scanned (as I did), it is no help at all.</p>
<p>My knowledge of C++ finally allowed me to figure out what was needed. - first, allocate an array of IntPtr (one for each ABS_BIR fingerprint scan you wish to pass). Then allocate memory for each structure into its corresponding IntPtr, and use Marshal to copy the structure into the allocated memory. Finally, pass a reference to the 0'th element of the array.</p>
<p>In actual fact, there is no need to Marshal the ABS_BIR structure during Enroll or Verify - it can be treated as an opaque array of bytes (with the length of the whole thing in the first 4 bytes) - other than the length, there is no other interesting data in the ABS_BIR structure.</p>
<p>Also, during Verify, you can make a single call to allocate enough memory for all the structures you want to pass, and calculate the values of the IntPtrs to pack the data into the single block of memory.</p>
<p>I hope this helps anyone else struggling with this SDK.</p>
<p>In response to anoop's comment, here is the code I use to call verify, to see if a scan corresponds to one of the scans in the database</p>
<pre>
BSTypes.ABS_OPERATION op = operation(1);
op.Timeout = 60000;
int res;
int matching_slot = 0;
res = BSApi.ABSVerify(_conn, ref op, (ushort)_templateIndex.Length, ref _templates[0],
ref matching_slot, 0); // BSTypes.ABS_FLAG_NOTIFICATION | BSTypes.ABS_FLAG_AUTOREPEAT);
</pre>
<p>To create the _templates array, you do this<p>
<pre>
int size = Marshal.SizeOf(typeof(BSTypes.ABS_BIR));
IntPtr[] templates = new IntPtr[number_of_elements];
templates[0] = Marshal.AllocHGlobal(size * number_of_elements);
byte[] zeroes = new byte[size];
int offset = 0;
int ind = 0;
foreach (byte[] b in list_of_scan_records) {
if(ind > 0) templates[ind] = new IntPtr((int)templates[0] + offset);
offset += size;
Marshal.Copy(zeroes, 0, templates[ind], zeroes.Length);
Marshal.Copy(b, 0, templates[ind], b.Length);
ind++;
}
</pre>
<p>number_of_elements is the number of scans in the database, and list_of_scan_records is a list containing a byte array for each record</p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com12tag:blogger.com,1999:blog-6905225402385483155.post-15238382209986001322011-02-19T17:44:00.000+00:002011-02-19T17:49:05.781+00:00VMWare Workstation on WindowsHaving abandoned CentOs as the host for my VMWare VMs, I went back to running Windows XP as the host. <div><br /></div><div>A bit of a pain (two sets of virus detectors, and all the other bloatedness of Windows). That would have been OK, except that most times I started the client, it decided it had only 1 monitor, and rearranged my desktop accordingly. So every morning, the first few minutes would be spent putting things back on the correct monitor. Would you believe that moving a quick launch toolbar from one monitor to another reorders all the icons?</div><div><br /></div><div><div>At least my USB 3 drive worked (and aren't they _fast_ !). And my headset.</div><div><br /></div><div>However, performance was not good, and too many things caused screen updating to stop working. And VM clients had a tendency to jump from one (ATI Hydravision) virtual desktop to another (on the server).</div><div><br /></div><div>The NTFS filesystem going corrupt, so that one of the 2GB files that made up my hard disk suddenly thought it was 2TB was the last straw.</div><div><br /></div></div><div>I finally gave in, and decided to "de-virtualise" my desktop. I took loads of backups, made a BartPE CD, booted it, and repartitioned my disk. Then I restored the backup of my VM client desktop, and rebooted.</div><div><br /></div><div>Then I was stuck in a boot loop - as soon as the Windows logo appeared, the machine rebooted. Safe mode (even safe mode with command line) did not help. The only way out was a repair install with the latest CD I had (XP64 SP1), followed by a whole day downloading updates and service packs and copies of Internet Explorer.</div><div><br /></div><div>So I can now advise that virtualisation is not ready to host your desktop on the one machine, and that changing the hardware of your Windows working environment is still a horrible nightmare.</div><div><br /></div>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-20340244412804804592011-02-19T17:42:00.001+00:002011-02-19T17:44:10.916+00:00CentOs and VMWare WorkstationI had other problems with my CentOs VMWare WOrkstation host environment. I have a Logitek USB headset, which I use with Skype in my VM client running Windows XP.<div><br /></div><div>However, a while ago the microphone stopped working - all I got from it was a load crackling noise. I tried buying a new headset, but that was the same - it seems to be a reaction between CentOs and VMWare.</div><div><br /></div><div>Yet another reason to abandon CentOs :-(</div>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-74595748855403999372011-02-19T17:36:00.001+00:002011-02-19T17:41:57.395+00:00CentOs and USB 3.0I run CentOs 5 as a host operating system for VMWare Workstation, and use a VM client as my main working environment.<div>I was finding backing up my environment to be a slow and painful process using USB2 disks, or the Gigabit network card.</div><div>I read that USB 3.0 was much faster, and that Linux was the first O/S to support it, so I bought a controller card and disk.</div><div>Then I found CentOs didn't support it :-(</div><div>I was encouraged by the nice people at <a href="http://elrepo.org/">el-repo</a> to try their experimental kernel for CentOs, and, after a lot of messing about, I managed to get it booted, and accessing the USB 3 disk. However, I couldn't also use their fglrx ATI Radeon driver at the same time (it only works with the stock CentOs kernel). As dual monitor support is vital to me, I gave up, and finally abandoned CentOs.</div>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-69162096581149999392009-12-03T16:49:00.001+00:002009-12-03T18:12:52.807+00:00U8230 MoDaCo ROM makes ShopSavvy work on Android T-Mobile PulseWell, I installed the <a href="http://android.modaco.com/content/t-mobile-pulse-pulse-modaco-com/296925/03-12-1-0-modaco-custom-rom-u8230-edition-featuring-wavesecure-stock-roms/">U8230 MoDaCo ROM</a>, and it sort of worked.<br /><br />Unfortunately, things (especially the front screen) kept crashing.<br /><br />However, after advice from the nice MoDaCo people, I did a factory reset...<br /><ul><li>Use the Quick Boot app to go into recovery mode</li><li>Allow the root shell access when the prompt comes up</li><li>Choose the factory reset option</li><li>When the system restarts it will come up with the standard French options - go into Settings/Locale and text/Select locale and choose English.</li><li>I found I had to reboot the phone again to make that setting take properly.</li><li>Now you have to reinstall all your apps (but, if you go to Market, My downloads, they are all listed ready to install). I have installed CoPilot Live (paid for), but it downloaded and installed OK, and re-registered fine.</li></ul><p>Because this version of the ROM has moved Google Maps into the data partition (to save space), the factory reset removed it (as it wipes the data partition). So I then had to reinstall the update again. I would advise factory resetting before installing this ROM.</p><p>There are some good things about this ROM though:</p><ul><li>ShopSavvy can use the camera like it should (the old version just showed a black screen).</li><li>Google contacts will sync OK (even if you add people to your Favorites).</li></ul><p> </p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-25789680193794682302009-12-03T12:01:00.000+00:002009-12-03T16:48:59.945+00:00ShopSavvy doesn't work on Android T-Mobile PulseOne of the highly recommended applications on Android is ShopSavvy. Apparently this lets you use the phone's camera to scan barcodes of products, and then tells you the best prices to buy them, both locally and on the 'Net.<br /><br />Sounds good, but doesn't work on my Pulse :-(<br /><br />However, the excellent Paul at MoDaCo has produced a custom rom based on the French U8230 version of this phone, which fixes the problem. (For those not wishing to root their phone, ShopSavvy have been told by the phone manufacturer that a new ROM image has been supplied to T-Mobile, so just wait patiently!)<br /><br />So I'm loading it now - for full instructions see <a href="http://trumphurst.blogspot.com/2009/12/rooting-android-on-t-mobile-pulse.html">http://trumphurst.blogspot.com/2009/12/rooting-android-on-t-mobile-pulse.html</a> - but use <a href="http://www.romraid.com/paul/pulse/update-pulse-u8230edition-1.0-core-signed.zip">http://www.romraid.com/paul/pulse/update-pulse-u8230edition-1.0-core-signed.zip</a> instead of update-pulse-1.3-core-signed.zip.Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com1tag:blogger.com,1999:blog-6905225402385483155.post-22244385403744321862009-12-03T10:45:00.000+00:002009-12-03T11:04:17.748+00:00SSH into my Android T-Mobile Pulse phoneHaving installed the MoDaCo Custom ROM into my rooted phone, I then tried to ssh into it. The first thing I needed was the password - the instructions weren't clear, but I eventually found it in Settings/About Phone/Setup Wizard.<br /><br />I used Putty to SSH into the phone (having got its IP address from my DHCP server logs) as root (using port 2222), and it worked. Now I wanted to use my public key, so I wouldn't be asked for the password again. Instructions were a bit fragmented, and I had a few false starts, but this is what I ended up doing:<br /><ul><li>cd /data/dropbear</li><li>mkdir .ssh</li><li>chmod 700 .ssh</li><li>cd .ssh</li><li>echo 'my public key' >authorized_keys</li><li>chmod 644 authorized_keys</li><li>cd ..</li><li>mount -o rw,remount -t yaffs2 /dev/block/mtdblock1 /system</li><li>edit /system/bin/dropbear.sh to add<br /> -R /data/dropbear/.ssh/authorized_keys<br> to the end of the command line.</li><li>mount -o ro,remount -t yaffs2 /dev/block/mtdblock1 /system</li><li>reboot the phone (type "reboot" at the command line, or use the Quick Boot app on the phone).</li></ul><br /><p>The mount commands switch the filesystem from read-only (its usual state) to read-write and back again.</p><br /><p>Brilliant - I now have password-free root access to my phone using ssh from my PC (which has a real keyboard). Some experimentation shows I have most of the commonly-used Linux commands available to me.</p><p></p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-23458309295741939332009-12-03T10:14:00.001+00:002009-12-03T18:44:57.515+00:00Rooting Android on the T-Mobile PulseBeing the techy that I am, I investigated getting ssh access into my phone (preferably as root). The site with the best information on this is <a href="http://android.modaco.com/content/t-mobile-pulse-pulse-modaco-com/294178/13-10-1-0-rooting-the-pulse-introducing-superboot/">http://android.modaco.com/content/t-mobile-pulse-pulse-modaco-com/294178/13-10-1-0-rooting-the-pulse-introducing-superboot/</a><br /><br />I didn't find the instructions there 100% clear, so here is what I did:<br /><ul><li>Install the CD that came with the phone - this is necessary to install USB drivers, adb, etc., so the computer can talk to the phone.</li><li>Download (to my PC) the superboot root image <a href="http://content.modaco.net/dropzone/1.1-pulse-superboot.zip">http://content.modaco.net/dropzone/1.1-pulse-superboot.zip</a></li><li>and the recovery image <a href="http://content.modaco.net/dropzone/1.2.3-pulse-amonrarecovery.zip">http://content.modaco.net/dropzone/1.2.3-pulse-amonrarecovery.zip</a> </li><li>and the MoDaCo Custom ROM <a href="http://www.romraid.com/paul/pulse/update-pulse-1.3-core-signed.zip">http://www.romraid.com/paul/pulse/update-pulse-1.3-core-signed.zip</a></li><li>and the stock T-Mobile image (in case of emergency) <a href="http://content.modaco.net/pulse/update-pulse-stock-V100R001GBRC85B116SP01-t-mobile-signed.zip">http://content.modaco.net/pulse/update-pulse-stock-V100R001GBRC85B116SP01-t-mobile-signed.zip</a></li><li>Turn the phone off, and unplug the USB cable.</li><li>Hold the volume down and red (end call) buttons, and press the power button. This puts the phone into bootloader mode.</li><li>Plug in the USB cable.</li><li>Unzip the superboot file, copy AdbWinApi.dll from the CD that came with the phone into the 1.1-pulse-superboot folder, and run .install-superboot-windows.bat.</li><li>At this point I restarted the phone by removing the battery, and tried it out - the phone was rooted, but I was unable to get into recovery mode to install the MoDaCo Custom ROM. Turns out I needed to install the recovery image first, and I think I could have done that straight away while the phone was still in bootloader mode.</li><li>Unzip the amonrecovery zip, copy AdbWinApi.dll from the CD that came with the phone into the 1.0-pulse-amonrarecovery folder, and run ._install-recovery-windows.bat.</li><li>Now restart the phone by removing the battery.</li><li>Go into the applications list (bottom right button on the home screen), and run the "Quick Boot" application that superboot has installed. Choose Recovery, and, when you get the sudo screen asking whether to allow root access, allow it. This puts the phone into recovery mode, which I think is a kind of boot image provided by amonrecovery. It's a bit like Windows recovery mode, or booting a Windows machine with a floppy disk - you can do stuff, but the main operating system is not running.</li><li>The first useful thing to do is to take a backup of the entire phone, using the Nandroid Backup option on the recovery menu. This backs up a complete image of the phone's ROM to the SD card, which you can restore later. I then turned USB mass storage on (so I could get to the SD card from my computer), and backed up that image to my computer.</li><li>Then I renamed the MoDaCo ROM zip (update-pulse-1.3-core-signed.zip) to plain update.zip, and copied it from my computer onto the SD card.</li><li>I turned off USB mass storage (so the phone could see the SD card again), and ran the "Apply sdcard:update.zip" option. This installed the MoDaCo ROM image.</li><li>Finally I rebooted the phone (from the menu). The reboot took <strong>ages</strong>. This is to be expected.</li></ul><p>SSH into the phone in my next post...</p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com1tag:blogger.com,1999:blog-6905225402385483155.post-17940246870594028672009-12-03T10:01:00.000+00:002009-12-03T10:14:08.020+00:00Android on the T-Mobile Pulse<p>I've always wanted a smartphone I can use anywhere to access the Internet, ssh into the servers I maintain, check my mail, etc. I was tempted by the iPhone, but put off by the enormous price, and the closed Apple-only system.<br /><br />Then I found the T-Mobile Pulse, available on pay-as-you-go for under £200, which runs Android. So I bought one a couple of weeks ago.<br /><br />It's a nice phone (although the camera is pretty awful). I really like the Android operating system - it does the kind of thing the iPhone does on the TV adverts, but it's open.<br /><br />I installed all kinds of good software on it: </p><ul><li>EStrongs File Explorer - gives me access to my Windows and Samba shares over my Wifi network.</li><li>Android-vnc-viewer - lets me control my desktop from the phone (in an emergency - the phone screen is a bit tiny for controlling twin 19" monitors!).</li><li>AndFTP - FTP/SFTP client.</li><li>TextEdit - does what it says on the tin.</li><li>ConnectBot - ssh/telnet client.</li><li>DynDNS - dynamic DNS client.</li><li>Skype Lite.</li><li>CoPilot Live Navigator - full turn-by-turn GPS with maps on the phone, so no Internet connection needed.</li></ul><p>I also put on quite a few other less vital bits an pieces - e.g. a spirit level (just like the TV ad), toggle switches for turning WiFi/GPS/3G/etc. on and off (to save going through the settings menu).</p><p> </p>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-80216265687470439962009-03-13T18:11:00.000+00:002012-12-28T16:11:04.643+00:00ifup: network-functions: line 52: eth0: No such file or directoryThe (external) power supply on my Linux box broke the other day. Tranquil PC sent me a new one, so I booted the machine up for the first time in ages. I noticed an error message as it was trying to bring up the eth0 interface (which is nicknamed "moors" on my machine):<br />
<code><br />ifup: network-functions: line 52: eth0: No such file or directory</code><br />
This appeared twice every time I booted the machine.<br />
<br />I looked in /etc/sysconfig/network-script/network-functions, and line 52 was the (rather unhelpful):<br /><code><br /> . $CONFIG</code><br />I went through a prolonged debugging session, putting trace code in ifup and network-functions, and I found the problem was caused by line 155 of ifup:<br /><code><br />is_available ${REALDEVICE}</code><br />REALDEVICE at this point is "eth0". is_available starts like this:<br /><code><br /> LC_ALL= LANG= ip -o link | grep -q $1<br /> [ "$?" = "1" ] || return 0<br /><br /> alias=`modprobe -c | awk "/^(alias|install)[[:space:]]+$1[[:space:]]/ { print \\$3 }"`<br /> if [ -z "$alias" -o "$alias" = "off" -o "$alias" = "/bin/true" ]; then<br /> return 2<br /> fi<br /> modprobe $1 > /dev/null 2>&1 || return 1<br /> # if it is a mainframe ccwgroup device, configure it before<br /> # trying to rename it:<br /> need_config ${1}</code><br />I haven't figured out what all the tests at the top do, but (for eth0 only, and only when rebooting) control comes through to the call to need_config. need_config looks like this:<br /><code><br /> CONFIG="ifcfg-${1}"<br /> [ -f "${CONFIG}" ] && return<br /> CONFIG="${1}"<br /> [ -f "${CONFIG}" ] && return<br /> local addr=`get_hwaddr ${1}`<br /> if [ -n "$addr" ]; then<br /> local nconfig=`get_config_by_hwaddr ${addr}`<br /> if [ -n "$nconfig" ] ; then<br /> CONFIG=$nconfig<br /> [ -f "${CONFIG}" ] && return<br /> fi<br /> fi</code><br />So CONFIG gets changed from "ifcfg-moors" (which is what it was to start with) to "eth0" - and there is no such file (nor an ifcfg-eth0) in /etc/sysconfig/network-scripts.<br />
<br />I have "fixed" the problem by adding a line to the top of need_config:<br /><code><br /> [ -f "${CONFIG}" ] && return</code><br />but this is the ravings of someone who doesn't really know what is going on!<br />
<br />Helpful suggestions welcome.<br />
<br />
Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-43683459958860405532009-03-05T16:52:00.000+00:002009-03-13T18:11:11.521+00:00Adding a second Internet connection - part 2Now I have routing working properly on my new router, I took the opportunity to move it onto eth0 (my firewalled, "dirty" interface).<br /><p><br />First, I set up a new aliased ethernet port on the Linux box, using the Gnome System Settings/Network tool. I gave this IP address 192.168.0.1 (no default gateway).<br /><p><br />Then I connected to the new router, and changed its IP address to 192.168.0.250. I physically moved it onto the eth0 network. Finally I telnetted to it and set up its own routes, as follows:<br /><code><br />D-Link> ip route addrom index 1<br />D-Link> ip route addrom name gbit<br />D-Link> ip route addrom set 192.168.3.0/24 192.168.0.1 1<br />D-Link> ip route addrom save<br />ip route addrom: save ok<br />D-Link> ip route addrom index 2<br />D-Link> ip route addrom name mbit<br />D-Link> ip route addrom set 192.168.1.0/24 192.168.0.1 1<br />D-Link> ip route addrom save<br />ip route addrom: save ok<br />D-Link> ip route addrom index 3<br />D-Link> ip route addrom name dirty<br />D-Link> ip route addrom set 192.168.2.0/24 192.168.0.1 1<br />D-Link> ip route addrom save<br />ip route addrom: save ok<br /></code><br />This set up the following static routes:<br /><code><br />Dest FF Len Device Gateway Metric stat Timer Use RN<br />192.168.0.0 00 24 enet0 192.168.0.250 1 041b 0 1150<br />192.168.1.0 00 24 enet0 192.168.0.1 1 001b 0 0<br />192.168.2.0 00 24 enet0 192.168.0.1 1 001b 0 0<br />192.168.3.0 00 24 enet0 192.168.0.1 1 001b 0 445<br /></code><br />Then I altered the routes on the Linux box as follows:<br /><code><br />ip route add 192.168.2.0/24 dev eth0 src 192.168.2.1 table ISP1<br />ip route add default via 192.168.2.5 table ISP1<br /><br />ip route add 192.168.0.0/24 dev eth0 src 192.168.0.1 table ISP2<br />ip route add default via 192.168.0.250 table ISP2<br /><br />ip route add 192.168.2.0/24 dev eth0 src 192.168.2.1<br />ip route add default via 192.168.2.5<br /><br />ip rule add from 192.168.2.1 table ISP1<br />ip rule add from 192.168.0.1 table ISP2<br /></code><br />I also set up static routes for some IP addresses I wanted to reach via one or other ISP (e.g. their DNS servers).<br /><p><br />That all works - I can connect in from outside via either of the two routers (I have set up identical NAT mappings on both). I can easily switch to the secondary router like this:<br /><code><br />ip route del default<br />ip route add default via 192.168.0.250<br /></code><br />I am now considering load balancing between the two routers. I think the commands to do this would be:<br /><code><br />ip route del default<br />ip route add default scope global nexthop via 192.168.2.5 dev eth0 weight 6 nexthop via 192.168.0.250 dev eth0 weight 1<br /></code>Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com0tag:blogger.com,1999:blog-6905225402385483155.post-39850459511919295492009-02-19T09:26:00.000+00:002009-03-05T17:12:52.440+00:00Adding a second Internet connectionI have just installed a second ADSL connection, intending it to be a backup in case the first one goes down. This comes with a DSL-2640R NAT router (including firewall).<br /><p><br />My existing network is somewhat complicated - at its heart is a CentOS 4 Linux box from <a href="http://www.tranquilpc.co.uk/T2.htm"> Tranquil PC</a>, with three network cards, which routes between the three networks.<br /><ul><br /><li>My existing ADSL router is on eth0 (192.168.2.1) at 192.168.2.5.<br /><li>I have a 100 Mbit network on eth1 (192.168.1.1)<br /><li>I have a Gbit network on eth2 (192.168.3.1)<br /></ul><br />Although I want untimately to set up load sharing and automatic failover, to start with I just wanted everything to work, viz:<br /><ul><br /><li>All machines on the network to have access to the Internet, and all other machines (including both ADSL routers).<br /><li>To be able to connect to the Linux box from outside, via <u>either</u> Internet connection.<br /></ul><br />The first thing I did was to assign the new DSL-2640R router IP address 192.168.1.250, turn off DHCP (so it didn't conflict with the existing DHCP server) and add it to the network on eth1. I originally tried to put it on the same network as the existing router, but I don't understand how it would be possible to distinguish outside traffic coming in via the two routers unless they were on separate interfaces. It may be worth trying a virtual interface here.<br /><h3>Allowing the router to see the other networks</h3><br />Now I could see the DSL-2640R from the Linux box, but not from either of the other networks (as the DSL-2640R did not have a setting for default gateway on its LAN side, so it couldn't find a route back to the other networks). <br /><p><br />I first tried setting up NAT on the Linux box for the eth0 interface, by editing /etc/sysconfig/iptables as follows:<br /><code><br />*nat<br />:PREROUTING ACCEPT [39:3410]<br />:POSTROUTING ACCEPT [33:2787]<br />:OUTPUT ACCEPT [10:677]<br />-A POSTROUTING -d 192.168.1.250 -o eth0 -j MASQUERADE <br />COMMIT<br /></code><br />That enabled me to see the web interface of the DSL-2640R from anywhere on my network, but did not allow incoming traffic from the router to see the rest of my network.<br /><p><br />I discovered that the router has a telnet interface, which shows the following help (once you have logged in and typed "help"):<br /><code><br />Valid commands are:<br />sys exit ether wan<br />ip bridge dot1q pktqos<br />show set lan<br /></code><br />Although I couldn't find any documentation for this interface, it looked remarkably familiar to the one on my ZyXel Prestige 660HW, for which I did have documentation.<br /><p><br />I therefore set up two static routes in rom (so they survive a reboot), as follows:<br /><code><br />D-Link> ip route addrom index 1<br />D-Link> ip route addrom name gbit<br />D-Link> ip route addrom set 192.168.3.0/24 192.168.1.1 1<br />D-Link> ip route addrom save<br />ip route addrom: save ok<br />D-Link> ip route addrom index 2<br />D-Link> ip route addrom name dirty<br />D-Link> ip route addrom set 192.168.2.0/24 192.168.1.1 1<br />D-Link> ip route addrom save<br />ip route addrom: save ok<br /></code><br />That worked fine, so I reverted iptables to its original state.<br /><h3>Enabling incoming traffic</h3><br />The next step was to enable incoming traffic from the DSL-2640R. I first opened up the necessary ports in the DSL-2640R's NAT setup, redirecting them all to the Linux box on 192.168.1.1. That allowed the incoming traffic, but the Linux box couldn't reply, because its default route back was via the original ADSL router at 192.168.2.5. Having read an article at <a href="http://lartc.org/howto/lartc.rpdb.multiple-links.html">http://lartc.org/howto/lartc.rpdb.multiple-links.html</a>, I amended the routing tables on the Linux box. I first added two new tables to /etc/iproute2/rt_tables<br /><code><br />200 ISP1<br />201 ISP2<br /></code><br />Then added routes to these tables:<br /><code><br />ip route add 192.168.2.0/24 dev eth0 src 192.168.2.1 table ISP1<br />ip route add default via 192.168.2.5 table ISP1<br /><br />ip route add 192.168.1.0/24 dev eth0 src 192.168.1.1 table ISP2<br />ip route add default via 192.168.1.250 table ISP2<br /><br />ip route add 192.168.2.0/24 dev eth0 src 192.168.2.1<br />ip route add default via 192.168.2.5<br /><br />ip rule add from 192.168.2.1 table ISP1<br />ip rule add from 192.168.1.1 table ISP2<br /></code><br /><p><br />I don't fully understand how all this works (and I would be grateful if anyone explains it to me), but it does seem to.<br /><h3>Switching between the two Internet connections</h3><br />The next step is to allow switching the default gateway between the two routers (in case the primary one goes down). This is done using a couple of scripts:<br /><code><br /># Switch to new Internet connection<br />ip route del default<br />ip route add default via 192.168.1.250<br /></code><br /><code><br />#Switch to original Internet connection<br />ip route del default<br />ip route add default via 192.168.2.5<br /></code><br /><p><br />That works too - I may set this up to switch automatically, or to load balance, but I think I've done enough for now.Nikki Lockehttp://www.blogger.com/profile/10540258053134317500noreply@blogger.com1