|
|
|
(def DEFAULT_ALPHABET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
|
|
|
|
|
|
|
|
(def DEFAULT_SEPS "cfhistuCFHISTU")
|
|
|
|
|
|
|
|
(def DEFAULT_SALT "")
|
|
|
|
|
|
|
|
(def DEFAULT_MIN_LENGTH 0)
|
|
|
|
|
|
|
|
(def MIN_ALPHABET_LENGTH 16)
|
|
|
|
|
|
|
|
(def SEP_DIV (/ 7 2))
|
|
|
|
|
|
|
|
(def GUARD_DIV 12)
|
|
|
|
|
|
|
|
(def DEFAULTS {:salt DEFAULT_SALT
|
|
|
|
:min-length DEFAULT_MIN_LENGTH
|
|
|
|
:alphabet DEFAULT_ALPHABET
|
|
|
|
:seps DEFAULT_SEPS})
|
|
|
|
|
|
|
|
(defn- map-indexed [f xs]
|
|
|
|
(map f xs (range 0 (length xs))))
|
|
|
|
|
|
|
|
(defn- int-hash [num i]
|
|
|
|
(mod num (+ 100 i)))
|
|
|
|
|
|
|
|
(defn- as-indexed [x]
|
|
|
|
(if (indexed? x) x [x]))
|
|
|
|
|
|
|
|
(defn- swap [arr i j]
|
|
|
|
(def a (in arr j))
|
|
|
|
(def b (in arr i))
|
|
|
|
(put arr i a)
|
|
|
|
(put arr j b)
|
|
|
|
)
|
|
|
|
|
|
|
|
(defn- difference [s1 s2]
|
|
|
|
(seq [x :in s1 :when (not (find |(= x $) s2))] x))
|
|
|
|
|
|
|
|
(defn- intersection [s1 s2]
|
|
|
|
(seq [x :in s1 y :in s2 :when (= x y)] x))
|
|
|
|
|
|
|
|
(defn balance [alph-bytes seps-bytes]
|
|
|
|
|
|
|
|
[
|
|
|
|
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
(defn consistent-shuffle [alph-bytes salt-bytes]
|
|
|
|
(if (empty? salt-bytes) alph-bytes
|
|
|
|
(let [alph-array (apply array alph-bytes)
|
|
|
|
max-index (- (length alph-array) 1)]
|
|
|
|
(var p 0)
|
|
|
|
|
|
|
|
(loop [i :down [max-index 0]]
|
|
|
|
(let [v (mod (- max-index i) (length salt-bytes))
|
|
|
|
n (get salt-bytes v)
|
|
|
|
j (mod (+ n v (set p (+ p n))) i)]
|
|
|
|
(swap alph-array i j)))
|
|
|
|
|
|
|
|
alph-array)))
|
|
|
|
|
|
|
|
(defn setup [opts]
|
|
|
|
(let [{:salt salt
|
|
|
|
:alphabet alphabet
|
|
|
|
:seps seps
|
|
|
|
:min-length min-length} (merge DEFAULTS opts)
|
|
|
|
alph-bytes (string/bytes alphabet)
|
|
|
|
salt-bytes (string/bytes salt)
|
|
|
|
seps-bytes (string/bytes seps)
|
|
|
|
alph-unbal (difference alph-bytes seps-bytes)
|
|
|
|
seps-unbal (intersection alph-bytes seps-bytes)
|
|
|
|
[seps-bal alph-bal] (balance alph-unbal
|
|
|
|
(consistent-shuffle seps-unbal salt-bytes))]
|
|
|
|
{
|
|
|
|
:seps (apply string/from-bytes seps-unbal)
|
|
|
|
:alph (apply string/from-bytes alph-unbal)
|
|
|
|
:salt salt
|
|
|
|
:min-length min-length
|
|
|
|
}))
|
|
|
|
|
|
|
|
(defn encode
|
|
|
|
"Convert nums to hashids encoded form"
|
|
|
|
[source & opts]
|
|
|
|
(let [config (setup (table ;opts))
|
|
|
|
nums (as-indexed source)
|
|
|
|
hash-int (reduce + 0 (map-indexed int-hash nums))]
|
|
|
|
(pp config)
|
|
|
|
"j0gW"))
|
|
|
|
|