+ (get-output-stream-string out))))
+
+
+(defun filter-plist (plist &rest keys-to-remove)
+ "Returns a copy of the given plist with indicated key-value pairs
+removed. keys are searched with #'MEMBER"
+ (declare (dynamic-extent keys-to-remove))
+ (when plist
+ (loop for (k v . rest) = plist then rest
+ unless (member k keys-to-remove)
+ collect k and collect v
+ while rest)))
+
+(defmacro make-weak-hash-table (&rest args)
+ "Creates a weak hash table for use in a cache."
+ `(progn
+
+ ;;NB: These are generally used for caches that may not have an alternate
+ ;;clearing mechanism. If you are on an implementation that doesn't support
+ ;;weak hash tables then you're memory may accumulate.
+
+ #-(or sbcl allegro clisp lispworks)
+ (warn "UNSAFE! use of weak hash on implementation without support. (see clsql/sql/utils.lisp to add)")
+
+ (make-hash-table
+ #+allegro :values #+allegro :weak
+ #+clisp :weak #+clisp :value
+ #+lispworks :weak-kind #+lispworks :value
+ #+sbcl :weakness #+sbcl :value
+ ,@args)
+ ))
+
+(defun to-slot-name (slot)
+ "try to turn what we got representing the slot into a slot name"
+ (etypecase slot
+ (symbol slot)
+ (slot-definition (slot-definition-name slot))))
+
+(defun to-class (it)
+ (etypecase it
+ (class it)
+ (symbol (find-class it))
+ (standard-object (class-of it))))
+
+(defun to-class-name (o)
+ (etypecase o
+ (symbol o)
+ (standard-class (class-name o))
+ (standard-object (class-name (class-of o)))))
+
+(defun easy-slot-value (obj slot)
+ "like slot-value except it accepts slot-names or defs
+ and returns nil when the slot is unbound"
+ (let ((n (to-slot-name slot)))
+ (when (and obj (slot-boundp obj n))
+ (slot-value obj n))))
+
+(defun (setf easy-slot-value) (new obj slot)
+ "like slot-value except it accepts slot-names or defs"
+ (setf (slot-value obj (to-slot-name slot)) new))
+
+(defun delist-if-single (x)
+ "if this is a single item in a list return it"
+ (if (and (listp x) (= 1 (length x)))
+ (first x)
+ x))