Wednesday, November 16, 2011

E-Mail, DNS, IPv6, and much more...

Well, I've been having a conversation with Paul Murphy about how IPv6 is going to kill SMTP as we know it. I was arguing that it really wasn't. Yes, there is more complex work involved because you're dealing with a much larger IP base, but it's still not THAT hard to do. Here's some pseudo-code (emphasis on pseudo, it's all sketched out in Notepad, nothing more, and conforms to no known language thus far) that should give you the gist of my point.

// Connection Opens
If (dSeenHosts.Contains(sFullIPv6Address)) {
    If (dSeenHosts(sFullIPv6Address).IPBanned) {
        dSeenHosts(sFullIPv6Address.Connections++;
        Connection.Write(sConnectionBannedMessage);
        Connection.Close();
        return;
    } Else {
        dSeenHosts(sFullIPv6Address).Connections++;
    }
} Else {
    string sPartialHost = sFullIPv6Address.SubString(0,28);
    If (dSeenHosts.BeginsWith(sPartialHost).Matches.Count > 0) {
        // We've found at least one previous connection from within 4 nybbles
        // of the full address.
        //
        // We can make an assumption then that this is the same ISP as the
        // previous connection.
       
        If (dSeenHosts.BeginsWith(sPartialHost).Matches.Count > 1) {
            // There's more than one match to this partial host.
            // Hosting site? or perhaps spammer?
            float fBannedPercentage = 0;
            ForEach (var oHost in dSeenHosts.BeginsWith(sPartialHost).Matches) {
                If (oHost.IPBanned)
                    fBannedPercentage++;
            }
            fBannedPercentage = fBannedPercentage/(dSeenHosts.BeginsWith(sPartialHost).Count + 1));
            // Add an additional one to allow for this (unprocessed) host.
            If (fBannedPercentage > 0.7) {
                // More than 70% of hosts seen from this group have been banned.
                Connection.Write(sConnectionBannedMessage);
                Connection.Close();
                dSeenHosts(sFullIPv6Address).Connections = 1;
                dSeenHosts(sFullIPv6Address).IPBanned = True;
                dSeenHosts(sFullIPv6Address).BannedDate = Now();
                dSeenHosts(sFullIPv6Address).BannedTimes = 1;
            } Else {
                dSeenHosts(sFullIPv6Address).Connections = 1;
                dSeenHosts(sFullIPv6Address).BannedTimes = 0;
            }
        } Else {
            // There's only one previous connection from within this nybble.
            dSeenHosts(sFullIPv6Address).Connections = 1;
            dSeenHosts(sFullIPv6Address).BannedTimes = 0;
        }
    }
}

If (!Connection.IsOpen()) return;
Connection.SendBanner();
string sHostName = Connection.GetHELO();
bool bHostNameChanged = False;
If (dSeenHosts(sFullIPv6Address).HostName.Length > 0) {
    If (dSeenHosts(sFullIPv6Address).HostName != sHostName) {
        // That's not what you said last time.
        dSeenHosts(sFullIPv6Address).HostName = sHostName;
        dSeenHosts(sFullIPv6Address).HostVerificationFailed = False;
        bHostNameChanged = True;
    }
} Else {
    dSeenHosts(sFullIPv6Address).HostName = sHostName;
}
If (!VerifyHostNameMatchesIP(sHostName,sFullIPv6Address)) {
    // Function only returns false if it gets a result that doesn't match
    // No result is not false.
    // Not banning for this. You could, if you really wanted to be strict, but
    // The disconnection error should show up on a poorly configured server
    // And a spammer gets disconnected here.
    Connection.Write(sHostNameDoesntMatchIPError);
    Connection.Close();
}
If (!Connection.IsOpen()) return;
MailMessage mMail = Connection.ReceiveMail();
If (!SPFVerify(mMail)) {
    Connection.Write(sSPFFailedError);
    Connection.Close();
    dSeenHosts(sFullIPv6Address).IPBanned = True;
    dSeenHosts(sFullIPv6Address).BannedDate = Now();
    dSeenHosts(sFullIPv6Address).BannedTimes++;
}
If (!Connection.IsOpen()) return;
If (!DKIMVerify(mMail)) {
    Connection.Write(sDKIMFailedError);
    Connection.Close();
    dSeenHosts(sFullIPv6Address).IPBanned = True;
    dSeenHosts(sFullIPv6Address).BannedDate = Now();
    dSeenHosts(sFullIPv6Address).BannedTimes++;
}
If (!Connection.IsOpen()) return;
If (!VerifyRecepient(mMail)) {
    Connection.Write(sNobodyByThatNameHereError);
    Connection.Close();
}
If (!Connection.IsOpen()) return;
If (!RunSpamScore(mMail)) {
    If (dSeenHosts(sFullIPv6Address).SpamScore > iUserSpamScore) {
        Connection.Write(sSpamScoreExceededError);
        Connection.Close();
        dSeenHosts(sFullIPv6Address).TimesSpammed++;
        If (dSeenHosts(sFullIPv6Address).TimesSpammed > iUserSpamTimes) {
            dSeenHosts(sFullIPv6Address).IPBanned = True;
            dSeenHosts(sFullIPv6Address).BannedDate = Now();
            dSeenHosts(sFullIPv6Address).BannedTimes++;
        }
    } Else {
        If (dSeenHosts(sFullIPv6Address).TimesSpammed > 0) {
            dSeenHosts(sFullIPv6Address).TimesSpammed--;
        }
    }
}
If (!Connection.IsOpen()) return;
Server.Store(mMail);
Connection.Write(sMessageReceivedOK);
Connection.Close();

