Wednesday, December 10, 2008

Jesus is Precious

The apostle Peter says, "To you who believe . . . [he] is precious" (1 Peter 2:7). The grace of God makes Christ precious to us, so that our possessions, our money, our time [and our abilities -ken] have all become eternally and utterly expendable. They used to be crucial to our happiness. They are not so now.
 Tim Keller, Ministries of Mercy, page 63 (The Motivation for Mercy: Grace and Generosity)

Sunday, November 2, 2008

Sword Project Bible Reader in Python updated

I've updated and finished the core functionality for a pure Python reader for SWORD Bible modules (hosted on github). I had previously posted an initial proof-of-concept, and now figured out how to map references to keys.

Still to do: OSIS rendering, abbreviation processing, and the sort of convenience stuff that a frontend would want (Next/Previous, etc.).

Friday, August 8, 2008

Supremacy of Christ

I want today to commend to each one of us the supremacy of Jesus Christ and his Gospel. It is both the supreme glory of God and the solid rock for our lives. These words don't do it justice. It's hard to find any words that do, but these by Piper do a lot better than mine:

http://www.youtube.com/watch?v=oYGLl0gO1dk&feature=related

We were made to know Christ, not do little trivial things.


I was also recently led to read a familiar passage a little differently. When I did, the emphasis lay on these words:

truth, righteousness, gospel of peace, faith, salvation, Word

They are of course the real things that comprise the "armor of God". I encourage you to likewise read Ephesians 6 with the supremacy of the Gospel in view.

