+void CYThrow(JSContextRef context, JSValueRef value);
+
+/* JavaScript Properties {{{ */
+JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, size_t index) {
+    JSValueRef exception(NULL);
+    JSValueRef value(JSObjectGetPropertyAtIndex(context, object, index, &exception));
+    CYThrow(context, exception);
+    return value;
+}
+
+JSValueRef CYGetProperty(JSContextRef context, JSObjectRef object, JSStringRef name) {
+    JSValueRef exception(NULL);
+    JSValueRef value(JSObjectGetProperty(context, object, name, &exception));
+    CYThrow(context, exception);
+    return value;
+}
+
+void CYSetProperty(JSContextRef context, JSObjectRef object, size_t index, JSValueRef value) {
+    JSValueRef exception(NULL);
+    JSObjectSetPropertyAtIndex(context, object, index, value, &exception);
+    CYThrow(context, exception);
+}
+
+void CYSetProperty(JSContextRef context, JSObjectRef object, JSStringRef name, JSValueRef value) {
+    JSValueRef exception(NULL);
+    JSObjectSetProperty(context, object, name, value, kJSPropertyAttributeNone, &exception);
+    CYThrow(context, exception);
+}
+/* }}} */
+/* JavaScript Strings {{{ */
+JSStringRef CYCopyJSString(id value) {
+    // XXX: this definition scares me; is anyone using this?!
+    return value == NULL ? NULL : JSStringCreateWithCFString(reinterpret_cast<CFStringRef>([value description]));
+}
+
+JSStringRef CYCopyJSString(const char *value) {
+    return value == NULL ? NULL : JSStringCreateWithUTF8CString(value);
+}
+
+JSStringRef CYCopyJSString(JSStringRef value) {
+    return value == NULL ? NULL : JSStringRetain(value);
+}
+
+JSStringRef CYCopyJSString(JSContextRef context, JSValueRef value) {
+    if (JSValueIsNull(context, value))
+        return NULL;
+    JSValueRef exception(NULL);
+    JSStringRef string(JSValueToStringCopy(context, value, &exception));
+    CYThrow(context, exception);
+    return string;
+}
+
+class CYJSString {
+  private:
+    JSStringRef string_;
+
+    void Clear_() {
+        if (string_ != NULL)
+            JSStringRelease(string_);
+    }
+
+  public:
+    CYJSString(const CYJSString &rhs) :
+        string_(CYCopyJSString(rhs.string_))
+    {
+    }
+
+    template <typename Arg0_>
+    CYJSString(Arg0_ arg0) :
+        string_(CYCopyJSString(arg0))
+    {
+    }
+
+    template <typename Arg0_, typename Arg1_>
+    CYJSString(Arg0_ arg0, Arg1_ arg1) :
+        string_(CYCopyJSString(arg0, arg1))
+    {
+    }
+
+    CYJSString &operator =(const CYJSString &rhs) {
+        Clear_();
+        string_ = CYCopyJSString(rhs.string_);
+        return *this;
+    }
+
+    ~CYJSString() {
+        Clear_();
+    }
+
+    void Clear() {
+        Clear_();
+        string_ = NULL;
+    }
+
+    operator JSStringRef() const {
+        return string_;
+    }
+};
+
+CFStringRef CYCopyCFString(JSStringRef value) {
+    return JSStringCopyCFString(kCFAllocatorDefault, value);
+}
+
+CFStringRef CYCopyCFString(JSContextRef context, JSValueRef value) {
+    return CYCopyCFString(CYJSString(context, value));
+}
+
+/* }}} */
+