May 032015
 

The Problem

I’ve been running a station from the bicycle for some time now and I suppose I’ve tried a few different battery types on the station.

Originally I ran 9Ah 12V gel cells, which work fine for about 6 months, then the load of the radio gets a bit much and I find myself taking two with me on a journey to work because one no longer lasts the day.  I replaced this with a 40Ah Thundersky LiFePO4 pack which I bought from EVWorks, which while good, weighed 8kg!  This is a lot lighter than an equivalent lead acid, gel cell or AGM battery, but it’s still a hefty load for a bicycle.

At the time that was the smallest I could get.  Eventually I found a mob that sold 10Ah packs. These particular cells were made by LiFeBatt, and while pricey, I’ve pretty much recouped my costs. (I’d have bought and disposed of about 16 gel cell batteries in this time at $50 each, versus $400 for one of these.)   These are what I’ve been running now since about mid 2011, and they’ve been pretty good for my needs.  They handle the load of the FT-857 okay on 2m FM which is what I use most of the time.

A week or two back though, I was using one of these packs outside with the home base in a “portable” set-up with my FT-897D.  Tuned up on the 40m WICEN net on 7075kHz, a few stations reported that I had scratchy audio.  Odd, the radio was known to be good, I’ve operated from the back deck before and not had problems, what changed?

The one and only thing different is I was using one of these 10Ah packs.  I’ve had fun with RF problems on the bicycle too.  On transmit, the battery was hovering around the 10.2V mark, perhaps a bit low.  Could it be the radio is distorting on voice peaks due to input current starvation?  I tried after the net swapping it for my 40Ah pack, which improved things.  Not totally cleared up, but it was better, and the pack hadn’t been charged in a while so it was probably a little low too.

The idea

I thought about the problem for a bit.  SSB requires full power on voice peaks.  For a 100W radio, that’s a 20A load right now.  Batteries don’t like this.  Perhaps there was a bit of internal resistance from age and the nature of the cells?  Could I do something to give it a little hand?

Supercapacitors are basically very high capacity electrolytic capacitors with a low breakdown voltage, normally in the order of a few volts and capacitances of over a farad.  They are good for temporarily storing charge that needs to be dumped into a load in a hurry.  Could this help?

My cells are in a series bank of 4: ~3.3V/cell with 4 cells gives me 13.2V.  There’s a battery balancer already present.  If a cell gets above 4V, that cell is toast, so the balancer is present to try to prevent that from happening.  I could buy these 1F 5.5V capacitors for only a few dollars each, so I thought, “what the hell, give it a try”.  I don’t have much information on them other that Elna Japan made them.  The plan was to make some capacitor “modules” that would hook in parallel to each cell.

My 13.2V battery pack, out of case

My 13.2V battery pack, out of its case

Supercapacitors

Supercapacitors

For my modules, the construction was simple, two reasonably heavy gauge wires tacked onto the terminals, the whole capacitor then encased in heatshrink tubing and ring lugs crimped to the leads. I was wondering whether I should solder a resistor and diode in parallel and put that in series with the supercap to prevent high in-rush current, but so far that hasn’t been necessary.

The re-assembled pack

I’ve put the pack back together and so far, it has charged up and is ready to face its first post-retrofit challenge.  I guess I’ll be trying out the HF station tomorrow to see how it goes.

Assembled pack

Assembled pack

The Verdict

Not a complete solution to the RF feedback, it seems to help in other ways. I did a quick test on the drive way first with the standard Yaesu handmic and with the headset. Headset still faces interference problems on HF, but I can wind it up to about 30W~40W now instead of 20.

More pondering to come but we’ll see what the other impacts are.

Apr 112015
 

To whom it may concern,

There have been reports of web browser sessions from people outside China to websites inside China being hijacked and having malware injected.  Dubbed “Great Cannon”, this malware having the sole purpose of carrying out distributed denial of service attacks on websites that the Chinese Government attempts to censor from its people.  Whether it be the Government there itself doing this deliberately, or someone hijacking major routing equipment is fundamentally irrelevant here, either way the owner of the said equipment needs to be found, and a stop put to this malware.

I can understand you wish to prevent people within your borders from accessing certain websites, but let me make one thing abundantly clear.

COUNT ME OUT!

