"""
YOU PROBABLY SHOULDN'T USE THIS

See http://fi.am/entry/urlsafe-base64-encodingdecoding-in-two-lines/

You can do this using Python's built-in base64 library in just two lines of code:

import base64

def uri_b64encode(s):
     return base64.urlsafe_b64encode(s).strip('=')

def uri_b64decode(s):
     return base64.urlsafe_b64decode(s + '=' * (len(s) % 4))

----------------------------------------------------

Utility functions for signing a string using SHA1, then shrinking that SHA1
hash down to as short a string as possible using lossless base65 compression.

>>> data = "Hello"
>>> secret = "sekrit"
>>> sig = sign(data, secret)
>>> sig
'F7wP0YkP663d-n3yRDQVd8p0GC'
>>> verify(data, secret, sig)
True

"""

# Characters that are NOT encoded by urllib.urlencode:
URLSAFE = '-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
BASE10 = "0123456789"

import hashlib

def sign(s, key):
    return base65_sha1(s + ':'  + key)

def verify(s, key, sig):
    return sign(s, key) == sig

def base65_sha1(s):
    return int_to_base65(int(hashlib.sha1(s).hexdigest(), 16))

def sha1_from_base65(s):
    i = base65_to_int(s)
    return hex(i).replace('0x', '')

def int_to_base65(i):
    return baseconvert(str(i).lower().replace('l', ''), BASE10, URLSAFE)

def base65_to_int(s):
    return baseconvert(s, URLSAFE, BASE10)

def baseconvert(number_string, from_digits, to_digits):
    "Convert a number between two bases of arbitrary digits"
    # Inspired by http://code.activestate.com/recipes/111286/
    # Convert number_string (in from_digits encoding) to an integer
    i = 0L
    for digit in str(number_string):
       i = i * len(from_digits) + from_digits.index(digit)
    # Convert integer to to_digits encoding
    res = []
    while i > 0:
        res.insert(0, to_digits[i % len(to_digits)])
        i = i / len(to_digits)
    return ''.join(res)

