Kindle URI Format

As many people, I am an avid user of Amazon Kindle. My family of three has two Kindles (2.0 and Paperwhite), my wife and I each have the app on our smart phones, and we each have Kindle for Windows on our laptops.

I was writing a document in Word and I wanted to be able to refer to particular sections of a Kindle book. I had a heck of a time figuring out the URI format, but I eventually put enough pieces together to give me what I wanted.

Here it is:

     kindle://book?action=open&asin=B003G4W49C&location=1178

There are more options than this, but this gets you to a particular location... it is made up of three components:
  1. action = open ... open the book
  2. asin = book identifier; you can find this in any number of ways. The easiest I've found is this:
    1. Go to your Kindle Content directory. Mine is C:\Users\Matt\Documents\My Kindle Content
    2. Then run findstr /m "Ender's Game" *.azw where in this case you would replace "Ender's Game" with your book's title.
  3. location = xxxxx ... whatever location you want to go to

Just thought I'd share...

Regular Expression for Book/Chapter of the Bible

What perl-compatible regular expression (PCRE) could match books/chapters of the bible?
How about this one:

/(^[123]?(\s+)?[a-zA-Z\s]+)(\s+)?([0-9]+)/




Everything between the first set of parenthesis is the book name. The parenthesis are done so we can pass the variables separately on to an array. This is a common task in working with PCRE, but for simply matching a pattern, may or may not be necessary. Though the second set, putting the \s+ in parenthesis, is for grouping as opposed to passing.

^[123]?
First we have to see if it is one of the books that starts with (^) a 1, 2, or 3 (e.g., 1 Chronicles, 3 John). The question-mark means that it's optional, because most books of the bible don't have those.

(\s+)?
Next we have to check if there is a space between that and the book name, because when somebody is searching for a book of the bible, they may get lazy (like me) and not put in a space. Again, it's optional as to whether or not it's there, so we use a question-mark.