I will not accept my web browser which is OUTSIDE China being hijacked and used as a mule for carrying out your attacks.  It is illegal for me to carry out these attacks, and I do not authorise the use of my hardware or Internet connection for this purpose.  If this persists, I will be blocking any and all Chinese-owned websites’ executable code in my browser.

This will hurt Chinese business more than it hurts me.  If you want to ruin yourselves economically, go ahead, it’ll be like old times before the Opium Wars.

Apr 102015
 

This afternoon, whilst waiting for a build job to complete I thought I’d do some further analysis on my annual mileage.

Now I don’t record my odometer readings daily (perhaps I should), but I do capture them every Sunday morning.  So I can possibly assume that the distance done for each day of a “run” is the total distance divided by the number of days.  I’m using a SQLite3 database to track this, question is, how do I extract this information?

This turned out to be the key to the answer.  I needed to enumerate all the days between two points.  SQLite3 has a julianday function, and with that I have been able to extract the information I need.

My database schema is simple. There are two tables:
CREATE TABLE bikes (id integer primary key not null, description varchar(64));
CREATE TABLE odometer (timestamp datetime not null default current_timestamp, action char(8) not null, bike_id integer not null, odometer real not null, constraint duplicate_log unique (timestamp, action, bike_id) on conflict replace);

Then there are the views.
CREATE VIEW run_id as select s.rowid as start_id, (select rowid from odometer where bike_id=s.bike_id and timestamp > s.timestamp and action='stop' order by timestamp asc limit 1) as stop_id from odometer as s where s.action='start';
CREATE VIEW "run" AS select start.timestamp as start_timestamp, stop.timestamp as stop_timestamp, start.bike_id as bike_id, start.odometer as start_odometer, stop.odometer as stop_odometer, stop.odometer-start.odometer as distance,julianday(start.timestamp) as start_day, julianday(stop.timestamp) as stop_day from (run_id join odometer as start on run_id.start_id=start.rowid) join odometer as stop on run_id.stop_id=stop.rowid;

The first view breaks up the start and stop events, and gives me row IDs for where each “run” starts and stops. I then use that in my run view to calculate distances and timestamps.

Here’s where the real voodoo lies, to enumerate days, I start at the very first timestamp in my dataset, find the Julian Day for that, then keep adding one day on until I get to the last timestamp. That gives me a list of Julian days that I can marry up to the data in the run view.

CREATE VIEW distance_by_day as
SELECT day_of_year, avg_distance FROM (
SELECT days.day - julianday(date(days.day,'start of year')) as day_of_year, sum(run.distance/max((run.stop_day-run.start_day),1))/count(*) as avg_distance
FROM run,
(WITH RECURSIVE
days(day) as (
SELECT julianday((select min(timestamp) from odometer))
union all
SELECT day+1 from days
limit cast(round(julianday((select max(timestamp) from odometer))-julianday((select min(timestamp) from odometer))) as int)
) SELECT day from days) as days
where
run.start_day < = days.day
AND run.stop_day >= days.day
group by day_of_year) dist_by_doy;

This is the result.

Distance by Day Of Year

Distance by Day Of Year

Apr 062015
 

I’ve been a long time user of PGP, had a keypair since about 2003.  OpenPGP has some nice advantages in that it’s a more social arrangement in that verification is done by physically meeting people.  I think it is more personal that way.

However, you still can get isolated islands, my old key was a branch of the strong set, having been signed by one person who did do a lot of key-signing, but sadly thanks to Heartbleed, I couldn’t trust it anymore.  So I’ve had to start anew.

The alternate way to ensure communications is to use some third party like a certificate authority and use S/MIME.  This is the other side of the coin, where a company verifies who you are.  The company is then entrusted to do their job properly.  If you trust the company’s certificate in your web browser or email client, you implicitly trust every non-revoked valid certificate that company has signed.  As such, there is a proliferation of companies that act as a CA, and a typical web browser will come with a list as long as your arm/leg/whatever.

I’ve just set up one such certificate for myself, using StartCOM‘s CA as the authority.  If you trust StartCOM, and want my GPG key, you’ll find a S/MIME signed email with my key here.  If you instead trust my GPG signature and want my S/MIME public key, you can get that here.  If you want to throw caution to the wind, you can get the bare GPG key or S/MIME public key instead.

Update: I noticed GnuPG 2.1 has been released, so I now have an ECDSA key; fingerprint B8AA 34BA 25C7 9416 8FAE  F315 A024 04BC 5865 0CF9.  You may use it or my existing RSA key if your software doesn’t support ECDSA.