Monday, October 17, 2011

Saksatchewan, land ripe for entrepreneurship, but unfortunately backwards in technology...

A recent piece in the National Post has Saskatchewan and Alberta claiming Canada's top 9 for entrepreneurial cities, but unfortunately this pretty graph doesn't give the whole story, at least not for Saskatchewan.

Saskatchewan is, it's true, experiencing unprecedented growth, and is one of the only Canadian provinces that hasn't had an increase in unemployment. However, from a technological and ecological standpoint, Saskatchewan is really quite behind the times. There are a few indicators of this, so let's take them one-by-one.

SaskTel's monopoly makes external companies establishing a telephonic presence in Saskatchewan difficult.

What do I mean by that? Well, it seems that SaskTel is reluctant/refusing to give out Saskatchewan (306) area code numbers to anyone who doesn't have a firm Saskatchewan presence. This makes it very difficult to get any kind of VoIP service, barring the one "Open" VoIP provider operating within Saskatchewan itself and which SaskTel has a majority holding, and Access Communication's "Closed" VoIP service for access customers only. While they've not explicitly stated so, I believe this may be the stumbling block that has kept such innovative services as Google's "Google Voice" service out of Canada, despite the fact that Canada and the US share a phone system. If you look at any VoIP provider out there, it's impossible to get a large provider to give you a 306 number, because they just can't get them.

Business internet connectivity is woefully lacking.

With any other city (Edmonton, Winnipeg, Toronto, Vancouver, Montreal), there are multiple providers and multiple connection lines running throughout. It's a simple(r) matter to get a high-bandwidth high-speed line (or several) running into an office, and it's dead easy to find a whole slew of Co-Location providers for hosting all manner of services. In Saskatchewan, you have 2 options, SaskTel and Access, and neither is what you'd call "Big". All internet-related and co-lo services go out-of-province. Establishing a cloud-based service here is difficult, at best.

Home internet connectivity is poor, and the good stuff is held back by the equipment provided.

There are 2 choices of home internet provider. Access, who's service tops out at 5Mb/1Mb, and who incorporates a limit on their supposedly "Unlimited" high-speed internet. SaskTel has recently introduced it's (fantastic) 25Mb/2Mb VDSL package, which is totally unlimited in every way, but is held up by one major hiccup. The 2Wire gateways all share the same software, and that software has something of a fatal flaw – If there are more than 1,000 connections active, the gateway will start randomly dropping connections to get back under the 1,000 connection ceiling. Watching a movie on Netflix and someone decides to open WoW? There goes your streaming movie. Trying to have a conversation on Windows Live Messenger? Watch the connection bounce up and down. SaskTel do acknowledge this is a problem, and if you want to pay out of your own pocket, they can replace their ADSL gateways with a Westell modem providing basic connectivity only, and you bring your own router. The problem is that top tier package (The VDSL 25/2 one) won't work with the Westell modems. So it's 2Wire or nothing. Meanwhile in the US, with similar infrastructure, providers are offing 100MB packages for similar prices as we are paying for our 5Mb ones, and in Europe, Gigabit connections are coming in thick and fast, for incredibly reasonable rates.

