Using Nuget Without Nuget?

For a project I’m using VS2010 express, and needed the Google drive apis, which are available on Nuget. Except that Nuget (despite their claims) does not install on 2010 express.

Solution? Two actually, depending on how complicated the transfer is:

Solution #1: For small files, no nasty dependencies. Quick and simple.

  • Sign up and log into Nuget.
  • Find the package manually (ie, “search”)
  • Along the left, the “How to Download” link has become “Download”
  • Download the files (blahblahblah.nupkg)
  • Unzip it (rename it to .zip, or just right-click+save if available).
  • Add the /package/ dir to your project directory.
  • Add project reference(s) to whatever files you’re using in that dir.

Solution #2: For large interconnected groups and interdependencies, like I found with Google (which linked all over Heaven and Earth):

  • Get a Visual Studio that can use Nuget (if nothing else, VS2013 Express does.)
  • Install Nuget, etc.
  • Create a new project.
  • Find the package, and follow the site’s directions to download it, which will also take care of references, dependencies, etc.
  • Close that project.
  • Copy the /packages/ directory over to your original (old) project – make sure it’s to the same location relative to the old project as it was to the new (so the relative paths stay the same).
  • Open both project’s *.vbproj files.
  • Copy over the new reference entries (keep a backup of the file just in case). The reference entries look like this:
    <ItemGroup>
    <Reference Include="Google.Apis">
    <HintPath>packagesGoogle.Apis.1.9.0libnet40Google.Apis.dll</HintPath>
    </Reference>
    ...etc
    </ItemGroup>
  • Save and open. At this point the references should exist, and the files all grouped together.
  • Save everything. With it all grouped into one package, you can now say “buh-BYE” to Nuget.

I think it’s a sad commentary on the world today that there’s another layer of “help” being embraced that just further complicates matters. I’ve had no problem downloading code from a .zip file and using it until now – so why Nuget? Using Nuget means poor access to older Visual Studio (I can’t run it from VS Express, and can’t buy older Pro versions), so it does seem to be effective in “helping” people upgrade to the latest (likely paid) VS. And of course, it helps with dependencies – but whatever happened to including ALL files and a demo program together in one package? After all, that’s what I’m going to end up having to do with this code…

Darn It! Pi Day Redux

So I’ve been planning Pi day ’15 for awhile – then forget.

And it was going to be so good, too – the 15 would make it work out really well:

Mar 14/15 -> 03 14 15 9 26 53 589 -> 03.14.15 9:26:53.589 (AM)

Oh well, missed that.

Anyhoo, here’s about 1,000 digits or so – I was going to include a picture, but it turns out a picture is worth a thousand words,it’s more like thirty thousand:

THREE POINT …

1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679 8214808651 3282306647 0938446095 5058223172 5359408128 4811174502 8410270193 8521105559 6446229489 5493038196 4428810975 6659334461 2847564823 3786783165 2712019091 4564856692 3460348610 4543266482 1339360726 0249141273 7245870066 0631558817 4881520920 9628292540 9171536436 7892590360 0113305305 4882046652 1384146951 9415116094 3305727036 5759591953 0921861173 8193261179 3105118548 0744623799 6274956735 1885752724 8912279381 8301194912 9833673362 4406566430 8602139494 6395224737 1907021798 6094370277 0539217176 2931767523 8467481846 7669405132 0005681271 4526356082 7785771342 7577896091 7363717872 1468440901 2249534301 4654958537 1050792279 6892589235 4201995611 2129021960 8640344181 5981362977 4771309960 5187072113 4999999837 2978049951 0597317328 1609631859 5024459455 3469083026 4252230825 3344685035 2619311881 7101000313 7838752886 5875332083 8142061717 7669147303 5982534904 2875546873 1159562863 8823537875 9375195778 1857780532 1712268066 1300192787 6611195909 2164201989

Brooklyn 99 And The 12 Men On An Island Puzzle

I was watching Brooklyn Nine-Nine and the ‘Captain Peralta’ episode when they posed this problem:

Twelve men are on a desert island, all with identical weights except for one of them, who is slightly lighter or heavier than the others. The only other thing on the island is a seesaw. There are no scales or means to measure weight otherwise. Can you determine which man has the different weight? You only get to use the seesaw three times.