Mar 312015
 

Every now and again, I get some invite to join some social network or to “Confirm I know ${PERSON}”.  It doesn’t really matter what platform you choose, the end result is the same.

There are a couple of reasons I do not participate on these systems.

Number one is that when I get home, I typically cannot be stuffed having much to do with computers.  Sure I’ll be checking what news has happened during the day, I have an RSS aggregator for that.  I’ll check what the weather is doing tomorrow (as a cyclist, this is of high importance).  I’ll check emails, as that is how I keep in touch with people (I know, how quaint, but it works).

Maybe check some public forums/newsgroups.  That’s about it.  I really cannot be stuffed doing much else having fought with computers all day, I’m really not in the mood when I get home.

Second reason is the nature of these social networks.  Much of the interaction happens behind the scenes.  You’re “sharing” to an audience behind closed doors.  That audience has to be a member of that same group to even see your material.  Don’t believe me?  Try to log into Facebook and then go “Friend” a Google+ user and share something with them.  Or how about go log into Google+ and “circle” (is that the term?) a Linked In user.  These new-breed “social” networks are about as anti-social as it gets.

They’re today’s bulletin board system.  I’m sorry, are we really abandoning the World Wide Web for what’s little more than a BBS?  About the only difference I see is that JavaScript and HTML5 replace the ANSI/DEC escape sequences of old.  It’s still an isolated silo from which your information is locked in and only those who have opted into that network can participate.

A forum can be publicly viewed in most cases, in fact forums generally have trouble attracting an audience if they’re not publicly visible.

Finally there’s the privacy.  Sharing what you’re doing in your day to day life is one thing.  You can share a lot without giving much away personally.  “Friend”-ing people however is basically uploading your social graph, one link at a time.  One’s social graph is one of the most personal things one can expose about themselves, and increasingly the privacy policies of these social networks have been found lacking in several aspects.

Companies have been working on sophisticated ways in order to search and map out these social graphs, they would not be doing this if there wasn’t financial incentive to do so.  Knowing who someone’s friends are is the first step in being able to manipulate that person.  I’d rather not be someone’s puppet.

There’s also the phishing risk.  They’re popular sites to try and spoof.  I recently received one alleging to be from The Register author Simon Rockman.  It could be authentic, but then again, anyone could sign up for an account on one of these social network, claim to be someone they’re not, and try to lure you in.  I’ve got no way of verifying this, and with a broken “Reply-to” header, in the bin it goes.

So, next time you think of putting my email address in to a form on a social network page to invite me to join, don’t bother.  I do respond to emails, I even respond to comments left here (unless they’re spam), but I will not respond to social network invites, in fact I may not even receive them.

Mar 192015
 
Tropical Cyclone Nathan, Forecast map as of 2:50PM

Tropical Cyclone Nathan, Forecast map as of 2:50PM

This cyclone has harassed the far north once already, wobbled out in the Pacific like a drunken cyclist as a tropical low, has gained strength again and is now making a bee-line for Cape Flattery.

As seen, it also looks like doing the same stunt headed for Gove once it’s finished touching up far north Queensland.  Whoever up there is doing this rain dancing, you can stop now, it’s seriously pissing off the weather gods.

National and IARU REGION III Emergency Frequencies (Please keep clear and listen for emergency traffic)

  • 80m
    • 3.600MHz LSB (IARU III+WICEN)
  • 40m
    • 7.075MHz LSB (WICEN)
    • 7.110MHz LSB (IARU III)
  • 20m
    • 14.125MHz USB (WICEN)
    • 14.300MHz USB (IARU III)
    • 14.183MHz USB: NOT an emergency frequency, but Queensland State WICEN hold a net on this frequency every Sunday morning at around 08:00+10:00 (22:00Z Saturday).
  • 15m
    • 21.190MHz USB (WICEN)
    • 21.360MHz USB (IARU III)
  • 10m
    • 28.450MHz USB (WICEN)

I’ll be keeping an ear out on 14.125MHz in the mornings.

Update 20 March 4:31am: It has made landfall between Cape Melville and Cape Flattery as a category 4 cyclone.

Mar 192015
 

Hi all,

This is more a note to self for future reference.  Qt has a nice handy reference counting memory management system by means of QSharedPointer and QWeakPointer.  The system is apparently thread-safe and seems to be totally transparent.

