<s> """<STR_LIT>""" <EOL> import math <EOL> DEFAULT_VALID_CHARS = "<STR_LIT>" <EOL> DEFAULT_OFFSET_PERCENT = <NUM_LIT:30> <EOL> DEFAULT_STRING_LENGTH = None <EOL> DEFAULT_MINIMUM_LENGTH = <NUM_LIT:5> <EOL> try : <EOL> from django . conf import settings <EOL> DEFAULT_VALID_CHARS = getattr ( settings , '<STR_LIT>' , DEFAULT_VALID_CHARS ) <EOL> DEFAULT_OFFSET_PERCENT = getattr ( settings , '<STR_LIT>' , DEFAULT_OFFSET_PERCENT ) <EOL> DEFAULT_STRING_LENGTH = getattr ( settings , '<STR_LIT>' , DEFAULT_STRING_LENGTH ) <EOL> DEFAULT_MINIMUM_LENGTH = getattr ( settings , '<STR_LIT>' , DEFAULT_MINIMUM_LENGTH ) <EOL> except ImportError : <EOL> pass <EOL> class FriendlyID ( object ) : <EOL> def __init__ ( self , offset_percent = None , valid_chars = None , string_length = None , minimum_length = <NUM_LIT:5> ) : <EOL> self . valid_chars = valid_chars or DEFAULT_VALID_CHARS <EOL> self . number_valid_chars = len ( self . valid_chars ) <EOL> minimum_length = minimum_length or DEFAULT_MINIMUM_LENGTH <EOL> self . minimum_size = self . number_valid_chars ** minimum_length - <NUM_LIT:1> <EOL> self . offset_percent = offset_percent or DEFAULT_OFFSET_PERCENT <EOL> self . _period_cache = { } <EOL> self . _offset_cache = { } <EOL> self . string_length = string_length or DEFAULT_STRING_LENGTH <EOL> def get_size ( self , num ) : <EOL> "<STR_LIT>" <EOL> possible_size = self . minimum_size <EOL> while num > possible_size : <EOL> possible_size *= self . number_valid_chars <EOL> return possible_size <EOL> def get_period ( self , size ) : <EOL> """<STR_LIT>""" <EOL> if size in self . _period_cache : <EOL> return self . _period_cache [ size ] <EOL> highest_acceptable_factor = int ( math . sqrt ( size ) ) <EOL> starting_point = len ( self . valid_chars ) > <NUM_LIT> and len ( self . valid_chars ) / <NUM_LIT:2> or <NUM_LIT> <EOL> for p in xrange ( starting_point , <NUM_LIT:7> , - <NUM_LIT:1> ) : <EOL> if size % p == <NUM_LIT:0> : <EOL> self . _period_cache [ size ] = p <EOL> return p <EOL> for p in xrange ( highest_acceptable_factor , starting_point + <NUM_LIT:1> , - <NUM_LIT:1> ) : <EOL> if size % p == <NUM_LIT:0> : <EOL> self . _period_cache [ size ] = p <EOL> return p <EOL> for p in [ <NUM_LIT:6> , <NUM_LIT:5> , <NUM_LIT:4> , <NUM_LIT:3> , <NUM_LIT:2> ] : <EOL> if size % p == <NUM_LIT:0> : <EOL> self . _period_cache [ size ] = p <EOL> return p <EOL> raise Exception , "<STR_LIT>" "<STR_LIT>" % SIZE <EOL> def get_offset ( self , size ) : <EOL> return size * self . offset_percent / <NUM_LIT:100> - <NUM_LIT:1> <EOL> def perfect_hash ( self , num , size ) : <EOL> """<STR_LIT>""" <EOL> period = self . get_period ( size ) <EOL> offset = self . get_offset ( size ) <EOL> return ( ( num + offset ) * ( size / period ) ) % ( size + <NUM_LIT:1> ) + <NUM_LIT:1> <EOL> def friendly_string ( self , num , size ) : <EOL> """<STR_LIT>""" <EOL> string = "<STR_LIT>" <EOL> while self . string_length and len ( string ) <= self . string_length or self . number_valid_chars ** len ( string ) <= size : <EOL> string = self . valid_chars [ num % self . number_valid_chars ] + string <EOL> num = num / self . number_valid_chars <EOL> return string <EOL> def encode ( self , num ) : <EOL> """<STR_LIT>""" <EOL> if num < <NUM_LIT:0> : return None <EOL> size = self . get_size ( num ) <EOL> hash = self . perfect_hash ( num , size ) <EOL> return self . friendly_string ( hash , size ) <EOL> def test ( max_number ) : <EOL> """<STR_LIT>""" <EOL> fi = FriendlyID ( ) <EOL> from collections import defaultdict <EOL> a = defaultdict ( ) <EOL> for i in range ( max_number + <NUM_LIT:1> ) : <EOL> if fi . encode ( i ) in a : <EOL> print a <EOL> return False <EOL> a [ fi . encode ( i ) ] = i <EOL> return True <EOL> def performance_test ( num = None ) : <EOL> """<STR_LIT>""" <EOL> if not num : <EOL> num = <NUM_LIT> <EOL> from timeit import Timer <EOL> t = Timer ( "<STR_LIT>" % num , "<STR_LIT>" ) <EOL> print t . timeit ( number = <NUM_LIT:1> ) <EOL> if __name__ == '<STR_LIT:__main__>' : <EOL> print "<STR_LIT>" <EOL> fi = FriendlyID ( ) <EOL> print <NUM_LIT:1> , fi . encode ( <NUM_LIT:1> ) <EOL> print <NUM_LIT:2> , fi . encode ( <NUM_LIT:2> ) <EOL> print <NUM_LIT:3> , fi . encode ( <NUM_LIT:3> ) <EOL> print <NUM_LIT:3> , fi . encode ( <NUM_LIT:3> ) <EOL> print <NUM_LIT:0> , fi . encode ( <NUM_LIT:0> ) <EOL> print - <NUM_LIT:1> , fi . encode ( - <NUM_LIT:1> ) <EOL> print "<STR_LIT>" , fi . encode ( <NUM_LIT> ** <NUM_LIT:5> - <NUM_LIT:1> ) <EOL> print "<STR_LIT>" , fi . encode ( <NUM_LIT> ** <NUM_LIT:5> ) <EOL> print "<STR_LIT>" , fi . encode ( <NUM_LIT> ) <EOL> print "<STR_LIT>" , fi . encode ( <NUM_LIT> ) </s>