[a-zA-Z\s]+
Next we have to check for all variations of capital or small letters, and we need to allow spaces as well for books like "Song of Solomon" (actually that's the only one with a space in it). Instead of the question-mark we have the plus, because at least one of these is required. You could also use [\p{L}\s]+ in PCRE, where \p{L}, or it's long form, \p{Letter} indicates a letter from any language.

The second set of parenthesis is the chapter...

(\s+)?
Again, the space (or more than one space for that matter) is optional between the book name and the chapter.

([0-9]+)
A chapter. At least one chapter is required (the + symbol).

Pretty easy, and honestly I put this blog entry in for myself to quickly refer to in case I have documented all my code badly (which I have!).

Humility and Resisting the Devil

First blog entry in over a year...

I was reading Luke 4:12, where the devil departed from tempting Jesus "until an opportune time." This is important to remember... that the devil is always looking for an opportune time. Because you have resisted him once (James 4:7), that doesn't mean he won't be back in the near future, as he is always on the prowl looking for someone to devour (1 Peter 5:8).

Interesting that both James 4:6-7 and 1 Peter 5:6-8 talk about humility just before they talk about resisting the devil... reminds me too of what I once heard someone say in a talk: The devil demanded to sift the apostles as wheat (Luke 22:31), which happened immediately after the argument about who was to be the greatest. And the "you" used in that verse is the plural one, probably meaning those involved in the conversation. The devil seized the opportunity where they were trying to be great in order to demand to have his way with them. And Jesus doesn't say, "I have prayed for you so he can't have you," because he knew the devil had a right to demand what what he was demanding. Instead Jesus said, "I have prayed for you [singular] that your [singular] faith may not fail. And when you have turned again, strengthen your brothers" (ESV). Jesus prayed specifically for Peter, the rock, that he would make it through this trial, then lead his brothers through it as well. And the greatest trial of their lives was just about to begin 14 verses later.

Here's my point (sometimes in my rambling I forget to get back there): If we are being severely tempted by the devil, let's resist him, but not forgot to ensure or confess that there be no seed of pride in us.

P.S., If you want more of my thoughts on Luke 22:31, read on.

It's interesting that the devil demanded (Greek: exētēsato) to sift Peter & the apostles as wheat. He had a right to do that. According to most modern translations, Jesus says that he prayed for Peter's recovery, yet the word used in Greek is "edeēthēn," which is not the word used for prayer anywhere else. Its only other usage is in Luke 9:40 where the man begged the disciples to cast the demon out of his son, but they were unable to. This tells me that the devil had a right to demand Peter and the apostles' sifting, and Jesus did not necessarily have a right to have his petition answered, at least not in the same way.

So it is a mercy for God to restore us after we have failed, not his duty.

Bible Search Algorithm part 1

I was searching for a bible search algorithm a while ago, and I couldn't find one publicly posted, so I wrote my own. Those familiar with the bible know that it is expressed in this format:
  • Book Chapter:Verse
  • e.g., John 3:16
But of course one can also show multiple references together using a combination of dashes, semi-colons, and commas.
  • John 4; James 1:2-8
    (Entire chapter 4 of John, James 1 verses 2 through 8)
  • John 7:40-8:11
    (John chapter 7 verse 40 through chapter 8 verse 11)
  • Ge 12:1-8; 15:1-6
    (Genesis chapter 12 verse 1 through 8, chapter 15 verse 1 through 6)
So I was considering how I could parse this down. I wrote to a few sites who do search results according to these generally agreed-upon principles, but I got no reply. So I wrote my own and thought I would share it. It's written in PHP but could certainly be adapted to anything. It does not use OOP and could probably be improved upon, but I am not a programmer by nature, so I figured I would just post what I have.

There are a few functions that work together to do the job. I will post the first one here with an explanation. This function normalizes the input into something that the other functions can use.


This function is designed to be called with the raw input. Here is what it would show for the various inputs above:

  • Array
    (
        [0] => John 4
        [1] => James 1:2-8
    )
  • Array
    (
        [0] => John 7:40-8:11
    )
  • Array
    (
        [0] => Ge 12:1-8
        [1] => Ge  15:1-6
    )

In the next post I'll talk about the next step in processing the data, which is breaking out the ranges into a top-most range and a bottom-most range using the hyphens as guidelines.

In subsequent posts, I'll outline the procedure for converting the abbreviation into the full book name (e.g., Ge → Genesis) and actually pulling data from the database, which may look different for different people depending on the database in use, etc.

Reading and remembering

As I was reading scripture today, I came upon Matthew 8, particularly the section that describes what one has to be willing to surrender to follow Jesus. I have read this dozens of times, but I had to "cheat" using Bible Gateway to remember where it was in scripture.

Something that I know already, but want to try more today, is sharing something you read and remember with other people. That is the best way to learn anything, not just where something is in scripture. I'm learning a new language right now, and it's well-known that the way to retain what you learn in a day is to repeat it and interact with it among lots of people.

May I be better at walking that out...

Application Performance II

I thought I would just tell a few quick stories about my encounters with application efficiency and how the network was blamed. In the spirit of humility, I'll offer where I feel I did poorly and where I did well, and what lessons I learned.

City Police Database
The biggest, most obvious example of this was when I was doing some consulting work for a city government, which shall of course remain nameless. They had gotten a new application (and when I say new, I mean it--it had not been seriously proven in any other installations). I was asked to make the application high-availability. The application was not ready to be installed yet, but I was to do the up-front work. The parameters were thus:
  • We don't want to buy any new network equipment
  • The redundancy must go across multiple sites, which are connected by DS3 links several hops away.
So I devised a method I thought was pretty good to fit these parameters. It used pre-existing Cisco 3845 routers: one at the "main site" and one at the "backup site." The 3 servers that made up the program (two application servers and one database server) went on a new VLAN that was routed by the 3845. The VLAN at the main site had one particular IP subnet and the VLAN at the backup site had another subnet. But each server had a loopback interface, and those interfaces were the ones that DNS pointed to. The 3845 at the main site used Cisco's IP SLA with tracking, tracking the application's TCP port on it's physical address. If the application went down, it stopped advertising the loopback /32 via EIGRP. The backup site would then start advertising, because it had a route to that /32 address but with an administrative distance of 200, which is lower than EIGRP's external administrative distance of 170.

All that is background, which is actually not related to my point. All of this redundancy stuff should probably not have been put in, at least without a careful up-front study of the application itself. That's another lesson: do your homework first, and save a lot of headache. If you have built a Cadillac simply to transport monkeys, you've probably wasted your time and efforts (and the customer's money). My personality type is ISTP, which if you know psychology, tells you why I went ahead and did all this.

It turns out that the application was horribly written in many ways--it didn't run as a service, it ran as a user-level program, so we had to set the servers to auto-login, etc. But the biggest problem was, and the point of this section, the performance. It had never been load-tested, nor had it been run over anything less than a gigabit network. So when it was slow, it was of course the fault of the network, and more specifically, the network engineer who obviously didn't know what he was doing.

Here's what we determined after I did a careful analysis of the application (without seeing any code or finding this out from the programmers who didn't speak English very well). The client component of the application, which sat on the user's workstation, was doing SQL queries in the background. Instead of doing a query like:
  • select COMPONENT from TABLE where SOMETHING > 100;
it was doing something like:
  • select * from TABLE;
then once it downloaded the huge amount of data, it would "post-filter" that. Yes, definitely a network problem when every query resulted in the downloading of over 100 megs of data, which would then be weeded out by the client software just to show 10 records.

It was really difficult maintaining humility in this, and I must confess that though I did maintain humility while investigating, I blew a gasket once I discovered the problem.

Pharmaceutical Database
There was a particular pharmaceutical company I consulted for who wanted a fast link between their main site and another site where many users were as well as off-site backups sat. They already had a DS3 between the sites, but they wanted to put in an additional 100 Mbps connection, which they did. I then configured all the routers, etc, to route things primarily down the 100 Mbps connection and secondarily down the DS3.

Everything was fine and we verified the routing was going the correct way, etc. But then the database backups started going much slower than they had before. After investigating, I discovered that the DS3 ran more-or-less directly from their office in West Bend, WI, to the office in Waukesha, WI. However, the 100 Mbps connection ran from West Bend, WI, up to the CO in St Paul, MN, then down to Waukesha, WI.

Obviously, the latency over the 100 Mbps connection was significantly more (25-30 milliseconds) than the latency over the DS3 since the distance was so much further. This can be understood here. So this was a network problem, if you will. However, again, the way the database was synchronizing, it was doing thousands of little queries, rather than a bulk transfer.

Here were some possible solutions, in no particular order.
  1. Modify all the computers to use a higher TCP window size using the Window scale option. Without window scaling, you have to consider latency when determining the maximum speed of a TCP session. It goes like this:

    Window Size (bytes)
    ------------------- * 8 bits/byte = bps

    Latency (sec)


    So 65535 / .025 * 8 = ~21 Mbps. So we could not get more than 21 Mbps from this connection.
  2. Make the syncing go over the DS3.
  3. Ask the programmers re-write the way the database synchronizes.
  4. Make the carrier reroute the 100 Mbps connection.
First we enabled TCP window scaling option for the two servers that needed to synchronize across this connection. That didn't seem to help. Then we dug into just how the application was working and discovered the little queries that made the syncing work, which would be unaffected by window sizing. So we tried option 3, because it was what we determined to be the best. The programmers laughed and said it was a networking problem and it was our fault because it used to work better. We probably should have pushed them harder and gotten management involved more, but we didn't. We tried option 4 but that was impossible because the carrier was based in MN and would have charged roughly a bazillion dollars to run fiber directly between the two sites, and this carrier was originally chosen precisely because they did a good price/sales job on the management.

Ultimately we made the syncing go over the DS3 using offset lists in EIGRP for /32 routes for those two servers. That also meant that there would be asynchronous routing when anything communicated across the WAN with one of those two servers (besides the server-to-server communication of course). No one cared, as long as it "worked better" and redundancy was there.

Two lessons from these experiences:
  • Do your homework! Don't rush ahead without asking a lot of good questions. Some things may seem obvious based on your past experience, but don't assume.
  • If you determine something to be the best option and it gets laughed off by the people you're suggesting it to, go to management ready to explain all the ins-and-outs of the problem as you understand it.
  • Whatever your personality type, attempt to show restraint in running ahead with solutions. Brain-storm, but remember that brainstorming is not meant to be implemented on a whim. Sleep on it and run it by colleagues and other smart people.
Remember, work as a team to get it resolved. If you blame someone else, try to put yourself in their shoes and always speak with humility and remind people you are on the same team--you just want to find the best solution. This kind of thinking is often contagious, and usually management will appreciate it. Of course, this isn't always true, and you can't control other people, but if you keep your cool, things will go better, at least for you.

Application Performance and the Jesus Way

Application Efficiency, Part I
The website Ethereal Mind, which I often read, had a recent post in response to another post by Matthew Norwood entitled Programming Bad Performance. It touched on something every network engineer feels when application performance is slow somewhere on the network. It's a topic I have dealt with a lot in my professional career so I uncharacteristically weighed-in with a comment, which I present below in a modified form...

It seems that the onus, or bur­den of proof, is often on the net­work engin­eer to fig­ure out just what the prob­lem is, since the net­work is this mys­ter­i­ous entity that most people don’t know much about. I have found two types of server admins in my exper­i­ence:
  • The ones that assume it’s their prob­lem and never think about the net­work, but then it proves to be a net­work prob­lem (often when attempt­ing to estab­lish com­mu­nic­a­tion between a ser­vice net­work and an internal net­work).
  • The ones that assume (along with all the users, usu­ally) that it is a net­work prob­lem and very quickly start point­ing fin­gers.
I have found that over the years I have learned a lot more about effi­cient data­base pro­gram­ming, ana­lyz­ing server cpu, memory, and disk util­iz­a­tion, etc, than I ever wanted to, as a means to simply find what the real prob­lem is. Greg at Etherealmind points out that prov­ing it’s not the net­work, or at least cast­ing plaus­ible reason to believe it’s not, will get you home on time. I agree with that, but in a world of people say­ing, “It’s not my prob­lem” and wash­ing their hands of it, I want to put forth a little more effort to get to the bot­tom of things.

Something else that I have learned is that humil­ity is really import­ant. If you start act­ing cocky and the prob­lem turns out to be yours, you really look like, and are, a jerk. Taking more of a “Let’s fig­ure this out together” atti­tude is much more likely to lead to suc­cess and team unity in the end. The real art is being able to foster and main­tain that atti­tude when other people seem to be out for blood.

The Jesus Connection
I'll make this my first post that crosses my two categories of blogging. Wanting to live life in a way that Jesus would do it, the previous paragraph helps see one or two ways of doing that. The bible often speaks of humility... three places that jump out to me:
  • Do nothing out of selfish ambition or vain conceit. Rather, in humility value others above yourselves, not looking to your own interests but each of you to the interests of the others (Philippians 2:3-4).
  • For those who exalt themselves will be humbled, and those who humble themselves will be exalted (Matthew 23:12).
  • When pride comes, then comes disgrace, but with humility comes wisdom (Proverbs 11:2)
Unity is also key to solving problems. It's amazing how humility and unity go together as well (I think that's pretty obvious). If everyone is cocky, it does not help team unity--it just creates divides. Be completely humble and gentle; be patient, bearing with one another in love. Make every effort to keep the unity of the Spirit through the bond of peace. There is one body and one Spirit, just as you were called to one hope (Ephesians 4:2-4).

Three of my favorite topics: humility, unity, and hope!

Previous working directory in Windows Command Prompt

Using bash in *nix has a handy feature: If you are in one directory and you switch to another one, you can use   cd -  to go back to the pr...