This is a version of the balance or twelve coin problem which is as old as the hills. Variations of it abound, and keeping them straight is a pain (and made for a few annoying minutes for me last night). Hence, here’s some solutions:

By the way, we’ll talk about coins numbered 01 through 12 from here on in – men, weights, marbles, it doesn’t matter. What is key is that you have a limited number of weighings, and only one is not like the others (optionally, you may know if it is lighter or heavier, but you may not).

Problem One: One Item is Heavier/Lighter. Find It.

Pretty easy if you know the coin is definitely heavier or lighter than the others, because the tilt of the scales gives you extra information (a lighter one will tip the scale up on that side, for example). So weigh 6 on one side, 6 on the other. Pick the lighter/heavier side which will contain your ‘bad’ coin. Then split those 6 into two groups of three, and do it again. The final three are tested this way: weigh 2 of them, one on each side. If it tilts, you know it’s the light/heavy one on the scale. If they balance, the odd one of the trio you didn’t weigh is the bad one. This final part is the ‘trick’, since some people are left wondering for the third step how you can weigh three items with one measurement – but as you can see, a balance between the two on the scale points the finger at the third one not on the scale…

This is the classic form of the puzzle, and likely the one referred to by Amy Santiago when she said “You place six on each side…”

Problem Two: One Item is Different (Maybe Heavier, Maybe Lighter). Find It.

Now it’s trickier – you don’t have the knowledge if it’s heavier or lighter, just that it is different. It can be done however. To make it easy, we’ll consider 12 coins, with one that is lighter or heavier, and numbered from 01 to 12, along with a pan scale:

Weighing 1: Weigh 4 on one side, 4 on the other. There’s three possible outcomes we care about here: The scale shows that the left side is heavier (LH), the right side is heavier (RH), or they are equal (EQ). So for
01,02,03,04 versus 05,06,07,08 and ignoring 09,10,11,12
Let’s look at each in detail:

  • Equal (EQ): If these are equal, then they are all good coins, and one of 09,10,11,12 is the problem – but we don’t know if they’re heavier or lighter!
    Weighing 2: Measure three of these coins against three of any of the others (which we now know are all good, so we’ll ignore their numbers):
    09,10,11 versus OK,OK,OK
    Results of weighing 2:

    • LH: We now know that one of 09,10,11 is heavy. So we use that to eliminate them in another weighing of two of them:
      Weighing 3: 09 versus 10
      Since we’ve already proven the bad coin is heavy, if one side or the other dips, that’s the bad coin. If it doesn’t, the odd coin out (11) is the ‘winner’, and heavy.
    • RH: The opposite of LH, we know the problem coin is lighter. Do the same test, but look for the scale to tip up to find our coin, or if balanced for it to be coin 11.
    • EQ: 09,10,11 are equal, so we know it’s 12, but we don’t know if it’s heavier or lighter. For that, just weigh against a good coin and see if it dips up or down:
      Weighing 3: 12 versus OK coin
  • With the result of Weighing 1, for both Left Heavier (LH) or Right Heavier (RH), we actually found two items of information from these weighings:
    1. Since one of these eight is the baddy, we’ve proven that the four we left off are ‘good’ coins.
    2. As well, because of this test, if we can somehow know the coin’s number, we’ll also know if it is heavier or lighter – for example, if the left side was heavier, and the coin is 03, we know it must be heavier; if coin 07, lighter.

    We now use this info to our advantage. The trick is to swap one coin on either side, and replace the remaining three coins on the right with three of those known good coins (keeping track of every coin of course). So we end up with:

    Weighing 2: 01,02,03,05 versus 04,OK,OK,OK
    The various possible results are as follows, based on the outcomes from Weighings 1 and 2:

    • Weighing 1 (LH) Weighing 2 (EQ): if this weighing is equal, the offending coin must be one of the ones we DIDN’T weigh this time – 06,07,08 – AND we know it’s light (since the scale was tipped up on that side in the first weighing). To pick the bad coin from these three, we do our third weighing of two of them:
      Weighing 3: 06 versus 07
      If equal, it’s 08 (and we already know it’s lighter), or if unequal, the lighter one is our culprit.
    • Weighing 1 (RH) Weighing 2 (EQ): Like the previous case, it’s one of 06,07,08 but this time we know it’s a heavy coin. Weigh 06 versus 07 and pick the heavier one, or if equal, 08.
    • Weighing 1 (LH) Weighing 2 (LH): We swapped 04 and 05, so if one of them was the bad coin, the scale should have tipped the other direction. It didn’t, so it must be one of 01,02,03 and we know the bad coin must be heavier. We already learned how to weigh and pick a coin from among three when we know if it is heavier or lighter (weigh two, and check for LH/RH/EQ) So we’re done here in three weighings.
    • Weighing 1 (LH) Weighing 2 (RH): In this case, the scale is now tilting the other way. Now we know it has to be one of the ones we swapped, 04 or 05. So we weigh one against a known good coin:
      weighing 3: 04 versus OK
      If they are equal, then 05 is the bad coin, and from weighing #1, we know it’s light; if not equal, then it’s 04, and heavy.
    • Weighing 1 (RH) Weighing 2 (LH): Since the scale switched directions between weighings, it’s 04 or 05. Again, do
      weighing 3: 04 versus OK
      and the result is 05+heavy if equal, or 04+light if not (based on Weighing #1).
    • Weighing 1 (RH) Weighing 2 (RH): Again, swapping 04 and 05 made no difference, so we know it’s 01,02,03 and that one of them is too light (based on weighing #1). Do our 2-coin test for weighing 3, and we’re done.

Whew!

But wait, there’s more:

Problem Three: The Brooklyn Nine-Nine Puzzle

Probably they just renamed the puzzle on the show from coins to men for a few laughs (one character spent time daydreaming who the men would be), but the fact is, that puzzle is not coins in a scale, but men on a seesaw. That makes the puzzle different, not just since you won’t likely get a group of men to balance exactly on a seesaw for weighing purposes (ignoring the practical impossibility of finding 11 men with the same weight to the gram), but because a seesaw is a long beam with many places to sit/weigh from – near the center as well as the far ends.

Of course, if you can get four men to somehow balance properly on a small spot you can solve this puzzle like the previous one, but you might also be able to improve it:

Just draw six lines on each side, evenly spaced from the ends to (almost) the center. All twelve men sit on the seesaw, one on each line. If the seesaw is only slightly unbalanced (the ends don’t go all the way to the ground when everyone sits still), then you have a crude weight measuring device. Have each man swap with an adjacent neighbor, and watch for the change in weight. Only the odd man out swapping will change the scale, and the change will indicate if he’s heavier or lighter than the rest.

One other point: Since the rule is “you only get to use the seesaw three times” and you actually keep everyone on the seesaw the whole time, you’ve actually solved the puzzle in just one ‘use’!

Want More Thought – Provoking Ideas? Click Here for the “The Dreamer’s Manifesto” – Neat-o Ideas For You To Use…

Thunderbird And The Error “The messages could not be filtered to folder ‘Junk’ because another operation is in progress.”

For the past couple of months I’ve been using Thunderbird for my email, finally replacing Eudora. All in all, well worth the transition, especially with the way it handles spam (and in particular, the RegEx plugin FiltaQuilla).

But lately, one message has been bugging me:

The messages could not be filtered to folder ‘Trash’ because another operation is in progress.

Needless to say, since my emails weren’t filtered, I had to do the work manually – very annoying.

A bit of research later, and the solution was simple: I had under the advice of another website reduced my auto-compaction rules to 1 meg. So as email came in, it triggered automatic compaction, which prevented the filtering. Bumped it up to 10meg, and problem went away.

Here’s how:

  • Go to menu Tools; Options; and tab ‘Network & Disk Space’
  • Increase the amount for “Compact all folders when it will…” to at least 10 meg.
  • …or better yet, uncheck the box, and be prompted to manually compact.

That’s it!

Too Much Puzzle For One Man (Or Woman)?

As part of our year of new and interesting brain challenges, the Missus just finished a jigsaw puzzle she picked up at the Dollar Store.

Who doesn’t love puppies?

Too Much Puzzle

Strange thing however, she ended up with an extra edge piece.

puzzle3I looked at this and immediately knew this was a puzzler for the ages, an allegory for today’s world.

allegory: a figure of speech in which abstract ideas and principles are described in terms of characters, figures and events

Ok, not an allegory – I meant a simile. Or a metaphor? Perhaps symbolism?

simile: a figure of speech that directly compares two things through the explicit use of connecting words such as like, as, etc.

metaphor: a figure of speech that identifies one thing as being the same as some unrelated other thing, thus strongly implying the similarities between the two

symbolism: use of symbols to signify ideas and qualities by giving them symbolic meanings that are different from their literal sense

Ironically, I can’t figure out which to apply.

irony: a figure of speech in which words are used in such a way that their intended meaning is different from the actual meaning of the words

I give up – there’s just too many literary devices out there (and if you want a comprehensive list, check out literary-devices.com)

But I do know this about that puppy puzzle:

  • Gwen found it quite aggravating to have that extra piece, and trying to find a home for it.
  • Anyone who’s done a puzzle knows you tend to put the edge pieces together first, so an extra piece there is a hair-puller for sure (or should I say Fer Shur? It just seems more appropriate here).
  • An unhappy person is out there with a puzzle missing an edge piece.

Somehow, this seems to fit the world of today – missing-or-too-many pieces, poor quality control, unnecessary frustration because people did their job(s) poorly, etc. A major lapse of quality in general. Even fun has a taint to it. Etc, etc, etc (or yada, yada, yada).

Or looked at another way, that could be the reason it’s at the Dollar Store, heavily discounted, and the puzzle has elicited just enough pleasure to accurately match its dollar value. Checks and balances exist, and so the world is a wonderful place.

Wait – maybe this in turn is some form of meta lesson, that how we perceive the world is how the world actually exists, since we rely on our senses to formulate our reality. The puzzle is good or bad, in that cup half full/half empty kinda way, and you are at the wheel, making the decision.

Nah.

Somebody screwed up, and now I’m left wondering how much fun it would be to give the puzzle to someone else to put together.

Cute puppies, though – all 501 pieces of them.

WordPress and XML-RPC With Visual BASIC .NET

My wife’s website is filled with photos she’s taken locally, and making sure they get up there handily is my job. Previously, she used a VB program I cobbled together to move photos from her various cameras onto the computer, then upload them to the site (lightbox style display on the Windows computer, FTP to upload the pics, etc). Unfortunately the final step, embedding the images in a post, was a quick hack (copy a link to the clipboard and paste into a new post) and that needed a fix.

So to fix it, the program now uploads the pic, and then creates a new post with the picture included, ready to edit and publish.

This magic happens via XML-RPC – which is a pre-SOAP method of making remote function calls over the Internet. Using it, the VB program can call one function and create a new post.

The steps are as follows:

  • Add handler code for XML-RPC. Fortunately, the very nice xml-rpc.net takes care of that, giving us a project we can compile to create a DLL to wrap XML-RPC calling. From there, we simply add the reference and DLL to the project, and get the basics of XML-RPC with little effort.
  • Decide what to call. WordPress supports several protocols (as noted on their site). In this case, I call the WordPress function metaWeblog.newPost which publishes a post with supplied text. My reason to use this? I had found some code called WordPressSharp that wrapped the WordPress functions, but it was GPL (which is always awkward if I ever decided to commercialize my code); a bit more searching found me at a site that described how to code for the metaWebblog call, and no GPL, so it was the winner!
  • Call it. The code to call is pretty straightforward – in fact, I wrapped it in a function for ease of use (change userName, userPwd, and xmlrpcURL to match your site):
    Imports CookComputing.XmlRpc
    
    ...
    
    Public Structure blogInfo
      Public title As String
      Public description As String
    End Structure
    
    Public Interface IgetCatList
      <CookComputing.XmlRpc.XmlRpcMethod("metaWeblog.newPost")> _
      Function NewPage(ByVal blogId As Integer, ByVal strUserName As String, ByVal strPassword As String, ByVal content As blogInfo, ByVal publish As Integer) As String
    End Interface
    
    Private Function DoPost(ByVal title As String, ByVal post As String) As Integer
      Dim newBlogPost As blogInfo = Nothing
      newBlogPost.title = title
      newBlogPost.description = post
      Dim categories As IgetCatList = CType(XmlRpcProxyGen.Create(GetType(IgetCatList)), IgetCatList)
      Dim clientProtocol As XmlRpcClientProtocol = CType(categories, XmlRpcClientProtocol)
      Dim userName As String = "blogusername" 
      Dim userPwd As String = "bloguserpassword"
      Dim xmlrpcURL As String = "http://egwebsite.com/xmlrpc.php"
      Dim publish As Integer = 0
      clientProtocol.Url = xmlrpcURL
      Dim result As String = Nothing
      result = ""
      Try
        result = categories.NewPage(1, userName, userPwd, newBlogPost, publish)
        If (0 = result) Then
          Throw New Exception("Unknown error in message")
        End If
        MessageBox.Show("Posted to Blog successfully! Post ID : " & result.ToString)
      Catch ex As Exception
        MessageBox.Show(ex.Message)
        Return 0
      End Try
      Return 1
    End Function

In this case, it would assign the post to the user selected, submit it as Draft (set publish to 1 to publish immediately), and assign it to the default category. The reason I kept it simple was that most posts will need some tweaking, so just get it up there and let the Missus adjust category, publish date, etc. Of course, you can modify this function to do what you want, or even set it up for another call entirely.

And that’s it. The result is a quick addon in VB for XML-RPC, and an easy way to communicate with WordPress from another program. So if you need to tame WordPress via VB.net, I’d heartily recommend the xml-rpc.net DLL.

‘Think Python’ Excercise 12-6 – Optimized Solution?

I’m busy working my way through Think Python and doing the excercises when I found an especially interesting one:

Exercise 12-6: Another ‘Car Talk Puzzler’:
What is the longest English word, that remains a valid English word, as you remove its letters one at a time? Now, letters can be removed from either end, or the middle, but you can’t rearrange any of the letters. Every time you drop a letter, you wind up with another English word. If you do that, you’re eventually going to wind up with one letter and that too is going to be an English word—one that’s found in the dictionary. I want to know what’s the longest word and how many letters does it have? I’m going to give you a little modest example: Sprite. Ok? You start off with sprite, you take a letter off, one from the interior of the word, take the r away, and we’re left with the word spite, then we take the e off the end, we’re left with spit, we take the s off, we’re left with pit, it, and I.

The answer, found on the Think Python site, consists of creating a dictionary, and then for every word in it:

  • Generate a list of all the words that can be made from it by removing one letter.
  • Check if each of these entries exists, and if so recursively check that word.

The end result is a list ending in a single letter word, and success. Finally, the largest list of all the words is passed out for display.

Using a dictionary, the result is quite fast – on my computer, it took about 2.2 seconds to read in and process 275k entries (which consisted of the Scrabble SOWPODS ‘official’ words list). But of course, I was wondering if it could be optimized.

Several changes came to mind:

  • Since we want the largest entries, we ignore smaller ones as we find matches. For example, if a five letter word is a winner, then we only test words greater than five letters in the future.
  • We know that eventually the one word answer has to be either ‘A’ or ‘I’, the only two single-letter words in English. For this reason, we can skip words not containing those letters. In our test file that means ignoring about 16% of the words – not much, but it adds up.
  • The routine is simpler – scanWord(array) is called on each entry in the dictionary (turned into a single entry array). The function takes that entry and creates a list of words which are missing one letter from it, and checks them against the dictionary (for example, passing in ‘DOG’ would create ‘OG’, ‘DG’, and ‘DO’). If any match, it’s added to the array, which is then passed recursively to scanWord(). If not, it’s on to the next entry. And of course, if none match, an empty array is passed back, the flag for failure (and a full array passed back is success).

Here’s my optimized code:

def make_word_dict():
    # this function copied from 'Think Python' exercise 12-6
    that contains the words as keys."""
    d = dict()
    fin = open("scrabble-sowpods.txt")
    for line in fin:
        word = line.strip().lower()
        d[word] = word
    for letter in ['a', 'i', '']:
        d[letter] = letter
    return d
  
def scanWord(a):
  w=a[len(a)-1]
  i=len(w)
  for k in range(0,i):
    x=w[:k]+w[k+1:]
    if (x in d):
      r=list(a)
      r.append(x)
      if (1==len(x)):
        return r
      r=scanWord(r)
      if (len(r)>0):
        return r
  return []

d=make_word_dict()
matchLen=-1
matchList=[]
for w in d:
  if (len(w)>matchLen):
    if ( 'a' in w or 'i' in w ):
      a=[w]
      l=scanWord(a)
      if (len(l)>0):
        matchLen=len(w)
        matchList=l
s=','.join(matchList)+'n'
print s

Using this the code the timing was about 0.88 sec versus 2.2 for the other one. However, since both loaded in the word list first (make_word_dict() – about 0.2 sec), the result was really 0.68 vs 2.0 on the processing – about 3X speed increase.

And the winner? An 11 character entry:

austringers, astringers, stringers, stingers, singers, singes, sines, sies, sis, is, i

Of course, it wasn’t the only one – here’s the other 11 character entries found:

breastfeeds, breastfeed, breastfed, breasted, reasted, easted, eased, ease, eas, as, a
carabineers, carabiners, carabines, carbines, carbies, caries, cries, cris, cis, is, i
carabineros, carabiners, carabines, carbines, carbies, caries, cries, cris, cis, is, i
carabiniers, carabiners, carabines, carbines, carbies, caries, cries, cris, cis, is, i
complecting, completing, competing, compting, comping, coping, oping, ping, pig, pi, i
housellings, houselling, houseling, housling, housing, hosing, hoing, hing, hin, in, i
scratchiest, scratchies, scratches, cratches, ratches, raches, aches, aces, ace, ae, a
streamlings, streamings, steamings, teamings, tamings, tamins, amins, ains, ins, is, i
unpreaching, upreaching, preaching, peaching, peching, eching, ehing, hing, hin, in, i

I’m starting to like Python…

A Word That Has Been ‘Literally’ Meaningless Since 1769

I like words – precisely placed, carefully sounded words than mean what they should, no more and no less.

Obviously then the current fascination with the misuse of ‘literally’ is something I am very much aware of.

Yes, I’m one of those folk – the kind that grit their teeth when ‘who’ and ‘whom’ are used interchangeably, get irritated when “it’s” is used as a possessive instead of a contraction, and remember that ‘like’ is a word meaning similar, or fond of – not a meaningless interjection after every fourth word in a conversation.

So of course I was literally seeing red when I heard that ‘literally’ now meant ‘figuratively’ as well. It has been ensconced in the dictionary along with ‘ginormous’ as a word meaning (according to the Oxford English Dictionary)

“c. colloq. Used to indicate that some (freq. conventional) metaphorical or hyperbolical expression is to be taken in the strongest admissible sense”

Or to put it another way, the word literally means nothing useful at all – or literally everything, depending on your point of view.

This isn’t the only case of a word being more or less its own antonym. Whilst Bible reading years ago I came across ‘cleave’, which can mean both to stick together, or to split apart. But since we don’t use cleave in most polite conversations, it just doesn’t seem to carry the same impact as literally does.

But there’s an interesting side point – two of the examples the OED use are really old:

1769: F. Brooke Hist. Emily Montague IV. ccxvii. 83 “He is a fortunate man to be introduced to such a party of fine women at his arrival; it is literally to feed among the lilies.”

1801: Spirit of Farmers’ Museum 262 “He is, literally, made up of marechal powder, cravat, and bootees.”

Unless the first fellow is eating lillies, and “marechal powder, cravat, and bootees” is code for blood and flesh, we have two ages-old cases of ‘literally’ being anything but literal.

And all this fuss about literally? Literally blown out of proportion. It’s been misused for almost a quarter of a millennium. Or you could argue that since words take their meaning from everyday use (and misuse), that it has literally been used correctly all that time to mean its own opposite.

So we might as well follow tradition, and literally paper the walls with the word. Literally.

I don’t know about you, but it’s enough to make a man literally cleave his mind… in a ginormous way, of course.

Easy Schedule For Your Bible Reading (Or Part of It)

As I plan the new year’s activities, one I wanted to focus on was my Bible reading; in particular reading the whole New World Translation in a year. There are many Bible reading schedulers out there, but I decided to write yet another one for several reasons: To allow partial reading (say, just the Christian Greek Scriptures in a month), flexible start date and end (for example, starting on Dec 4 for 28 days), and accurate – since my version uses the word counts of each chapter, and maintains an error tally, the resulting schedule keeps the word count per day very even (as even as chapters allow!) Of course, the scheduler doesn’t just work with the NWT, since the word counts of the chapters in most Bibles are about the same (just over 875k total words for the NWT, by the way). Note there is no need to worry about years, as it understands that if the end date is earlier than the start date, you mean to go into the next year. Also note that Feb 29 on leap years is skipped.

Here it is – feel free to use it to set up your schedule of Bible reading:

Start Month/Day Start Book End Month/Day End Book
   

Schedule Displayed Here…