One gotcha though, is two QSharedPointer objects cannot share the same pointer unless one is cloned from the other (either directly or via QWeakPointer).  The other is that you must leave deletion of the object to QSharedPointer.  You’ve given it your precious pointer, it has adopted it and while you may call the object, it is no longer yours, so don’t go deleting it.

So you create an object, you want to pass a reference to yourself to some other object.  How?  Like this?

QSharedPointer<MyClass> MyClass::ref() {
    return QSharedPointer<MyClass>(this); /* NO! */
}

No, not like that! That will create QSharedPointer instances left right and centre. Not what you want to do at all. What you need to do, is create the initial reference, but then store a weak reference to it. Then all future calls, you simply call the toStrongRef method of the weak reference to get a QSharedPointer that’s linked to the first one you handed out.

Then, having done this, when you create your new object, you create it with the new keyword as normal, take a QSharedPointer reference to it, then forget all about the original pointer! You can get it back by calling the data method of the pointer object.

To make it simple, here’s a base class you can inherit to do this for you.

    #include <QWeakPointer>
    #include <QSharedPointer>

    /*!
     * Self-Reference helper.  This allows for objects to maintain
     * references to "this" via the QSharedPointer reference-counting
     * smart pointers.
     */
    template<typename T>
    class SelfRef {
        public:
            /*!
             * Get a strong reference to this object.
             */
            QSharedPointer<T>    ref()
            {
                QSharedPointer<T> this_ref(this->this_weak);
                if (this_ref.isNull()) {
                    this_ref = QSharedPointer<T>((T*)this);
                    this->this_weak = this_ref.toWeakRef();
                }
                return this_ref;
            }

            /*!
             * Get a weak reference to this object.
             */
            QWeakPointer<T>        weakRef() const
            {
                return this->this_weak;
            }
        private:
            /*! A weak reference to this object */
            QWeakPointer<T>        this_weak;
    };

Example usage:

#include <iostream>
#include <stdexcept>
#include "SelfRef.h"

class Test : public SelfRef<Test> {
        public:
                Test()
                {
                        std::cout << __func__ << std::endl;
                        this->freed = false;
                }
                ~Test()
                {
                        std::cout << __func__ << std::endl;
                        this->freed = true;
                }

                void test() {
                        if (this->freed)
                                throw std::runtime_error("Already freed!");
                        std::cout
                                << "Test object is at "
                                << (void*)this
                                << std::endl;
                }

                bool                    freed;
                QSharedPointer<Test>    another;
};

int main(void) {
        Test* a = new Test();
        if (a != NULL) {
                QSharedPointer<Test> ref1 = a->ref();
                if (!ref1.isNull()) {
                        QSharedPointer<Test> ref2 = a->ref();
                        ref2->test();
                }
                ref1->test();
        }
        a->test();
        return 0;
}

Note that the line before the return is a deliberate use after free bug to prove the pointer really was freed.  Also note that the idea of setting a boolean flag to indicate the constructor has been called only works here because nothing happens between that use after free attempt and the destructor being called.  Don’t rely on this to see if your object is being called after destruction.  This is what the output session from gdb looks like:

RC=0 stuartl@rikishi /tmp/qtsp $ make CXXFLAGS=-g
g++ -c -g -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I. -o test.o test.cpp
g++ -Wl,-O1 -o qtsp test.o    -L/usr/lib64/qt4 -lQtGui -L/usr/lib64 -L/usr/lib64/qt4 -L/usr/X11R6/lib -lQtCore -lgthread-2.0 -lglib-2.0 -lpthread 
RC=0 stuartl@rikishi /tmp/qtsp $ gdb ./qtsp 
GNU gdb (Gentoo 7.7.1 p1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./qtsp...done.
(gdb) r
Starting program: /tmp/qtsp/qtsp 
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Test
Test object is at 0x555555759c90
Test object is at 0x555555759c90
~Test
terminate called after throwing an instance of 'std::runtime_error'
  what():  Already freed!

Program received signal SIGABRT, Aborted.
0x00007ffff5820775 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff5820775 in raise () from /lib64/libc.so.6
#1  0x00007ffff5821bf8 in abort () from /lib64/libc.so.6
#2  0x00007ffff610cd75 in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
#3  0x00007ffff6109ec8 in ?? () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
#4  0x00007ffff6109f15 in std::terminate() () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
#5  0x00007ffff610a2e9 in __cxa_throw () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
#6  0x0000555555555cea in Test::test (this=0x555555759c90) at test.cpp:20
#7  0x0000555555555315 in main () at test.cpp:41
(gdb) up
#1  0x00007ffff5821bf8 in abort () from /lib64/libc.so.6
(gdb) up
#2  0x00007ffff610cd75 in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
(gdb) up
#3  0x00007ffff6109ec8 in ?? () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
(gdb) up
#4  0x00007ffff6109f15 in std::terminate() () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
(gdb) up
#5  0x00007ffff610a2e9 in __cxa_throw () from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libstdc++.so.6
(gdb) up
#6  0x0000555555555cea in Test::test (this=0x555555759c90) at test.cpp:20
20                                      throw std::runtime_error("Already freed!");
(gdb) up
#7  0x0000555555555315 in main () at test.cpp:41
41              a->test();
(gdb) quit
A debugging session is active.

        Inferior 1 [process 17906] will be killed.

Quit anyway? (y or n) y

You’ll notice it fails right on that second last line because the last QSharedPointer went out of scope before this.  This is why you forget all about the pointer once you create the first QSharedPointer.

To remove the temptation to use the pointer directly, you can make all your constructors protected (or private) and use a factory that returns a QSharedPointer to your new object.

A useful macro for doing this:

/*!
 * Create an instance of ClassName with the given arguments
 * and immediately return a reference to it.
 *
 * @returns	QSharedPointer<ClassName> object
 */
#define newRef(ClassName, args ...)	\
	((new ClassName(args))->ref().dynamicCast<ClassName>())
Mar 022015
 

Well, it’s been a year and a half since I last posted details about the bicycle mobile station.  Shortly after getting the Talon on the road, setting it up with the top box and lighting, and having gotten the bugs worked out of that set-up, I decided to get a second mounting plate and set my daily commuter up the same way, doing away with the flimsy rear basket in place of a mounting plate for the top box.

VK4MSL/BM today after the trip home from work.

VK4MSL/BM today after the trip home from work.

That particular bike people might recognise from earlier posts, it’s my first real serious commuter bike. Now in her 5th year, has done over 10200km since 2012.  (The Talon has done 5643km in that time.) You can add to that probably another 5000km or so done between 2010 and 2012. It’s had a new rear wheel (a custom one, after having a spate of spoke breakages) and the drive chain has been upgraded to 9-speed. The latter upgrade alone gave it a new lease on life.

Both upgrades being money well spent, as was the upgrade to hydraulic brakes early in the bike’s lifetime. I suppose I’ve spent in those upgrades alone close to $1400, but worth it as it has given me quite good service so far.

As for my time with the top box. Some look at it and quiz me about how much weight it adds. The box itself isn’t that heavy, it just looks it. I can carry a fair bit of luggage, and at present, with my gear and tools in it it weighs 12kg. Heavy, but not too heavy for me to manage.

Initially when I first got it, it was great, but then as things flexed over time, I found I was intermittently getting problems with the top box coming off.  This cost me one HF antenna and today, the top box sports a number of battle-scars as a result.

The fix to this?  Pick a spot inside the top box that’s clear of the pannier rack rails and the rear tyre, and drill a 5mm hole through.  Then, when you mount the top box, insert an M5 bolt through the mounting plate and into the bottom of the top box and tighten with a 5mm wing nut.  The box now will not come loose.

vk4msl-bm-2713

Still lit up like a Christmas tree from this morning’s ride.

The lights still work, and now there’s a small rear-view camera.  On the TODO list is to rig up a 5V USB socket to power that camera with so that it isn’t draining the rather small internal battery (good for 4 hours apparently).

The station has had an upgrade, I bought a new LDG Z-100Plus automatic tuner which I’m yet to fully try out.  This replaces the aging Yaesu FC-700 manual tuner which, although very good, is fiddly to use in a mobile set-up and doesn’t tune 6m easily.

One on-going problem now not so much on the Boulder but on the Talon is an issue with pannier racks failing.  This started happening when I bought the pannier bags, essentially on the side I carry my battery pack (2kg), I repeatedly get the pannier rack failing.  The racks I use are made by Topeak and have a built-in spacer to accomodate disc brake calipers.  This seems to be a weak spot, I’ve now had two racks fail at about the same point.

Interestingly on the Boulder which also has disc brakes, I use the standard version of the same rack, and do not get the same failures.  Both are supposedly rated to 25kg, and my total load would be under 16kg. Something is amiss.

A recurring flaw with the Topeak racks

I’m on the look-out for a more rugged rack that will tolerate this kind of usage, although having seen this, I am inspired to try a DIY solution.  Then if a part fails, I can probably get replacement parts in any typical hardware store.  A hack saw and small drill are not heavy items to carry, and I can therefore get myself out of trouble if problems arise.

Feb 282015
 

Well, it’s been about 7½ years since I bought my first bike and started riding, and really, about 5 years since I started riding seriously as a means of transportation.

In late 2011 my father and I went halves in a pair of GPS/CB radio units, it was a 2 for 1 deal and so we bought these two units at about $400 each, normally they’d be about $700 individually. So there I started logging the distance I covered. I just used the in-built odometer on the GPS, resetting it when the bike went in for service.

When I got the mountain bike, I realised I needed to track the distance covered by each bike to ensure they all went in at their 1000km service on-time. So being a programmer by trade, I coded up a crude CGI/Perl script that used a SQLite back-end to log the odometer readings. It was a simple HTML form where I could enter the distance at regular intervals.  Crucially, it worked with the “feature phone” I used at the time.

The SQL views (no such thing as stored procedures in standard SQLite3) took care of actually calculating the differentials and so I used that to track my progress. So far so good. I’ve now had this in place since mid-2012 and I’ve brought in some of my data from early 2012, thus I’m now starting to see some trends.

Distances by year

Year Distance (km)
2012 5594.9
2013 4837.78
2014 4593.42

Am I getting lazy? Well, hard to say there. I go out less on the weekends and have also optimised my routes to reduce distances somewhat.  Some of this is weather-dependent, in the heat one does not feel like going outdoors.

Distance by month-of-year

Month Distance (km)
01 282.59
02 406.20
03 409.10
04 377.42
05 511.29
06 493.36
07 330.01
08 532.05
09 494.21
10 470.14
11 370.27
12 394.13

I’m not sure why there’s a lull in activity around July, but the most active months seem to be May and August.  The lull in January can be somewhat attributed to the end of the Christmas break.  I guess if anything, I should aim to be more active in July when the weather is the coolest.

Guess I’ll be keeping an eye on what happens over time with these stats and see if I can get them up a bit.

The following graph will continuously update as I pump data in. We’ll see what happens.

Distance by month-of-year

Feb 202015
 

All,

As an update on this…

Due to some issues (browser pop up behavior for example), with the Superfish Visual Discovery browser add-on, we have temporarily removed Superfish from our consumer systems until such time as Superfish is able to provide a software build that addresses these issues. As for units already in market, we have requested that Superfish auto-update a fix that addresses these issues.

To be clear, Superfish comes with Lenovo consumer products only and is a technology that helps users find and discover products visually. The technology instantly analyzes images on the web and presents identical and similar product offers that may have lower prices, helping users search for images without knowing exactly what an item is called or how to describe it in a typical text-based search engine.

The Superfish Visual Discovery engine analyzes an image 100% algorithmically, providing similar and near identical images in real time without the need for text tags or human intervention. When a user is interested in a product, Superfish will search instantly among more than 70,000 stores to find similar items and compare prices so the user can make the best decision on product and price.

Superfish technology is purely based on contextual/image and not behavioral. It does not profile nor monitor user behavior. It does not record user information. It does not know who the user is. Users are not tracked nor re-targeted. Every session is independent. When using Superfish for the first time, the user is presented the Terms of User and Privacy Policy, and has option not to accept these terms, i.e., Superfish is then disabled.

Mark Hopkins, Lenovo Support

That’s alright Mark, I’ve permanently removed Lenovo from my list of future suppliers. If I buy a Lenovo product, I’m going to insist the machine is delivered to me completely formatted of hardware and supplied with media to do a clean installation since it is clear you cannot be trusted to put an OS on a computer and not botch it in some manner.

I think there should be a law against this sort of bundling: too long machines have been delivered with crippling bloatware that either wastes system resources, causes security headaches or both. Sure, bundle some software, BUT ASK THE CUSTOMER BEFORE YOU INSTALL IT!