One observation I took from that is that one way that the Cross breaks the enemy's power is by removing the allure of the things that he offers. When the enemy offered Jesus bread, he didn't want it because he had something better. If you're concerned about your health, the enemy can control you with something that promises health (like a meditation technique, in my parents' case). But if the Holy Spirit has given you a new heart that regards the love of God as better than life, the temptation of worldly health will have no power over you. In that way, the Gospel (truth, faith, salvation, God's word, etc.) is your armor.

Other observations about the Gospel? Comment away...

Wednesday, August 6, 2008

Sword Project Bible Reader in Python

Update: I've updated this and put in on GitHub.

The SWORD API is complex. I did at one point try the SWIG wrapper, but that was still quite difficult to get right.

Fortunately, as complicated as the code is, what it actually does turns out to be very simple. With the help of zverse.cpp, libtool gdb examples/cmdline/lookup, and the Holy Spirit, I came up with this simple Python file to read a verse given an index:

#!/usr/bin/env python

# * ztext format documentation
# I'll use Python's struct module's format strings.
# See http://docs.python.org/lib/module-struct.html
# Take the Old Testament (OT) for example. Three files:
#
# - ot.bzv: Maps verses to character ranges in compressed buffers.
# 10 bytes ('<IIH') for each verse in the Bible:
# - buffer_num (I): which compressed buffer the verse is located in
# - verse_start (I): the location in the uncompressed buffer where the verse begins
# - verse_len (H): length of the verse, in uncompressed characters
# These 10-byte records are densely packed, indexed by VerseKey 'Indicies' (docs later).
# So the record for the verse with index x starts at byte 10*x.
#
# - ot.bzs: Tells where the compressed buffers start and end.
# 12 bytes ('<III') for each compressed buffer:
# - offset (I): where the compressed buffer starts in the file
# - size (I): the length of the compressed data, in bytes
# - uc_size (I): the length of the uncompressed data, in bytes (unused)
# These 12-byte records are densely packed, indexed by buffer_num (see previous).
# So the record for compressed buffer buffer_num starts at byte 12*buffer_num.
#
# - ot.bzz: Contains the compressed text. Read 'size' bytes starting at 'offset'.
#
# NT is analogous.

# Configuration (set this to your own modules path):

modules_path = '/home/kcarnold/.sword/modules/texts/ztext'


import struct, zlib
from os.path import join as path_join

class ZModule(object):
def __init__(self, module):
self.module = module
self.files = {
'ot': self.get_files('ot'),
'nt': self.get_files('nt')
}

def get_files(self, testament):
'''Given a testament ('ot' or 'nt'), returns a tuple of files
(verse_to_buf, buf_to_loc, text)
'''
base = path_join(modules_path, self.module)
v2b_name, b2l_name, text_name = [path_join(base, '%s.bz%s' % (testament, code))
for code in ('v', 's', 'z')]
return [open(name, 'rb') for name in (v2b_name, b2l_name, text_name)]

def text(self, testament, index):
'''Get the text for a given index.'''
verse_to_buf, buf_to_loc, text = self.files[testament]

# Read the verse record.
verse_to_buf.seek(10*index)
buf_num, verse_start, verse_len = struct.unpack('<IIH', verse_to_buf.read(10))

uncompressed_text = self.uncompressed_text(testament, buf_num)
return uncompressed_text[verse_start:verse_start+verse_len]

def uncompressed_text(self, testament, buf_num):
verse_to_buf, buf_to_loc, text = self.files[testament]

# Determine where the compressed data starts and ends.
buf_to_loc.seek(buf_num*12)
offset, size, uc_size = struct.unpack('<III', buf_to_loc.read(12))

# Get the compressed data.
text.seek(offset)
compressed_data = text.read(size)
return zlib.decompress(compressed_data)

if __name__=='__main__':
import sys
mod_name = sys.argv[1]
testament = sys.argv[2]
index = int(sys.argv[3])

module = ZModule(mod_name)
print module.text(testament, index)

This was a one-evening project, mostly taken up by the reverse-engineering. As you can see, Python provides a lot of the foundation work so that the code we actually have to write is very small.

I still need to figure out how human-readable verse identifiers get mapped to those numerical indices. It's hidden somewhere in VerseKey...

Wednesday, July 23, 2008

For everyone who has been worrying about me...

No need to worry. The worst was really only about a day and a half, and it's been gradually and surely getting better since then. The rash is still there, but it's gone down a lot and now only hurts just enough to remind me that it's there.

So I add a third point to my previous post: 3. How quickly we forget. With the pain basically gone, so is my passion about those two points. It was very real then, but now it's a distant memory. I'm reminded of the stones of remembrance that the Israelites took from the Jordan as they were crossing over; even then, how quickly they forgot! (See Joshua 4:3-7)

Sunday, July 20, 2008

Gospel notes from having shingles

After my mysterious rash turned excruciatingly painful last night, I got it checked out this morning. Turns out it's a classic presentation of shingles. But I'd had it for more than a week before starting medication today, so it's quite painful. In fact, I think it's the first thing that I've experienced that makes me want to say, "it hurts like hell!" And thus I realized:

  1. Praise GOD that although I deserve to endure this for eternity, thanks to Jesus's work I don't have to!

    And if your eye causes you to sin, tear it out. It is better for you to enter the kingdom of God with one eye than with two eyes to be thrown into hell, ‘where their worm does not die and the fire is not quenched.’ (Mark 9:47-48)


    Then the king said to the attendants, ‘Bind him hand and foot and cast him into the outer darkness. In that place there will be weeping and gnashing of teeth.’ For many are called, but few are chosen.” (Matthew 22:13)


    4 Surely he has borne our griefs
    and carried our sorrows;
    yet we esteemed him stricken,
    smitten by God, and afflicted.

    5 But he was wounded for our transgressions;
    he was crushed for our iniquities;
    upon him was the chastisement that brought us peace,
    and with his stripes we are healed.

    6 All we like sheep have gone astray;
    we have turned every one to his own way;
    and the LORD has laid on him
    the iniquity of us all. (Isaiah 53:3-6)


  2. I want my attitude toward my sins be more like my attitude toward this virus.

    This virus is a tiny, otherwise insignificant pest. But I want to kill it! I want it out, never to return.

    Oh, that I would view my sins the same way! I'm usually content to let them hide in me; they're small and insignificant and I have more important things to be concerned about. But if I could just see them for what they really are -- painful ruptures in my soul that steal my joy away from God and maul God's dwelling place -- then I'd see how good it is to rip them out!

    For if you live according to the flesh you will die, but if by the Spirit you put to death the deeds of the body, you will live. (Romans 8:13)



God may be gracious and bring even more observations to my attention; he's actually shown me a lot in this and I praise him for it (though sometimes with gritted teeth!). Jesus, let me not waste my suffering.



More than that, we rejoice in our sufferings, knowing that suffering produces endurance, and endurance produces character, and character produces hope, and hope does not put us to shame, because God's love has been poured into our hearts through the Holy Spirit who has been given to us. (Romans 5:3-5)

Saturday, July 5, 2008

From Tablet ignites debate on messiah and resurrection:
"His mission is that he has to be put to death by the Romans to suffer so his blood will be the sign for redemption to come," Knohl said. "This is the sign of the son of Joseph. This is the conscious view of Jesus himself. This gives the Last Supper an absolutely different meaning. To shed blood is not for the sins of people but to bring redemption to Israel."
Very interesting article. The true Gospel is that Jesus's death accomplished both atonement for the sins of the people and by that, redemption for Israel. (i.e., those who are, like Isaac, children of the promise, and from every race, nation, tribe, and tongue.)

In short, the "new" discovery just confirms what we've known all along: "that Christ died for our sins according to the Scriptures" (1 Corinthians 15:3).

Friday, June 20, 2008

Django mini-series

I'm running a Django mini-series on Will Larson's blog, called Wielding Django. So far I have written:

  1. Minimalism

  2. Up to Speed

  3. JSON, Object-Oriented Views, and Starting a Real App



I'm mainly posting this to provide a place for discussion in the comments.

Saturday, June 7, 2008

mp3rename

I had a sizable collection of sermons that were named very badly (e.g., just the name). I was unsatisfied with all the mp3 renaming tools I found; they wouldn't get the output I wanted, or wouldn't read id3v2 tags, or etc. So, using python-eyeD3, I wrote my own.


#!/usr/bin/env python

import eyeD3, os, sys

default_subs = {
':': ' -',
}

bad_chars = ['?','/',':']

def clean(x, subs=default_subs, bad_chars=bad_chars):
for a,b in subs.iteritems():
x = x.replace(a,b)
for c in bad_chars:
x = x.replace(c,'')
return x

def do_rename_file(fname):
tag = eyeD3.Tag()
tag.link(fname)

name = []

num = tag.getTrackNum()[0]
if num:
name.append('%02d' % num)
name.append('-')

artist = tag.getArtist()
if artist:
name.append(clean(artist))
name.append('-')

title = tag.getTitle()
if title:
name.append(clean(title))

name = ''.join(name)

if not title:
print 'Not renaming %s - not enough tag data' % fname
return

name = name+'.mp3'

print 'Renaming "%s" to "%s": (OK,q,sub_name)' % (fname, name)
x=raw_input()
if len(x) > 2:
name = x
elif len(x) > 0:
print 'OK, skipping.'
return

os.rename(fname, name)

if __name__=='__main__':
for f in sys.argv[1:]:
do_rename_file(f)


You can modify the output format by... changing the code. But python is pretty readable.