SaskPower's short-sighted attitude to providing power services holds back green energy solutions.

Pretty much everywhere else in the world, power companies support green solutions. Time-of-use charging to even power loads and use excess capacity during off-peak hours, for instance, and buying back excess power from customers who have invested in green solutions like photo-voltaic cells and wind turbines. In fact, in the UK, you can "Rent your roof" to 3rd party companies, they will fit and maintain for 25 years (for free) the PV array and equipment, and take the buy-back profits from the power supplier, which you reap the benefit of considerably cheaper power bills.

Saskatchewan is perfect for wind generation – huge open flat prairie makes for long days and nights of strong, consistent winds. And on those rare days it isn't blowing to beat the band, it's hot and sunny all day long, with the "Living Skies" bathing the province in free sunlight. But without a buy-back option from the power provider, the investment in turbines and photo-voltaics is extremely heavy – you have to have enough to power your house & lands, and enough capacity to store during the leaner times, living entirely "off-grid", or you have to "throw away" the excess capacity you have during abundant times (Which SaskPower will gladly take off your hands for nothing) and eat the cost during lean times. With buy-back you make money during your abundant times, providing power back to the grid and your neighbours and offsetting the cost of the installation, and you're able to fall back on the grid when your system doesn't make quite enough.

As it stands, there are a few minor wind generating stations in Saskatchewan, though no solar stations that I am aware of. And this is a real shame. With all the open space, abundant sunlight and ever-present wind, Saskatchewan could become the power-generating capital of Canada, which would open huge employment opportunities across the province.

Agriculture has a firm hold on the economy and governmental attention, and almost nothing's going to change that.

Yes, farming and farming-related industries are big here. Huge, in fact. Indeed, I'd estimate that 55-70% of the jobs in Saskatchewan are in farming, the next 10-15% of the jobs are in service industries related to farming, 5-10% are mining and oil, and the rest are retail. There is no real technological center for Saskatchewan, and it seems that the Saskatchewan government isn't interested in any way in fostering any kind of high-tech infrastructure. Instead, they seem keen on squeezing every last dollar out of the farming industry, and draining the province dry of it's planet-killing hydrocarbons. While agriculture is a steady economic engine, and oil is a good short-term high profit business, neither really advances the province in any way, and neither is particularly attractive for outside investment or the growth of the province as a whole. As a child in Saskatchewan it seems there are only four realistic career options: Farming, Construction, Retail or Nursing. If you have the right blend of ethnicity and/or (dis)ability you may be able to meet quotas for RCMP recruitment. But any modern jobs are simply out of reach, or not worth pursuing as there's virtually no market for them.

In conclusion.

Wow, did this ever turn out to be WAY longer than I thought it would. Anyway, in conclusion, from a purely numerical standpoint, Saskatchewan looks like a great place to set up a new business. But when you look at the details, it becomes apparent that Saskatchewan is being held back, dragging it's feet on entering the modern era, and thus is destined to be left way behind. Modern businesses are in short supply, and very low demand, and what would be common services and industries anywhere else are demoted to niche markets. With a governmental and economic tendency towards stagnation and social conservatism, Saskatchewan is in serious danger of becoming even more of "the big empty space between Edmonton and Montreal". Perhaps it was a sign when the passenger trains stopped coming here all those years ago. I'm reminded of the Simpsons movie, when Springfield gets covered in a dome to protect the rest of the US from it's hideous environmental record – "[GPS announcer] Coming up on your right... Nothing...".

I'm not sure if Darren's going to read this (It's him to whom this will be tweeted first, as it was he that let me know about the above-mentioned chart), but I'll put it out there anyway. Do feel free to comment and correct anything in here that's wrong. It's written from my personal experience living here in Regina for the past 7 years after moving over from England, so it may not be entirely accurate, it is merely the impression I have received, and something that needs to be changed post-haste.

Saturday, April 9, 2011

Culinary quirks

It seems that every country has it's selection of culinary quirks. From the PB&J to Lutefisk, these dishes are often things that would make you scratch your head and ask "Whoever would have thought of doing THAT? What were they thinking?". But for all their strangeness, some (not all, I'll admit, but some) creations come under the "Now that's actually not half bad" part of the spectrum. So let's take a look at a few of these, shall we?

Starting off with the American classic, the PB&J. That's "Peanut Butter and Jelly (sandwich)", though that's the (Am.E) version of Jelly (A preserve not dissimilar to Jam, made entirely of juice, without pips, seeds or pulp of any kind, though oddly enough in this particular "dish", using Jam is just as appropriate). The mixture of dense protien, dry starch and sweet fruit (often also with a crunch, depending on the type of peanut butter used) makes this a dish of wildly clashing contrasts, which shouldn't work at all. And yet, it does, with the sweetness of the jam mellowing the gluing action of the peanut butter. And this can be extended. My wife is quite the fan of peanut butter and honey sandwiches, which is a little too much to my British palate.

And speaking of British palates, here's something entirely from my homeworld, which often has people looking at me askance: The Crisp and Salad Cream Sandwich.

Let me translate. Br.E Crisps are Am.E Potato Chips. In this particular regard, they should be "Ready Salted" flavour. Fortunately, Walkers crisps do exist in the US and Canada, though they use the brand name "Lays", and in this case "Lays Classic" chips are a perfect substitute. As for "Salad Cream", I found it here in Canada in Safeway, labelled as "Heinz Salad Cream English Dressing", with the interesting french version underneath being (translated back into English) "English Salad Cream Vinaigrette". So you take two slices of plain bread, add butter or margarine to taste, then layer on the Br.E Crisps/Am.E Chips. You need at least 3 layers, as they compress as you squash/hold the sandwich (in fact, some pre-compression may be required before assembly), and even coverage with large and unwieldy slices of potato is very difficult to manage with a single layer (Not impossible, I'm sure someone could engineer broken pieces of crisp/chip to fill the holes, but the flavour is a little too subtle with just a single layer). Then drizzle with the salad cream. This is easier said than done, of course, as a full bottle will produce a massive rush once you have gotten it going. Indeed, when the bottle is new, a much safer technique would be to insert a knife into the bottle and spread the salad cream in a thin layer on the un-coated piece of bread. Once you have creamed your sandwich, you assemble, pressing down with a flat hand on top to break down the crisps/chips into small chunks. Then you eat.

Crunchy, salty, smooth and tangy flavours and textures flood the mouth, and you know you have reached the pinnacle of sandwich nirvana. The crunching sounds continue unabated as you eat mouthful after mouthful of ingredients that were never in a million years meant to be used together, and you find it is good.

Switching gears a little, though still talking about things on bread, let's move our attention to Bitumen. Or to give it it's brand name: "Marmite".

Technically speaking, Marmite is a yeast extract, a residue of the brewing process, and many foods out there have marmite in them, albeit in it's more raw state. It's also one of the most divisive of foodstuffs out there – whole advertising campaigns have been based around the simple fact that you either love it, or hate it. So what do you do with this substance that looks not unlike road tar? Well, you spread it on bread, of course. But there is a VERY important point to make here – If you cannot see the texture of the bread through the layer of marmite, you have spread it TOO THICK! For beginners, especially, you will want to try and scrape the marmite off the bread again. the thin layer of residue that is left is more than enough for your first try. This is intense stuff, packed with flavour, and a major source of Umami, the taste that is strongly associated with meatiness. The other main source of Umami is, of course, Mono-Sodium Glutamate, or MSG.

So, what does it taste like? That's incredibly difficult to describe. Salty is certainly a contender. If you have ever had (Br.E) Beef Stock/(Am.E) Beef Broth or Consommé, imagine that, but concentrated at least a thousand times. That's what happens in your mouth, and you either love it, or hate it. Other notables in this family of substances are Bovril (Beef Extract, and not the brand of concentrated cooking stock in the US supermarkets) and Vegemite.

What else? How about "Chips on a Baguette"? Again, we're firmly in Br.E territory here, so let's expand. (Br.E) "Chips" would be (Am.E) French Fries, though "Steak Cut" fries are closer to a proper British Chip than the shoestring things the Americans typically call "Fries". And a Baguette would be a (Am.E) French Loaf or (Am.E/Br.E) French Stick, or perhaps a (Very Am.E) Submarine bun (Though those, again, aren't quite right. If you've ever seen a woman carrying shopping in a Hollywood film, she'll have a long thin loaf of bread sticking out the top of her paper bag of groceries – That's a Baguette). So, you slice your Baguette (Not all the way through, enough to make a hinge), you butter the inside (optionally), you fill the newly-made cavity with (Br.E) Chips/ (Am.E) Steak-Cut fries, and you sprinkle grated cheese over the top. Then you eat it quick as the cheese melts and your mouth exclaims in joy.

And they say we Brits have a bland palate!

Sunday, September 19, 2010

Some recording stats from my MythTV box...

Here are the current stats from my PVR. Interesting numbers to show just how much (or how little) TV we actually watch.

Recording Statistics

Number of shows:
246
Number of episodes:
12448
First recording:
Sunday January 23rd, 2005
Last recording:
Sunday September 19th, 2010
Total Running Time:
5 years 7 months 26 days 10 hrs 27 mins
Total Recorded:
1 year 2 months 8 days 13 hrs 47 mins
Percent of time spent recording:
10%
Shows Channels
Title Recorded Last Recorded # Title Recorded Last Recorded
How It's Made 1123 September 18 2010 1 CTV Toronto 679 September 18 2010
The Daily Show With Jon Stewart 948 September 16 2010 2 Space 217 September 14 2010
The Colbert Report 896 September 16 2010 3 CTV 200 September 18 2010
Law & Order 529 September 17 2010 4 Discovery 166 September 18 2010
Flip That House 485 October 18 2008 5 NBC Boston 130 September 2 2010
Star Trek: Voyager 472 September 7 2010 6 Mystery 114 September 19 2010
Star Trek: The Next Generation 395 November 26 2008 7 Comedy 95 July 28 2010
Frasier 368 December 3 2007 8 Global 72 July 12 2010
CSI: Crime Scene Investigation 366 May 20 2010 9 CTV NTV 72 September 19 2010
CSI: Miami 356 August 3 2010 10 Fox Boston 71 September 13 2010
Law & Order: Special Victims Unit 329 September 19 2010 11 CityTV Edmonton 71 September 16 2010
Law & Order: Criminal Intent 328 September 15 2010 12 CBS Seattle 70 August 21 2010
Due South 312 August 29 2008 13 ABC Boston 40 September 8 2010
Without a Trace 303 May 19 2009 14 A&E 38 August 3 2010
JAG 299 March 6 2008 15 Viva 36 June 8 2010
Cold Case 290 August 21 2010 16 CTV Vancouver 28 September 18 2010
MythBusters 262 September 12 2010 17 CityTV Calgary 21 September 18 2010
NCIS 240 September 1 2010 18 Showcase 17 July 2 2010
CSI: NY 230 June 30 2010 19 CityTV Toronto 16 September 9 2010
Battlestar Galactica 206 June 21 2009 20 Global Calgary 14 September 1 2010
Criminal Minds 197 June 29 2010 21 NBC Seattle 10 October 8 2009
House 192 September 19 2010 22 Fox Seattle 10 February 15 2010
Star Trek: Deep Space Nine 180 October 21 2008 23 Showcase Diva 9 June 12 2010
Tripping the Rift 178 September 12 2008 24 Global Vancouver 7 April 3 2010
Pimp My Ride 173 March 5 2009 25 Spike TV 5 February 5 2009

Monday, August 9, 2010

On HTML5, Video tags and Subtitles

Recently I read a rant about how HTML5 doesn't have closed caption support. This is true, but it's not so much of a hurdle as you might think. In a few hours I have worked out (mostly) a system that would work exactly the same way as the proposed extension (Barring the CSS wizardry requested – I'm not sure how to handle the requested pseudo-element selectors, so this one uses nice, simple CSS classes), all in nice, cross-platform JavaScript.

The script is copied below. I've not actually run it, or tested it, as I don't have any HTML5 video or SRT subtitle tracks to work with, but it should work in theory. And even if it doesn't, this is a reasonable starting point for building a complete system.

It's reasonably well commented, and should work just fine. I've not added any code to display the tracks dropdown, or to handle updating that part, and there's nothing in there to handle switching subtitle tracks, but that is a UI consideration IMHO. I may come back to this post and add that functionality at a later date. It also relies on being able to insert HTML elements inside a VIDEO tag. If that doesn't work, this could easily be changed to place an absolutely-positioned DIV over the top of the video, rather than drawing a DIV inside the video tag.

// Get array of videos on page
var v=document.getElementsByTagName("video");
 
// Loop through that array
for (var iVideos=0;iVideos<v.length;iVideos++) {
 
    // If the video has a "Track" element (or two)
    if v[iVideos].hasElement("track") {
        v[iVideos].tracks = [];
        v[iVideos].trackSelected = -1; // Change this to an index to change the displaying subtitle.
        // Get an array of tracks for each video
        var t=v[iVideos].getElementsByTagName("track");
        
        // Look through those tracks
        for (var iTracks=0;iTracks<t.length;iTracks++) {
            
            // If the kind is "Captions" or "Subtitles"
            if (t[iTracks].getAttribute("kind").toLowerCase()=="captions" || t[iTracks].getAttribute("kind").toLowerCase()=="subtitles") {
                
                // Add an object to the tracks array for this video object
                var iNewPos = v[iVideos].tracks.push({
                    "label": t[iTracks].getAttribute("label"), 
                    "kind": t[iTracks].getAttribute("kind"), 
                    "src": t[iTracks].getAttribute("src"),
                    "srclang": t[iTracks].getAttribute("srclang"),
                    "element": v[iVideos]
                });
                
                // Set up an async web request to fetch the text of the SRT file
                var xmlhttp=new XMLHttpRequest();
                if (!xmlhttp) 
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                
                // Store a reference to where we are, so we can work with it without having to wander through the page again
                xmlhttp.track = v[iVideos].tracks[iNewPos];
                xmlhttp.onreadystatechanged = new function() {
                    
                    // If we have a valid response
                    if (this.readyState == 4 && this.status == 200) {
                        
                        // Store the text, and fire off an SRT parser
                        this.track.webSRTText=responseText;
                        parseWebSRT(this.track);
                    }
                }
                
                // Fire off the request asynchronously
                xmlhttp.open("GET",t[iTracks].getAttribute("src"),true);
            }
        }
        
        // Set up a container for the subtitles
        var oSubtitleDiv = new document.createElement("div");
        oSubtitleDiv.style.position = "relative";
        oSubtitleDiv.style.bottom = "0px";
        oSubtitleDiv.style.left = "0px";
        oSubtitleDiv.style.right = "0px";
        oSubtitleDiv.cssClass = "cue";
        v[iVideos].appendChild(oSubtitleDiv);
        v[iVideos].subtitleDiv = oSubtitleDiv;
        v[iVideos].displaying = -1;
        
        // Set a function to update the subtitle container
        // Hopefully this doesn't fire TOO often, might want to only let this run every
        // x cycles or so, to ensure we don't bog the system down
        v[iVideos].timeupdate = new function() {
            if (this.trackSelected) {
                var track = this.tracks[this.trackSelected];
                if (track.cues) {
                    for (var iSRT=0;iSRT<track.cues.length;iSRT++) {
                        if (v[iVideos].currentTime > track.cues[iSRT].start && v[iVideos].currentTime < track.cues[iSRT].end) {
                            if (v[iVideos].displaying != iSRT) {
                                
                                // Remove the currently displaying contents
                                this.subtitleDiv.innerHTML = "";
                                
                                // Add the lines in this SRT file
                                for (var sLine in track.cues[iSRT].lines) {
                                    var oLine = new document.createElement("p");
                                    oLine.appendChild(document.createTextNode(sLine));
                                    this.subtitleDiv.appendChild(oLine);
                                }
                                this.subtitleDiv.cssClass = "cue cue" + track.cues[iSRT].cuenumber;
                                v[iVideos].displaying = iSRT;
                            }
                        }
                    }
                }
            }
        }
    }        
}
 
function parseWebSRT(track) {
    
    // Set up a variable to contain the text, with normalised line endings
    var text = track.webSRTText.replace(/(\r\n|\r|\n)/g, '\n');
    
    // Split the source into SRT blocks
    var aSRTParts = text.split("\n\n");
    
    var webSRT = [];
    
    // For each SRT part
    for (sPart in aSRTParts) {
        
        // Split it into lines
        var aSRTLines = sPart.split("\n");
        
        // Separate out the lines
        var aTimes = aSRTLines[1].split(" --> ");
        
        // Start time is the first defined
        var sStart = aTimes[0];
        
        // End time is the second defined. There may be some junk after it, separated by a space, so drop the rest
        // WARNING: This may barf, not tested
        var sEnd = aTimes[1].split(" ",2)[0];
        
        // Parse the times
        var iStart = parseSRTTime(sStart);
        var iEnd = parseSRTTime(sEnd);
        
        // Add the cue to the array
        var iNewPos = webSRT.push({
            "cuenumber": parseInt(aSRTLines[0]),
            "start": iStart,
            "end": iEnd,
            "lines": []
        })
        
        // Add the text lines to the newly-created cue object's lines property
        for (var i=2;i<aSRTLines.length;i++) {
            webSRT[iNewPos].lines.push(aSRTLines[i]);
        }
    }
    
    // Set the cues variable
    track.cues = webSRT;
}
 
function parseSRTTime(sTime) {
    
    // Split the time into parts, separated by colons
    aTimeParts = sTime.split(":");
    
    // The last part is the time in seconds, followed by a comma, followed by the time in ms
    // Easy way to sort that is to replace the , with a . and parse it as a float
    var iSecs = parseFloat(aTimeParts[aTimeParts.length - 1].replace(",","."));
    var iPosition = 60;
    
    // Loop through the parts BACKWARDS
    for (i=aTimeParts.length-2;i>0;i--) {
        
        // Increment the number of seconds, dependant on the position
        iSecs += parseInt(aTimeParts[i]) * iPosition;
        
        // Moving to the next highest denomenator, multiply by 60.
        // As the SRT only lists up to hours, this is a safe assumption to make
        iPosition = iPosition * 60;
    }
    
    // return the number of seconds total
    return iSecs;
}

Saturday, February 27, 2010

Umbraco… Not ready for the limelight yet?

I’ve been trying to use Umbraco CMS with my web host (See yesterday’s rant for a little more on that), but it seems that every version prior to 4.1 won’t run under “Medium Trust” (Something my web host seems to need). Thus I have downloaded the 4.1b2 version of Umbraco, and what do I find?

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Request failed.

Source Error:

Line 145:            <providers>
Line 146:                <clear />
Line 147:                <add name="UmbracoRoleProvider" type="umbraco.providers.members.UmbracoRoleProvider" />
Line 148:            </providers>
Line 149:        </roleManager>

Looking through the bugtracker, I find the answer that “This'll be because I haven't brought my replacements for umbraco.providers into the 4.1 trunk yet. Will do later on today.” That was posted on the 18th, and the issue was marked as “Fixed”, yet going through the changelogs there doesn’t appear to be any such fix applied as of yet.

This kind of thing is infuriating, and makes the past 3 months spent learning Umbraco’s templating and design system a complete waste. At the moment, I can’t use this system, as powerful and nice as it is, which means I’ve wasted valuable time. So I’m on the lookout for another open-source (or at least free-to-use) CMS system that supports discussion fora, is reasonably simple to use on the back end, and works under Medium Trust .net v2 (Perhaps v3.5, but given that 3.5 runs on-top of v2, it’s difficult to see what version is actually installed). I’d also prefer C#, but that’s not really a necessity.

Anyone have any suggestions?

1&1 Internet – Great pricing, not so hot .Net support, Atrocious billing…

Well, here we go with another rant. It’s been a little too long since the last one of these, so here we go.

I have an account with 1&1 internet, to do Microsoft Web Hosting. The price was great for what you get (I mean, really, check it out for yourself!) but for billing… I guess it would be easier if we had a credit card, but the banks seem to disagree with us on that, so we used (or at least tried to use) a Visa Gift Card instead.

They have difficulty accepting them, it seems. And while you can pay with PayPal, it uses PayPal’s “Pre-Authorised Debit” system. Great, except for two things. One, it needs a credit card associated with the account, and two, it doesn’t work at all outside the US. Not that you can see that. You can go (from their merchant link to set it up) and set the authorisation, choose the maximum amount they can take, and as far as you can see everything is AOK. But if you sign in to your PayPal account (Using your country’s portal), there’s no sign of any pre-authorised options, you can’t adjust them or anything. ‘Cause it’s US only.

So now I have paid them using a Swift EFT, a direct electronic money transfer from my bank to them. I called them to confirm they’ve received it, and they claim so, but I’m still getting automated messages on my account details page saying it’s overdue. *sigh*. I’ll call them again on Monday and see what they say.

The other issue is that they run their .net apps at Medium trust, and with little sign of what version and extensions are installed.

The “Medium Trust” lead me to not be able to use Umbraco 4.0b (Which I was developing against on my local staging site). I’m hoping they’re running .net 3.5, ‘cause then I can use the newly-released Umbraco 4.1b (Which does work against Medium trust, but Requires .net 3.5). If they’re not running .net 3.5, I’m going to be screwed here, quite honestly. At that point it starts looking more cost and effort effective to buy a basic box on Amazon EC2 and use that to host, though the bandwidth costs there would be the main expense.

Still, live and learn, huh?