packages feed

Salsa (empty) → 0.1.0.1

raw patch · 33 files changed

+6251/−0 lines, 33 filesdep +Win32dep +basedep +bytestringsetup-changedbinary-added

Dependencies added: Win32, base, bytestring

Files

+ Docs/Thesis.pdf view

binary file changed (absent → 339936 bytes)

+ Driver/Driver.cs view
@@ -0,0 +1,1146 @@+//
+// Salsa .NET Driver
+//
+// Copyright: (c) 2007-2008 Andrew Appleyard
+// Licence:   BSD3 (see LICENSE)
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Net;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+
+[assembly: AssemblyTitle("Salsa")]
+[assembly: AssemblyDescription(".NET Bridge for Haskell")]
+[assembly: AssemblyProduct("Salsa")]
+[assembly: AssemblyCopyright("Copyright © 2007-2008 Andrew Appleyard")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
+// TODO: Consider caching the results of the Get*Stub(string, ...) methods
+//       (although it's not really necessary, Haskell will cache the results).
+
+namespace Salsa
+{
+    public class Driver
+    {
+        internal static AssemblyBuilder _assemblyBuilder;
+        internal static ModuleBuilder _dynamicModuleBuilder;
+        internal static TypeBuilder _stubsTypeBuilder;
+
+        static Driver()
+        {
+            //Console.WriteLine("Using Salsa.dll (version {0})",
+            //    Assembly.GetExecutingAssembly().GetName().Version);
+
+            Trace.Listeners.Add(new ConsoleTraceListener());
+            System.Windows.Forms.Application.EnableVisualStyles();
+
+            _assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
+                new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.RunAndSave);
+            _dynamicModuleBuilder = _assemblyBuilder.DefineDynamicModule("DynamicModule", "Dynamic.dll");
+            _stubsTypeBuilder = _dynamicModuleBuilder.DefineType("Stubs");
+
+            _inTable.Add(_nextId++, true);  // ObjectId 1
+            _inTable.Add(_nextId++, false); // ObjectId 2
+        }
+
+        public static IntPtr Boot()
+        {
+            // TODO: Accept an option from Salsa for the threading model to use
+            // Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
+
+            return GetPointerToMethod("GetPointerToMethod");
+        }
+
+        /// <summary>
+        /// Returns a native function pointer (as an int) to a stub wrapping the given method.
+        /// </summary>
+        /// <remarks>
+        /// This is the first .NET function called by Haskell, and is called by using the 
+        /// ICLRRuntimeHost.ExecuteInDefaultAppDomain method.
+        /// </remarks>
+        public static IntPtr GetPointerToMethod(string methodName)
+        {
+            //Trace.WriteLine("GetPointerToMethod(" + methodName + ")");
+            //Console.WriteLine("Called on thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
+
+            MethodInfo meth = typeof(Driver).GetMethod(methodName);
+            if (meth == null)
+                throw new ArgumentException("Method not found.", "methodName");
+
+            // Return a delegate pointing to the indicated method (cast to an int 
+            // so we can call this method using ExecuteInDefaultAppDomain)
+            return GenerateMethodStub(meth);
+        }
+
+        #region Entry points
+
+        /// <summary>
+        /// This method is called by Haskell so that the .NET side of the bridge
+        /// has access to the Haskell function 'freeHaskellFunPtr'.
+        /// </summary>
+        public static void SetFreeHaskellFunPtr(IntPtr freeHaskellFunPtr)
+        {
+            if (freeHaskellFunPtr == IntPtr.Zero)
+            {
+                // Clear any previously stored delegate wrapping 'freeHaskellFunPtr'
+                // (this will prevent calls into Haskell from .NET finalizers)
+                FreeHaskellFunPtr = null;
+            }
+            else
+            {
+                // Store the delegate wrapping the 'freeHaskellFunPtr' function passed in
+                FreeHaskellFunPtr =
+                    (FreeHaskellFunPtrDelegate)Marshal.GetDelegateForFunctionPointer(
+                        freeHaskellFunPtr, typeof(FreeHaskellFunPtrDelegate));
+            }
+            Trace.WriteLine(string.Format("SetFreeHaskellFunPtr(0x{0:x})", freeHaskellFunPtr));
+        }
+
+        public static FreeHaskellFunPtrDelegate FreeHaskellFunPtr;
+
+        /// <summary>
+        /// Saves the assembly containing the dynamically generated wrapper methods and 
+        /// delegate classes created during the bridge operation.
+        /// </summary>
+        public static void SaveDynamicAssembly()
+        {
+            _stubsTypeBuilder.CreateType();
+
+            string fileName = Path.GetFileName(_dynamicModuleBuilder.FullyQualifiedName);
+            Console.WriteLine("Saving dynamic assembly: " + fileName);
+            _assemblyBuilder.Save(fileName);
+        }
+
+        /// <summary>
+        /// Given the class, name, and signature of a method or constructor, returns a 
+        /// native function pointer to a delegate that calls the method or constructor
+        /// when invoked.
+        /// </summary>
+        /// <remarks>
+        /// Use a 'methodName' of '.ctor' to obtain a constructor stub.
+        /// </remarks>
+        public static IntPtr GetMethodStub(string className, string methodName,
+            string parameterTypeNames)
+        {
+            if (methodName == ".ctor")
+            {
+                ConstructorInfo con = Util.StringToType(className).GetConstructor(
+                    Util.StringToTypes(parameterTypeNames));
+                return GenerateConstructorStub(con);
+            }
+            else
+            {
+                MethodInfo meth = Util.StringToType(className).GetMethod(
+                    methodName, Util.StringToTypes(parameterTypeNames));
+                return GenerateMethodStub(meth);
+            }
+        }
+
+        /// <summary>
+        /// Given the name of a delegate type, returns a function pointer to a delegate that,
+        /// when called, instantiates delegate instances of the given delegate type when given
+        /// a pointer to a Haskell function.
+        /// </summary>
+        public static IntPtr GetDelegateConstructorStub(string delegateTypeName)
+        {
+            Type delegateType = Util.StringToType(delegateTypeName);
+            return GenerateDelegateConstructorStub(delegateType);
+        }
+
+        /// <summary>
+        /// Given the class and name of a field, returns a native function pointer to a 
+        /// delegate that returns the value of the field when invoked.
+        /// </summary>
+        public static IntPtr GetFieldGetStub(string className, string fieldName)
+        {
+            FieldInfo field = Util.StringToType(className).GetField(fieldName);
+            return GenerateFieldGetStub(field);
+        }
+
+        /// <summary>
+        /// Given the class and name of a field, returns a native function pointer to a 
+        /// delegate that sets the value of the field when invoked.
+        /// </summary>
+        public static IntPtr GetFieldSetStub(string className, string fieldName)
+        {
+            FieldInfo field = Util.StringToType(className).GetField(fieldName);
+            return GenerateFieldSetStub(field);
+        }
+
+        /// <summary>
+        /// Given a value type, returns a native function pointer to a method that 
+        /// boxes values of the given value type.
+        /// </summary>
+        public static IntPtr GetBoxStub(string typeName)
+        {
+            Type typeToBox = Util.StringToType(typeName);
+            return GenerateBoxStub(typeToBox);
+        }
+
+        #endregion
+
+        #region Foreign object references (object in-table)
+
+        /// <summary>
+        /// Maps object identifiers to .NET references.  Allows foreign object identifiers 
+        /// to be dereferenced to .NET object references.  Also ensures that .NET objects 
+        /// referred to from Haskell are kept alive.
+        /// </summary>
+        static Dictionary<int, object> _inTable = new Dictionary<int, Object>();
+
+        static int _nextId = 1;
+
+        /// <summary>
+        /// Registers the given object in the 'in table' and returns the object id
+        /// that was assigned to it.
+        /// </summary>
+        public static int RegisterObject(object o)
+        {
+            if (o == null) 
+                return 0;
+
+            if (o is bool?) // HACK for Nullable<bool>
+            {
+                bool b = (bool)o;
+                return b ? 1 : 2;
+            }
+
+            lock (_inTable)
+            {
+                _inTable.Add(_nextId, o);
+                return _nextId++;
+            }
+        }
+
+        public static object GetObject(int oId)
+        {
+            if (oId == 0) // 0 represents a null reference
+                return null;
+
+            if (oId == 1) // 1 represents boxed true
+                return true; // TODO: Return pre-boxed instance?
+            if (oId == 2) // 0 represents boxed false
+                return false;
+
+            lock (_inTable)
+            {
+                object o;
+                if (_inTable.TryGetValue(oId, out o))
+                    return o;
+                else
+                {
+                    throw new ArgumentException("No object exists with id: " + oId);
+                    // FIXME: This exception will occur in the current implementation of the 
+                    //        bridge if a Haskell garbage collection (and finalization) runs 
+                    //        while a Haskell-implemented delegate is returning an object.
+                    //        Given that this condition tends not to occur with the current
+                    //        implementation of the GHC RTS, and that most delegates in .NET
+                    //        don't return a value at all, I'm leaving the fix for later.
+                }
+            }
+        }
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        public delegate void ReleaseObjectDelegate(int oId);
+        private static ReleaseObjectDelegate _ReleaseObjectDelegate = ReleaseObject;
+
+        public static void ReleaseObject(int oId)
+        {
+            lock (_inTable)
+            {
+                _inTable.Remove(oId);
+            }
+        }
+
+        #endregion
+
+        #region Managed delegate references (function pointer in-table)
+
+        /// <summary>
+        /// Maintains references to any .NET delegates that have a native function pointer
+        /// referring to them (as obtained using Marshal.GetFunctionPointerForDelegate), so 
+        /// that they are not collected prematurely.
+        /// </summary>
+        private static Dictionary<IntPtr, Delegate> _dotNetFunPtrDelegates = new Dictionary<IntPtr, Delegate>();
+
+        /// <summary>
+        /// Returns a native function pointer for calling the given .NET delegate.  A 
+        /// reference to the delegate is stored in _dotNetFunPtrDelegates to prevent
+        /// the delegate from being garbage collected while the function pointer is 
+        /// still being used.
+        /// </summary>
+        private static IntPtr GetDotNetFunPtrForDelegate(Delegate d) // TODO: Perhaps rename 'RegisterDelegate'
+        {
+            IntPtr funPtr = Marshal.GetFunctionPointerForDelegate(d);
+            lock (_dotNetFunPtrDelegates)
+                _dotNetFunPtrDelegates.Add(funPtr, d);
+            return funPtr;
+        }
+
+        /// <summary>
+        /// This method is called to indicate that the given native function pointer 
+        /// will no longer be called from Haskell.  It allows the associated .NET
+        /// delegate to be garbage collected provided there are no other references
+        /// to it.
+        /// </summary>
+        public static void FreeDotNetFunPtr(IntPtr funPtr) // TODO: Perhaps rename 'ReleaseDelegate'
+        {
+            lock (_dotNetFunPtrDelegates)
+                _dotNetFunPtrDelegates.Remove(funPtr);
+        }
+
+        #endregion
+
+        #region Stub method generation
+
+        /// <summary>
+        /// Generates a dynamic method of the given name and signature, containing the instructions 
+        /// produced by 'ilWriter'.  A delegate to the method, is returned to the caller as a native
+        /// function pointer.
+        /// </summary>
+        /// <remarks>
+        /// This method also writes the method to the 'Stubs' class in 'Dynamic.dll' for debugging 
+        /// purposes.
+        /// </remarks>
+        private static IntPtr GenerateDynamicMethod(string methodName,
+            DelegateSignature methodSignature, ILWriterDelegate ilWriter)
+        {
+            if (true)
+            {
+                // Optional: generate an implementation of the stub method inside the 'Stubs'
+                //           class (which is saved to 'Dynamic.dll') for debugging purposes.
+                MethodBuilder savedMethod = _stubsTypeBuilder.DefineMethod(methodName, MethodAttributes.Public,
+                    methodSignature.ReturnType, methodSignature.ParameterTypes);
+                ilWriter(savedMethod.GetILGenerator());
+            }
+
+            // Generate a dynamic method of the given name and signature, and the 
+            // IL instructions given by 'ilWriter', then return a delegate to the
+            // method as a function pointer.
+
+            // [stubReturnType] [classType]_[methodname]([classType] this, [args...]):
+            DynamicMethod method = new DynamicMethod(methodName, methodSignature.ReturnType,
+                methodSignature.ParameterTypes, typeof(Driver));
+            ilWriter(method.GetILGenerator());
+
+            return GetDotNetFunPtrForDelegate(method.CreateDelegate(methodSignature.ToDelegateType()));
+        }
+
+        /// <summary>
+        /// Returns a native function pointer to a wrapper stub that accepts foreign 
+        /// parameters, marshals them, calls the indicated constructor, and returns the
+        /// resulting object instance (marshaled as necessary).
+        /// </summary>
+        /// <remarks>
+        /// The returned function pointer should be freed with 'FreeDotNetFunPtr'.
+        /// When used to construct a value type, 'con' may be null, in which case 
+        /// no constructor is called (the value is just initialised to zero).
+        /// </remarks>
+        public static IntPtr GenerateConstructorStub(ConstructorInfo con)
+        {
+            Type type = con.DeclaringType;
+
+            if (!type.IsValueType && con == null)
+                throw new ArgumentNullException("'con' cannot be null if creating a reference type.");
+
+            // Generate a dynamic method that does the following:
+            //
+            //     Int32 [classType]New([args...])
+            //     {
+            //         [classType] o = new [classType]([args... using GetObject ... ]);
+            //         (box o if it is a value type)
+            //         return Driver.RegisterObject(o);
+            //     }
+
+            // Signature of the stub method returned (as a delegate) by this function
+            DelegateSignature methodSignature = new DelegateSignature(
+                typeof(Int32), 
+                con == null ? Type.EmptyTypes : 
+                              ConvertToStubTypes(Util.MapParametersToTypes(con.GetParameters())));
+
+            return GenerateDynamicMethod(type.Name + "New", methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    if (con == null) // Initialise object to zero?
+                    {
+                        // Initialise the object in a local variable
+                        ilg.DeclareLocal(type);
+                        ilg.Emit(OpCodes.Ldloca_S, (byte)0);
+                        ilg.Emit(OpCodes.Initobj, type);
+
+                        // Load the object onto the stack
+                        ilg.Emit(OpCodes.Ldloc_0);
+                    }
+                    else // Call object constructor:
+                    {
+                        // Load (and unmarshal), the arguments to the constructor stub
+                        EmitParameterLoading(ilg, 0, con.GetParameters());
+
+                        // Call the constructor, i.e. 'o = new [classType]([unmarshaled args])'
+                        ilg.Emit(OpCodes.Newobj, con);
+                    }
+
+                    // Return the new object (marshaled as an index)
+                    EmitToStub(ilg, type);
+                    ilg.Emit(OpCodes.Ret);
+                });
+        }
+
+        /// <summary>
+        /// Returns a native function pointer to a stub method that calls the given
+        /// method, marshaling arguments as necessary.
+        /// </summary>
+        /// <remarks>
+        /// The returned function pointer should be freed with 'FreeDotNetFunPtr'.
+        /// </remarks>
+        public static IntPtr GenerateMethodStub(MethodInfo meth)
+        {
+            Type classType = meth.DeclaringType;
+
+            // Generate a dynamic method that does the following:
+            //
+            //     [stubReturnType] [classType]_[methodName]([classType] this, [args...])
+            //       OR (if a static method)
+            //     [stubReturnType] [classType]_[methodName]([args...])
+            //     {
+            //         [resultType] r = this.[methodName]([marshaledThis], [marshaled args]);
+            //           OR (if a static method)
+            //         [resultType] r = [className].[methodName]([marshaled args]);
+            //
+            //         return r; OR return Driver.RegisterObject(r);
+            //     }
+
+            // Signature of the stub method returned (as a delegate) by this function
+            DelegateSignature methodSignature = new DelegateSignature(
+                ConvertToStubType(meth.ReturnParameter.ParameterType),
+                meth.IsStatic ? ConvertToStubTypes(Util.MapParametersToTypes(meth.GetParameters())) :
+                    Util.ConcatArray<Type>(
+                        ConvertToStubType(meth.DeclaringType),
+                        ConvertToStubTypes(Util.MapParametersToTypes(meth.GetParameters()))));
+
+            return GenerateDynamicMethod(classType.Name + "_" + meth.Name, methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    // Load (and unmarshal), the arguments to the method stub, then call the real method
+                    if (meth.IsStatic)
+                    {
+                        EmitParameterLoading(ilg, 0, meth.GetParameters());
+                        ilg.Emit(OpCodes.Call, meth);
+                    }
+                    else
+                    {
+                        EmitParameterLoading(ilg, 0, meth.DeclaringType);
+                        EmitParameterLoading(ilg, 1, meth.GetParameters());
+                        ilg.Emit(OpCodes.Callvirt, meth);
+                    }
+
+                    // Unmarshal and return the result
+                    EmitMarshaledReturn(ilg, meth.ReturnParameter);
+                });
+        }
+
+        /// <summary>
+        /// Instantiates a delegate that, given an IntPtr to a Haskell function, returns a
+        /// delegate instance (of the given delegate type) that wraps this native function
+        /// (and deals with parameter value marshaling and finalization).
+        /// </summary>
+        /// <param name="delegateType">Type of delegate returned by the returned delegate.</param>
+        /// <returns>
+        /// Wrapper delegate that accepts an IntPtr and returns a delegate of the
+        /// indicated type.
+        /// </returns>
+        public static IntPtr GenerateDelegateConstructorStub(Type delegateType)
+        {
+            // Obtain (creating, if necessary) the type of a wrapper class for the delegate
+            Type wrapperType = GetDelegateWrapperType(delegateType);
+
+            DelegateSignature delegateSignature = DelegateSignature.FromDelegateType(delegateType);
+
+            // Generate a dynamic method that does the following:
+            //
+            //     Int32 [delegateType]New(IntPtr funPtr)
+            //     {
+            //         [wrapperType] wrapper = new [wrapperType](funPtr);
+            //         Delegate d = new [delegateType](wrapper.Invoke);
+            //         return Driver.RegisterObject(d);
+            //     }
+
+            // Signature of the method returned (as a delegate) by this function (the
+            // method accepts an IntPtr to a Haskell function and returns an instantiated
+            // .NET delegate for it)
+            DelegateSignature methodSignature = new DelegateSignature(
+                typeof(Int32), new Type[] { typeof(IntPtr) });
+
+            return GenerateDynamicMethod(delegateType.Name + "New", methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    // wrapper = new [wrapperType](funPtr):
+                    ilg.Emit(OpCodes.Ldarg_0);
+                    ilg.Emit(OpCodes.Newobj, wrapperType.GetConstructor(new Type[] { typeof(IntPtr) }));
+
+                    // Obtain wrapper.Invoke
+                    ilg.Emit(OpCodes.Ldftn, wrapperType.GetMethod("Invoke"));
+
+                    // Delegate d = new [delegateType](wrapper.Invoke):
+                    ilg.Emit(OpCodes.Newobj, delegateType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
+
+                    // return Driver.RegisterObject(d):
+                    ilg.Emit(OpCodes.Call, MemberInfos.Driver_RegisterObject);
+                    ilg.Emit(OpCodes.Ret);
+                });
+        }
+
+        /// <summary>
+        /// Returns a native function pointer to a stub method that retrieves the value
+        /// of the given static or instance field.
+        /// </summary>
+        /// <remarks>
+        /// The returned function pointer should be freed with 'FreeDotNetFunPtr'.
+        /// </remarks>
+        public static IntPtr GenerateFieldGetStub(FieldInfo field)
+        {
+            // Signature of the stub method returned (as a delegate) by this function
+            DelegateSignature methodSignature = new DelegateSignature(
+                ConvertToStubType(field.FieldType),
+                field.IsStatic ? Type.EmptyTypes : new Type[] { ConvertToStubType(field.DeclaringType) });
+
+            return GenerateDynamicMethod(field.DeclaringType.Name + "_field_get_" + field.Name, methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    if (field.IsStatic)
+                    {
+                        if (field.IsLiteral)
+                        {
+                            // FIXME: Move literal calculation to the generator, and add
+                            //        support for literal values in the bridge (i.e.
+                            //        values other than 'Obj ObjectId's
+                            object literalValue = field.GetRawConstantValue();
+                            if (literalValue is Int32)
+                                ilg.Emit(OpCodes.Ldc_I4, (Int32)literalValue);
+                        }
+                        else
+                            ilg.Emit(OpCodes.Ldsfld, field);
+                    }
+                    else
+                    {
+                        // Load (and unmarshal) the argument to the method stub, then load the field value
+                        EmitParameterLoading(ilg, 0, field.DeclaringType);
+                        ilg.Emit(OpCodes.Ldfld, field);
+                    }
+
+                    // Unmarshal and return the result
+                    EmitToStub(ilg, field.FieldType);
+                    ilg.Emit(OpCodes.Ret);
+                });
+        }
+
+        /// <summary>
+        /// Returns a native function pointer to a stub method that sets the value
+        /// of the given static or instance field.
+        /// </summary>
+        /// <remarks>
+        /// The returned function pointer should be freed with 'FreeDotNetFunPtr'.
+        /// </remarks>
+        public static IntPtr GenerateFieldSetStub(FieldInfo field)
+        {
+            // Signature of the stub method returned (as a delegate) by this function
+            DelegateSignature methodSignature = new DelegateSignature(
+                typeof(void),
+                field.IsStatic ? 
+                    new Type[] { ConvertToStubType(field.FieldType) } : 
+                    new Type[] { ConvertToStubType(field.DeclaringType), ConvertToStubType(field.FieldType) });
+
+            return GenerateDynamicMethod(field.DeclaringType.Name + "_field_set_" + field.Name, methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    if (field.IsStatic)
+                    {
+                        // Load (and unmarshal) the field value from the stub call
+                        EmitParameterLoading(ilg, 0, field.FieldType);
+                        ilg.Emit(OpCodes.Stsfld, field);
+                    }
+                    else
+                    {
+                        // Load (and unmarshal) the instance argument and field value from the stub call
+                        EmitParameterLoading(ilg, 0, field.DeclaringType);
+                        EmitParameterLoading(ilg, 1, field.FieldType);
+                        ilg.Emit(OpCodes.Stfld, field);
+                    }
+
+                    ilg.Emit(OpCodes.Ret);
+                });
+        }
+
+        /// <summary>
+        /// Returns a native function pointer to a stub method that returns a 
+        /// reference to the given value (boxing value types as necessary).
+        /// </summary>
+        /// <remarks>
+        /// The returned function pointer should be freed with 'FreeDotNetFunPtr'.
+        /// </remarks>
+        public static IntPtr GenerateBoxStub(Type typeToBox)
+        {
+            // Signature of the stub method returned (as a delegate) by this function
+            DelegateSignature methodSignature = new DelegateSignature(
+                typeof(Int32), new Type[] { ConvertToStubType(typeToBox) });
+
+            return GenerateDynamicMethod("box_" + typeToBox.Name, methodSignature,
+                delegate(ILGenerator ilg)
+                {
+                    // Load the (unboxed) value
+                    EmitParameterLoading(ilg, 0, typeToBox);
+
+                    if (typeToBox.IsValueType)
+                    {
+                        // Box the type value to as an object
+                        ilg.Emit(OpCodes.Box, typeToBox);
+                    }
+
+                    // Marshal the object instance out as an object index
+                    EmitToStub(ilg, typeof(object));
+                    ilg.Emit(OpCodes.Ret);
+                });
+        }
+
+        #endregion
+
+        #region Parameter and result marshaling
+
+        private static bool IsMarshaledByIndex(Type t)
+        {
+            return !t.IsPrimitive && t != typeof(void) && t != typeof(string);
+        }
+
+        /// <summary>
+        /// Returns the type of 'MarshalAs' attribute that should be attached to 
+        /// parameters/results of the given type, if any.
+        /// </summary>
+        private static UnmanagedType? MarshalTypeAs(Type t)
+        {
+            if (t == typeof(string))
+                return UnmanagedType.LPWStr;
+            else
+                return null;
+        }
+
+        /// <summary>
+        /// Given an array of parameters (say of a constructor, or method), returns the 
+        /// array of types that a corresponding wrapper stub would accept.
+        /// </summary>
+        private static Type[] ConvertToStubTypes(Type[] types)
+        {
+            return Util.MapArray<Type, Type>(ConvertToStubType, types);
+        }
+
+        private static Type ConvertToStubType(Type type)
+        {
+            if (IsMarshaledByIndex(type))
+                return typeof(Int32);
+            else
+                return type;
+        }
+
+        /// <summary>
+        /// Emits code (via the given IL generator) to load a single parameter of the given 
+        /// type from the given argument index and on to the stack.  It ensures that object 
+        /// types (which are marshaled by index), are resolved to the appropriate .NET object 
+        /// instance.
+        /// </summary>
+        private static void EmitParameterLoading(ILGenerator ilg, int argumentIndex, Type parameterType)
+        {
+            Util.EmitLdarg(ilg, argumentIndex);
+            EmitFromStub(ilg, parameterType);
+        }
+
+        // Converts a value on the stack from a stub stub to the associated 'real' .NET type
+        /// <summary>
+        /// Emits code to convert a value on the stack from a stub type to the associated
+        /// 'real' .NET type.
+        /// </summary>
+        /// <remarks>
+        /// For example, when called for the 'Button' type, code is emitted to convert an 
+        /// Int32 object identifier into a Button; but when called with the 'String' type 
+        /// no code is emitted at all since the stub type matches the desired .NET type 
+        /// exactly.
+        /// </remarks>
+        private static void EmitFromStub(ILGenerator ilg, Type valueType)
+        {
+            if (IsMarshaledByIndex(valueType))
+            {
+                // [valueType]x = ([valueType])GetObject(value):
+
+                // Call GetObject on the object index to obtain the object instance
+                ilg.Emit(OpCodes.Call, MemberInfos.Driver_GetObject);
+
+                // Cast from Object to the appropriate type for the value (unboxing if necessary)
+                ilg.Emit(OpCodes.Unbox_Any, valueType);
+
+                // Note, the above instruction is equivalent to:
+                //
+                //   if (valueType.IsValueType)
+                //   {
+                //       ilg.Emit(OpCodes.Unbox, valueType);
+                //       ilg.Emit(OpCodes.Ldobj);
+                //   }
+                //   else
+                //       ilg.Emit(OpCodes.Castclass, valueType);
+                //
+            }
+            else
+            {
+                // Leave value as is
+            }
+        }
+
+        /// <summary>
+        /// Emits code (via the given IL generator) to load parameters of the given types 
+        /// from the arguments of the method (starting with 'startingArgument') and on to 
+        /// the stack.  It ensures that object types (which are marshaled by index), are 
+        /// resolved to the appropriate .NET object instance.
+        /// </summary>
+        private static void EmitParameterLoading(ILGenerator ilg, int startingArgument,
+            IEnumerable<ParameterInfo> parameterInfos)
+        {
+            int argumentIndex = startingArgument;
+            foreach (ParameterInfo parameterInfo in parameterInfos)
+            {
+                Type parameterType = parameterInfo.ParameterType;
+                Util.EmitLdarg(ilg, argumentIndex++);
+                EmitFromStub(ilg, parameterType);
+            }
+        }
+
+        private static void EmitToStub(ILGenerator ilg, Type type)
+        {
+            if (IsMarshaledByIndex(type))
+            {
+                if (type.IsValueType)
+                {
+                    // Box the value type for passing it to RegisterObject
+                    ilg.Emit(OpCodes.Box, type);
+                }
+
+                // Marshal the object instance out as an object index, by
+                // calling RegisterObject
+                ilg.Emit(OpCodes.Call, MemberInfos.Driver_RegisterObject);
+            }
+            else
+            {
+                // Leave value as is
+            }
+        }
+
+        /// <summary>
+        /// Emits code (via the given IL generator) to return the value on the top of the
+        /// stack, knowing that its type is given by 'returnParameterInfo'.  It ensures 
+        /// that object types (which are marshaled by index), are returned as an index.
+        /// </summary>
+        private static void EmitMarshaledReturn(ILGenerator ilg, ParameterInfo returnParameterInfo)
+        {
+            Type parameterType = returnParameterInfo.ParameterType;
+            EmitToStub(ilg, parameterType);
+            ilg.Emit(OpCodes.Ret);
+        }
+
+        #endregion
+
+        #region Delegate wrappers
+
+        /// <summary>
+        /// Maintains a cache of the delegate wrapper types that have been generated.
+        /// </summary>
+        private static Dictionary<string, Type> _delegateWrapperTypes =
+            new Dictionary<string, Type>();
+
+        private static Type GetDelegateWrapperType(Type delegateType)
+        {
+            string wrapperTypeName = delegateType.Name + "Wrapper";
+            lock (_delegateWrapperTypes)
+            {
+                Type type;
+                if (!_delegateWrapperTypes.TryGetValue(wrapperTypeName, out type))
+                {
+                    // Could not find wrapper class of appropriate type in the cache: create one
+                    type = CreateDelegateWrapperType(wrapperTypeName, delegateType);
+                    _delegateWrapperTypes.Add(wrapperTypeName, type);
+                }
+                return type;
+            }
+        }
+
+        /// <summary>
+        /// Creates (and returns the type of) a class that wraps a pointer to a
+        /// Haskell function as a .NET delegate.  The class ensures that the
+        /// wrapper function pointer is freed when the delegate is no longer being 
+        /// used by .NET.  It also performs any translation from .NET values to
+        /// interop values (object references are converted to object identifiers).
+        /// </summary>
+        /// <param name="delegateType">Type of delegate produced by the wrapper</param>
+        private static Type CreateDelegateWrapperType(string name, Type delegateType)
+        {
+            // Obtain the signature of the delegate being produced
+            DelegateSignature delegateSignature = DelegateSignature.FromDelegateType(delegateType);
+
+            // Obtain the delegate type of the associated thunk for calling into Haskell
+            Type thunkDelegateType = new DelegateSignature(
+                ConvertToStubType(delegateSignature.ReturnType),
+                ConvertToStubTypes(delegateSignature.ParameterTypes)).ToDelegateType();
+
+            TypeBuilder typeBuilder = _dynamicModuleBuilder.DefineType(name,
+                TypeAttributes.Public | TypeAttributes.Sealed);
+
+            // Define the _thunkDelegate field
+            FieldBuilder thunkDelegateField = typeBuilder.DefineField("_thunkDelegate",
+                thunkDelegateType, FieldAttributes.Private);
+
+            {
+                // Define the constructor for the wrapper type:
+                //
+                //     public DelegateWrapper(IntPtr funPtrToWrap)
+                //     {
+                //         _thunkDelegate = (ThunkDelegate)
+                //             Marshal.GetDelegateForFunctionPointer(
+                //                 funPtrToWrap, typeof(ThunkDelegate));
+                //     }
+
+                ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
+                    MethodAttributes.Public | MethodAttributes.RTSpecialName,
+                    CallingConventions.Standard, new Type[] { typeof(IntPtr) });
+                ILGenerator ilg = constructorBuilder.GetILGenerator();
+
+                // Call Object's constructor
+                ilg.Emit(OpCodes.Ldarg_0);
+                ilg.Emit(OpCodes.Call, MemberInfos.Object_ctor);
+
+                ilg.Emit(OpCodes.Ldarg_0); // Load this (for the 'stfld' below)
+                ilg.Emit(OpCodes.Ldarg_1); // Load funPtrToWrap
+
+                ilg.Emit(OpCodes.Ldtoken, thunkDelegateType); // Load typeof(ThunkDelegate)
+                ilg.Emit(OpCodes.Call, MemberInfos.Type_GetTypeFromHandle);
+
+                // Call (ThunkDelegate)Marshal.GetDelegateForFunctionPointer(
+                //          funPtrToWrap, typeof(ThunkDelegate))
+                ilg.Emit(OpCodes.Call, MemberInfos.Marshal_GetDelegateForFunctionPointer);
+                ilg.Emit(OpCodes.Castclass, thunkDelegateType);
+
+                // Store in _thunkDelegate
+                ilg.Emit(OpCodes.Stfld, thunkDelegateField);
+
+                ilg.Emit(OpCodes.Ret);
+            }
+
+            {
+                // Define a Finalize method for the wrapper class:
+                //
+                //     ~Delegate()
+                //     {
+                //         if (Driver.FreeHaskellFunPtr != null)
+                //             Driver.FreeHaskellFunPtr(Marshal.GetFunctionPointerForDelegate(
+                //                 _thunkDelegate));
+                //     }
+
+                MethodBuilder finalizeMethod = typeBuilder.DefineMethod("Finalize",
+                    MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual);
+                finalizeMethod.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed);
+                ILGenerator ilg = finalizeMethod.GetILGenerator();
+                Label endLabel = ilg.DefineLabel();
+
+                // Obtain the freeHaskellFunPtr delegate
+                ilg.Emit(OpCodes.Ldsfld, MemberInfos.Driver_FreeHaskellFunPtr);
+
+                // Return immediately if the delegate is null
+                ilg.Emit(OpCodes.Ldc_I4_0);
+                ilg.Emit(OpCodes.Beq, endLabel);
+
+                // Obtain the freeHaskellFunPtr delegate (again)
+                ilg.Emit(OpCodes.Ldsfld, MemberInfos.Driver_FreeHaskellFunPtr);
+
+                // Load _thunkDelegate
+                ilg.Emit(OpCodes.Ldarg_0);
+                ilg.Emit(OpCodes.Ldfld, thunkDelegateField);
+
+                // Call Marshal.GetFunctionPointerForDelegate to obtain the original function pointerusing 
+                ilg.Emit(OpCodes.Call, MemberInfos.Marshal_GetFunctionPointerForDelegate);
+
+                // Invoke freeHaskellFunPtr on this function pointer
+                ilg.Emit(OpCodes.Call, MemberInfos.FreeHaskellFunPtrDelegate_Invoke);
+
+                ilg.MarkLabel(endLabel);
+                ilg.Emit(OpCodes.Ret);
+            }
+
+            {
+                // Define an Invoke method that calls _thunkDelegate after marshaling
+                // the arguments as necessary:
+                //
+                //    private void Invoke(...)
+                //    {
+                //        _thunkDelegate(... using RegisterObject as appropriate ...);
+                //    }
+
+                MethodBuilder invokeMethod = typeBuilder.DefineMethod("Invoke",
+                    MethodAttributes.Public, delegateSignature.ReturnType, delegateSignature.ParameterTypes);
+                ILGenerator ilg = invokeMethod.GetILGenerator();
+
+                // Load _thunkDelegate (for calling it later)
+                ilg.Emit(OpCodes.Ldarg_0);
+                ilg.Emit(OpCodes.Ldfld, thunkDelegateField);
+
+                // Load the parameters (and marshal according to type)
+                for (int i = 0; i < delegateSignature.ParameterTypes.Length; i++)
+                {
+                    Util.EmitLdarg(ilg, i + 1);
+                    EmitToStub(ilg, delegateSignature.ParameterTypes[i]);
+                }
+
+                ilg.Emit(OpCodes.Callvirt, thunkDelegateType.GetMethod("Invoke"));
+                EmitFromStub(ilg, delegateSignature.ReturnType);
+                ilg.Emit(OpCodes.Ret);
+            }
+
+            return typeBuilder.CreateType();
+        }
+
+        #endregion
+
+        #region DelegateSignature implementation
+
+        public struct DelegateSignature
+        {
+            private Type _returnType;
+            private Type[] _parameterTypes;
+
+            public Type ReturnType
+            {
+                get { return _returnType; }
+            }
+
+            public Type[] ParameterTypes
+            {
+                get { return _parameterTypes; }
+            }
+
+            public DelegateSignature(Type returnType, Type[] parameterTypes)
+            {
+                _returnType = returnType;
+                _parameterTypes = parameterTypes;
+            }
+
+            public override string ToString()
+            {
+                StringBuilder sb = new StringBuilder();
+                foreach (Type parameter in _parameterTypes)
+                {
+                    sb.Append(parameter.Name);
+                    sb.Append("To");
+                }
+                sb.Append(_returnType.Name);
+                return sb.ToString();
+            }
+
+            public static DelegateSignature FromDelegateType(Type delegateType)
+            {
+                MethodInfo invokeMethod = delegateType.GetMethod("Invoke");
+                return new DelegateSignature(
+                    invokeMethod.ReturnType,
+                    Util.MapParametersToTypes(invokeMethod.GetParameters()));
+            }
+
+            #region Delegate creation
+
+            /// <summary>
+            /// Maintains a cache of the delegate types that have been generated.
+            /// </summary>
+            private static Dictionary<string, Type> _delegateTypes =
+                new Dictionary<string, Type>();
+
+            /// <summary>
+            /// Returns (after creating, if necessary) a delegate type of the given type signature.
+            /// </summary>
+            public Type ToDelegateType()
+            {
+                string delegateName = ToString() + "Delegate";
+                lock (_delegateTypes)
+                {
+                    Type type;
+                    if (!_delegateTypes.TryGetValue(delegateName, out type))
+                    {
+                        // Could not find delegate of appropriate type in the cache: create one
+                        type = CreateDelegateType(delegateName);
+                        _delegateTypes.Add(delegateName, type);
+                    }
+                    return type;
+                }
+            }
+
+            /// <summary>
+            /// Dynamically creates (and returns the type of) a delegate class with the given 
+            /// name and type signature.
+            /// </summary>
+            private Type CreateDelegateType(string name)
+            {
+                TypeBuilder typeBuilder = Driver._dynamicModuleBuilder.DefineType(name,
+                    TypeAttributes.Class | TypeAttributes.Public |
+                    TypeAttributes.Sealed | TypeAttributes.AnsiClass |
+                    TypeAttributes.AutoClass, typeof(System.MulticastDelegate));
+
+                // Add a '[UnmanagedFunctionPointer(CallingConvention.StdCall)]' attribute to the delegate
+                typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(
+                    typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new Type[] { typeof(CallingConvention) }),
+                    new object[] { CallingConvention.StdCall }));
+
+                ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
+                    MethodAttributes.RTSpecialName | MethodAttributes.HideBySig |
+                    MethodAttributes.Public, CallingConventions.Standard,
+                    new Type[] { typeof(object), typeof(System.IntPtr) });
+                constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
+
+                MethodBuilder methodBuilder = typeBuilder.DefineMethod("Invoke", MethodAttributes.Public |
+                    MethodAttributes.HideBySig | MethodAttributes.NewSlot |
+                    MethodAttributes.Virtual,
+                    ReturnType, ParameterTypes);
+                methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
+
+                // For the return type and any parameter types
+                for (int i = 0; i < ParameterTypes.Length + 1; i++)
+                {
+                    UnmanagedType? marshalAs;
+                    if (i == 0)
+                        marshalAs = MarshalTypeAs(ReturnType);
+                    else
+                        marshalAs = MarshalTypeAs(ParameterTypes[i - 1]);
+
+                    if (marshalAs != null)
+                    {
+                        // Add a MarshalAs attribute to the return/parameter
+                        ParameterBuilder pb = methodBuilder.DefineParameter(i, ParameterAttributes.None, null);
+                        pb.SetCustomAttribute(new CustomAttributeBuilder(
+                                typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(UnmanagedType) }),
+                                new object[] { marshalAs.Value }));
+                    }
+                }
+                return typeBuilder.CreateType();
+            }
+
+            #endregion
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// A delegate for the signature of the Haskell function 'freeHaskellFunPtr'.
+    /// </summary>
+    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+    public delegate void FreeHaskellFunPtrDelegate(IntPtr funPtr);
+
+    /// <summary>
+    /// A delegate for code the emits IL instructions on demand.
+    /// </summary>
+    public delegate void ILWriterDelegate(ILGenerator ilg);
+
+    /// <summary>
+    /// Stores references to commonly used reflection object instances.
+    /// </summary>
+    internal static class MemberInfos
+    {
+        public static readonly MethodInfo Type_GetTypeFromHandle =
+            typeof(Type).GetMethod("GetTypeFromHandle");
+
+        public static readonly ConstructorInfo Object_ctor =
+            typeof(object).GetConstructor(Type.EmptyTypes);
+
+        public static readonly MethodInfo Marshal_GetDelegateForFunctionPointer =
+            typeof(Marshal).GetMethod("GetDelegateForFunctionPointer");
+
+        public static readonly MethodInfo Marshal_GetFunctionPointerForDelegate =
+            typeof(Marshal).GetMethod("GetFunctionPointerForDelegate");
+
+        public static readonly MethodInfo Marshal_StringToHGlobalUni =
+            typeof(Marshal).GetMethod("StringToHGlobalUni");
+
+        public static readonly MethodInfo Marshal_StringToHGlobalAnsi =
+            typeof(Marshal).GetMethod("StringToHGlobalAnsi");
+
+        public static readonly FieldInfo Driver_FreeHaskellFunPtr =
+            typeof(Driver).GetField("FreeHaskellFunPtr", BindingFlags.Static | BindingFlags.Public);
+
+        public static readonly MethodInfo Driver_RegisterObject =
+            typeof(Driver).GetMethod("RegisterObject", BindingFlags.Static | BindingFlags.Public);
+
+        public static readonly MethodInfo Driver_GetObject =
+            typeof(Driver).GetMethod("GetObject", BindingFlags.Static | BindingFlags.Public);
+
+        public static readonly MethodInfo FreeHaskellFunPtrDelegate_Invoke =
+            typeof(FreeHaskellFunPtrDelegate).GetMethod("Invoke");
+    }
+
+    internal static class Util
+    {
+        public static Type StringToType(string s)
+        {
+            return Type.GetType(s, true);
+        }
+
+        public static Type[] StringToTypes(string s)
+        {
+            return Util.MapArray<string, Type>(delegate(string t)
+                { return StringToType(t); },
+                s.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
+        }
+
+        public static T[] ConcatArray<T>(T[] a, T[] b)
+        {
+            T[] r = new T[a.Length + b.Length];
+            for (int i = 0; i < a.Length; i++)
+                r[i] = a[i];
+            for (int i = 0; i < b.Length; i++)
+                r[a.Length + i] = b[i];
+            return r;
+        }
+
+        public static T[] ConcatArray<T>(T x, T[] b)
+        {
+            T[] r = new T[1 + b.Length];
+            r[0] = x;
+            for (int i = 0; i < b.Length; i++)
+                r[1 + i] = b[i];
+            return r;
+        }
+
+        public static B[] MapArray<A, B>(Func<A, B> f, A[] xs)
+        {
+            B[] r = new B[xs.Length];
+            for (int i = 0; i < xs.Length; i++)
+                r[i] = f(xs[i]);
+            return r;
+        }
+
+        public delegate B Func<A, B>(A x1);
+
+        public static Type[] MapParametersToTypes(ParameterInfo[] parameters)
+        {
+            return MapArray<ParameterInfo, Type>(
+                delegate(ParameterInfo p) { return p.ParameterType; },
+                parameters);
+        }
+
+        public static void EmitLdarg(ILGenerator ilg, int argumentIndex)
+        {
+            if (argumentIndex == 0) ilg.Emit(OpCodes.Ldarg_0);
+            else if (argumentIndex == 1) ilg.Emit(OpCodes.Ldarg_1);
+            else if (argumentIndex == 2) ilg.Emit(OpCodes.Ldarg_2);
+            else if (argumentIndex == 3) ilg.Emit(OpCodes.Ldarg_3);
+            else if (argumentIndex <= 255) ilg.Emit(OpCodes.Ldarg_S, (byte)argumentIndex);
+            else ilg.Emit(OpCodes.Ldarg, (int)argumentIndex);
+        }
+    }
+}
+ Driver/Driver.proj view
@@ -0,0 +1,35 @@+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- Compile 'Driver.hs' into 'Salsa.dll' using the C# compiler -->
+  <Target Name="BuildDriver">
+    <Csc Sources="Driver.cs"
+         TargetType="library"
+         OutputAssembly="Salsa.dll"
+         Optimize="true"
+         FileAlignment="512" />
+  </Target>
+
+  <!-- Run 'Embed.hs' to embed 'Salsa.dll' into a Haskell module -->
+  <Target Name="EmbedDriver" 
+          Inputs="Salsa.dll;Embed.hs"
+          Outputs="Driver.hs"
+          DependsOnTargets="BuildDriver">
+    <Exec Command="runhaskell Embed Salsa.dll > Driver.hs" />
+  </Target>
+
+  <!-- Copy 'Driver.hs' into the Salsa library tree -->
+  <Target Name="CopyDriver"
+          DependsOnTargets="EmbedDriver">
+    <Copy SourceFiles="Driver.hs"
+          DestinationFiles="..\Foreign\Salsa\Driver.hs" />
+  </Target>
+
+  <Target Name="Build" DependsOnTargets="CopyDriver" />
+
+  <Target Name="Clean" >
+    <Delete Files="Salsa.dll" />
+    <Delete Files="Driver.hs" />
+  </Target>
+
+  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
+</Project>
+ Driver/Embed.hs view
@@ -0,0 +1,37 @@+-----------------------------------------------------------------------------
+-- |
+-- Program     : Embed
+-- Copyright   : (c) 2007-2008 Andrew Appleyard
+-- Licence     : BSD-style (see LICENSE)
+-- 
+-- Generates a Haskell module that contains the binary data of the Salsa
+-- driver assembly (typically, Salsa.dll) as an (unboxed) string literal.  This
+-- is used to embed the driver assembly in every program that uses Salsa.
+--
+-----------------------------------------------------------------------------
+module Main where
+
+import System.Environment
+import qualified Data.ByteString as S
+import Text.Printf
+import Control.Monad
+import Data.Time.LocalTime (getZonedTime)
+
+main :: IO ()
+main = do
+    now <- getZonedTime
+    putStrLn ("-- Generated " ++ show now)
+    putStrLn "module Foreign.Salsa.Driver (driverData) where"
+    putStrLn "import qualified Data.ByteString.Char8 as B"
+    putStrLn "{-# NOINLINE driverData #-}"
+    putStr "driverData = B.pack \""
+    [inputFile] <- getArgs
+    S.readFile inputFile >>= print
+    putStrLn "\""
+
+  where print s = do let (xs,ys) = S.splitAt 20 s 
+                     putStr "\\\n  \\"
+                     mapM_ (\x -> printf "\\x%02x" x) (S.unpack xs)
+                     when (not $ S.null ys) (print ys)
+
+-- vim:set ts=4 sw=4 expandtab:
+ Driver/README view
@@ -0,0 +1,12 @@+
+Building:
+
+  To build the driver assembly, run 'msbuild' in the 'Driver' directory.  This
+  will compile Driver.cs into Salsa.dll, embed it as an unpacked byte string in
+  Driver.hs, and then copy it into the Foreign\Salsa directory.
+
+  You can also build the driver by hand:
+
+    csc -filealign:512 -optimize+ -out:Salsa.dll -target:library Driver.cs
+    runhaskell Embed Salsa.dll > ../Salsa/Driver.hs
+
+ Foreign/Salsa.hs view
@@ -0,0 +1,30 @@+-----------------------------------------------------------------------------+-- |+-- Module      : Salsa+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Salsa: a .NET bridge for Haskell.+--+-----------------------------------------------------------------------------+module Foreign.Salsa (+    Obj, _Obj,+    null_, isNull,+    ( # ), (>>=#),+    new, invoke, set, get, delegate,+    AttrOp(..),+    withCLR, startCLR, stopCLR,+    Arr,         _Arr,+    Int32,+    cast, Coercible,+    Object_(..), _Object,+    Type_(..),   _Type,+    Int32_,      _Int32,+    String_,     _String+    ) where++import Foreign.Salsa.Core+import Foreign.Salsa.Common+import Foreign.Salsa.CLR++-- vim:set sw=4 ts=4 expandtab:
+ Foreign/Salsa/Binding.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE ForeignFunctionInterface, TypeSynonymInstances, ScopedTypeVariables #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.Binding+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Exports data types and functions required by the generated binding files.+--+-----------------------------------------------------------------------------+module Foreign.Salsa.Binding (+    module Foreign.Salsa.Common,+    module Foreign.Salsa.Core,+    module Foreign.Salsa.CLR,+    module Foreign.Salsa.TypePrelude,+    module Foreign.Salsa.Resolver,+    withCWString, CWString, FunPtr, unsafePerformIO, liftM,+    type_GetType+    ) where++import Foreign.Salsa.Common+import Foreign.Salsa.Core+import Foreign.Salsa.CLR+import Foreign.Salsa.TypePrelude+import Foreign.Salsa.Resolver++import Foreign hiding (new)+import Foreign.C.String++import Control.Monad (liftM)++-- TODO: Perhaps move some/all of this into the generator, so that it can be+--       CLR-version neutral.++--+-- Import the System.Type.GetType(String) and System.Type.MakeArrayType(Int32)+-- methods so they can be used in the implementations of 'typeOf' as produced by+-- the generator.+--++type Type_GetType_stub = CWString -> Bool -> IO ObjectId+foreign import stdcall "dynamic" make_Type_GetType_stub :: FunPtr Type_GetType_stub -> Type_GetType_stub++{-# NOINLINE type_GetType_stub #-}+type_GetType_stub :: Type_GetType_stub+type_GetType_stub = make_Type_GetType_stub $ unsafePerformIO $ getMethodStub+    "System.Type, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" "GetType"+    "System.String;System.Boolean"++type_GetType typeName = marshalMethod2s type_GetType_stub undefined undefined (typeName, True)+++type Type_MakeArrayType_stub = ObjectId -> Int32 -> IO ObjectId+foreign import stdcall "dynamic" make_Type_MakeArrayType_stub :: FunPtr Type_MakeArrayType_stub -> Type_MakeArrayType_stub++{-# NOINLINE type_MakeArrayType_stub #-}+type_MakeArrayType_stub :: Type_MakeArrayType_stub+type_MakeArrayType_stub = make_Type_MakeArrayType_stub $ unsafePerformIO $ getMethodStub+    "System.Type, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" "MakeArrayType"+    "System.Int32"++-- +-- Typeable instances for primitive types+--++instance Typeable Int32  where typeOf _ = typeOfString "System.Int32"+instance Typeable String where typeOf _ = typeOfString "System.String"+instance Typeable Bool   where typeOf _ = typeOfString "System.Boolean"+instance Typeable Double where typeOf _ = typeOfString "System.Double"++typeOfString :: String -> Obj Type_+typeOfString s = unsafePerformIO $ do+--    putStrLn $ "typeOfString: " ++ s+    type_GetType s+--    marshalMethod1s type_GetType_stub undefined undefined s++-- Define the typeOf function for arrays by first calling typeOf on the element type,+-- and then using the Type.MakeArrayType method to return the associated one-dimensional+-- array type:+instance Typeable t => Typeable (Arr t) where+  typeOf _ = unsafePerformIO $+    marshalMethod1i type_MakeArrayType_stub (typeOf (undefined :: t)) undefined (1 :: Int32)+    -- Note: this function requires ScopedTypeVariables++-- Define typeOf for reference types in terms of the associated static type.+instance Typeable t => Typeable (Obj t) where+  typeOf _ = typeOf (undefined :: t)++-- vim:set sw=4 ts=4 expandtab:
+ Foreign/Salsa/CLR.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.CLR+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Provides convenient functions for accessing the CLR, including: loading+-- the CLR into the process, releasing .NET object references, and obtaining+-- dynamically-generated stub functions for calling into .NET from Haskell.+--+-----------------------------------------------------------------------------+module Foreign.Salsa.CLR (+    withCLR,+    startCLR, stopCLR,+    ObjectId,+    releaseObject,+    getMethodStub,+    getFieldGetStub,+    getFieldSetStub,+    getDelegateConstructorStub,+    boxString, boxInt32, boxBoolean +    ) where++import Data.Int+import Foreign hiding (new, newForeignPtr)+import Foreign.C.String++import Foreign.Salsa.CLRHost++-- | Identifies a foreign (.NET) object instance+type ObjectId = Int32++-- | Starts the .NET execution engine before executing the given IO action, and+--   finally stopping the execution engine.  This can only be performed once+--   in a process.+withCLR :: IO a -> IO a+withCLR action = do+    startCLR+    r <- action+    stopCLR+    return r++startCLR :: IO ()+startCLR = do+    start_ICorRuntimeHost clrHost++    -- Allow .NET to call into Haskell and free unused function pointer wrappers+    setFreeHaskellFunPtr ++stopCLR :: IO ()+stopCLR = do+    -- saveDynamicAssembly -- (for debugging)++    -- Prevent .NET finalizers from calling into Haskell (and causing access violations)+    clearFreeHaskellFunPtr++    stop_ICorRuntimeHost clrHost+    return ()++-- | 'clrHost' stores a reference to the ICLRRuntimeHost for the .NET execution+--   engine that is hosted in the process.+{-# NOINLINE clrHost #-}+clrHost :: ICorRuntimeHost+clrHost = unsafePerformIO $ corBindToRuntimeEx+++-- | @'unsafeGetPointerToMethod' m@ returns a function pointer to the method @m@ +--  as implemented in the Salsa .NET driver assembly (Salsa.dll).  It is safe only+--  if the type of the resulting function pointer matches that of the method given.+unsafeGetPointerToMethod :: String -> IO (FunPtr a)+unsafeGetPointerToMethod methodName = do+    result <- withCWString methodName $ \methodName' -> getPointerToMethodRaw methodName'+    if result == nullFunPtr+        then error $ "Unable to execute Salsa.dll method '" ++ methodName ++ "'."+        else return result++{-# NOINLINE getPointerToMethodRaw #-}+getPointerToMethodRaw :: GetPointerToMethodDelegate a+getPointerToMethodRaw = makeGetPointerToMethodDelegate $ unsafePerformIO $ loadDriverAndBoot clrHost++type GetPointerToMethodDelegate a = CWString -> IO (FunPtr a)+foreign import stdcall "dynamic" makeGetPointerToMethodDelegate :: FunPtr (GetPointerToMethodDelegate a) ->+    GetPointerToMethodDelegate a+++-- | Releases the .NET object indicated by the given object id.+{-# NOINLINE releaseObject #-}+releaseObject :: ObjectId -> IO ()+releaseObject = makeReleaseObjectDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "ReleaseObject"++type ReleaseObjectDelegate = ObjectId -> IO ()+foreign import stdcall "dynamic" makeReleaseObjectDelegate :: FunPtr ReleaseObjectDelegate -> ReleaseObjectDelegate+++-- | Passes a function pointer to the 'freeHaskellFunPtr' function into .NET so+--   that Haskell FunPtr's can be freed from .NET code.+setFreeHaskellFunPtr :: IO ()+setFreeHaskellFunPtr = do+    funPtr <- wrapFreeHaskellFunPtr freeHaskellFunPtr+    setFreeHaskellFunPtrRaw funPtr+    -- Note: since the function passed into .NET may be used by .NET at any+    --       point until the engine is shutdown, and the engine is only loaded+    --       once per process, we don't need to free it.+++-- | Clears the 'freeHaskellFunPtr' pointer on the .NET side to prevent finalizers from+--   calling into Haskell (and causing access violations).+clearFreeHaskellFunPtr :: IO ()+clearFreeHaskellFunPtr = setFreeHaskellFunPtrRaw nullFunPtr+++{-# NOINLINE setFreeHaskellFunPtrRaw #-}+setFreeHaskellFunPtrRaw :: (FunPtr (FunPtr a -> IO ()) -> IO ())+setFreeHaskellFunPtrRaw = makeSetFreeHaskellFunPtrDelegate $ unsafePerformIO $+    unsafeGetPointerToMethod "SetFreeHaskellFunPtr"+  +foreign import stdcall "dynamic" makeSetFreeHaskellFunPtrDelegate ::+    FunPtr (FunPtr (FunPtr a -> IO ()) -> IO ()) -> (FunPtr (FunPtr a -> IO ()) -> IO ())++foreign import stdcall "wrapper" wrapFreeHaskellFunPtr :: +    (FunPtr a -> IO ()) -> IO (FunPtr (FunPtr a -> IO ()))+++-- | 'saveDynamicAssembly' saves the assembly containing the dynamically-generated+--   wrapper stubs to disk (for debugging purposes).+{-# NOINLINE saveDynamicAssembly #-}+saveDynamicAssembly :: IO ()+saveDynamicAssembly = makeSaveDynamicAssemblyDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "SaveDynamicAssembly"++type SaveDynamicAssemblyDelegate = IO ()+foreign import stdcall "dynamic" makeSaveDynamicAssemblyDelegate :: FunPtr SaveDynamicAssemblyDelegate -> SaveDynamicAssemblyDelegate+++-- | @'getMethodStub' c m s@ returns a function pointer to a function that, when+--   called, invokes the method with name @m@ and signature @s@ in class @c@.+--+--   @s@ should be a semi-colon delimited list of parameter types indicating the+--   desired overload of the given method.+getMethodStub :: String -> String -> String -> IO (FunPtr f)+getMethodStub className methodName parameterTypeNames = do+    withCWString className $ \className' ->+        withCWString methodName $ \methodName' ->+            withCWString parameterTypeNames $ \parameterTypeNames' ->+                return $ getMethodStubRaw className' methodName' parameterTypeNames'++{-# NOINLINE getMethodStubRaw #-}+getMethodStubRaw :: GetMethodStubDelegate a+getMethodStubRaw = makeGetMethodStubDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "GetMethodStub"++type GetMethodStubDelegate a = CWString -> CWString -> CWString -> FunPtr a+foreign import stdcall "dynamic" makeGetMethodStubDelegate :: FunPtr (GetMethodStubDelegate a) ->+    (GetMethodStubDelegate a)+++-- | @'getFieldGetStub' c f@ returns a function pointer to a function that, when+--   called, gets the value of the field @f@ in class @c@.+getFieldGetStub :: String -> String -> IO (FunPtr f)+getFieldGetStub className fieldName = do+    withCWString className $ \className' ->+        withCWString fieldName $ \fieldName' ->+            return $ getFieldGetStubRaw className' fieldName'++{-# NOINLINE getFieldGetStubRaw #-}+getFieldGetStubRaw :: GetFieldGetStubDelegate a+getFieldGetStubRaw = makeGetFieldGetStubDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "GetFieldGetStub"++type GetFieldGetStubDelegate a = CWString -> CWString -> FunPtr a+foreign import stdcall "dynamic" makeGetFieldGetStubDelegate :: FunPtr (GetFieldGetStubDelegate a) ->+    (GetFieldGetStubDelegate a)+++-- | @'getFieldSetStub' c f@ returns a function pointer to a function that, when+--   called, sets the value of the field @f@ in class @c@ to the given value.+getFieldSetStub :: String -> String -> IO (FunPtr f)+getFieldSetStub className fieldName = do+    withCWString className $ \className' ->+        withCWString fieldName $ \fieldName' ->+            return $ getFieldSetStubRaw className' fieldName'++{-# NOINLINE getFieldSetStubRaw #-}+getFieldSetStubRaw :: GetFieldSetStubDelegate a+getFieldSetStubRaw = makeGetFieldSetStubDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "GetFieldSetStub"++type GetFieldSetStubDelegate a = CWString -> CWString -> FunPtr a+foreign import stdcall "dynamic" makeGetFieldSetStubDelegate :: FunPtr (GetFieldSetStubDelegate a) ->+    (GetFieldSetStubDelegate a)+++-- | @'getDelegateConstructorStub' dt wrapper@ returns an action that, given a+--   function, will return a reference to a .NET delegate object that calls the+--   provided function.  The delegate constructed will be of the type @dt@.  +--   The function @wrapper@ will be called in order to wrap the given function+--   as a function pointer for passing into .NET.+getDelegateConstructorStub :: String -> (f -> IO (FunPtr f)) -> IO (f -> IO ObjectId)+getDelegateConstructorStub delegateTypeName wrapper = do+    -- Obtain a function pointer to a function that, when called with a+    -- function pointer compatible with the given wrapper function, returns+    -- a reference to a .NET delegate object that calls the function.+    delegateConstructor <- withCWString delegateTypeName $+        \delegateTypeName' -> getDelegateConstructorStubRaw delegateTypeName' ++    -- Returns a function that accepts a function, 'f' implementing the+    -- delegate, converts 'f' to a function pointer, and then wraps it+    -- up as a .NET delegate.+    return $ \f -> do+        fFunPtr <- wrapper f+        (makeDelegateConstructor delegateConstructor) fFunPtr++{-# NOINLINE getDelegateConstructorStubRaw #-}+getDelegateConstructorStubRaw :: GetDelegateConstructorStubDelegate a+getDelegateConstructorStubRaw = makeGetDelegateConstructorStubDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "GetDelegateConstructorStub"++type GetDelegateConstructorStubDelegate a = CWString -> IO (FunPtr (FunPtr a -> IO ObjectId))+foreign import stdcall "dynamic" makeGetDelegateConstructorStubDelegate :: FunPtr (GetDelegateConstructorStubDelegate a) ->+    (GetDelegateConstructorStubDelegate a)++type DelegateConstructor a = FunPtr a -> IO ObjectId+foreign import stdcall "dynamic" makeDelegateConstructor :: FunPtr (DelegateConstructor a) -> (DelegateConstructor a)++--+-- Boxing support+--++-- | @'getBoxStub' t@ returns a function pointer to a function that, when+--   called, returns a boxed object reference to the given type.+getBoxStub :: String -> IO (FunPtr f)+getBoxStub typeName = do+    withCWString typeName $ \typeName' -> return $ getBoxStubRaw typeName'++{-# NOINLINE getBoxStubRaw #-}+getBoxStubRaw :: GetBoxStubDelegate a+getBoxStubRaw = makeGetBoxStubDelegate $ unsafePerformIO $ unsafeGetPointerToMethod "GetBoxStub"++type GetBoxStubDelegate a = CWString -> FunPtr a+foreign import stdcall "dynamic" makeGetBoxStubDelegate :: FunPtr (GetBoxStubDelegate a) -> GetBoxStubDelegate a+++boxString :: String -> IO ObjectId+boxString s = withCWString s $ \s' -> boxStringStub s'++type BoxStringStub = CWString -> IO ObjectId+foreign import stdcall "dynamic" makeBoxStringStub :: FunPtr BoxStringStub -> BoxStringStub++{-# NOINLINE boxStringStub #-}+boxStringStub :: BoxStringStub+boxStringStub = makeBoxStringStub $ unsafePerformIO $ getBoxStub "System.String"+++boxInt32 :: Int32 -> IO ObjectId+boxInt32 = boxInt32Stub++type BoxInt32Stub = Int32 -> IO ObjectId+foreign import stdcall "dynamic" makeBoxInt32Stub :: FunPtr BoxInt32Stub -> BoxInt32Stub++{-# NOINLINE boxInt32Stub #-}+boxInt32Stub :: BoxInt32Stub+boxInt32Stub = makeBoxInt32Stub $ unsafePerformIO $ getBoxStub "System.Int32"+++boxBoolean :: Bool -> ObjectId+boxBoolean True  = boxedTrue+boxBoolean False = boxedFalse++{-# NOINLINE boxedTrue #-}+boxedTrue  = unsafePerformIO $ boxBooleanStub True++{-# NOINLINE boxedFalse #-}+boxedFalse = unsafePerformIO $ boxBooleanStub False++type BoxBooleanStub = Bool -> IO ObjectId+foreign import stdcall "dynamic" makeBoxBooleanStub :: FunPtr BoxBooleanStub -> BoxBooleanStub++{-# NOINLINE boxBooleanStub #-}+boxBooleanStub :: BoxBooleanStub+boxBooleanStub = makeBoxBooleanStub $ unsafePerformIO $ getBoxStub "System.Boolean"++-- vim:set ts=4 sw=4 expandtab:
+ Foreign/Salsa/CLRHost.hs view
@@ -0,0 +1,383 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.CLRHost+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Exposes some of the methods of the ICLRRuntimeHost COM interface, which+-- can be used to host the the Microsoft CLR in the process, and to execute+-- code from a .NET assembly.  Includes basic functionality for dealing+-- with the Microsoft COM.+--+-----------------------------------------------------------------------------+module Foreign.Salsa.CLRHost (+    corBindToRuntimeEx,+    start_ICorRuntimeHost,+    stop_ICorRuntimeHost,+    loadDriverAndBoot,+    ICorRuntimeHost+    ) where++import Data.Word+import Data.Int+import Foreign.Ptr+import Foreign.Storable+import Foreign.Marshal+import Foreign.C.String+import System.Win32+import System.IO+import Control.Exception (bracket)+import Unsafe.Coerce (unsafeCoerce)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.ByteString as S+import Text.Printf++import Foreign.Salsa.Driver++--+-- Global static functions for hosting the CLR+--++type ICorRuntimeHost = InterfacePtr++-- | 'corBindToRunTimeEx' loads the CLR execution engine into the process and returns+--   a COM interface for it.+corBindToRuntimeEx :: IO ICorRuntimeHost+corBindToRuntimeEx = do+    -- Load the 'mscoree' dynamic library into the process.  This is the+    -- 'stub' library for the .NET execution engine, and is used to load an+    -- appropriate version of the real runtime via a call to+    -- 'CorBindToRuntimeEx'.+    hMscoree <- loadLibrary "mscoree.dll"++    -- Obtain a pointer to the 'CorBindToRuntimeEx' function from mscoree.dll+    corBindToRuntimeExAddr <- getProcAddress hMscoree "CorBindToRuntimeEx"+    let corBindToRuntimeEx = makeCorBindToRuntimeEx $ castPtrToFunPtr corBindToRuntimeExAddr++    let clsid_CorRuntimeHost = Guid 0xCB2F6723 0xAB3A 0x11D2 0x9C 0x40 0x00 0xC0 0x4F 0xA3 0x0A 0x3E+        iid_ICorRuntimeHost  = Guid 0xCB2F6722 0xAB3A 0x11D2 0x9C 0x40 0x00 0xC0 0x4F 0xA3 0x0A 0x3E++    -- Request the shim (mscoree.dll) to load a version of the runtime into the+    -- process, returning a pointer to an implementation of the ICorRuntimeHost+    -- for controlling the runtime.+    with (nullPtr :: ICorRuntimeHost) $ \clrHostPtr -> do+        -- Call 'corBindToRuntimeEx' to obtain an ICorRuntimeHost +        with clsid_CorRuntimeHost $ \refCLSID_CorRuntimeHost -> +            with iid_ICorRuntimeHost $ \refIID_ICorRuntimeHost -> +                corBindToRuntimeEx nullPtr nullPtr 0 refCLSID_CorRuntimeHost+                    refIID_ICorRuntimeHost clrHostPtr >>= checkHR "CorBindToRuntimeEx"+        peek clrHostPtr++type CorBindToRuntimeEx = LPCWSTR -> LPCWSTR -> DWORD -> Ptr CLSID -> Ptr IID -> Ptr ICorRuntimeHost -> IO HResult+foreign import stdcall "dynamic" makeCorBindToRuntimeEx :: FunPtr CorBindToRuntimeEx -> CorBindToRuntimeEx+++-- | 'start_ICorRuntimeHost' calls the Start method of the given ICorRuntimeHost interface.+start_ICorRuntimeHost this = do+    -- Initialise COM (and the threading model)+    coInitializeEx nullPtr coInit_ApartmentThreaded+    -- TODO: Allow the library user to select their desired threading model+    --       (we use an STA for the time being so we can use GUI libraries).++    f <- getInterfaceFunction 10 makeStart this+    f this >>= checkHR "ICorRuntimeHost.Start"++type Start = ICorRuntimeHost -> IO HResult+foreign import stdcall "dynamic" makeStart :: FunPtr Start -> Start+++-- | 'stop_ICorRuntimeHost' calls the Stop method of the given ICorRuntimeHost interface.+stop_ICorRuntimeHost this = do+    f <- getInterfaceFunction 11 makeStop this+    f this >>= checkHR "ICorRuntimeHost.Stop"++    coUninitialize++type Stop = ICorRuntimeHost -> IO HResult+foreign import stdcall "dynamic" makeStop :: FunPtr Stop -> Stop+++-- | 'getDefaultDomain_ICorRuntimeHost' calls the GetDefaultDOmain method of the given+--   ICorRuntimeHost interface.+getDefaultDomain_ICorRuntimeHost this = do+    f <- getInterfaceFunction 13 makeGetDefaultDomain this+    with (nullPtr :: InterfacePtr) $ \appDomainPtr -> do+        f this appDomainPtr >>= checkHR "ICorRuntimeHost.GetDefaultDomain"+        peek appDomainPtr++type GetDefaultDomain = ICorRuntimeHost -> Ptr InterfacePtr -> IO HResult+foreign import stdcall "dynamic" makeGetDefaultDomain :: FunPtr GetDefaultDomain -> GetDefaultDomain+++type AppDomain = InterfacePtr -- mscorlib::_AppDomain++-- | 'load_AppDomain' calls mscorlib::_AppDomain.Load_3(SafeArray* rawAssembly, _Assembly** result).+load_AppDomain this rawAssembly = do+    f <- getInterfaceFunction 45 makeLoad_AppDomain this+    with (nullPtr :: Assembly) $ \assemblyPtr -> do+        f this rawAssembly assemblyPtr >>= checkHR "AppDomain.Load"+        peek assemblyPtr++type Load_AppDomain = AppDomain -> SafeArray -> Ptr Assembly -> IO HResult+foreign import stdcall "dynamic" makeLoad_AppDomain :: FunPtr Load_AppDomain -> Load_AppDomain++-- | 'load_AppDomain_2' calls mscorlib::_AppDomain.Load_2(BStr assemblyString, _Assembly** result).+load_AppDomain_2 this assemblyString = do+    f <- getInterfaceFunction 44 makeLoad_AppDomain_2 this+    withBStr assemblyString $ \assemblyString' -> do+        with (nullPtr :: InterfacePtr) $ \assemblyPtr -> do+            f this assemblyString' assemblyPtr >>= checkHR "AppDomain.Load"+            peek assemblyPtr++type Load_AppDomain_2 = AppDomain -> BStr -> Ptr InterfacePtr -> IO HResult+foreign import stdcall "dynamic" makeLoad_AppDomain_2 :: FunPtr Load_AppDomain_2 -> Load_AppDomain_2+++type Assembly = InterfacePtr -- mscorlib::_Assembly++-- | 'getType_Assembly' calls mscorlib::_Assembly.GetType_2(BStr name, _Type** result).+getType_Assembly this name = do+    f <- getInterfaceFunction 17 makeGetType_Assembly this+    withBStr name $ \name' ->+        with (nullPtr :: Type) $ \typePtr -> do+            f this name' typePtr >>= checkHR "Assembly.GetType"+            t <- peek typePtr+            if t == nullPtr then error "Assembly.GetType failed"+                            else return t++type GetType_Assembly = Assembly -> BStr -> Ptr Type -> IO HResult+foreign import stdcall "dynamic" makeGetType_Assembly :: FunPtr GetType_Assembly -> GetType_Assembly+++type Type = InterfacePtr -- mscorlib::_Type++-- | 'invokeMember_Type' calls mscorlib::_Type.InvokeMember_3(BStr name,+--   BindingFlags invokeAttr, _Binder* binder, Variant target, SafeArray* args,+--   Variant* result) to invoke a method without a binder, target or any arguments.+invokeMember_Type this memberName = do+    f <- getInterfaceFunction 57 {- _Type.InvokeMember_3 -} makeInvokeMember_Type this+    withBStr memberName $ \memberName' ->+        with emptyVariant $ \resultPtr -> do+            f this memberName' 256 {- BindingFlags.InvokeMethod -}+                nullPtr 0 0 nullPtr resultPtr >>= checkHR "Type.InvokeMember"+            peek resultPtr++-- Portability note: Type.InvokeMember accepts a by-value variant argument (as its fourth+--                   argument).  In the declaration below, this is encoded as two Word64+--                   arguments.+type InvokeMember_Type = Type -> BStr -> Word32 -> Ptr () -> Word64 -> Word64 -> Ptr () -> Ptr Variant -> IO HResult+foreign import stdcall "dynamic" makeInvokeMember_Type :: FunPtr InvokeMember_Type -> InvokeMember_Type+++-- | 'loadDriverAndBoot' loads the Salsa driver assembly into the application domain from +--   memory (the binary data is originally stored in 'driverData'), and then invokes the+--   Boot method (from the Salsa.Driver class) to obtain a function pointer for invoking +--   the 'GetPointerToMethod' method.+loadDriverAndBoot :: ICorRuntimeHost -> IO (FunPtr (CWString -> IO (FunPtr a)))+loadDriverAndBoot clrHost = do+    -- Obtain an _AppDomain interface pointer to the default application domain+    withInterface (getDefaultDomain_ICorRuntimeHost clrHost) $ \untypedAppDomain -> do+        let iid_AppDomain = Guid 0x05F696DC 0x2B29 0x3663 0xAD 0x8B 0xC4 0x38 0x9C 0xF2 0xA7 0x13+        withInterface (queryInterface untypedAppDomain iid_AppDomain) $ \appDomain -> do++            -- Create a safe array for the contents of the driver assembly binary+            bracket (prim_SafeArrayCreateVector varType_UI1 0 (fromIntegral $ S.length driverData))+                    (prim_SafeArrayDestroy)+                (\sa -> do+                    -- Copy the driver assembly data into the safe array+                    saDataPtr <- with (nullPtr :: Ptr Word8) $ \ptr ->+                                      prim_SafeArrayAccessData sa ptr >> peek ptr+                    S.useAsCStringLen driverData $ \(bsPtr,bsLen) -> do+                        copyBytes saDataPtr (unsafeCoerce bsPtr) bsLen +                    prim_SafeArrayUnaccessData sa++                    -- Load the driver assembly into the application domain+                    withInterface (load_AppDomain appDomain sa) $ \assembly -> do++                        -- Obtain a _Type interface pointer to the Salsa.Driver type+                        withInterface (getType_Assembly assembly "Salsa.Driver") $ \typ -> do++                            -- Invoke the Boot method of Salsa.Driver to obtain a function+                            -- pointer to the 'GetPointerToMethod' method+                            (Variant _ returnValue) <- invokeMember_Type typ "Boot"++                            -- Return a wrapper function for the 'GetPointerToMethod' method+                            return $ unsafeCoerce returnValue)++{-++-- | 'executeInDefaultAppDomain_ICLRRuntimeHost' calls the ExecuteInDefaultAppDomain+--   method of the given ICLRRuntimeHost interface.+executeInDefaultAppDomain_ICLRRuntimeHost :: ICLRRuntimeHost -> String -> String -> String -> String -> IO DWORD+executeInDefaultAppDomain_ICLRRuntimeHost this assemblyPath typeName methodName argument = do+    f <- getInterfaceFunction 11 makeExecuteInDefaultAppDomain this+    with (0 :: DWORD) $ \resultPtr -> do+        hResult <- withCWString assemblyPath $ \assemblyPath' -> +                       withCWString typeName $ \typeName' ->+                           withCWString methodName $ \methodName' ->+                               withCWString argument $ \argument' ->+                                   f this assemblyPath' typeName' methodName' argument' resultPtr+        peek resultPtr++type ExecuteInDefaultAppDomain = ICLRRuntimeHost -> LPCWSTR -> LPCWSTR -> LPCWSTR -> LPCWSTR -> Ptr DWORD -> IO HResult+foreign import stdcall "dynamic" makeExecuteInDefaultAppDomain :: FunPtr ExecuteInDefaultAppDomain -> ExecuteInDefaultAppDomain++-}++--+-- Types and functions for programming the COM+--++type HResult  = Word32+type CLSID    = Guid+type IID      = Guid++-- | 'InterfacePtr' is a pointer to an arbitrary COM interface (which is a pointer to+--   a vtable of function pointers for the interface methods).+type InterfacePtr = Ptr (Ptr (FunPtr ()))+++-- | 'queryInterface' calls the QueryInterface method of the given COM interface.+queryInterface this iid = do+    f <- getInterfaceFunction 0 {- QueryInterface -} makeQueryInterface this+    with (nullPtr :: InterfacePtr) $ \interfacePtr -> do+        with iid $ \refIID -> f this refIID interfacePtr >>= checkHR "IUnknown.QueryInterface"+        peek interfacePtr++type QueryInterface = InterfacePtr -> Ptr IID -> Ptr InterfacePtr -> IO HResult+foreign import stdcall "dynamic" makeQueryInterface :: FunPtr QueryInterface -> QueryInterface+++-- | 'release' calls the Release method of the given COM interface.+release this = do+    f <- getInterfaceFunction 2 {- Release -} makeRelease this+    f this++type Release = InterfacePtr -> IO Word32+foreign import stdcall "dynamic" makeRelease :: FunPtr Release -> Release+++-- | 'withInterface i f' is like 'bracket' but for COM interface pointers, it calls+--   'release' once the computation is finished.+withInterface :: (IO InterfacePtr) -> (InterfacePtr -> IO a) -> IO a+withInterface i = bracket i (\x -> if x == nullPtr then return 0 else release x)+++-- | 'getInterfaceFunction' @i makeFun obj@ is an action that returns the @i@th function+--   of the COM interface referred to by @obj@.  The function is returned as a Haskell+--   function by passing it through @makeFun@.+getInterfaceFunction :: Int -> (FunPtr a -> b) -> InterfacePtr -> IO b+getInterfaceFunction index makeFun this = do+    -- Obtain a pointer to the appropriate element in the vtable for this interface+    funPtr <- peek this >>= (flip peekElemOff) index+    -- Cast the function pointer to the expected type, and import it as a Haskell function+    return $ makeFun $ castFunPtr funPtr+++foreign import stdcall "CoInitializeEx" coInitializeEx :: Ptr () -> Int32 -> IO HResult+foreign import stdcall "CoUninitialize" coUninitialize :: IO ()++coInit_MultiThreaded     = 0 :: Int32+coInit_ApartmentThreaded = 2 :: Int32++data Guid = Guid Word32 Word16 Word16 Word8 Word8 Word8 Word8 Word8 Word8 Word8 Word8 +    deriving (Show, Eq)++instance Storable Guid where+    sizeOf    _ = 16+    alignment _ = 4++    peek guidPtr = do+        a  <- peek $ plusPtr guidPtr 0 +        b  <- peek $ plusPtr guidPtr 4+        c  <- peek $ plusPtr guidPtr 6+        d0 <- peek $ plusPtr guidPtr 8+        d1 <- peek $ plusPtr guidPtr 9+        d2 <- peek $ plusPtr guidPtr 10+        d3 <- peek $ plusPtr guidPtr 11+        d4 <- peek $ plusPtr guidPtr 12+        d5 <- peek $ plusPtr guidPtr 13+        d6 <- peek $ plusPtr guidPtr 14+        d7 <- peek $ plusPtr guidPtr 15+        return $ Guid a b c d0 d1 d2 d3 d4 d5 d6 d7++    poke guidPtr (Guid a b c d0 d1 d2 d3 d4 d5 d6 d7) = do+        poke (plusPtr guidPtr 0)  a+        poke (plusPtr guidPtr 4)  b+        poke (plusPtr guidPtr 6)  c+        poke (plusPtr guidPtr 8)  d0+        poke (plusPtr guidPtr 9)  d1+        poke (plusPtr guidPtr 10) d2+        poke (plusPtr guidPtr 11) d3+        poke (plusPtr guidPtr 12) d4+        poke (plusPtr guidPtr 13) d5+        poke (plusPtr guidPtr 14) d6+        poke (plusPtr guidPtr 15) d7++--+-- Variant Support+--++data Variant = Variant VarType Word64 deriving (Show, Eq)+type VarType = Word16++varType_Empty, varType_UI1 :: VarType+varType_Empty = 0+varType_UI1   = 17++emptyVariant = Variant varType_Empty 0++instance Storable Variant where+    sizeOf    _ = 16+    alignment _ = 8++    peek ptr = do+        a  <- peek $ plusPtr ptr 0 +        b  <- peek $ plusPtr ptr 8+        return $ Variant a b++    poke ptr (Variant a b) = do+        poke (plusPtr ptr 0) a+        poke (plusPtr ptr 2) (0 :: Word16)+        poke (plusPtr ptr 4) (0 :: Word16)+        poke (plusPtr ptr 6) (0 :: Word16)+        poke (plusPtr ptr 8) b++--+-- Safe Array Support+--++newtype SafeArray = SafeArray (Ptr ()) deriving (Show, Eq)++foreign import stdcall "SafeArrayCreateVector" prim_SafeArrayCreateVector :: VarType -> Int32 -> Word32 -> IO SafeArray+foreign import stdcall "SafeArrayAccessData"   prim_SafeArrayAccessData   :: SafeArray -> Ptr (Ptr a) -> IO HResult+foreign import stdcall "SafeArrayUnaccessData" prim_SafeArrayUnaccessData :: SafeArray -> IO HResult +foreign import stdcall "SafeArrayDestroy"      prim_SafeArrayDestroy      :: SafeArray -> IO HResult++--+-- BStr Support+--++newtype BStr = BStr (Ptr ()) deriving (Show, Eq)++sysAllocString :: String -> IO BStr+sysAllocString s = withCWString s prim_SysAllocString+foreign import stdcall "oleauto.h SysAllocString" prim_SysAllocString :: CWString -> IO BStr++sysFreeString :: BStr -> IO ()+sysFreeString = prim_SysFreeString+foreign import stdcall "oleauto.h SysFreeString" prim_SysFreeString :: BStr -> IO ()++withBStr :: String -> (BStr -> IO a) -> IO a+withBStr s = bracket (sysAllocString s) (sysFreeString)++--+-- HResult Support+--++checkHR :: String -> HResult -> IO HResult+checkHR msg 0 = return 0+checkHR msg r = error $ printf "%s failed (0x%8x)" msg r++-- vim:set ts=4 sw=4 expandtab:
+ Foreign/Salsa/Common.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE EmptyDataDecls #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.Common+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Exports data types and functions that are used throughout the bridge+-- implementation.+--+-----------------------------------------------------------------------------+module Foreign.Salsa.Common (+    Obj(..),          _Obj,+    Null,+    Object_(..),      _Object,+    Type_(..),        _Type,+    Int32,   Int32_,  _Int32,+    String,  String_, _String,+    Arr,              _Arr,+    Array_,           _Array+    ) where++import Foreign hiding (new, newForeignPtr)++import Foreign.Salsa.TypePrelude+import Foreign.Salsa.CLR++-- | @Obj a@ represents a .NET object instance of type @a@.+data Obj a = Obj !ObjectId !(ForeignPtr ()) +           | ObjNull++data Null++-- Value-level equivalent of Obj type constructor:+_Obj :: t -> Obj t+_Obj _ = undefined++instance Show (Obj a) where+    show (Obj id _) = "Object(" ++ show id ++ ")"+    show ObjNull    = "Object(null)"++-- Labels for elementary .NET types+data Object_ = Object_                  -- System.Object+data Type_   = Type_                    -- System.Type+data Array_  = Array_                   -- System.Array+_Type   = undefined :: Type_+_Object = undefined :: Object_+_Array  = undefined :: Array_++-- Synonym labels for the primitive types+type String_ = String+type Int32_  = Int32+_String = undefined :: String_+_Int32  = undefined :: Int32_++-- | Represents .NET array types of element type @t@.+data Arr t++-- -- Value-level equivalent of Arr type constructor:+_Arr :: t -> Arr t+_Arr t = undefined++-- vim:set sw=4 ts=4 expandtab:
+ Foreign/Salsa/Core.hs view
@@ -0,0 +1,446 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, EmptyDataDecls #-}+{-# LANGUAGE ExistentialQuantification, FlexibleContexts, TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables, TypeSynonymInstances, FlexibleInstances #-}+{-# OPTIONS_GHC -fallow-undecidable-instances #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.Core+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-----------------------------------------------------------------------------+module Foreign.Salsa.Core where++import Unsafe.Coerce (unsafeCoerce)+import Foreign.C.String+import System.Win32++import Foreign hiding (new, newForeignPtr)+import Foreign.Concurrent (newForeignPtr)++import Foreign.Salsa.Common+import Foreign.Salsa.TypePrelude+import Foreign.Salsa.Resolver+import Foreign.Salsa.CLR++-- Reverse function application+x # f = f x++-- Binding to the target of a method invocation+t >>=# m = t >>= ( # m )++null_ :: Obj Null+null_ = ObjNull++isNull :: Obj a -> Bool+isNull ObjNull = True+isNull _       = False++--+-- Method invocation+--++-- | @'Candidates' t m@ is a type-level list of the members of a particular+--   method group, given the type @t@ and method name @m@.  The overload+--   resolution algorithm chooses the appropriate member of the method group+--   (from this list) according to the argument types.+type family Candidates t m++-- Calls 'ResolveMember', converting argument tuples to/from type-level lists,+-- and passing it the appropriate list of candidate signatures.+type family Resolve t m args+type instance Resolve t m args = ListToTuple (ResolveMember (TupleToList args) (Candidates t m))++-- | 'Invoker' provides type-based dispatch to method implementations, and +--   a constrainted result type for method invocations.+class Invoker t m args where +    type Result t m args+    rawInvoke :: t -> m -> args -> Result t m args++-- | @'invoke' t m args@ invokes the appropriate method @m@ in type @t@ given+--  the tuple of arguments @args@.+invoke :: forall t m args args'.+          (Resolve t m args ~ args',+           Coercible args args',+           Invoker t m args') =>+           t -> m -> args -> Result t m args'+invoke t m args = rawInvoke t m (coerce args :: args')++--+-- Constructor invocation+--++data Ctor = Ctor deriving (Show, Eq)++-- | @'new' t args@ invokes the appropriate constructor for the type @t@+--   given the tuple of arguments @args@, and returns an instance of the+--   constructed type.+new t args = invoke t Ctor args++--+-- Delegate support+--++class Delegate dt where+    type DelegateT dt -- ^ High-level function type for the delegate implementation++    -- | @'delegate' dt h@ calls the constructor for the delegate of type @t@, returning+    --   a .NET delegate object of the same type whose implementation is the Haskell+    --   function, @h@.+    delegate :: dt -> (DelegateT dt) -> IO (Obj dt)+++--+-- Attribute system for .NET properties and events+--++-- | @Prop t pn@ represents a .NET property with name @pn@, on the target object/class @t@.+class Prop t pn where+    type PropGT t pn -- ^ type of property when retrieved; () if write-only+    type PropST t pn -- ^ type of property when set; () if read-only+    setProp :: t -> pn -> PropST t pn -> IO ()+    getProp :: t -> pn -> IO (PropGT t pn)++-- | @Event t en@ represents a .NET event with name @pn@, on the target object/class @t@.+class Event t en where+    type EventT t en -- ^ type of the event delegate+    addEvent, removeEvent :: t -> en -> EventT t en -> IO ()++infix 0 :==, :=, :=>, :~, :+, :-, :+>, :->++-- | @AttrOp t@ represents a get/set operation on a .NET property, or an+--   add/remove operation on a .NET event, on a object/class of type @t@.+data AttrOp t+    = forall p. (Prop  t p) => p :== (PropST t p)               -- assign value to property (monotyped)+    | forall p v. (Prop t p, +                   ConvertsTo v (PropST t p) ~ TTrue,+                   Coercible  v (PropST t p)) =>+                               p := v                           -- assign value to property (w/ implicit conversion)+    | forall p v. (Prop  t p,+                 ConvertsTo v (PropST t p) ~ TTrue,+                 Coercible  v (PropST t p)) =>+                               p :=> IO v                       -- assign result of IO action to property +    | forall p. (Prop  t p) => p :~  (PropGT t p -> PropST t p) -- update property+    | forall e. (Event t e) => e :+  (EventT t e)               -- add event listener+    | forall e. (Event t e) => e :-  (EventT t e)               -- remove event listener+    | forall e. (Event t e) => e :+> IO (EventT t e)            -- add result of IO action to event listeners+    | forall e. (Event t e) => e :-> IO (EventT t e)            -- remove result of IO action from event listeners++-- | @'get' t p@ retrieves the value of property @p@ on the target object/class @t@.+get :: Prop t p => t -> p -> IO (PropGT t p)+get = getProp++-- | @'set' t ops@ applies the operations @ops@ to the object/class @t@.+set :: forall t. {-Target t =>-} t -> [AttrOp t] -> IO ()+set t ops = mapM_ applyOp ops+    where applyOp :: AttrOp t -> IO ()+          applyOp (p :== v) = setProp t p v+          applyOp (p :=  v) = setProp t p (coerce v)+          applyOp (p :=> v) = v >>= (\v -> setProp t p (coerce v))+          applyOp (p :~  f) = getProp t p >>= setProp t p . f+          applyOp (e :+  h) = h #   addEvent    t e+          applyOp (e :-  h) = h #   removeEvent t e+          applyOp (e :+> h) = h >>= addEvent    t e+          applyOp (e :-> h) = h >>= removeEvent t e++    -- +    -- Note: a lexically scoped type variable is required in the definition of this+    -- function.  Both the 'forall t.' in the type signature for 'set' and the the+    -- type signature for 'applyOp' are required to ensure that the 't' variable+    -- used in 'set' is the same 't' as that used in 'applyOp'.  Without the scoped +    -- type variable, GHC is unable to deduce the desired Prop instance for the call+    -- to 'setProp'.+    --+++-- | 'TupleToList t' is the type-level list representation of the tuple @t@+--   containing marshalable types.  This allows arguments to .NET members to+--   be passed as tuples, which have a much neater syntax than lists.+type family TupleToList t+type instance TupleToList ()             = TNil+type instance TupleToList (Obj x)        = Obj x  ::: TNil+type instance TupleToList String         = String ::: TNil+type instance TupleToList Int32          = Int32  ::: TNil+type instance TupleToList Bool           = Bool   ::: TNil+type instance TupleToList Double         = Double ::: TNil+type instance TupleToList (a,b)          = a ::: b ::: TNil+type instance TupleToList (a,b,c)        = a ::: b ::: c ::: TNil+type instance TupleToList (a,b,c,d)      = a ::: b ::: c ::: d ::: TNil+type instance TupleToList (a,b,c,d,e)    = a ::: b ::: c ::: d ::: e ::: TNil+-- ...++-- | 'ListToTuple l' is the tuple type associated with the type-level list @l@.+type family ListToTuple t+type instance ListToTuple (Error x)                            = Error x -- propagate errors+type instance ListToTuple TNil                                 = ()+type instance ListToTuple (a ::: TNil)                         = a+type instance ListToTuple (a ::: b ::: TNil)                   = (a,b) +type instance ListToTuple (a ::: b ::: c ::: TNil)             = (a,b,c)+type instance ListToTuple (a ::: b ::: c ::: d ::: TNil)       = (a,b,c,d)+type instance ListToTuple (a ::: b ::: c ::: d ::: e ::: TNil) = (a,b,c,d,e)+-- ...++--+-- Type reflection (connects Haskell types to .NET types)+--++-- | The class 'Typeable' provides access to the underlying .NET type that is +--   associated with a given Haskell type.+class Typeable t where +    -- | Returns the .NET System.Type instance for values of type 't'.+    --   The value of 't' is not evaluated by the function.+    typeOf :: t -> Obj Type_++-- TODO: Perhaps rename Typeable to Type or SalsaType or Target?+++--+-- Value coercion+--++-- | @'Coercible' from to@ provides a function 'coerce' for implicitly converting+--   values of type @from@ to @to@.  It applies only to high-level bridge types+--   (low-level conversions are handled by the marshaling system).  It always+--   succeeds.+class Coercible from to where+    -- | @'coerce' v@ returns the value @v@ implicitly converted to the desired type.+    coerce :: from -> to++instance Coercible Int32   Int32   where coerce = id+instance Coercible String  String  where coerce = id+instance Coercible Bool    Bool    where coerce = id+instance Coercible Double  Double  where coerce = id+instance Coercible Int32   Double  where coerce = fromIntegral+instance Coercible (Obj f) (Obj t) where coerce = unsafeCoerce++instance Coercible String  (Obj t) where+    coerce s = unsafePerformIO (boxString s >>= unmarshal) -- boxing conversion+    -- TODO: Ensure that this is sufficiently referentially transparent.++instance Coercible Int32  (Obj t) where+    coerce i = unsafePerformIO (boxInt32 i >>= unmarshal) -- boxing conversion+    -- TODO: Ensure that this is sufficiently referentially transparent.++-- Coercible tuples:+instance Coercible ()      ()      where coerce = id+instance (Coercible f0 t0, Coercible f1 t1) =>+    Coercible (f0,f1) (t0,t1) where+    coerce (f0,f1) = (coerce f0, coerce f1)+instance (Coercible f0 t0, Coercible f1 t1, Coercible f2 t2) =>+    Coercible (f0,f1,f2) (t0,t1,t2) where+    coerce (f0,f1,f2) = (coerce f0, coerce f1, coerce f2)+-- ...++-- Lift coerce into the IO monad+instance (Coercible f t) => Coercible f (IO t)  where +    coerce = return . coerce++cast v = coerce v++-- Checked implicit conversion:+convert :: (Coercible from to, ConvertsTo from to ~ TTrue) => from -> to+convert v = coerce v++-- TODO: Fix up the whole: coerce vs. cast vs. convert thing.+--       Work out what's required (i.e. implicit/explicit conversions,+--       checked or unchecked, etc.)++--+-- Marshaling support+--++-- For converting between Haskell types and the proxy types used for+-- communicating with .NET.++-- | The class 'Marshal' allows high-level Haskell types to be converted into +--   low-level types when calling into FFI functions.+class Marshal from to where+    marshal :: from -> (to -> IO a) -> IO a++instance Marshal String CWString where+    marshal s = withCWString s++instance Marshal (Obj a) ObjectId where+    -- | @'marshal' o k@ provides access to the object identifier in @o@ within+    --   the IO action @k@, ensuring that the .NET object instance is kept alive+    --   during the action (like 'withForeignPtr' except for .NET objects).+    marshal (Obj oId fp) k = withForeignPtr fp (\_ -> k oId)+    marshal ObjNull      k = k 0++instance Marshal Int Int32 where+    marshal v f = f (toEnum v)++instance Marshal ()     ()     where marshal = ( # )+instance Marshal String String where marshal = ( # )+instance Marshal Int32  Int32  where marshal = ( # )+instance Marshal Bool   Bool   where marshal = ( # )+instance Marshal Double Double where marshal = ( # )++-- Special case for Nullable<Boolean>+instance Marshal (Maybe Bool) ObjectId where+    marshal Nothing      k = k 0 +    marshal (Just True)  k = k 1+    marshal (Just False) k = k 2+++-- | The class 'Unmarshal' allows low-level types returned by FFI functions to+--   to be converted into high-level Haskell types.+class Unmarshal from to where+    unmarshal :: from -> IO to++instance Unmarshal a () where+    unmarshal _ = return ()++instance Unmarshal ObjectId (Obj a) where+    -- | @'unmarshal' o@ wraps the .NET object identified by @o@ as an Obj value.+    -- 'releaseObject' is called with the object identifier when the Obj is+    -- garbage collected.+    unmarshal 0   = return ObjNull+    unmarshal oId = newForeignPtr nullPtr (releaseObject oId) >>= return . Obj oId++instance Unmarshal CWString String where+    unmarshal s = do+        s' <- peekCWString s+        localFree s -- Free the string allocated by the .NET marshaler (use+                    -- LocalFree for LPWSTRs and SysFreeString for BSTRs)+        return s'++instance Unmarshal String String where unmarshal = return+instance Unmarshal Int32  Int32  where unmarshal = return+instance Unmarshal Bool   Bool   where unmarshal = return+instance Unmarshal Double Double where unmarshal = return++-- Special case for Nullable<Boolean>+instance Unmarshal ObjectId (Maybe Bool) where+    unmarshal id | id == 1 = return $ Just True+                 | id == 2 = return $ Just False+                 | id == 0 = return $ Nothing+                 | otherwise = error "unmarshal: unexpected ObjectId for Maybe Bool"+++-- TODO: Generate the functions below using Template Haskell (this code is hideous).++-- Generic marshaling functions for instance methods+-- (marshal the target object and the tuple of arguments then call the given+--  function and unmarshal the result)+marshalMethod0i f o _ ()        = marshal o (\o' -> f o') >>= unmarshal+marshalMethod1i f o _ (a)       = marshal o (\o' -> marshal a (\a' -> f o' a')) >>= unmarshal+marshalMethod2i f o _ (a,b)     = marshal o (\o' -> marshal a (\a' -> marshal b (\b' -> f o' a' b'))) >>= unmarshal+marshalMethod3i f o _ (a,b,c)   = marshal o (\o' -> marshal a (\a' -> marshal b (\b' -> marshal c (\c' -> f o' a' b' c')))) >>= unmarshal+marshalMethod4i f o _ (a,b,c,d) =+    marshal o (\o' -> marshal a (\a' -> marshal b (\b' -> marshal c (\c' ->+    marshal d (\d' -> f o' a' b' c' d'))))) >>= unmarshal+marshalMethod5i f o _ (a1,a2,a3,a4,a5) =+    marshal o (\o'   -> marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' ->+    marshal a4 (\a4' -> marshal a5 (\a5' -> f o' a1' a2' a3' a4' a5')))))) >>= unmarshal+marshalMethod6i f o _ (a1,a2,a3,a4,a5,a6) =+    marshal o (\o'   -> marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' ->+    marshal a4 (\a4' -> marshal a5 (\a5' -> marshal a6 (\a6' -> +    f o' a1' a2' a3' a4' a5' a6'))))))) >>= unmarshal+marshalMethod7i f o _ (a1,a2,a3,a4,a5,a6,a7) =+    marshal o (\o'   -> marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' ->+    marshal a4 (\a4' -> marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' ->+    f o' a1' a2' a3' a4' a5' a6' a7')))))))) >>= unmarshal+marshalMethod8i f o _ (a1,a2,a3,a4,a5,a6,a7,a8) =+    marshal o (\o'   -> marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' ->+    marshal a4 (\a4' -> marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' ->+    marshal a8 (\a8' ->+    f o' a1' a2' a3' a4' a5' a6' a7' a8'))))))))) >>= unmarshal+marshalMethod9i f o _ (a1,a2,a3,a4,a5,a6,a7,a8,a9) =+    marshal o (\o'   -> marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' ->+    marshal a4 (\a4' -> marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' ->+    marshal a8 (\a8' -> marshal a9 (\a9' ->+    f o' a1' a2' a3' a4' a5' a6' a7' a8' a9')))))))))) >>= unmarshal+marshalMethod10i f o _ (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) =+    marshal o   (\o'   -> marshal a1  (\a1'  -> marshal a2  (\a2'  -> marshal a3  (\a3'  ->+    marshal a4  (\a4'  -> marshal a5  (\a5'  -> marshal a6  (\a6'  -> marshal a7  (\a7'  ->+    marshal a8  (\a8'  -> marshal a9  (\a9'  -> marshal a10 (\a10' ->+    f o' a1' a2' a3' a4' a5' a6' a7' a8' a9' a10'))))))))))) >>= unmarshal+marshalMethod11i f o _ (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) =+    marshal o   (\o'   -> marshal a1  (\a1'  -> marshal a2  (\a2'  -> marshal a3  (\a3'  ->+    marshal a4  (\a4'  -> marshal a5  (\a5'  -> marshal a6  (\a6'  -> marshal a7  (\a7'  ->+    marshal a8  (\a8'  -> marshal a9  (\a9'  -> marshal a10 (\a10' -> marshal a11 (\a11' ->+    f o' a1' a2' a3' a4' a5' a6' a7' a8' a9' a10' a11')))))))))))) >>= unmarshal+-- ...++-- Generic marshaling functions for static methods+-- (marshal the tuple of arguments then call the given function and unmarshal+--  the result)+marshalMethod0s f _ _ ()        = f >>= unmarshal+marshalMethod1s f _ _ (a)       = marshal a (\a' -> f a') >>= unmarshal+marshalMethod2s f _ _ (a,b)     = marshal a (\a' -> marshal b (\b' -> f a' b')) >>= unmarshal+marshalMethod3s f _ _ (a,b,c)   = marshal a (\a' -> marshal b (\b' -> marshal c (\c' -> f a' b' c'))) >>= unmarshal+marshalMethod4s f _ _ (a,b,c,d) =+    marshal a (\a' -> marshal b (\b' -> marshal c (\c' -> marshal d (\d' ->+    f a' b' c' d')))) >>= unmarshal+marshalMethod5s f _ _ (a,b,c,d,e) =+    marshal a (\a' -> marshal b (\b' -> marshal c (\c' -> marshal d (\d' ->+    marshal e (\e' -> f a' b' c' d' e'))))) >>= unmarshal+marshalMethod6s f _ _ (a1,a2,a3,a4,a5,a6) =+    marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' -> marshal a4 (\a4' ->+    marshal a5 (\a5' -> marshal a6 (\a6' -> f a1' a2' a3' a4' a5' a6')))))) >>= unmarshal+marshalMethod7s f _ _ (a1,a2,a3,a4,a5,a6,a7) =+    marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' -> marshal a4 (\a4' ->+    marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' ->+    f a1' a2' a3' a4' a5' a6' a7'))))))) >>= unmarshal+marshalMethod8s f _ _ (a1,a2,a3,a4,a5,a6,a7,a8) =+    marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' -> marshal a4 (\a4' ->+    marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' -> marshal a8 (\a8' ->+    f a1' a2' a3' a4' a5' a6' a7' a8')))))))) >>= unmarshal+marshalMethod9s f _ _ (a1,a2,a3,a4,a5,a6,a7,a8,a9) =+    marshal a1 (\a1' -> marshal a2 (\a2' -> marshal a3 (\a3' -> marshal a4 (\a4' ->+    marshal a5 (\a5' -> marshal a6 (\a6' -> marshal a7 (\a7' -> marshal a8 (\a8' ->+    marshal a9 (\a9' ->+    f a1' a2' a3' a4' a5' a6' a7' a8' a9'))))))))) >>= unmarshal+marshalMethod10s f _ _ (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) =+    marshal a1  (\a1'  -> marshal a2  (\a2'  -> marshal a3  (\a3'  -> marshal a4  (\a4'  ->+    marshal a5  (\a5'  -> marshal a6  (\a6'  -> marshal a7  (\a7'  -> marshal a8  (\a8'  ->+    marshal a9  (\a9'  -> marshal a10 (\a10' ->+    f a1' a2' a3' a4' a5' a6' a7' a8' a9' a10')))))))))) >>= unmarshal+marshalMethod11s f _ _ (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) =+    marshal a1  (\a1'  -> marshal a2  (\a2'  -> marshal a3  (\a3'  -> marshal a4  (\a4'  ->+    marshal a5  (\a5'  -> marshal a6  (\a6'  -> marshal a7  (\a7'  -> marshal a8  (\a8'  ->+    marshal a9  (\a9'  -> marshal a10 (\a10' -> marshal a11 (\a11' ->+    f a1' a2' a3' a4' a5' a6' a7' a8' a9' a10' a11'))))))))))) >>= unmarshal+-- ...++-- Converts a function accepting and returning high-level types, to a function+-- that takes and returns low-level (base) types.++marshalFn0 f = do+    o <- f+    oId <- marshal o return+    return oId++marshalFn1 f = \a1' -> unmarshal a1' >>= (\a1 -> f a1 >>= flip marshal return)++marshalFn2 f = \f1 f2 -> do+    t1 <- unmarshal f1+    t2 <- unmarshal f2+    r <- f t1 t2+    --+    -- FIXME: We might have an issue here when 'r' is an object (Obj).  After+    -- marshal returns, it is possible that no references to 'r' remain in+    -- Haskell.  If the finalizer for the object is called before the +    -- identifier is returned to .NET and looked up in the in-table, then+    -- the lookup will fail.  The following code forces this error:+    --+    --   marshal r return >>= (\rId -> performGC >> yield >> return rId)+    --+    marshal r return++marshalFn3 f = \a1' a2' a3' -> +    unmarshal a1' >>= (\a1 -> unmarshal a2' >>= (\a2 -> unmarshal a3' >>= (\a3 ->+    (f a1 a2 a3 >>= flip marshal return))))++marshalFn4 f = \a1' a2' a3' a4' -> +    unmarshal a1' >>= (\a1 -> unmarshal a2' >>= (\a2 -> unmarshal a3' >>= (\a3 ->+    unmarshal a4' >>= (\a4 -> (f a1 a2 a3 a4 >>= flip marshal return)))))++marshalFn5 f = \a1' a2' a3' a4' a5' -> +    unmarshal a1' >>= (\a1 -> unmarshal a2' >>= (\a2 -> unmarshal a3' >>= (\a3 ->+    unmarshal a4' >>= (\a4 -> unmarshal a5' >>= (\a5 ->+    (f a1 a2 a3 a5 a5 >>= flip marshal return))))))+-- ...++-- vim:set sw=4 ts=4 expandtab:
+ Foreign/Salsa/Driver.hs view
@@ -0,0 +1,953 @@+-- Generated 2008-10-06 01:24:30.052 AUS Eastern Daylight Time
+module Foreign.Salsa.Driver (driverData) where
+import qualified Data.ByteString.Char8 as B
+{-# NOINLINE driverData #-}
+driverData = B.pack "\
+  \\x4d\x5a\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff\x00\x00\xb8\x00\x00\x00\
+  \\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x80\x00\x00\x00\x0e\x1f\xba\x0e\x00\xb4\x09\xcd\x21\xb8\x01\x4c\xcd\x21\x54\x68\
+  \\x69\x73\x20\x70\x72\x6f\x67\x72\x61\x6d\x20\x63\x61\x6e\x6e\x6f\x74\x20\x62\x65\
+  \\x20\x72\x75\x6e\x20\x69\x6e\x20\x44\x4f\x53\x20\x6d\x6f\x64\x65\x2e\x0d\x0d\x0a\
+  \\x24\x00\x00\x00\x00\x00\x00\x00\x50\x45\x00\x00\x4c\x01\x03\x00\x1d\xce\xe8\x48\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x0e\x21\x0b\x01\x08\x00\x00\x42\x00\x00\
+  \\x00\x06\x00\x00\x00\x00\x00\x00\x3e\x61\x00\x00\x00\x20\x00\x00\x00\x80\x00\x00\
+  \\x00\x00\x40\x00\x00\x20\x00\x00\x00\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\
+  \\x04\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\
+  \\x03\x00\x40\x05\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\
+  \\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x60\x00\x00\
+  \\x53\x00\x00\x00\x00\x80\x00\x00\x60\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x20\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x08\x20\x00\x00\x48\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2e\x74\x65\x78\
+  \\x74\x00\x00\x00\x44\x41\x00\x00\x00\x20\x00\x00\x00\x42\x00\x00\x00\x02\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x60\x2e\x72\x73\x72\
+  \\x63\x00\x00\x00\x60\x03\x00\x00\x00\x80\x00\x00\x00\x04\x00\x00\x00\x44\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x40\x2e\x72\x65\x6c\
+  \\x6f\x63\x00\x00\x0c\x00\x00\x00\x00\xa0\x00\x00\x00\x02\x00\x00\x00\x48\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x42\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x61\x00\x00\x00\x00\x00\x00\
+  \\x48\x00\x00\x00\x02\x00\x05\x00\x9c\x35\x00\x00\x4c\x2b\x00\x00\x01\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x30\x04\x00\xcc\x00\x00\x00\
+  \\x00\x00\x00\x00\x73\x09\x00\x00\x0a\x80\x05\x00\x00\x04\x17\x80\x06\x00\x00\x04\
+  \\x14\xfe\x06\x0d\x00\x00\x06\x73\x23\x00\x00\x06\x80\x07\x00\x00\x04\x73\x0a\x00\
+  \\x00\x0a\x80\x08\x00\x00\x04\x73\x0b\x00\x00\x0a\x80\x09\x00\x00\x04\x28\x0c\x00\
+  \\x00\x0a\x73\x0d\x00\x00\x0a\x6f\x0e\x00\x00\x0a\x26\x28\x0f\x00\x00\x0a\x28\x10\
+  \\x00\x00\x0a\x72\x01\x00\x00\x70\x73\x11\x00\x00\x0a\x19\x6f\x12\x00\x00\x0a\x80\
+  \\x01\x00\x00\x04\x7e\x01\x00\x00\x04\x72\x21\x00\x00\x70\x72\x3d\x00\x00\x70\x6f\
+  \\x13\x00\x00\x0a\x80\x02\x00\x00\x04\x7e\x02\x00\x00\x04\x72\x55\x00\x00\x70\x6f\
+  \\x14\x00\x00\x0a\x80\x03\x00\x00\x04\x7e\x05\x00\x00\x04\x7e\x06\x00\x00\x04\x25\
+  \\x17\x58\x80\x06\x00\x00\x04\x17\x8c\x24\x00\x00\x01\x6f\x15\x00\x00\x0a\x7e\x05\
+  \\x00\x00\x04\x7e\x06\x00\x00\x04\x25\x17\x58\x80\x06\x00\x00\x04\x16\x8c\x24\x00\
+  \\x00\x01\x6f\x15\x00\x00\x0a\x2a\x2e\x72\x61\x00\x00\x70\x28\x03\x00\x00\x06\x2a\
+  \\x13\x30\x03\x00\x2b\x00\x00\x00\x01\x00\x00\x11\xd0\x02\x00\x00\x02\x28\x16\x00\
+  \\x00\x0a\x02\x28\x17\x00\x00\x0a\x0a\x06\x2d\x10\x72\x87\x00\x00\x70\x72\xab\x00\
+  \\x00\x70\x73\x18\x00\x00\x0a\x7a\x06\x28\x12\x00\x00\x06\x2a\xbe\x02\x7e\x19\x00\
+  \\x00\x0a\x28\x1a\x00\x00\x0a\x2c\x07\x14\x80\x04\x00\x00\x04\x2a\x02\xd0\x05\x00\
+  \\x00\x02\x28\x16\x00\x00\x0a\x28\x1b\x00\x00\x0a\x74\x05\x00\x00\x02\x80\x04\x00\
+  \\x00\x04\x2a\x00\x13\x30\x02\x00\x37\x00\x00\x00\x02\x00\x00\x11\x7e\x03\x00\x00\
+  \\x04\x6f\x1c\x00\x00\x0a\x26\x7e\x02\x00\x00\x04\x6f\x1d\x00\x00\x0a\x28\x1e\x00\
+  \\x00\x0a\x0a\x72\xc1\x00\x00\x70\x06\x28\x1f\x00\x00\x0a\x28\x20\x00\x00\x0a\x7e\
+  \\x01\x00\x00\x04\x06\x6f\x21\x00\x00\x0a\x2a\x00\x13\x30\x03\x00\x40\x00\x00\x00\
+  \\x03\x00\x00\x11\x03\x72\xf5\x00\x00\x70\x28\x22\x00\x00\x0a\x2c\x19\x02\x28\x38\
+  \\x00\x00\x06\x04\x28\x39\x00\x00\x06\x6f\x23\x00\x00\x0a\x0a\x06\x28\x11\x00\x00\
+  \\x06\x2a\x02\x28\x38\x00\x00\x06\x03\x04\x28\x39\x00\x00\x06\x6f\x24\x00\x00\x0a\
+  \\x0b\x07\x28\x12\x00\x00\x06\x2a\x13\x30\x01\x00\x0e\x00\x00\x00\x04\x00\x00\x11\
+  \\x02\x28\x38\x00\x00\x06\x0a\x06\x28\x13\x00\x00\x06\x2a\x00\x00\x13\x30\x02\x00\
+  \\x14\x00\x00\x00\x05\x00\x00\x11\x02\x28\x38\x00\x00\x06\x03\x6f\x25\x00\x00\x0a\
+  \\x0a\x06\x28\x14\x00\x00\x06\x2a\x13\x30\x02\x00\x14\x00\x00\x00\x05\x00\x00\x11\
+  \\x02\x28\x38\x00\x00\x06\x03\x6f\x25\x00\x00\x0a\x0a\x06\x28\x15\x00\x00\x06\x2a\
+  \\x13\x30\x01\x00\x0e\x00\x00\x00\x04\x00\x00\x11\x02\x28\x38\x00\x00\x06\x0a\x06\
+  \\x28\x16\x00\x00\x06\x2a\x00\x00\x1b\x30\x03\x00\x50\x00\x00\x00\x06\x00\x00\x11\
+  \\x02\x2d\x02\x16\x2a\x02\x75\x04\x00\x00\x1b\x2c\x0e\x02\xa5\x24\x00\x00\x01\x0a\
+  \\x06\x2d\x02\x18\x2a\x17\x2a\x7e\x05\x00\x00\x04\x25\x0c\x28\x26\x00\x00\x0a\x7e\
+  \\x05\x00\x00\x04\x7e\x06\x00\x00\x04\x02\x6f\x15\x00\x00\x0a\x7e\x06\x00\x00\x04\
+  \\x25\x17\x58\x80\x06\x00\x00\x04\x0b\xde\x07\x08\x28\x27\x00\x00\x0a\xdc\x07\x2a\
+  \\x01\x10\x00\x00\x02\x00\x27\x00\x20\x47\x00\x07\x00\x00\x00\x00\x1b\x30\x03\x00\
+  \\x59\x00\x00\x00\x07\x00\x00\x11\x02\x2d\x02\x14\x2a\x02\x17\x33\x07\x17\x8c\x24\
+  \\x00\x00\x01\x2a\x02\x18\x33\x07\x16\x8c\x24\x00\x00\x01\x2a\x7e\x05\x00\x00\x04\
+  \\x25\x0c\x28\x26\x00\x00\x0a\x7e\x05\x00\x00\x04\x02\x12\x00\x6f\x28\x00\x00\x0a\
+  \\x2c\x04\x06\x0b\xde\x1d\x72\x01\x01\x00\x70\x02\x8c\x2e\x00\x00\x01\x28\x29\x00\
+  \\x00\x0a\x73\x2a\x00\x00\x0a\x7a\x08\x28\x27\x00\x00\x0a\xdc\x07\x2a\x00\x00\x00\
+  \\x01\x10\x00\x00\x02\x00\x27\x00\x29\x50\x00\x07\x00\x00\x00\x00\x1b\x30\x02\x00\
+  \\x22\x00\x00\x00\x08\x00\x00\x11\x7e\x05\x00\x00\x04\x25\x0a\x28\x26\x00\x00\x0a\
+  \\x7e\x05\x00\x00\x04\x02\x6f\x2b\x00\x00\x0a\x26\xde\x07\x06\x28\x27\x00\x00\x0a\
+  \\xdc\x2a\x00\x00\x01\x10\x00\x00\x02\x00\x0c\x00\x0e\x1a\x00\x07\x00\x00\x00\x00\
+  \\x1b\x30\x03\x00\x2a\x00\x00\x00\x09\x00\x00\x11\x02\x28\x2c\x00\x00\x0a\x0a\x7e\
+  \\x08\x00\x00\x04\x25\x0b\x28\x26\x00\x00\x0a\x7e\x08\x00\x00\x04\x06\x02\x6f\x2d\
+  \\x00\x00\x0a\xde\x07\x07\x28\x27\x00\x00\x0a\xdc\x06\x2a\x00\x00\x01\x10\x00\x00\
+  \\x02\x00\x13\x00\x0e\x21\x00\x07\x00\x00\x00\x00\x1b\x30\x02\x00\x22\x00\x00\x00\
+  \\x0a\x00\x00\x11\x7e\x08\x00\x00\x04\x25\x0a\x28\x26\x00\x00\x0a\x7e\x08\x00\x00\
+  \\x04\x02\x6f\x2e\x00\x00\x0a\x26\xde\x07\x06\x28\x27\x00\x00\x0a\xdc\x2a\x00\x00\
+  \\x01\x10\x00\x00\x02\x00\x0c\x00\x0e\x1a\x00\x07\x00\x00\x00\x00\x13\x30\x05\x00\
+  \\x65\x00\x00\x00\x0b\x00\x00\x11\x7e\x03\x00\x00\x04\x02\x1c\x0f\x01\x28\x27\x00\
+  \\x00\x06\x0f\x01\x28\x28\x00\x00\x06\x6f\x2f\x00\x00\x0a\x0a\x04\x06\x6f\x30\x00\
+  \\x00\x0a\x6f\x34\x00\x00\x06\x02\x0f\x01\x28\x27\x00\x00\x06\x0f\x01\x28\x28\x00\
+  \\x00\x06\xd0\x02\x00\x00\x02\x28\x16\x00\x00\x0a\x73\x31\x00\x00\x0a\x0b\x04\x07\
+  \\x6f\x32\x00\x00\x0a\x6f\x34\x00\x00\x06\x07\x0f\x01\x28\x2c\x00\x00\x06\x6f\x33\
+  \\x00\x00\x0a\x28\x0e\x00\x00\x06\x2a\x1e\x02\x28\x34\x00\x00\x0a\x2a\x00\x00\x00\
+  \\x03\x30\x03\x00\x7a\x00\x00\x00\x00\x00\x00\x00\x02\x7b\x1a\x00\x00\x04\x2d\x37\
+  \\x03\x02\x7b\x19\x00\x00\x04\x6f\x35\x00\x00\x0a\x26\x03\x7e\x36\x00\x00\x0a\x16\
+  \\x6f\x37\x00\x00\x0a\x03\x7e\x38\x00\x00\x0a\x02\x7b\x19\x00\x00\x04\x6f\x39\x00\
+  \\x00\x0a\x03\x7e\x3a\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2b\x23\x03\x16\x02\x7b\x1a\
+  \\x00\x00\x04\x6f\x3c\x00\x00\x0a\x28\x1d\x00\x00\x06\x03\x7e\x3d\x00\x00\x0a\x02\
+  \\x7b\x1a\x00\x00\x04\x6f\x3e\x00\x00\x0a\x03\x02\x7b\x19\x00\x00\x04\x28\x1e\x00\
+  \\x00\x06\x03\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x00\x00\x13\x30\x05\x00\
+  \\x9b\x00\x00\x00\x0c\x00\x00\x11\x73\x45\x00\x00\x06\x0b\x07\x02\x7d\x1a\x00\x00\
+  \\x04\x07\x07\x7b\x1a\x00\x00\x04\x6f\x40\x00\x00\x0a\x7d\x19\x00\x00\x04\x07\x7b\
+  \\x19\x00\x00\x04\x6f\x41\x00\x00\x0a\x2d\x13\x07\x7b\x1a\x00\x00\x04\x2d\x0b\x72\
+  \\x37\x01\x00\x70\x73\x42\x00\x00\x0a\x7a\x12\x00\xd0\x2e\x00\x00\x01\x28\x16\x00\
+  \\x00\x0a\x07\x7b\x1a\x00\x00\x04\x2c\x17\x07\x7b\x1a\x00\x00\x04\x6f\x3c\x00\x00\
+  \\x0a\x28\x3d\x00\x00\x06\x28\x19\x00\x00\x06\x2b\x05\x7e\x43\x00\x00\x0a\x28\x29\
+  \\x00\x00\x06\x07\x7b\x19\x00\x00\x04\x6f\x44\x00\x00\x0a\x72\x9d\x01\x00\x70\x28\
+  \\x1f\x00\x00\x0a\x06\x07\xfe\x06\x46\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\
+  \\x00\x06\x2a\x1e\x02\x28\x34\x00\x00\x0a\x2a\x00\x03\x30\x03\x00\x79\x00\x00\x00\
+  \\x00\x00\x00\x00\x02\x7b\x1b\x00\x00\x04\x6f\x45\x00\x00\x0a\x2c\x25\x03\x16\x02\
+  \\x7b\x1b\x00\x00\x04\x6f\x3c\x00\x00\x0a\x28\x1d\x00\x00\x06\x03\x7e\x46\x00\x00\
+  \\x0a\x02\x7b\x1b\x00\x00\x04\x6f\x47\x00\x00\x0a\x2b\x35\x03\x16\x02\x7b\x1b\x00\
+  \\x00\x04\x6f\x40\x00\x00\x0a\x28\x1b\x00\x00\x06\x03\x17\x02\x7b\x1b\x00\x00\x04\
+  \\x6f\x3c\x00\x00\x0a\x28\x1d\x00\x00\x06\x03\x7e\x48\x00\x00\x0a\x02\x7b\x1b\x00\
+  \\x00\x04\x6f\x47\x00\x00\x0a\x03\x02\x7b\x1b\x00\x00\x04\x6f\x49\x00\x00\x0a\x28\
+  \\x1f\x00\x00\x06\x2a\x00\x00\x00\x13\x30\x05\x00\xb1\x00\x00\x00\x0d\x00\x00\x11\
+  \\x73\x47\x00\x00\x06\x0c\x08\x02\x7d\x1b\x00\x00\x04\x08\x7b\x1b\x00\x00\x04\x6f\
+  \\x40\x00\x00\x0a\x0a\x12\x01\x08\x7b\x1b\x00\x00\x04\x6f\x49\x00\x00\x0a\x6f\x4a\
+  \\x00\x00\x0a\x28\x1a\x00\x00\x06\x08\x7b\x1b\x00\x00\x04\x6f\x45\x00\x00\x0a\x2d\
+  \\x2c\x08\x7b\x1b\x00\x00\x04\x6f\x40\x00\x00\x0a\x28\x1a\x00\x00\x06\x08\x7b\x1b\
+  \\x00\x00\x04\x6f\x3c\x00\x00\x0a\x28\x3d\x00\x00\x06\x28\x19\x00\x00\x06\x28\x01\
+  \\x00\x00\x2b\x2b\x15\x08\x7b\x1b\x00\x00\x04\x6f\x3c\x00\x00\x0a\x28\x3d\x00\x00\
+  \\x06\x28\x19\x00\x00\x06\x28\x29\x00\x00\x06\x06\x6f\x44\x00\x00\x0a\x72\xa5\x01\
+  \\x00\x70\x08\x7b\x1b\x00\x00\x04\x6f\x44\x00\x00\x0a\x28\x4b\x00\x00\x0a\x07\x08\
+  \\xfe\x06\x48\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\x00\x06\x2a\x1e\x02\x28\
+  \\x34\x00\x00\x0a\x2a\x00\x00\x00\x13\x30\x06\x00\xa5\x00\x00\x00\x0e\x00\x00\x11\
+  \\x03\x7e\x4c\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x03\x7e\x3d\x00\x00\x0a\x02\x7b\x1c\
+  \\x00\x00\x04\x17\x8d\x0b\x00\x00\x01\x0a\x06\x16\xd0\x27\x00\x00\x01\x28\x16\x00\
+  \\x00\x0a\xa2\x06\x6f\x23\x00\x00\x0a\x6f\x3e\x00\x00\x0a\x03\x7e\x4d\x00\x00\x0a\
+  \\x02\x7b\x1c\x00\x00\x04\x72\xa9\x01\x00\x70\x6f\x17\x00\x00\x0a\x6f\x47\x00\x00\
+  \\x0a\x03\x7e\x3d\x00\x00\x0a\x02\x7b\x1d\x00\x00\x04\x18\x8d\x0b\x00\x00\x01\x0b\
+  \\x07\x16\xd0\x01\x00\x00\x01\x28\x16\x00\x00\x0a\xa2\x07\x17\xd0\x27\x00\x00\x01\
+  \\x28\x16\x00\x00\x0a\xa2\x07\x6f\x23\x00\x00\x0a\x6f\x3e\x00\x00\x0a\x03\x7e\x46\
+  \\x00\x00\x0a\x7e\x14\x00\x00\x04\x6f\x47\x00\x00\x0a\x03\x7e\x3f\x00\x00\x0a\x6f\
+  \\x3b\x00\x00\x0a\x2a\x00\x00\x00\x13\x30\x05\x00\x78\x00\x00\x00\x0f\x00\x00\x11\
+  \\x73\x49\x00\x00\x06\x0b\x07\x02\x7d\x1d\x00\x00\x04\x07\x07\x7b\x1d\x00\x00\x04\
+  \\x28\x20\x00\x00\x06\x7d\x1c\x00\x00\x04\x07\x7b\x1d\x00\x00\x04\x28\x2b\x00\x00\
+  \\x06\x26\x12\x00\xd0\x2e\x00\x00\x01\x28\x16\x00\x00\x0a\x17\x8d\x0b\x00\x00\x01\
+  \\x0c\x08\x16\xd0\x27\x00\x00\x01\x28\x16\x00\x00\x0a\xa2\x08\x28\x29\x00\x00\x06\
+  \\x07\x7b\x1d\x00\x00\x04\x6f\x44\x00\x00\x0a\x72\x9d\x01\x00\x70\x28\x1f\x00\x00\
+  \\x0a\x06\x07\xfe\x06\x4a\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\x00\x06\x2a\
+  \\x1e\x02\x28\x34\x00\x00\x0a\x2a\x13\x30\x03\x00\x94\x00\x00\x00\x10\x00\x00\x11\
+  \\x02\x7b\x1e\x00\x00\x04\x6f\x4e\x00\x00\x0a\x2c\x47\x02\x7b\x1e\x00\x00\x04\x6f\
+  \\x4f\x00\x00\x0a\x2c\x27\x02\x7b\x1e\x00\x00\x04\x6f\x50\x00\x00\x0a\x0a\x06\x75\
+  \\x2e\x00\x00\x01\x2c\x49\x03\x7e\x51\x00\x00\x0a\x06\xa5\x2e\x00\x00\x01\x6f\x52\
+  \\x00\x00\x0a\x2b\x36\x03\x7e\x53\x00\x00\x0a\x02\x7b\x1e\x00\x00\x04\x6f\x54\x00\
+  \\x00\x0a\x2b\x23\x03\x16\x02\x7b\x1e\x00\x00\x04\x6f\x40\x00\x00\x0a\x28\x1b\x00\
+  \\x00\x06\x03\x7e\x55\x00\x00\x0a\x02\x7b\x1e\x00\x00\x04\x6f\x54\x00\x00\x0a\x03\
+  \\x02\x7b\x1e\x00\x00\x04\x6f\x56\x00\x00\x0a\x28\x1e\x00\x00\x06\x03\x7e\x3f\x00\
+  \\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x13\x30\x05\x00\x8b\x00\x00\x00\x11\x00\x00\x11\
+  \\x73\x4b\x00\x00\x06\x0b\x07\x02\x7d\x1e\x00\x00\x04\x12\x00\x07\x7b\x1e\x00\x00\
+  \\x04\x6f\x56\x00\x00\x0a\x28\x1a\x00\x00\x06\x07\x7b\x1e\x00\x00\x04\x6f\x4e\x00\
+  \\x00\x0a\x2d\x1d\x17\x8d\x0b\x00\x00\x01\x0c\x08\x16\x07\x7b\x1e\x00\x00\x04\x6f\
+  \\x40\x00\x00\x0a\x28\x1a\x00\x00\x06\xa2\x08\x2b\x05\x7e\x43\x00\x00\x0a\x28\x29\
+  \\x00\x00\x06\x07\x7b\x1e\x00\x00\x04\x6f\x40\x00\x00\x0a\x6f\x44\x00\x00\x0a\x72\
+  \\xb7\x01\x00\x70\x07\x7b\x1e\x00\x00\x04\x6f\x44\x00\x00\x0a\x28\x4b\x00\x00\x0a\
+  \\x06\x07\xfe\x06\x4c\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\x00\x06\x2a\x1e\
+  \\x02\x28\x34\x00\x00\x0a\x2a\x00\x03\x30\x03\x00\x73\x00\x00\x00\x00\x00\x00\x00\
+  \\x02\x7b\x1f\x00\x00\x04\x6f\x4e\x00\x00\x0a\x2c\x25\x03\x16\x02\x7b\x1f\x00\x00\
+  \\x04\x6f\x56\x00\x00\x0a\x28\x1b\x00\x00\x06\x03\x7e\x57\x00\x00\x0a\x02\x7b\x1f\
+  \\x00\x00\x04\x6f\x54\x00\x00\x0a\x2b\x35\x03\x16\x02\x7b\x1f\x00\x00\x04\x6f\x40\
+  \\x00\x00\x0a\x28\x1b\x00\x00\x06\x03\x17\x02\x7b\x1f\x00\x00\x04\x6f\x56\x00\x00\
+  \\x0a\x28\x1b\x00\x00\x06\x03\x7e\x58\x00\x00\x0a\x02\x7b\x1f\x00\x00\x04\x6f\x54\
+  \\x00\x00\x0a\x03\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x00\x13\x30\x06\x00\
+  \\xae\x00\x00\x00\x12\x00\x00\x11\x73\x4d\x00\x00\x06\x0b\x07\x02\x7d\x1f\x00\x00\
+  \\x04\x12\x00\xd0\x38\x00\x00\x01\x28\x16\x00\x00\x0a\x07\x7b\x1f\x00\x00\x04\x6f\
+  \\x4e\x00\x00\x0a\x2d\x30\x18\x8d\x0b\x00\x00\x01\x0c\x08\x16\x07\x7b\x1f\x00\x00\
+  \\x04\x6f\x40\x00\x00\x0a\x28\x1a\x00\x00\x06\xa2\x08\x17\x07\x7b\x1f\x00\x00\x04\
+  \\x6f\x56\x00\x00\x0a\x28\x1a\x00\x00\x06\xa2\x08\x2b\x1b\x17\x8d\x0b\x00\x00\x01\
+  \\x0d\x09\x16\x07\x7b\x1f\x00\x00\x04\x6f\x56\x00\x00\x0a\x28\x1a\x00\x00\x06\xa2\
+  \\x09\x28\x29\x00\x00\x06\x07\x7b\x1f\x00\x00\x04\x6f\x40\x00\x00\x0a\x6f\x44\x00\
+  \\x00\x0a\x72\xcf\x01\x00\x70\x07\x7b\x1f\x00\x00\x04\x6f\x44\x00\x00\x0a\x28\x4b\
+  \\x00\x00\x0a\x06\x07\xfe\x06\x4e\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\x00\
+  \\x06\x2a\x1e\x02\x28\x34\x00\x00\x0a\x2a\x00\x00\x03\x30\x03\x00\x47\x00\x00\x00\
+  \\x00\x00\x00\x00\x03\x16\x02\x7b\x20\x00\x00\x04\x28\x1b\x00\x00\x06\x02\x7b\x20\
+  \\x00\x00\x04\x6f\x41\x00\x00\x0a\x2c\x11\x03\x7e\x59\x00\x00\x0a\x02\x7b\x20\x00\
+  \\x00\x04\x6f\x39\x00\x00\x0a\x03\xd0\x01\x00\x00\x01\x28\x16\x00\x00\x0a\x28\x1e\
+  \\x00\x00\x06\x03\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x00\x13\x30\x05\x00\
+  \\x5c\x00\x00\x00\x13\x00\x00\x11\x73\x4f\x00\x00\x06\x0b\x07\x02\x7d\x20\x00\x00\
+  \\x04\x12\x00\xd0\x2e\x00\x00\x01\x28\x16\x00\x00\x0a\x17\x8d\x0b\x00\x00\x01\x0c\
+  \\x08\x16\x07\x7b\x20\x00\x00\x04\x28\x1a\x00\x00\x06\xa2\x08\x28\x29\x00\x00\x06\
+  \\x72\xe7\x01\x00\x70\x07\x7b\x20\x00\x00\x04\x6f\x44\x00\x00\x0a\x28\x1f\x00\x00\
+  \\x0a\x06\x07\xfe\x06\x50\x00\x00\x06\x73\x33\x00\x00\x06\x28\x10\x00\x00\x06\x2a\
+  \\xa2\x02\x6f\x5a\x00\x00\x0a\x2d\x1e\x02\xd0\x38\x00\x00\x01\x28\x16\x00\x00\x0a\
+  \\x2e\x11\x02\xd0\x2b\x00\x00\x01\x28\x16\x00\x00\x0a\xfe\x01\x16\xfe\x01\x2a\x16\
+  \\x2a\x00\x00\x00\x13\x30\x02\x00\x1f\x00\x00\x00\x14\x00\x00\x11\x02\xd0\x2b\x00\
+  \\x00\x01\x28\x16\x00\x00\x0a\x33\x08\x1f\x15\x73\x5b\x00\x00\x0a\x2a\x12\x00\xfe\
+  \\x15\x05\x00\x00\x1b\x06\x2a\x4e\x14\xfe\x06\x1a\x00\x00\x06\x73\x5c\x00\x00\x0a\
+  \\x02\x28\x02\x00\x00\x2b\x2a\x56\x02\x28\x17\x00\x00\x06\x2c\x0b\xd0\x2e\x00\x00\
+  \\x01\x28\x16\x00\x00\x0a\x2a\x02\x2a\x3e\x02\x03\x28\x3e\x00\x00\x06\x02\x04\x28\
+  \\x1c\x00\x00\x06\x2a\x96\x03\x28\x17\x00\x00\x06\x2c\x1c\x02\x7e\x46\x00\x00\x0a\
+  \\x7e\x15\x00\x00\x04\x6f\x47\x00\x00\x0a\x02\x7e\x5d\x00\x00\x0a\x03\x6f\x39\x00\
+  \\x00\x0a\x2a\x00\x1b\x30\x04\x00\x40\x00\x00\x00\x15\x00\x00\x11\x03\x0a\x04\x6f\
+  \\x5e\x00\x00\x0a\x0d\x2b\x20\x09\x6f\x5f\x00\x00\x0a\x0b\x07\x6f\x4a\x00\x00\x0a\
+  \\x0c\x02\x06\x25\x17\x58\x0a\x28\x3e\x00\x00\x06\x02\x08\x28\x1c\x00\x00\x06\x09\
+  \\x6f\x60\x00\x00\x0a\x2d\xd8\xde\x0a\x09\x2c\x06\x09\x6f\x61\x00\x00\x0a\xdc\x2a\
+  \\x01\x10\x00\x00\x02\x00\x09\x00\x2c\x35\x00\x0a\x00\x00\x00\x00\xb6\x03\x28\x17\
+  \\x00\x00\x06\x2c\x24\x03\x6f\x41\x00\x00\x0a\x2c\x0c\x02\x7e\x59\x00\x00\x0a\x03\
+  \\x6f\x39\x00\x00\x0a\x02\x7e\x46\x00\x00\x0a\x7e\x14\x00\x00\x04\x6f\x47\x00\x00\
+  \\x0a\x2a\x00\x00\x13\x30\x02\x00\x1a\x00\x00\x00\x04\x00\x00\x11\x03\x6f\x4a\x00\
+  \\x00\x0a\x0a\x02\x06\x28\x1e\x00\x00\x06\x02\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\
+  \\x0a\x2a\x00\x00\x1b\x30\x03\x00\x4d\x00\x00\x00\x16\x00\x00\x11\x02\x6f\x44\x00\
+  \\x00\x0a\x72\xf1\x01\x00\x70\x28\x1f\x00\x00\x0a\x0a\x7e\x09\x00\x00\x04\x25\x0d\
+  \\x28\x26\x00\x00\x0a\x7e\x09\x00\x00\x04\x06\x12\x01\x6f\x62\x00\x00\x0a\x2d\x14\
+  \\x06\x02\x28\x21\x00\x00\x06\x0b\x7e\x09\x00\x00\x04\x06\x07\x6f\x63\x00\x00\x0a\
+  \\x07\x0c\xde\x07\x09\x28\x27\x00\x00\x0a\xdc\x08\x2a\x00\x00\x00\x01\x10\x00\x00\
+  \\x02\x00\x1d\x00\x27\x44\x00\x07\x00\x00\x00\x00\x13\x30\x06\x00\x68\x02\x00\x00\
+  \\x17\x00\x00\x11\x03\x28\x2b\x00\x00\x06\x0a\x12\x00\x28\x27\x00\x00\x06\x28\x1a\
+  \\x00\x00\x06\x12\x00\x28\x28\x00\x00\x06\x28\x19\x00\x00\x06\x73\x29\x00\x00\x06\
+  \\x13\x0c\x12\x0c\x28\x2c\x00\x00\x06\x0b\x7e\x02\x00\x00\x04\x02\x20\x01\x01\x00\
+  \\x00\x6f\x64\x00\x00\x0a\x0c\x08\x72\x01\x02\x00\x70\x07\x17\x6f\x65\x00\x00\x0a\
+  \\x0d\x08\x20\x06\x10\x00\x00\x17\x17\x8d\x0b\x00\x00\x01\x13\x0d\x11\x0d\x16\xd0\
+  \\x27\x00\x00\x01\x28\x16\x00\x00\x0a\xa2\x11\x0d\x6f\x66\x00\x00\x0a\x13\x04\x11\
+  \\x04\x6f\x67\x00\x00\x0a\x13\x05\x11\x05\x7e\x4c\x00\x00\x0a\x6f\x3b\x00\x00\x0a\
+  \\x11\x05\x7e\x46\x00\x00\x0a\x7e\x0e\x00\x00\x04\x6f\x3e\x00\x00\x0a\x11\x05\x7e\
+  \\x4c\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x11\x05\x7e\x68\x00\x00\x0a\x6f\x3b\x00\x00\
+  \\x0a\x11\x05\x7e\x69\x00\x00\x0a\x07\x6f\x39\x00\x00\x0a\x11\x05\x7e\x46\x00\x00\
+  \\x0a\x7e\x0d\x00\x00\x04\x6f\x47\x00\x00\x0a\x11\x05\x7e\x46\x00\x00\x0a\x7e\x0f\
+  \\x00\x00\x04\x6f\x47\x00\x00\x0a\x11\x05\x7e\x6a\x00\x00\x0a\x07\x6f\x39\x00\x00\
+  \\x0a\x11\x05\x7e\x58\x00\x00\x0a\x09\x6f\x54\x00\x00\x0a\x11\x05\x7e\x3f\x00\x00\
+  \\x0a\x6f\x3b\x00\x00\x0a\x08\x72\x1f\x02\x00\x70\x20\xc4\x00\x00\x00\x6f\x6b\x00\
+  \\x00\x0a\x13\x06\x11\x06\x16\x6f\x6c\x00\x00\x0a\x11\x06\x6f\x30\x00\x00\x0a\x13\
+  \\x07\x11\x07\x6f\x6d\x00\x00\x0a\x13\x08\x11\x07\x7e\x53\x00\x00\x0a\x7e\x13\x00\
+  \\x00\x04\x6f\x54\x00\x00\x0a\x11\x07\x7e\x6e\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x11\
+  \\x07\x7e\x6f\x00\x00\x0a\x11\x08\x6f\x70\x00\x00\x0a\x11\x07\x7e\x53\x00\x00\x0a\
+  \\x7e\x13\x00\x00\x04\x6f\x54\x00\x00\x0a\x11\x07\x7e\x4c\x00\x00\x0a\x6f\x3b\x00\
+  \\x00\x0a\x11\x07\x7e\x55\x00\x00\x0a\x09\x6f\x54\x00\x00\x0a\x11\x07\x7e\x46\x00\
+  \\x00\x0a\x7e\x10\x00\x00\x04\x6f\x47\x00\x00\x0a\x11\x07\x7e\x46\x00\x00\x0a\x7e\
+  \\x16\x00\x00\x04\x6f\x47\x00\x00\x0a\x11\x07\x11\x08\x6f\x71\x00\x00\x0a\x11\x07\
+  \\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x08\x72\xa9\x01\x00\x70\x1c\x12\x00\x28\
+  \\x27\x00\x00\x06\x12\x00\x28\x28\x00\x00\x06\x6f\x2f\x00\x00\x0a\x13\x09\x11\x09\
+  \\x6f\x30\x00\x00\x0a\x13\x0a\x11\x0a\x7e\x4c\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x11\
+  \\x0a\x7e\x55\x00\x00\x0a\x09\x6f\x54\x00\x00\x0a\x16\x13\x0b\x2b\x22\x11\x0a\x11\
+  \\x0b\x17\x58\x28\x3e\x00\x00\x06\x11\x0a\x12\x00\x28\x28\x00\x00\x06\x11\x0b\x9a\
+  \\x28\x1e\x00\x00\x06\x11\x0b\x17\x58\x13\x0b\x11\x0b\x12\x00\x28\x28\x00\x00\x06\
+  \\x8e\x69\x32\xd1\x11\x0a\x7e\x48\x00\x00\x0a\x07\x72\xa9\x01\x00\x70\x6f\x17\x00\
+  \\x00\x0a\x6f\x47\x00\x00\x0a\x11\x0a\x12\x00\x28\x27\x00\x00\x06\x28\x1c\x00\x00\
+  \\x06\x11\x0a\x7e\x3f\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x08\x6f\x1c\x00\x00\x0a\x2a\
+  \\x1e\x02\x28\x34\x00\x00\x0a\x2a\x1e\x02\x7b\x0a\x00\x00\x04\x2a\x1e\x02\x7b\x0b\
+  \\x00\x00\x04\x2a\x3e\x02\x03\x7d\x0a\x00\x00\x04\x02\x04\x7d\x0b\x00\x00\x04\x2a\
+  \\x13\x30\x02\x00\x51\x00\x00\x00\x18\x00\x00\x11\x73\x74\x00\x00\x0a\x0a\x02\x7b\
+  \\x0b\x00\x00\x04\x0c\x16\x0d\x2b\x21\x08\x09\x9a\x0b\x06\x07\x6f\x44\x00\x00\x0a\
+  \\x6f\x75\x00\x00\x0a\x26\x06\x72\x31\x02\x00\x70\x6f\x75\x00\x00\x0a\x26\x09\x17\
+  \\x58\x0d\x09\x08\x8e\x69\x32\xd9\x06\x02\x7b\x0a\x00\x00\x04\x6f\x44\x00\x00\x0a\
+  \\x6f\x75\x00\x00\x0a\x26\x06\x6f\x76\x00\x00\x0a\x2a\x00\x00\x00\x13\x30\x03\x00\
+  \\x23\x00\x00\x00\x01\x00\x00\x11\x02\x72\xa9\x01\x00\x70\x6f\x17\x00\x00\x0a\x0a\
+  \\x06\x6f\x77\x00\x00\x0a\x06\x6f\x3c\x00\x00\x0a\x28\x3d\x00\x00\x06\x73\x29\x00\
+  \\x00\x06\x2a\x00\x1b\x30\x03\x00\x53\x00\x00\x00\x16\x00\x00\x11\x02\xfe\x16\x04\
+  \\x00\x00\x02\x6f\x76\x00\x00\x0a\x72\x37\x02\x00\x70\x28\x1f\x00\x00\x0a\x0a\x7e\
+  \\x0c\x00\x00\x04\x25\x0d\x28\x26\x00\x00\x0a\x7e\x0c\x00\x00\x04\x06\x12\x01\x6f\
+  \\x62\x00\x00\x0a\x2d\x14\x02\x06\x28\x2d\x00\x00\x06\x0b\x7e\x0c\x00\x00\x04\x06\
+  \\x07\x6f\x63\x00\x00\x0a\x07\x0c\xde\x07\x09\x28\x27\x00\x00\x0a\xdc\x08\x2a\x00\
+  \\x01\x10\x00\x00\x02\x00\x23\x00\x27\x4a\x00\x07\x00\x00\x00\x00\x13\x30\x06\x00\
+  \\x65\x01\x00\x00\x19\x00\x00\x11\x7e\x02\x00\x00\x04\x03\x20\x01\x01\x02\x00\xd0\
+  \\x02\x00\x00\x01\x28\x16\x00\x00\x0a\x6f\x78\x00\x00\x0a\x0a\x06\xd0\x43\x00\x00\
+  \\x01\x28\x16\x00\x00\x0a\x17\x8d\x0b\x00\x00\x01\x13\x06\x11\x06\x16\xd0\x44\x00\
+  \\x00\x01\x28\x16\x00\x00\x0a\xa2\x11\x06\x28\x23\x00\x00\x0a\x17\x8d\x01\x00\x00\
+  \\x01\x13\x07\x11\x07\x16\x19\x8c\x44\x00\x00\x01\xa2\x11\x07\x73\x79\x00\x00\x0a\
+  \\x6f\x7a\x00\x00\x0a\x06\x20\x86\x10\x00\x00\x17\x18\x8d\x0b\x00\x00\x01\x13\x08\
+  \\x11\x08\x16\xd0\x01\x00\x00\x01\x28\x16\x00\x00\x0a\xa2\x11\x08\x17\xd0\x27\x00\
+  \\x00\x01\x28\x16\x00\x00\x0a\xa2\x11\x08\x6f\x66\x00\x00\x0a\x0b\x07\x19\x6f\x7b\
+  \\x00\x00\x0a\x06\x72\xa9\x01\x00\x70\x20\xc6\x01\x00\x00\x02\x28\x27\x00\x00\x06\
+  \\x02\x28\x28\x00\x00\x06\x6f\x2f\x00\x00\x0a\x0c\x08\x19\x6f\x6c\x00\x00\x0a\x16\
+  \\x0d\x38\x88\x00\x00\x00\x09\x2d\x0f\x02\x28\x27\x00\x00\x06\x28\x18\x00\x00\x06\
+  \\x13\x04\x2b\x11\x02\x28\x28\x00\x00\x06\x09\x17\x59\x9a\x28\x18\x00\x00\x06\x13\
+  \\x04\x12\x04\x28\x7c\x00\x00\x0a\x2c\x58\x08\x09\x16\x14\x6f\x7d\x00\x00\x0a\x13\
+  \\x05\x11\x05\xd0\x4b\x00\x00\x01\x28\x16\x00\x00\x0a\x17\x8d\x0b\x00\x00\x01\x13\
+  \\x09\x11\x09\x16\xd0\x0e\x00\x00\x01\x28\x16\x00\x00\x0a\xa2\x11\x09\x28\x23\x00\
+  \\x00\x0a\x17\x8d\x01\x00\x00\x01\x13\x0a\x11\x0a\x16\x12\x04\x28\x7e\x00\x00\x0a\
+  \\x8c\x0e\x00\x00\x01\xa2\x11\x0a\x73\x79\x00\x00\x0a\x6f\x7f\x00\x00\x0a\x09\x17\
+  \\x58\x0d\x09\x02\x28\x28\x00\x00\x06\x8e\x69\x17\x58\x3f\x68\xff\xff\xff\x06\x6f\
+  \\x1c\x00\x00\x0a\x2a\x2e\x73\x0b\x00\x00\x0a\x80\x0c\x00\x00\x04\x2a\x00\x00\x00\
+  \\x03\x30\x03\x00\x01\x01\x00\x00\x00\x00\x00\x00\xd0\x0b\x00\x00\x01\x28\x16\x00\
+  \\x00\x0a\x72\x49\x02\x00\x70\x28\x17\x00\x00\x0a\x80\x0d\x00\x00\x04\xd0\x01\x00\
+  \\x00\x01\x28\x16\x00\x00\x0a\x7e\x43\x00\x00\x0a\x28\x23\x00\x00\x0a\x80\x0e\x00\
+  \\x00\x04\xd0\x28\x00\x00\x01\x28\x16\x00\x00\x0a\x72\x6d\x02\x00\x70\x28\x17\x00\
+  \\x00\x0a\x80\x0f\x00\x00\x04\xd0\x28\x00\x00\x01\x28\x16\x00\x00\x0a\x72\xa9\x02\
+  \\x00\x70\x28\x17\x00\x00\x0a\x80\x10\x00\x00\x04\xd0\x28\x00\x00\x01\x28\x16\x00\
+  \\x00\x0a\x72\xe5\x02\x00\x70\x28\x17\x00\x00\x0a\x80\x11\x00\x00\x04\xd0\x28\x00\
+  \\x00\x01\x28\x16\x00\x00\x0a\x72\x0b\x03\x00\x70\x28\x17\x00\x00\x0a\x80\x12\x00\
+  \\x00\x04\xd0\x02\x00\x00\x02\x28\x16\x00\x00\x0a\x72\x33\x03\x00\x70\x1f\x18\x6f\
+  \\x81\x00\x00\x0a\x80\x13\x00\x00\x04\xd0\x02\x00\x00\x02\x28\x16\x00\x00\x0a\x72\
+  \\x57\x03\x00\x70\x1f\x18\x28\x82\x00\x00\x0a\x80\x14\x00\x00\x04\xd0\x02\x00\x00\
+  \\x02\x28\x16\x00\x00\x0a\x72\x75\x03\x00\x70\x1f\x18\x28\x82\x00\x00\x0a\x80\x15\
+  \\x00\x00\x04\xd0\x05\x00\x00\x02\x28\x16\x00\x00\x0a\x72\xa9\x01\x00\x70\x28\x17\
+  \\x00\x00\x0a\x80\x16\x00\x00\x04\x2a\x22\x02\x17\x28\x83\x00\x00\x0a\x2a\x1e\x02\
+  \\x28\x38\x00\x00\x06\x2a\x00\x00\x13\x30\x05\x00\x37\x00\x00\x00\x1a\x00\x00\x11\
+  \\x7e\x17\x00\x00\x04\x2d\x11\x14\xfe\x06\x3f\x00\x00\x06\x73\x84\x00\x00\x0a\x80\
+  \\x17\x00\x00\x04\x7e\x17\x00\x00\x04\x02\x17\x8d\x4e\x00\x00\x01\x0a\x06\x16\x1f\
+  \\x3b\x9d\x06\x17\x6f\x85\x00\x00\x0a\x28\x03\x00\x00\x2b\x2a\x00\x13\x30\x04\x00\
+  \\x4b\x00\x00\x00\x1b\x00\x00\x11\x02\x8e\x69\x03\x8e\x69\x58\x8d\x0a\x00\x00\x1b\
+  \\x0a\x16\x0b\x2b\x12\x06\x07\x02\x07\xa3\x0a\x00\x00\x1b\xa4\x0a\x00\x00\x1b\x07\
+  \\x17\x58\x0b\x07\x02\x8e\x69\x32\xe8\x16\x0c\x2b\x16\x06\x02\x8e\x69\x08\x58\x03\
+  \\x08\xa3\x0a\x00\x00\x1b\xa4\x0a\x00\x00\x1b\x08\x17\x58\x0c\x08\x03\x8e\x69\x32\
+  \\xe4\x06\x2a\x00\x13\x30\x04\x00\x33\x00\x00\x00\x1c\x00\x00\x11\x17\x03\x8e\x69\
+  \\x58\x8d\x0a\x00\x00\x1b\x0a\x06\x16\x02\xa4\x0a\x00\x00\x1b\x16\x0b\x2b\x14\x06\
+  \\x17\x07\x58\x03\x07\xa3\x0a\x00\x00\x1b\xa4\x0a\x00\x00\x1b\x07\x17\x58\x0b\x07\
+  \\x03\x8e\x69\x32\xe6\x06\x2a\x00\x13\x30\x05\x00\x2d\x00\x00\x00\x1d\x00\x00\x11\
+  \\x03\x8e\x69\x8d\x0b\x00\x00\x1b\x0a\x16\x0b\x2b\x18\x06\x07\x02\x03\x07\xa3\x0a\
+  \\x00\x00\x1b\x6f\x86\x00\x00\x0a\xa4\x0b\x00\x00\x1b\x07\x17\x58\x0b\x07\x03\x8e\
+  \\x69\x32\xe2\x06\x2a\x1e\x02\x6f\x4a\x00\x00\x0a\x2a\x92\x7e\x18\x00\x00\x04\x2d\
+  \\x11\x14\xfe\x06\x40\x00\x00\x06\x73\x87\x00\x00\x0a\x80\x18\x00\x00\x04\x7e\x18\
+  \\x00\x00\x04\x02\x28\x04\x00\x00\x2b\x2a\x00\x00\x03\x30\x03\x00\x62\x00\x00\x00\
+  \\x00\x00\x00\x00\x03\x2d\x0c\x02\x7e\x4c\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x03\
+  \\x17\x33\x0c\x02\x7e\x68\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x03\x18\x33\x0c\x02\
+  \\x7e\x88\x00\x00\x0a\x6f\x3b\x00\x00\x0a\x2a\x03\x19\x33\x0c\x02\x7e\x89\x00\x00\
+  \\x0a\x6f\x3b\x00\x00\x0a\x2a\x03\x20\xff\x00\x00\x00\x30\x0e\x02\x7e\x8a\x00\x00\
+  \\x0a\x03\xd2\x6f\x37\x00\x00\x0a\x2a\x02\x7e\x8b\x00\x00\x0a\x03\x6f\x52\x00\x00\
+  \\x0a\x2a\x00\x00\x42\x53\x4a\x42\x01\x00\x01\x00\x00\x00\x00\x00\x0c\x00\x00\x00\
+  \\x76\x32\x2e\x30\x2e\x35\x30\x37\x32\x37\x00\x00\x00\x00\x05\x00\x6c\x00\x00\x00\
+  \\x4c\x0f\x00\x00\x23\x7e\x00\x00\xb8\x0f\x00\x00\xf4\x11\x00\x00\x23\x53\x74\x72\
+  \\x69\x6e\x67\x73\x00\x00\x00\x00\xac\x21\x00\x00\x8c\x03\x00\x00\x23\x55\x53\x00\
+  \\x38\x25\x00\x00\x10\x00\x00\x00\x23\x47\x55\x49\x44\x00\x00\x00\x48\x25\x00\x00\
+  \\x04\x06\x00\x00\x23\x42\x6c\x6f\x62\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\
+  \\x57\x15\xa2\x09\x09\x0e\x00\x00\x00\xfa\x01\x33\x00\x16\x00\x00\x01\x00\x00\x00\
+  \\x4f\x00\x00\x00\x0f\x00\x00\x00\x20\x00\x00\x00\x50\x00\x00\x00\x5f\x00\x00\x00\
+  \\x8b\x00\x00\x00\x13\x00\x00\x00\x1d\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\
+  \\x02\x00\x00\x00\x0d\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x09\x00\x00\x00\
+  \\x06\x00\x00\x00\x04\x00\x00\x00\x00\x00\x0a\x00\x01\x00\x00\x00\x00\x00\x06\x00\
+  \\x9c\x00\x95\x00\x06\x00\xa3\x00\x95\x00\x06\x00\xb5\x00\x95\x00\x06\x00\xda\x00\
+  \\xc3\x00\x06\x00\xfb\x00\xc3\x00\x06\x00\x1f\x01\xc3\x00\x06\x00\x06\x02\xeb\x01\
+  \\x06\x00\x62\x02\x95\x00\x06\x00\xd6\x02\xc4\x02\x06\x00\xfe\x02\xc4\x02\x06\x00\
+  \\x1c\x03\x95\x00\x06\x00\x41\x03\xc4\x02\x06\x00\x98\x03\x95\x00\x06\x00\xc2\x03\
+  \\xa3\x03\x06\x00\x03\x04\xc3\x00\x06\x00\x31\x04\xeb\x01\x06\x00\x3f\x04\xc4\x02\
+  \\x06\x00\xc0\x04\x95\x00\x06\x00\xcd\x04\x95\x00\x06\x00\xec\x06\xc4\x02\x06\x00\
+  \\x09\x07\xc4\x02\x06\x00\x22\x07\xc4\x02\x06\x00\x3d\x07\xc4\x02\x06\x00\x56\x07\
+  \\xc4\x02\x06\x00\x73\x07\xc4\x02\x06\x00\xaa\x07\x8a\x07\x06\x00\xca\x07\x8a\x07\
+  \\x0a\x00\xfb\x07\xe8\x07\x0a\x00\x01\x08\xe8\x07\x0a\x00\x27\x08\xe8\x07\x0a\x00\
+  \\x3c\x08\xe8\x07\x0e\x00\x63\x08\x4e\x08\x06\x00\x82\x08\x95\x00\x06\x00\x9e\x08\
+  \\xc4\x02\x06\x00\xab\x08\xc3\x00\x06\x00\xf6\x08\x95\x00\x06\x00\x09\x09\x95\x00\
+  \\x06\x00\x37\x09\x95\x00\x06\x00\x5b\x09\x95\x00\x06\x00\x73\x09\xa3\x03\x06\x00\
+  \\xa4\x09\xc4\x02\x06\x00\xcc\x09\xc2\x09\x06\x00\xdd\x09\x95\x00\x06\x00\xeb\x09\
+  \\x95\x00\x06\x00\x6e\x0a\x5d\x0a\x06\x00\x91\x0a\x95\x00\x06\x00\xde\x0a\xc3\x00\
+  \\x06\x00\xec\x0a\xc4\x02\x06\x00\x19\x0b\xc3\x00\x06\x00\x74\x0b\xc3\x00\x06\x00\
+  \\x8e\x0b\xc3\x00\x06\x00\x96\x0b\xc3\x00\x06\x00\xbb\x0b\xc4\x02\x06\x00\xdf\x0b\
+  \\xc4\x02\x06\x00\x0c\x0c\x95\x00\x06\x00\xbb\x0d\x95\x00\x06\x00\x60\x0e\xeb\x01\
+  \\x06\x00\x9b\x0e\x88\x0e\x06\x00\xb0\x0e\x95\x00\x06\x00\xdd\x0e\xc4\x02\x06\x00\
+  \\xec\x0e\xc3\x00\x06\x00\xf9\x0e\xc4\x02\x06\x00\x15\x0f\xc3\x00\x06\x00\x28\x0f\
+  \\xc4\x02\x06\x00\x67\x0f\xc4\x02\x06\x00\x93\x0f\xc3\x00\x06\x00\xbc\x0f\xa3\x03\
+  \\x06\x00\xde\x0f\xa3\x03\x06\x00\x0e\x10\xa3\x03\x06\x00\x24\x10\xa3\x03\x06\x00\
+  \\x55\x10\x49\x10\x06\x00\x6a\x10\xc3\x00\x06\x00\xa1\x10\xc3\x00\x06\x00\xb2\x10\
+  \\xc4\x02\x06\x00\xd6\x10\xa3\x03\x06\x00\xf3\x10\x8a\x07\x06\x00\x0e\x11\xc4\x02\
+  \\x06\x00\x5d\x11\x95\x00\x06\x00\x62\x11\x95\x00\x00\x00\x00\x00\x01\x00\x00\x00\
+  \\x00\x00\x01\x00\x01\x00\x01\x00\x00\x00\x14\x00\x1b\x00\x05\x00\x01\x00\x01\x00\
+  \\x02\x01\x00\x00\x21\x00\x00\x00\x09\x00\x0a\x00\x23\x00\x0a\x01\x10\x00\x37\x00\
+  \\x00\x00\x0d\x00\x0a\x00\x27\x00\x01\x01\x00\x00\x49\x00\x1b\x00\x09\x00\x0d\x00\
+  \\x2f\x00\x01\x01\x00\x00\x63\x00\x1b\x00\x09\x00\x0d\x00\x33\x00\x80\x01\x10\x00\
+  \\x74\x00\x1b\x00\x05\x00\x0d\x00\x37\x00\x80\x01\x10\x00\x80\x00\x1b\x00\x05\x00\
+  \\x17\x00\x38\x00\x02\x01\x00\x00\x85\x00\x00\x00\x09\x00\x19\x00\x41\x00\x03\x01\
+  \\x10\x00\x36\x0b\x00\x00\x05\x00\x19\x00\x45\x00\x03\x01\x10\x00\x36\x0c\x00\x00\
+  \\x05\x00\x1b\x00\x47\x00\x03\x01\x10\x00\xa8\x0c\x00\x00\x05\x00\x1c\x00\x49\x00\
+  \\x03\x01\x10\x00\x08\x0d\x00\x00\x05\x00\x1e\x00\x4b\x00\x03\x01\x10\x00\x80\x0d\
+  \\x00\x00\x05\x00\x1f\x00\x4d\x00\x03\x01\x10\x00\xc0\x0d\x00\x00\x05\x00\x20\x00\
+  \\x4f\x00\x13\x00\xea\x00\x0a\x00\x13\x00\x09\x01\x0e\x00\x13\x00\x2b\x01\x12\x00\
+  \\x16\x00\x71\x01\x28\x00\x11\x00\x13\x02\x39\x00\x11\x00\x1c\x02\x41\x00\x11\x00\
+  \\x3d\x02\x4e\x00\x11\x00\x6b\x02\x57\x00\x11\x00\x6c\x04\xce\x00\x01\x00\xf1\x04\
+  \\xfd\x00\x01\x00\xfd\x04\x01\x01\x11\x00\x49\x05\xce\x00\x36\x00\x94\x05\x54\x01\
+  \\x36\x00\xab\x05\x58\x01\x36\x00\xb7\x05\x54\x01\x36\x00\xdd\x05\x54\x01\x36\x00\
+  \\x03\x06\x54\x01\x36\x00\x1e\x06\x54\x01\x36\x00\x3a\x06\x5c\x01\x36\x00\x53\x06\
+  \\x54\x01\x36\x00\x69\x06\x54\x01\x36\x00\x7a\x06\x54\x01\x11\x00\x39\x11\x0d\x05\
+  \\x11\x00\xa1\x11\x5f\x05\x06\x00\x49\x0b\xfd\x00\x06\x00\x4e\x0b\x58\x01\x06\x00\
+  \\x49\x0c\x54\x01\x06\x00\xbb\x0c\xfd\x00\x06\x00\xc7\x0c\xfd\x00\x06\x00\x1b\x0d\
+  \\x5c\x01\x06\x00\x1b\x0d\x5c\x01\x06\x00\xd4\x0d\xfd\x00\x50\x20\x00\x00\x00\x00\
+  \\x91\x18\x3d\x01\x16\x00\x01\x00\x28\x21\x00\x00\x00\x00\x96\x00\x44\x01\x1a\x00\
+  \\x01\x00\x34\x21\x00\x00\x00\x00\x96\x00\x49\x01\x1e\x00\x01\x00\x6b\x21\x00\x00\
+  \\x00\x00\x96\x00\x5c\x01\x23\x00\x02\x00\x9c\x21\x00\x00\x00\x00\x96\x00\x83\x01\
+  \\x16\x00\x03\x00\xe0\x21\x00\x00\x00\x00\x96\x00\x97\x01\x2c\x00\x03\x00\x2c\x22\
+  \\x00\x00\x00\x00\x96\x00\xa5\x01\x1e\x00\x06\x00\x48\x22\x00\x00\x00\x00\x96\x00\
+  \\xc0\x01\x33\x00\x07\x00\x68\x22\x00\x00\x00\x00\x96\x00\xd0\x01\x33\x00\x09\x00\
+  \\x88\x22\x00\x00\x00\x00\x96\x00\xe0\x01\x1e\x00\x0b\x00\xa4\x22\x00\x00\x00\x00\
+  \\x96\x00\x24\x02\x44\x00\x0c\x00\x10\x23\x00\x00\x00\x00\x96\x00\x33\x02\x49\x00\
+  \\x0d\x00\x88\x23\x00\x00\x00\x00\x96\x00\x54\x02\x52\x00\x0e\x00\xc8\x23\x00\x00\
+  \\x00\x00\x91\x00\x82\x02\x60\x00\x0f\x00\x10\x24\x00\x00\x00\x00\x96\x00\x9d\x02\
+  \\x23\x00\x10\x00\x50\x24\x00\x00\x00\x00\x91\x00\xae\x02\x66\x00\x11\x00\x54\x25\
+  \\x00\x00\x00\x00\x96\x00\xe6\x02\x6f\x00\x14\x00\x8c\x26\x00\x00\x00\x00\x96\x00\
+  \\x09\x03\x75\x00\x15\x00\x08\x28\x00\x00\x00\x00\x96\x00\x21\x03\x7b\x00\x16\x00\
+  \\x34\x29\x00\x00\x00\x00\x96\x00\x4b\x03\x81\x00\x17\x00\x54\x2a\x00\x00\x00\x00\
+  \\x96\x00\x60\x03\x81\x00\x18\x00\x6c\x2b\x00\x00\x00\x00\x96\x00\x75\x03\x7b\x00\
+  \\x19\x00\xd4\x2b\x00\x00\x00\x00\x91\x00\x85\x03\x87\x00\x1a\x00\x00\x2c\x00\x00\
+  \\x00\x00\x91\x00\xd0\x03\x8d\x00\x1b\x00\x2b\x2c\x00\x00\x00\x00\x91\x00\xde\x03\
+  \\x98\x00\x1c\x00\x3f\x2c\x00\x00\x00\x00\x91\x00\xf1\x03\xa1\x00\x1d\x00\x55\x2c\
+  \\x00\x00\x00\x00\x91\x00\x0f\x04\xa8\x00\x1e\x00\x65\x2c\x00\x00\x00\x00\x91\x00\
+  \\x24\x04\xb1\x00\x21\x00\x8c\x2c\x00\x00\x00\x00\x91\x00\x0f\x04\xb9\x00\x23\x00\
+  \\xe8\x2c\x00\x00\x00\x00\x91\x00\x4d\x04\xb1\x00\x26\x00\x18\x2d\x00\x00\x00\x00\
+  \\x91\x00\x58\x04\xc6\x00\x28\x00\x40\x2d\x00\x00\x00\x00\x91\x00\x82\x04\xa1\x00\
+  \\x2a\x00\xac\x2d\x00\x00\x00\x00\x91\x00\x99\x04\xd7\x00\x2b\x00\x20\x30\x00\x00\
+  \\x00\x00\x86\x18\xb3\x04\xdf\x00\x2d\x00\x00\x00\x00\x00\x03\x00\x86\x18\xb3\x04\
+  \\xe3\x00\x2d\x00\x00\x00\x00\x00\x03\x00\xc6\x01\xb9\x04\xe9\x00\x2f\x00\x00\x00\
+  \\x00\x00\x03\x00\xc6\x01\xdb\x04\xee\x00\x30\x00\x00\x00\x00\x00\x03\x00\xc6\x01\
+  \\xe7\x04\xf7\x00\x33\x00\x28\x30\x00\x00\x00\x00\x86\x08\x0d\x05\x06\x01\x34\x00\
+  \\x30\x30\x00\x00\x00\x00\x86\x08\x1c\x05\x0b\x01\x34\x00\x38\x30\x00\x00\x00\x00\
+  \\x86\x18\xb3\x04\x11\x01\x34\x00\x48\x30\x00\x00\x00\x00\xc6\x00\x2f\x05\x1a\x01\
+  \\x36\x00\xa8\x30\x00\x00\x00\x00\x96\x00\x38\x05\x1e\x01\x36\x00\xd8\x30\x00\x00\
+  \\x00\x00\x86\x00\x58\x05\x06\x01\x37\x00\x48\x31\x00\x00\x00\x00\x81\x00\x67\x05\
+  \\x25\x01\x37\x00\xb9\x32\x00\x00\x00\x00\x91\x18\x3d\x01\x16\x00\x38\x00\x00\x00\
+  \\x00\x00\x03\x00\x86\x18\xb3\x04\xe3\x00\x38\x00\x00\x00\x00\x00\x03\x00\xc6\x01\
+  \\xb9\x04\x36\x01\x3a\x00\x00\x00\x00\x00\x03\x00\xc6\x01\xdb\x04\x3b\x01\x3b\x00\
+  \\x00\x00\x00\x00\x03\x00\xc6\x01\xe7\x04\xf7\x00\x3e\x00\x00\x00\x00\x00\x03\x00\
+  \\x86\x18\xb3\x04\xe3\x00\x3f\x00\x00\x00\x00\x00\x03\x00\xc6\x01\xb9\x04\x44\x01\
+  \\x41\x00\x00\x00\x00\x00\x03\x00\xc6\x01\xdb\x04\x4a\x01\x42\x00\x00\x00\x00\x00\
+  \\x03\x00\xc6\x01\xe7\x04\xf7\x00\x45\x00\xc8\x32\x00\x00\x00\x00\x91\x18\x3d\x01\
+  \\x16\x00\x46\x00\xd5\x33\x00\x00\x00\x00\x96\x00\x9b\x06\x60\x01\x46\x00\xe8\x33\
+  \\x00\x00\x00\x00\x96\x00\xa8\x06\x66\x01\x47\x00\x2c\x34\x00\x00\x00\x00\x96\x00\
+  \\xb6\x06\x6d\x01\x48\x00\x84\x34\x00\x00\x00\x00\x96\x00\xb6\x06\x7a\x01\x4a\x00\
+  \\xc4\x34\x00\x00\x00\x00\x96\x00\xc4\x06\x86\x01\x4c\x00\x05\x35\x00\x00\x00\x00\
+  \\x96\x00\xcd\x06\x98\x01\x4e\x00\x2c\x35\x00\x00\x00\x00\x96\x00\xe2\x06\xa1\x01\
+  \\x4f\x00\xde\x33\x00\x00\x00\x00\x91\x00\x25\x11\x60\x01\x51\x00\xfd\x34\x00\x00\
+  \\x00\x00\x91\x00\x86\x11\x58\x05\x52\x00\x00\x00\x00\x00\x03\x00\x86\x18\xb3\x04\
+  \\xe3\x00\x53\x00\x00\x00\x00\x00\x03\x00\xc6\x01\xb9\x04\xa8\x01\x55\x00\x00\x00\
+  \\x00\x00\x03\x00\xc6\x01\xdb\x04\xaf\x01\x56\x00\x00\x00\x00\x00\x03\x00\xc6\x01\
+  \\xe7\x04\xb9\x01\x59\x00\xc1\x24\x00\x00\x00\x00\x86\x18\xb3\x04\xdf\x00\x5a\x00\
+  \\xcc\x24\x00\x00\x00\x00\x86\x00\x52\x0b\x44\x01\x5a\x00\xfb\x25\x00\x00\x00\x00\
+  \\x86\x18\xb3\x04\xdf\x00\x5b\x00\x04\x26\x00\x00\x00\x00\x86\x00\x4e\x0c\x44\x01\
+  \\x5b\x00\x49\x27\x00\x00\x00\x00\x86\x18\xb3\x04\xdf\x00\x5c\x00\x54\x27\x00\x00\
+  \\x00\x00\x86\x00\xd4\x0c\x44\x01\x5c\x00\x8c\x28\x00\x00\x00\x00\x86\x18\xb3\x04\
+  \\xdf\x00\x5d\x00\x94\x28\x00\x00\x00\x00\x86\x00\x21\x0d\x44\x01\x5d\x00\xcb\x29\
+  \\x00\x00\x00\x00\x86\x18\xb3\x04\xdf\x00\x5e\x00\xd4\x29\x00\x00\x00\x00\x86\x00\
+  \\x93\x0d\x44\x01\x5e\x00\x0e\x2b\x00\x00\x00\x00\x86\x18\xb3\x04\xdf\x00\x5f\x00\
+  \\x18\x2b\x00\x00\x00\x00\x86\x00\xde\x0d\x44\x01\x5f\x00\x00\x00\x01\x00\xfe\x08\
+  \\x00\x00\x01\x00\x49\x09\x00\x00\x01\x00\x02\x0a\x00\x00\x02\x00\xfe\x08\x00\x00\
+  \\x03\x00\x0c\x0a\x00\x00\x01\x00\x2e\x0a\x00\x00\x01\x00\x02\x0a\x00\x00\x02\x00\
+  \\x3f\x0a\x00\x00\x01\x00\x02\x0a\x00\x00\x02\x00\x3f\x0a\x00\x00\x01\x00\x52\x0a\
+  \\x00\x00\x01\x00\x5b\x0a\x00\x00\x01\x00\x81\x0a\x00\x00\x01\x00\x81\x0a\x00\x00\
+  \\x01\x00\x9e\x0a\x00\x00\x01\x00\xbe\x0a\x00\x00\x01\x00\xfe\x08\x00\x00\x02\x00\
+  \\xc5\x0a\x00\x00\x03\x00\xd5\x0a\x00\x00\x01\x00\x4e\x0b\x00\x00\x01\x00\x49\x0c\
+  \\x00\x00\x01\x00\xc7\x0c\x00\x00\x01\x00\x1b\x0d\x00\x00\x01\x00\x1b\x0d\x00\x00\
+  \\x01\x00\xd4\x0d\x00\x00\x01\x00\xf8\x0d\x00\x00\x01\x00\xf8\x0d\x00\x00\x01\x00\
+  \\x0a\x0e\x00\x00\x01\x00\x49\x0b\x00\x00\x01\x00\x70\x0b\x00\x00\x02\x00\x10\x0e\
+  \\x00\x00\x03\x00\x1e\x0e\x00\x00\x01\x00\x70\x0b\x00\x00\x02\x00\x2c\x0e\x00\x00\
+  \\x01\x00\x70\x0b\x00\x00\x02\x00\x40\x0e\x00\x00\x03\x00\x51\x0e\x00\x00\x01\x00\
+  \\x70\x0b\x00\x00\x02\x00\x49\x0b\x00\x00\x01\x00\x70\x0b\x00\x00\x02\x00\xc4\x0e\
+  \\x00\x00\x01\x00\xc7\x0c\x00\x00\x01\x00\xd8\x0e\x00\x00\x02\x00\xc7\x0c\x00\x00\
+  \\x01\x00\xf0\x0f\x00\x00\x02\x00\xf7\x0f\x00\x00\x01\x00\x81\x0a\x00\x00\x01\x00\
+  \\x81\x0a\x00\x00\x02\x00\xfe\x0f\x00\x00\x03\x00\xf0\x0f\x00\x00\x01\x00\x07\x10\
+  \\x00\x00\x01\x00\x2f\x10\x00\x00\x02\x00\x3a\x10\x00\x00\x01\x00\xc7\x0c\x00\x00\
+  \\x01\x00\xd8\x0e\x00\x00\x01\x00\xf0\x0f\x00\x00\x02\x00\xf7\x0f\x00\x00\x01\x00\
+  \\xbe\x0a\x00\x00\x01\x00\xbe\x0a\x00\x00\x02\x00\xfe\x0f\x00\x00\x03\x00\xf0\x0f\
+  \\x00\x00\x01\x00\x07\x10\x00\x00\x01\x00\xf0\x0f\x00\x00\x02\x00\xf7\x0f\x00\x00\
+  \\x01\x00\x70\x0b\x00\x00\x01\x00\x70\x0b\x00\x00\x02\x00\xfe\x0f\x00\x00\x03\x00\
+  \\xf0\x0f\x00\x00\x01\x00\x07\x10\x00\x00\x01\x00\x1b\x11\x00\x00\x01\x00\x1b\x11\
+  \\x00\x00\x01\x00\x7b\x11\x00\x00\x02\x00\x7d\x11\x00\x00\x01\x00\x7f\x11\x00\x00\
+  \\x02\x00\x7d\x11\x00\x00\x01\x00\x81\x11\x00\x00\x02\x00\x83\x11\x00\x00\x01\x00\
+  \\xc7\x11\x00\x00\x01\x00\x70\x0b\x00\x00\x02\x00\x10\x0e\x00\x00\x01\x00\xf8\x0d\
+  \\x00\x00\x01\x00\xc5\x11\x00\x00\x01\x00\xf0\x0f\x00\x00\x02\x00\xf7\x0f\x00\x00\
+  \\x01\x00\xf0\x11\x00\x00\x01\x00\xf0\x11\x00\x00\x02\x00\xfe\x0f\x00\x00\x03\x00\
+  \\xf0\x0f\x00\x00\x01\x00\x07\x10\x00\x00\x01\x00\x70\x0b\x00\x00\x01\x00\x70\x0b\
+  \\x00\x00\x01\x00\x70\x0b\x00\x00\x01\x00\x70\x0b\x00\x00\x01\x00\x70\x0b\x00\x00\
+  \\x01\x00\x70\x0b\xa1\x00\xb3\x04\xc0\x01\xa9\x00\xb3\x04\xc0\x01\xb1\x00\xb3\x04\
+  \\xc0\x01\xb9\x00\xb3\x04\xc0\x01\xc1\x00\xb3\x04\xc0\x01\xc9\x00\xb3\x04\xc0\x01\
+  \\xd1\x00\xb3\x04\xe9\x00\xd9\x00\xb3\x04\xdf\x00\x0c\x00\xb3\x04\xdf\x00\x14\x00\
+  \\xb3\x04\xdf\x00\x1c\x00\xb3\x04\xdf\x00\xe1\x00\x19\x08\xdc\x01\xf1\x00\xb3\x04\
+  \\xdf\x00\xe9\x00\x4a\x08\xe1\x01\x01\x01\x6f\x08\x16\x00\x09\x01\x8c\x08\xe7\x01\
+  \\x11\x01\xb3\x04\xc0\x01\x09\x01\xc1\x08\xed\x01\x21\x00\xd7\x08\xf8\x01\x29\x00\
+  \\xeb\x08\xff\x01\x0c\x00\x4a\x08\x05\x02\x59\x00\x1b\x09\x0d\x02\x59\x00\x2d\x09\
+  \\x15\x02\x31\x01\xb3\x04\x1b\x02\x39\x01\x62\x09\x26\x02\x39\x01\x67\x09\x29\x02\
+  \\x41\x01\x7b\x09\x2f\x02\x31\x00\x99\x09\x06\x01\x49\x01\xab\x09\x1a\x01\x51\x01\
+  \\xd1\x09\x37\x02\x59\x01\xe4\x09\x3c\x02\x61\x01\xf3\x09\x42\x02\x21\x00\xfd\x09\
+  \\xc0\x01\x59\x01\x67\x09\x4b\x02\x59\x00\x1f\x0a\x51\x02\x59\x00\x2d\x09\x59\x02\
+  \\x59\x00\x49\x0a\x6e\x02\x69\x01\x76\x0a\x7f\x02\x69\x01\x7c\x0a\x7f\x02\x0c\x00\
+  \\x85\x0a\x8f\x02\x59\x01\xe4\x09\x98\x02\x31\x01\xb3\x04\xc0\x01\x0c\x00\x97\x0a\
+  \\xa9\x02\x41\x01\xa0\x0a\x60\x00\x14\x00\x4a\x08\x05\x02\x14\x00\x97\x0a\xa9\x02\
+  \\x31\x00\xfd\x0a\xcd\x02\x79\x01\x0a\x0b\xdc\x02\x89\x01\xb3\x04\xe1\x02\x89\x01\
+  \\x0a\x0b\xdc\x02\x89\x01\x27\x0b\xed\x02\x09\x00\xb3\x04\xdf\x00\x79\x00\x81\x0b\
+  \\xfd\x02\x99\x01\x9d\x0b\x05\x03\x79\x00\xa6\x0b\x0a\x03\x99\x01\xab\x0b\x05\x03\
+  \\x79\x00\xa6\x0b\x12\x03\x99\x01\xb3\x0b\x05\x03\x79\x00\xa6\x0b\x1b\x03\xa9\x01\
+  \\xc6\x0b\x22\x03\x99\x01\xd4\x0b\x05\x03\x79\x00\xa6\x0b\x28\x03\x99\x01\xdb\x0b\
+  \\x05\x03\xb1\x01\xea\x0b\x06\x01\x59\x00\xfc\x0b\x31\x03\xb9\x01\xb3\x04\xc0\x01\
+  \\x59\x00\x22\x0c\x01\x01\xb1\x01\x2d\x0c\x1a\x01\xa9\x01\x67\x0c\x31\x03\x99\x01\
+  \\x74\x0c\x05\x03\x79\x00\xa6\x0b\x3c\x03\x99\x01\x79\x0c\x05\x03\x51\x00\x82\x0c\
+  \\x45\x03\x89\x00\x96\x0c\x06\x01\x59\x01\xe4\x09\x4f\x03\x99\x01\xfa\x0c\x05\x03\
+  \\x99\x01\x02\x0d\x05\x03\x61\x00\x67\x0c\x31\x03\x61\x00\x3c\x0d\x31\x03\x61\x00\
+  \\x4a\x0d\x72\x03\x99\x01\x5e\x0d\x05\x03\x79\x00\xa6\x0b\x76\x03\x99\x01\x65\x0d\
+  \\x05\x03\x79\x00\xa6\x0b\x7e\x03\x99\x01\x6c\x0d\x05\x03\x61\x00\x72\x0d\x06\x01\
+  \\x99\x01\xae\x0d\x05\x03\x99\x01\xb5\x0d\x05\x03\x99\x01\xf4\x0d\x05\x03\x59\x00\
+  \\xfa\x0d\x31\x03\x2c\x00\xb3\x04\xb3\x03\x34\x00\xb3\x04\xe3\x00\x99\x01\x36\x0e\
+  \\x05\x03\x3c\x00\x6e\x0e\xd9\x03\x44\x00\x7c\x0e\xeb\x03\xd1\x01\xa7\x0e\x31\x03\
+  \\xd9\x01\xbc\x0e\xdf\x00\x1c\x00\x85\x0a\x8f\x02\x1c\x00\x4a\x08\x05\x02\x29\x00\
+  \\xeb\x08\x0e\x04\x31\x00\x09\x0f\x17\x04\x31\x00\x3b\x0f\x23\x04\xf9\x01\x0a\x0b\
+  \\xdc\x02\x99\x01\x4d\x0f\x05\x03\x99\x01\x55\x0f\x05\x03\x99\x01\x5d\x0f\x05\x03\
+  \\x31\x00\xfd\x0a\x32\x04\x79\x01\x7c\x0f\x3c\x04\x79\x00\x99\x0f\x43\x04\x99\x01\
+  \\xa5\x0f\x05\x03\x99\x01\xae\x0f\x05\x03\x79\x00\xa6\x0b\x49\x04\x79\x00\xb2\x0f\
+  \\x53\x04\x19\x02\xb3\x04\x7e\x04\x29\x02\xb3\x04\x8e\x04\x39\x02\xb3\x04\xdf\x00\
+  \\x39\x02\x63\x10\x95\x04\x09\x00\x2f\x05\x1a\x01\x51\x00\x0d\x05\x06\x01\x29\x00\
+  \\xeb\x08\xa8\x04\x41\x02\xb3\x04\xb3\x04\x31\x00\x81\x10\xbb\x04\xf9\x01\x7c\x0f\
+  \\x3c\x04\x2c\x00\x94\x10\x31\x03\x79\x01\xc6\x10\xc2\x04\x2c\x00\xe9\x10\xeb\x03\
+  \\x49\x02\x81\x10\xbb\x04\x61\x02\xb3\x04\xdf\x00\x59\x00\x49\x0a\xf4\x04\x59\x00\
+  \\x2d\x09\xfd\x04\x59\x00\x1d\x11\x06\x05\x4c\x00\xb3\x04\xe3\x00\x59\x01\x75\x11\
+  \\x1e\x05\x64\x00\xb9\x04\xa8\x01\x6c\x00\xb3\x04\xe3\x00\x99\x01\xd2\x11\x05\x03\
+  \\x99\x01\xda\x11\x05\x03\x99\x01\xe2\x11\x05\x03\x99\x01\xea\x11\x05\x03\x2e\x00\
+  \\x2b\x00\xbe\x05\x2e\x00\x3b\x00\xdb\x05\x2e\x00\x43\x00\xe4\x05\x2e\x00\x33\x00\
+  \\xb3\x05\x2e\x00\x0b\x00\x79\x05\x2e\x00\x1b\x00\x86\x05\x2e\x00\x23\x00\xb3\x05\
+  \\x63\x00\x93\x03\x85\x04\xa3\x00\x93\x03\x85\x04\x43\x01\x03\x04\xef\x04\x63\x01\
+  \\x03\x04\xef\x04\x83\x01\x03\x04\xef\x04\xa3\x01\x03\x04\xef\x04\xc3\x01\x03\x04\
+  \\xef\x04\xe3\x01\x03\x04\xef\x04\xe1\x02\x03\x04\xef\x04\x01\x03\x03\x04\xef\x04\
+  \\xe0\x07\x03\x04\xef\x04\x00\x08\x03\x04\xef\x04\x21\x02\x47\x02\x62\x02\x69\x02\
+  \\x74\x02\x84\x02\x9e\x02\xaf\x02\xb8\x02\xc3\x02\xf4\x02\x35\x03\x56\x03\x5f\x03\
+  \\x68\x03\x87\x03\x8b\x03\x95\x03\xa2\x03\xb9\x03\xf0\x03\xff\x03\x5a\x04\x9c\x04\
+  \\xcd\x04\x2e\x05\x36\x05\x3e\x05\x51\x05\x04\x00\x01\x00\x00\x00\x7a\x05\x2b\x01\
+  \\x00\x00\x85\x05\x30\x01\x02\x00\x27\x00\x03\x00\x02\x00\x28\x00\x05\x00\xc5\x01\
+  \\xcc\x01\xd4\x01\x79\x02\xac\x03\xc2\x03\xd2\x03\xe3\x03\x16\x05\x33\x05\x45\x05\
+  \\x48\x05\x69\x05\x04\x80\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x1b\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\
+  \\x8c\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\
+  \\x95\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\
+  \\x4e\x08\x00\x00\x00\x00\x03\x00\x02\x00\x04\x00\x02\x00\x09\x00\x08\x00\x0a\x00\
+  \\x02\x00\x0b\x00\x02\x00\x0c\x00\x02\x00\x0d\x00\x02\x00\x0e\x00\x02\x00\x0f\x00\
+  \\x02\x00\x00\x00\x00\x00\x12\x00\xbf\x00\x01\x00\x00\x00\x12\x00\xc1\x00\x00\x00\
+  \\x00\x00\x75\x00\xc2\x06\x00\x00\x00\x00\x77\x00\xc2\x06\x00\x00\x00\x00\x79\x00\
+  \\xbf\x00\x01\x00\x00\x00\x79\x00\xc1\x00\x76\x00\x4a\x03\x78\x00\xcb\x03\x78\x00\
+  \\x28\x05\x78\x00\x72\x05\x00\x00\x00\x3c\x4d\x6f\x64\x75\x6c\x65\x3e\x00\x53\x61\
+  \\x6c\x73\x61\x2e\x64\x6c\x6c\x00\x44\x72\x69\x76\x65\x72\x00\x53\x61\x6c\x73\x61\
+  \\x00\x52\x65\x6c\x65\x61\x73\x65\x4f\x62\x6a\x65\x63\x74\x44\x65\x6c\x65\x67\x61\
+  \\x74\x65\x00\x44\x65\x6c\x65\x67\x61\x74\x65\x53\x69\x67\x6e\x61\x74\x75\x72\x65\
+  \\x00\x46\x72\x65\x65\x48\x61\x73\x6b\x65\x6c\x6c\x46\x75\x6e\x50\x74\x72\x44\x65\
+  \\x6c\x65\x67\x61\x74\x65\x00\x49\x4c\x57\x72\x69\x74\x65\x72\x44\x65\x6c\x65\x67\
+  \\x61\x74\x65\x00\x4d\x65\x6d\x62\x65\x72\x49\x6e\x66\x6f\x73\x00\x55\x74\x69\x6c\
+  \\x00\x46\x75\x6e\x63\x60\x32\x00\x6d\x73\x63\x6f\x72\x6c\x69\x62\x00\x53\x79\x73\
+  \\x74\x65\x6d\x00\x4f\x62\x6a\x65\x63\x74\x00\x4d\x75\x6c\x74\x69\x63\x61\x73\x74\
+  \\x44\x65\x6c\x65\x67\x61\x74\x65\x00\x56\x61\x6c\x75\x65\x54\x79\x70\x65\x00\x41\
+  \\x00\x42\x00\x53\x79\x73\x74\x65\x6d\x2e\x52\x65\x66\x6c\x65\x63\x74\x69\x6f\x6e\
+  \\x2e\x45\x6d\x69\x74\x00\x41\x73\x73\x65\x6d\x62\x6c\x79\x42\x75\x69\x6c\x64\x65\
+  \\x72\x00\x5f\x61\x73\x73\x65\x6d\x62\x6c\x79\x42\x75\x69\x6c\x64\x65\x72\x00\x4d\
+  \\x6f\x64\x75\x6c\x65\x42\x75\x69\x6c\x64\x65\x72\x00\x5f\x64\x79\x6e\x61\x6d\x69\
+  \\x63\x4d\x6f\x64\x75\x6c\x65\x42\x75\x69\x6c\x64\x65\x72\x00\x54\x79\x70\x65\x42\
+  \\x75\x69\x6c\x64\x65\x72\x00\x5f\x73\x74\x75\x62\x73\x54\x79\x70\x65\x42\x75\x69\
+  \\x6c\x64\x65\x72\x00\x2e\x63\x63\x74\x6f\x72\x00\x42\x6f\x6f\x74\x00\x47\x65\x74\
+  \\x50\x6f\x69\x6e\x74\x65\x72\x54\x6f\x4d\x65\x74\x68\x6f\x64\x00\x53\x65\x74\x46\
+  \\x72\x65\x65\x48\x61\x73\x6b\x65\x6c\x6c\x46\x75\x6e\x50\x74\x72\x00\x46\x72\x65\
+  \\x65\x48\x61\x73\x6b\x65\x6c\x6c\x46\x75\x6e\x50\x74\x72\x00\x53\x61\x76\x65\x44\
+  \\x79\x6e\x61\x6d\x69\x63\x41\x73\x73\x65\x6d\x62\x6c\x79\x00\x47\x65\x74\x4d\x65\
+  \\x74\x68\x6f\x64\x53\x74\x75\x62\x00\x47\x65\x74\x44\x65\x6c\x65\x67\x61\x74\x65\
+  \\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x53\x74\x75\x62\x00\x47\x65\x74\x46\
+  \\x69\x65\x6c\x64\x47\x65\x74\x53\x74\x75\x62\x00\x47\x65\x74\x46\x69\x65\x6c\x64\
+  \\x53\x65\x74\x53\x74\x75\x62\x00\x47\x65\x74\x42\x6f\x78\x53\x74\x75\x62\x00\x53\
+  \\x79\x73\x74\x65\x6d\x2e\x43\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x47\x65\
+  \\x6e\x65\x72\x69\x63\x00\x44\x69\x63\x74\x69\x6f\x6e\x61\x72\x79\x60\x32\x00\x5f\
+  \\x69\x6e\x54\x61\x62\x6c\x65\x00\x5f\x6e\x65\x78\x74\x49\x64\x00\x52\x65\x67\x69\
+  \\x73\x74\x65\x72\x4f\x62\x6a\x65\x63\x74\x00\x47\x65\x74\x4f\x62\x6a\x65\x63\x74\
+  \\x00\x5f\x52\x65\x6c\x65\x61\x73\x65\x4f\x62\x6a\x65\x63\x74\x44\x65\x6c\x65\x67\
+  \\x61\x74\x65\x00\x52\x65\x6c\x65\x61\x73\x65\x4f\x62\x6a\x65\x63\x74\x00\x44\x65\
+  \\x6c\x65\x67\x61\x74\x65\x00\x5f\x64\x6f\x74\x4e\x65\x74\x46\x75\x6e\x50\x74\x72\
+  \\x44\x65\x6c\x65\x67\x61\x74\x65\x73\x00\x47\x65\x74\x44\x6f\x74\x4e\x65\x74\x46\
+  \\x75\x6e\x50\x74\x72\x46\x6f\x72\x44\x65\x6c\x65\x67\x61\x74\x65\x00\x46\x72\x65\
+  \\x65\x44\x6f\x74\x4e\x65\x74\x46\x75\x6e\x50\x74\x72\x00\x47\x65\x6e\x65\x72\x61\
+  \\x74\x65\x44\x79\x6e\x61\x6d\x69\x63\x4d\x65\x74\x68\x6f\x64\x00\x53\x79\x73\x74\
+  \\x65\x6d\x2e\x52\x65\x66\x6c\x65\x63\x74\x69\x6f\x6e\x00\x43\x6f\x6e\x73\x74\x72\
+  \\x75\x63\x74\x6f\x72\x49\x6e\x66\x6f\x00\x47\x65\x6e\x65\x72\x61\x74\x65\x43\x6f\
+  \\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x53\x74\x75\x62\x00\x4d\x65\x74\x68\x6f\x64\
+  \\x49\x6e\x66\x6f\x00\x47\x65\x6e\x65\x72\x61\x74\x65\x4d\x65\x74\x68\x6f\x64\x53\
+  \\x74\x75\x62\x00\x54\x79\x70\x65\x00\x47\x65\x6e\x65\x72\x61\x74\x65\x44\x65\x6c\
+  \\x65\x67\x61\x74\x65\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x53\x74\x75\x62\
+  \\x00\x46\x69\x65\x6c\x64\x49\x6e\x66\x6f\x00\x47\x65\x6e\x65\x72\x61\x74\x65\x46\
+  \\x69\x65\x6c\x64\x47\x65\x74\x53\x74\x75\x62\x00\x47\x65\x6e\x65\x72\x61\x74\x65\
+  \\x46\x69\x65\x6c\x64\x53\x65\x74\x53\x74\x75\x62\x00\x47\x65\x6e\x65\x72\x61\x74\
+  \\x65\x42\x6f\x78\x53\x74\x75\x62\x00\x49\x73\x4d\x61\x72\x73\x68\x61\x6c\x65\x64\
+  \\x42\x79\x49\x6e\x64\x65\x78\x00\x4e\x75\x6c\x6c\x61\x62\x6c\x65\x60\x31\x00\x53\
+  \\x79\x73\x74\x65\x6d\x2e\x52\x75\x6e\x74\x69\x6d\x65\x2e\x49\x6e\x74\x65\x72\x6f\
+  \\x70\x53\x65\x72\x76\x69\x63\x65\x73\x00\x55\x6e\x6d\x61\x6e\x61\x67\x65\x64\x54\
+  \\x79\x70\x65\x00\x4d\x61\x72\x73\x68\x61\x6c\x54\x79\x70\x65\x41\x73\x00\x43\x6f\
+  \\x6e\x76\x65\x72\x74\x54\x6f\x53\x74\x75\x62\x54\x79\x70\x65\x73\x00\x43\x6f\x6e\
+  \\x76\x65\x72\x74\x54\x6f\x53\x74\x75\x62\x54\x79\x70\x65\x00\x49\x4c\x47\x65\x6e\
+  \\x65\x72\x61\x74\x6f\x72\x00\x45\x6d\x69\x74\x50\x61\x72\x61\x6d\x65\x74\x65\x72\
+  \\x4c\x6f\x61\x64\x69\x6e\x67\x00\x45\x6d\x69\x74\x46\x72\x6f\x6d\x53\x74\x75\x62\
+  \\x00\x49\x45\x6e\x75\x6d\x65\x72\x61\x62\x6c\x65\x60\x31\x00\x50\x61\x72\x61\x6d\
+  \\x65\x74\x65\x72\x49\x6e\x66\x6f\x00\x45\x6d\x69\x74\x54\x6f\x53\x74\x75\x62\x00\
+  \\x45\x6d\x69\x74\x4d\x61\x72\x73\x68\x61\x6c\x65\x64\x52\x65\x74\x75\x72\x6e\x00\
+  \\x5f\x64\x65\x6c\x65\x67\x61\x74\x65\x57\x72\x61\x70\x70\x65\x72\x54\x79\x70\x65\
+  \\x73\x00\x47\x65\x74\x44\x65\x6c\x65\x67\x61\x74\x65\x57\x72\x61\x70\x70\x65\x72\
+  \\x54\x79\x70\x65\x00\x43\x72\x65\x61\x74\x65\x44\x65\x6c\x65\x67\x61\x74\x65\x57\
+  \\x72\x61\x70\x70\x65\x72\x54\x79\x70\x65\x00\x2e\x63\x74\x6f\x72\x00\x49\x6e\x76\
+  \\x6f\x6b\x65\x00\x49\x41\x73\x79\x6e\x63\x52\x65\x73\x75\x6c\x74\x00\x41\x73\x79\
+  \\x6e\x63\x43\x61\x6c\x6c\x62\x61\x63\x6b\x00\x42\x65\x67\x69\x6e\x49\x6e\x76\x6f\
+  \\x6b\x65\x00\x45\x6e\x64\x49\x6e\x76\x6f\x6b\x65\x00\x5f\x72\x65\x74\x75\x72\x6e\
+  \\x54\x79\x70\x65\x00\x5f\x70\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x73\
+  \\x00\x67\x65\x74\x5f\x52\x65\x74\x75\x72\x6e\x54\x79\x70\x65\x00\x67\x65\x74\x5f\
+  \\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x73\x00\x54\x6f\x53\x74\x72\
+  \\x69\x6e\x67\x00\x46\x72\x6f\x6d\x44\x65\x6c\x65\x67\x61\x74\x65\x54\x79\x70\x65\
+  \\x00\x5f\x64\x65\x6c\x65\x67\x61\x74\x65\x54\x79\x70\x65\x73\x00\x54\x6f\x44\x65\
+  \\x6c\x65\x67\x61\x74\x65\x54\x79\x70\x65\x00\x43\x72\x65\x61\x74\x65\x44\x65\x6c\
+  \\x65\x67\x61\x74\x65\x54\x79\x70\x65\x00\x52\x65\x74\x75\x72\x6e\x54\x79\x70\x65\
+  \\x00\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x73\x00\x54\x79\x70\x65\
+  \\x5f\x47\x65\x74\x54\x79\x70\x65\x46\x72\x6f\x6d\x48\x61\x6e\x64\x6c\x65\x00\x4f\
+  \\x62\x6a\x65\x63\x74\x5f\x63\x74\x6f\x72\x00\x4d\x61\x72\x73\x68\x61\x6c\x5f\x47\
+  \\x65\x74\x44\x65\x6c\x65\x67\x61\x74\x65\x46\x6f\x72\x46\x75\x6e\x63\x74\x69\x6f\
+  \\x6e\x50\x6f\x69\x6e\x74\x65\x72\x00\x4d\x61\x72\x73\x68\x61\x6c\x5f\x47\x65\x74\
+  \\x46\x75\x6e\x63\x74\x69\x6f\x6e\x50\x6f\x69\x6e\x74\x65\x72\x46\x6f\x72\x44\x65\
+  \\x6c\x65\x67\x61\x74\x65\x00\x4d\x61\x72\x73\x68\x61\x6c\x5f\x53\x74\x72\x69\x6e\
+  \\x67\x54\x6f\x48\x47\x6c\x6f\x62\x61\x6c\x55\x6e\x69\x00\x4d\x61\x72\x73\x68\x61\
+  \\x6c\x5f\x53\x74\x72\x69\x6e\x67\x54\x6f\x48\x47\x6c\x6f\x62\x61\x6c\x41\x6e\x73\
+  \\x69\x00\x44\x72\x69\x76\x65\x72\x5f\x46\x72\x65\x65\x48\x61\x73\x6b\x65\x6c\x6c\
+  \\x46\x75\x6e\x50\x74\x72\x00\x44\x72\x69\x76\x65\x72\x5f\x52\x65\x67\x69\x73\x74\
+  \\x65\x72\x4f\x62\x6a\x65\x63\x74\x00\x44\x72\x69\x76\x65\x72\x5f\x47\x65\x74\x4f\
+  \\x62\x6a\x65\x63\x74\x00\x46\x72\x65\x65\x48\x61\x73\x6b\x65\x6c\x6c\x46\x75\x6e\
+  \\x50\x74\x72\x44\x65\x6c\x65\x67\x61\x74\x65\x5f\x49\x6e\x76\x6f\x6b\x65\x00\x53\
+  \\x74\x72\x69\x6e\x67\x54\x6f\x54\x79\x70\x65\x00\x53\x74\x72\x69\x6e\x67\x54\x6f\
+  \\x54\x79\x70\x65\x73\x00\x43\x6f\x6e\x63\x61\x74\x41\x72\x72\x61\x79\x00\x54\x00\
+  \\x4d\x61\x70\x41\x72\x72\x61\x79\x00\x4d\x61\x70\x50\x61\x72\x61\x6d\x65\x74\x65\
+  \\x72\x73\x54\x6f\x54\x79\x70\x65\x73\x00\x45\x6d\x69\x74\x4c\x64\x61\x72\x67\x00\
+  \\x41\x73\x73\x65\x6d\x62\x6c\x79\x46\x69\x6c\x65\x56\x65\x72\x73\x69\x6f\x6e\x41\
+  \\x74\x74\x72\x69\x62\x75\x74\x65\x00\x41\x73\x73\x65\x6d\x62\x6c\x79\x56\x65\x72\
+  \\x73\x69\x6f\x6e\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x41\x73\x73\x65\x6d\x62\
+  \\x6c\x79\x43\x6f\x70\x79\x72\x69\x67\x68\x74\x41\x74\x74\x72\x69\x62\x75\x74\x65\
+  \\x00\x41\x73\x73\x65\x6d\x62\x6c\x79\x50\x72\x6f\x64\x75\x63\x74\x41\x74\x74\x72\
+  \\x69\x62\x75\x74\x65\x00\x41\x73\x73\x65\x6d\x62\x6c\x79\x44\x65\x73\x63\x72\x69\
+  \\x70\x74\x69\x6f\x6e\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x41\x73\x73\x65\x6d\
+  \\x62\x6c\x79\x54\x69\x74\x6c\x65\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x53\x79\
+  \\x73\x74\x65\x6d\x2e\x52\x75\x6e\x74\x69\x6d\x65\x2e\x43\x6f\x6d\x70\x69\x6c\x65\
+  \\x72\x53\x65\x72\x76\x69\x63\x65\x73\x00\x43\x6f\x6d\x70\x69\x6c\x61\x74\x69\x6f\
+  \\x6e\x52\x65\x6c\x61\x78\x61\x74\x69\x6f\x6e\x73\x41\x74\x74\x72\x69\x62\x75\x74\
+  \\x65\x00\x52\x75\x6e\x74\x69\x6d\x65\x43\x6f\x6d\x70\x61\x74\x69\x62\x69\x6c\x69\
+  \\x74\x79\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x53\x79\x73\x74\x65\x6d\x2e\x44\
+  \\x69\x61\x67\x6e\x6f\x73\x74\x69\x63\x73\x00\x54\x72\x61\x63\x65\x00\x54\x72\x61\
+  \\x63\x65\x4c\x69\x73\x74\x65\x6e\x65\x72\x43\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\
+  \\x00\x67\x65\x74\x5f\x4c\x69\x73\x74\x65\x6e\x65\x72\x73\x00\x43\x6f\x6e\x73\x6f\
+  \\x6c\x65\x54\x72\x61\x63\x65\x4c\x69\x73\x74\x65\x6e\x65\x72\x00\x54\x72\x61\x63\
+  \\x65\x4c\x69\x73\x74\x65\x6e\x65\x72\x00\x41\x64\x64\x00\x53\x79\x73\x74\x65\x6d\
+  \\x2e\x57\x69\x6e\x64\x6f\x77\x73\x2e\x46\x6f\x72\x6d\x73\x00\x41\x70\x70\x6c\x69\
+  \\x63\x61\x74\x69\x6f\x6e\x00\x45\x6e\x61\x62\x6c\x65\x56\x69\x73\x75\x61\x6c\x53\
+  \\x74\x79\x6c\x65\x73\x00\x41\x70\x70\x44\x6f\x6d\x61\x69\x6e\x00\x67\x65\x74\x5f\
+  \\x43\x75\x72\x72\x65\x6e\x74\x44\x6f\x6d\x61\x69\x6e\x00\x41\x73\x73\x65\x6d\x62\
+  \\x6c\x79\x4e\x61\x6d\x65\x00\x41\x73\x73\x65\x6d\x62\x6c\x79\x42\x75\x69\x6c\x64\
+  \\x65\x72\x41\x63\x63\x65\x73\x73\x00\x44\x65\x66\x69\x6e\x65\x44\x79\x6e\x61\x6d\
+  \\x69\x63\x41\x73\x73\x65\x6d\x62\x6c\x79\x00\x44\x65\x66\x69\x6e\x65\x44\x79\x6e\
+  \\x61\x6d\x69\x63\x4d\x6f\x64\x75\x6c\x65\x00\x44\x65\x66\x69\x6e\x65\x54\x79\x70\
+  \\x65\x00\x42\x6f\x6f\x6c\x65\x61\x6e\x00\x6d\x65\x74\x68\x6f\x64\x4e\x61\x6d\x65\
+  \\x00\x52\x75\x6e\x74\x69\x6d\x65\x54\x79\x70\x65\x48\x61\x6e\x64\x6c\x65\x00\x47\
+  \\x65\x74\x54\x79\x70\x65\x46\x72\x6f\x6d\x48\x61\x6e\x64\x6c\x65\x00\x47\x65\x74\
+  \\x4d\x65\x74\x68\x6f\x64\x00\x41\x72\x67\x75\x6d\x65\x6e\x74\x45\x78\x63\x65\x70\
+  \\x74\x69\x6f\x6e\x00\x66\x72\x65\x65\x48\x61\x73\x6b\x65\x6c\x6c\x46\x75\x6e\x50\
+  \\x74\x72\x00\x49\x6e\x74\x50\x74\x72\x00\x5a\x65\x72\x6f\x00\x6f\x70\x5f\x45\x71\
+  \\x75\x61\x6c\x69\x74\x79\x00\x4d\x61\x72\x73\x68\x61\x6c\x00\x47\x65\x74\x44\x65\
+  \\x6c\x65\x67\x61\x74\x65\x46\x6f\x72\x46\x75\x6e\x63\x74\x69\x6f\x6e\x50\x6f\x69\
+  \\x6e\x74\x65\x72\x00\x43\x72\x65\x61\x74\x65\x54\x79\x70\x65\x00\x4d\x6f\x64\x75\
+  \\x6c\x65\x00\x67\x65\x74\x5f\x46\x75\x6c\x6c\x79\x51\x75\x61\x6c\x69\x66\x69\x65\
+  \\x64\x4e\x61\x6d\x65\x00\x53\x79\x73\x74\x65\x6d\x2e\x49\x4f\x00\x50\x61\x74\x68\
+  \\x00\x47\x65\x74\x46\x69\x6c\x65\x4e\x61\x6d\x65\x00\x53\x74\x72\x69\x6e\x67\x00\
+  \\x43\x6f\x6e\x63\x61\x74\x00\x43\x6f\x6e\x73\x6f\x6c\x65\x00\x57\x72\x69\x74\x65\
+  \\x4c\x69\x6e\x65\x00\x53\x61\x76\x65\x00\x63\x6c\x61\x73\x73\x4e\x61\x6d\x65\x00\
+  \\x70\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x4e\x61\x6d\x65\x73\x00\x47\
+  \\x65\x74\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x00\x64\x65\x6c\x65\x67\x61\
+  \\x74\x65\x54\x79\x70\x65\x4e\x61\x6d\x65\x00\x66\x69\x65\x6c\x64\x4e\x61\x6d\x65\
+  \\x00\x47\x65\x74\x46\x69\x65\x6c\x64\x00\x74\x79\x70\x65\x4e\x61\x6d\x65\x00\x6f\
+  \\x00\x53\x79\x73\x74\x65\x6d\x2e\x54\x68\x72\x65\x61\x64\x69\x6e\x67\x00\x4d\x6f\
+  \\x6e\x69\x74\x6f\x72\x00\x45\x6e\x74\x65\x72\x00\x45\x78\x69\x74\x00\x6f\x49\x64\
+  \\x00\x54\x72\x79\x47\x65\x74\x56\x61\x6c\x75\x65\x00\x49\x6e\x74\x33\x32\x00\x52\
+  \\x65\x6d\x6f\x76\x65\x00\x64\x00\x47\x65\x74\x46\x75\x6e\x63\x74\x69\x6f\x6e\x50\
+  \\x6f\x69\x6e\x74\x65\x72\x46\x6f\x72\x44\x65\x6c\x65\x67\x61\x74\x65\x00\x66\x75\
+  \\x6e\x50\x74\x72\x00\x6d\x65\x74\x68\x6f\x64\x53\x69\x67\x6e\x61\x74\x75\x72\x65\
+  \\x00\x69\x6c\x57\x72\x69\x74\x65\x72\x00\x4d\x65\x74\x68\x6f\x64\x42\x75\x69\x6c\
+  \\x64\x65\x72\x00\x4d\x65\x74\x68\x6f\x64\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\
+  \\x00\x44\x65\x66\x69\x6e\x65\x4d\x65\x74\x68\x6f\x64\x00\x47\x65\x74\x49\x4c\x47\
+  \\x65\x6e\x65\x72\x61\x74\x6f\x72\x00\x44\x79\x6e\x61\x6d\x69\x63\x4d\x65\x74\x68\
+  \\x6f\x64\x00\x43\x72\x65\x61\x74\x65\x44\x65\x6c\x65\x67\x61\x74\x65\x00\x3c\x3e\
+  \\x63\x5f\x5f\x44\x69\x73\x70\x6c\x61\x79\x43\x6c\x61\x73\x73\x31\x00\x74\x79\x70\
+  \\x65\x00\x63\x6f\x6e\x00\x3c\x47\x65\x6e\x65\x72\x61\x74\x65\x43\x6f\x6e\x73\x74\
+  \\x72\x75\x63\x74\x6f\x72\x53\x74\x75\x62\x3e\x62\x5f\x5f\x30\x00\x69\x6c\x67\x00\
+  \\x4c\x6f\x63\x61\x6c\x42\x75\x69\x6c\x64\x65\x72\x00\x44\x65\x63\x6c\x61\x72\x65\
+  \\x4c\x6f\x63\x61\x6c\x00\x4f\x70\x43\x6f\x64\x65\x73\x00\x4f\x70\x43\x6f\x64\x65\
+  \\x00\x4c\x64\x6c\x6f\x63\x61\x5f\x53\x00\x45\x6d\x69\x74\x00\x49\x6e\x69\x74\x6f\
+  \\x62\x6a\x00\x4c\x64\x6c\x6f\x63\x5f\x30\x00\x4d\x65\x74\x68\x6f\x64\x42\x61\x73\
+  \\x65\x00\x47\x65\x74\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x73\x00\x4e\x65\x77\x6f\
+  \\x62\x6a\x00\x52\x65\x74\x00\x4d\x65\x6d\x62\x65\x72\x49\x6e\x66\x6f\x00\x67\x65\
+  \\x74\x5f\x44\x65\x63\x6c\x61\x72\x69\x6e\x67\x54\x79\x70\x65\x00\x67\x65\x74\x5f\
+  \\x49\x73\x56\x61\x6c\x75\x65\x54\x79\x70\x65\x00\x41\x72\x67\x75\x6d\x65\x6e\x74\
+  \\x4e\x75\x6c\x6c\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x00\x45\x6d\x70\x74\x79\x54\
+  \\x79\x70\x65\x73\x00\x67\x65\x74\x5f\x4e\x61\x6d\x65\x00\x3c\x3e\x63\x5f\x5f\x44\
+  \\x69\x73\x70\x6c\x61\x79\x43\x6c\x61\x73\x73\x34\x00\x6d\x65\x74\x68\x00\x3c\x47\
+  \\x65\x6e\x65\x72\x61\x74\x65\x4d\x65\x74\x68\x6f\x64\x53\x74\x75\x62\x3e\x62\x5f\
+  \\x5f\x33\x00\x67\x65\x74\x5f\x49\x73\x53\x74\x61\x74\x69\x63\x00\x43\x61\x6c\x6c\
+  \\x00\x43\x61\x6c\x6c\x76\x69\x72\x74\x00\x67\x65\x74\x5f\x52\x65\x74\x75\x72\x6e\
+  \\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x00\x67\x65\x74\x5f\x50\x61\x72\x61\x6d\x65\
+  \\x74\x65\x72\x54\x79\x70\x65\x00\x3c\x3e\x63\x5f\x5f\x44\x69\x73\x70\x6c\x61\x79\
+  \\x43\x6c\x61\x73\x73\x37\x00\x77\x72\x61\x70\x70\x65\x72\x54\x79\x70\x65\x00\x64\
+  \\x65\x6c\x65\x67\x61\x74\x65\x54\x79\x70\x65\x00\x3c\x47\x65\x6e\x65\x72\x61\x74\
+  \\x65\x44\x65\x6c\x65\x67\x61\x74\x65\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\
+  \\x53\x74\x75\x62\x3e\x62\x5f\x5f\x36\x00\x4c\x64\x61\x72\x67\x5f\x30\x00\x4c\x64\
+  \\x66\x74\x6e\x00\x3c\x3e\x63\x5f\x5f\x44\x69\x73\x70\x6c\x61\x79\x43\x6c\x61\x73\
+  \\x73\x61\x00\x66\x69\x65\x6c\x64\x00\x3c\x47\x65\x6e\x65\x72\x61\x74\x65\x46\x69\
+  \\x65\x6c\x64\x47\x65\x74\x53\x74\x75\x62\x3e\x62\x5f\x5f\x39\x00\x67\x65\x74\x5f\
+  \\x49\x73\x4c\x69\x74\x65\x72\x61\x6c\x00\x47\x65\x74\x52\x61\x77\x43\x6f\x6e\x73\
+  \\x74\x61\x6e\x74\x56\x61\x6c\x75\x65\x00\x4c\x64\x63\x5f\x49\x34\x00\x4c\x64\x73\
+  \\x66\x6c\x64\x00\x4c\x64\x66\x6c\x64\x00\x67\x65\x74\x5f\x46\x69\x65\x6c\x64\x54\
+  \\x79\x70\x65\x00\x3c\x3e\x63\x5f\x5f\x44\x69\x73\x70\x6c\x61\x79\x43\x6c\x61\x73\
+  \\x73\x64\x00\x3c\x47\x65\x6e\x65\x72\x61\x74\x65\x46\x69\x65\x6c\x64\x53\x65\x74\
+  \\x53\x74\x75\x62\x3e\x62\x5f\x5f\x63\x00\x53\x74\x73\x66\x6c\x64\x00\x53\x74\x66\
+  \\x6c\x64\x00\x56\x6f\x69\x64\x00\x3c\x3e\x63\x5f\x5f\x44\x69\x73\x70\x6c\x61\x79\
+  \\x43\x6c\x61\x73\x73\x31\x30\x00\x74\x79\x70\x65\x54\x6f\x42\x6f\x78\x00\x3c\x47\
+  \\x65\x6e\x65\x72\x61\x74\x65\x42\x6f\x78\x53\x74\x75\x62\x3e\x62\x5f\x5f\x66\x00\
+  \\x42\x6f\x78\x00\x74\x00\x67\x65\x74\x5f\x49\x73\x50\x72\x69\x6d\x69\x74\x69\x76\
+  \\x65\x00\x74\x79\x70\x65\x73\x00\x61\x72\x67\x75\x6d\x65\x6e\x74\x49\x6e\x64\x65\
+  \\x78\x00\x70\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x00\x76\x61\x6c\x75\
+  \\x65\x54\x79\x70\x65\x00\x55\x6e\x62\x6f\x78\x5f\x41\x6e\x79\x00\x73\x74\x61\x72\
+  \\x74\x69\x6e\x67\x41\x72\x67\x75\x6d\x65\x6e\x74\x00\x70\x61\x72\x61\x6d\x65\x74\
+  \\x65\x72\x49\x6e\x66\x6f\x73\x00\x49\x45\x6e\x75\x6d\x65\x72\x61\x74\x6f\x72\x60\
+  \\x31\x00\x47\x65\x74\x45\x6e\x75\x6d\x65\x72\x61\x74\x6f\x72\x00\x67\x65\x74\x5f\
+  \\x43\x75\x72\x72\x65\x6e\x74\x00\x53\x79\x73\x74\x65\x6d\x2e\x43\x6f\x6c\x6c\x65\
+  \\x63\x74\x69\x6f\x6e\x73\x00\x49\x45\x6e\x75\x6d\x65\x72\x61\x74\x6f\x72\x00\x4d\
+  \\x6f\x76\x65\x4e\x65\x78\x74\x00\x49\x44\x69\x73\x70\x6f\x73\x61\x62\x6c\x65\x00\
+  \\x44\x69\x73\x70\x6f\x73\x65\x00\x72\x65\x74\x75\x72\x6e\x50\x61\x72\x61\x6d\x65\
+  \\x74\x65\x72\x49\x6e\x66\x6f\x00\x6e\x61\x6d\x65\x00\x54\x79\x70\x65\x41\x74\x74\
+  \\x72\x69\x62\x75\x74\x65\x73\x00\x46\x69\x65\x6c\x64\x42\x75\x69\x6c\x64\x65\x72\
+  \\x00\x46\x69\x65\x6c\x64\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x44\x65\x66\
+  \\x69\x6e\x65\x46\x69\x65\x6c\x64\x00\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\
+  \\x42\x75\x69\x6c\x64\x65\x72\x00\x43\x61\x6c\x6c\x69\x6e\x67\x43\x6f\x6e\x76\x65\
+  \\x6e\x74\x69\x6f\x6e\x73\x00\x44\x65\x66\x69\x6e\x65\x43\x6f\x6e\x73\x74\x72\x75\
+  \\x63\x74\x6f\x72\x00\x4c\x64\x61\x72\x67\x5f\x31\x00\x4c\x64\x74\x6f\x6b\x65\x6e\
+  \\x00\x43\x61\x73\x74\x63\x6c\x61\x73\x73\x00\x4d\x65\x74\x68\x6f\x64\x49\x6d\x70\
+  \\x6c\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x53\x65\x74\x49\x6d\x70\x6c\x65\
+  \\x6d\x65\x6e\x74\x61\x74\x69\x6f\x6e\x46\x6c\x61\x67\x73\x00\x4c\x61\x62\x65\x6c\
+  \\x00\x44\x65\x66\x69\x6e\x65\x4c\x61\x62\x65\x6c\x00\x4c\x64\x63\x5f\x49\x34\x5f\
+  \\x30\x00\x42\x65\x71\x00\x4d\x61\x72\x6b\x4c\x61\x62\x65\x6c\x00\x55\x6e\x6d\x61\
+  \\x6e\x61\x67\x65\x64\x46\x75\x6e\x63\x74\x69\x6f\x6e\x50\x6f\x69\x6e\x74\x65\x72\
+  \\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x43\x61\x6c\x6c\x69\x6e\x67\x43\x6f\x6e\
+  \\x76\x65\x6e\x74\x69\x6f\x6e\x00\x6f\x62\x6a\x65\x63\x74\x00\x6d\x65\x74\x68\x6f\
+  \\x64\x00\x63\x61\x6c\x6c\x62\x61\x63\x6b\x00\x72\x65\x73\x75\x6c\x74\x00\x53\x74\
+  \\x72\x75\x63\x74\x4c\x61\x79\x6f\x75\x74\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\
+  \\x4c\x61\x79\x6f\x75\x74\x4b\x69\x6e\x64\x00\x72\x65\x74\x75\x72\x6e\x54\x79\x70\
+  \\x65\x00\x70\x61\x72\x61\x6d\x65\x74\x65\x72\x54\x79\x70\x65\x73\x00\x53\x79\x73\
+  \\x74\x65\x6d\x2e\x54\x65\x78\x74\x00\x53\x74\x72\x69\x6e\x67\x42\x75\x69\x6c\x64\
+  \\x65\x72\x00\x41\x70\x70\x65\x6e\x64\x00\x43\x75\x73\x74\x6f\x6d\x41\x74\x74\x72\
+  \\x69\x62\x75\x74\x65\x42\x75\x69\x6c\x64\x65\x72\x00\x53\x65\x74\x43\x75\x73\x74\
+  \\x6f\x6d\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x67\x65\x74\x5f\x48\x61\x73\x56\
+  \\x61\x6c\x75\x65\x00\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x42\x75\x69\x6c\x64\x65\
+  \\x72\x00\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x41\x74\x74\x72\x69\x62\x75\x74\x65\
+  \\x73\x00\x44\x65\x66\x69\x6e\x65\x50\x61\x72\x61\x6d\x65\x74\x65\x72\x00\x4d\x61\
+  \\x72\x73\x68\x61\x6c\x41\x73\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x67\x65\x74\
+  \\x5f\x56\x61\x6c\x75\x65\x00\x43\x6f\x6d\x70\x69\x6c\x65\x72\x47\x65\x6e\x65\x72\
+  \\x61\x74\x65\x64\x41\x74\x74\x72\x69\x62\x75\x74\x65\x00\x42\x69\x6e\x64\x69\x6e\
+  \\x67\x46\x6c\x61\x67\x73\x00\x73\x00\x47\x65\x74\x54\x79\x70\x65\x00\x3c\x53\x74\
+  \\x72\x69\x6e\x67\x54\x6f\x54\x79\x70\x65\x73\x3e\x62\x5f\x5f\x30\x00\x3c\x3e\x39\
+  \\x5f\x5f\x43\x61\x63\x68\x65\x64\x41\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\x4d\x65\x74\
+  \\x68\x6f\x64\x44\x65\x6c\x65\x67\x61\x74\x65\x31\x00\x43\x68\x61\x72\x00\x53\x74\
+  \\x72\x69\x6e\x67\x53\x70\x6c\x69\x74\x4f\x70\x74\x69\x6f\x6e\x73\x00\x53\x70\x6c\
+  \\x69\x74\x00\x61\x00\x62\x00\x78\x00\x66\x00\x78\x73\x00\x3c\x4d\x61\x70\x50\x61\
+  \\x72\x61\x6d\x65\x74\x65\x72\x73\x54\x6f\x54\x79\x70\x65\x73\x3e\x62\x5f\x5f\x32\
+  \\x00\x3c\x3e\x39\x5f\x5f\x43\x61\x63\x68\x65\x64\x41\x6e\x6f\x6e\x79\x6d\x6f\x75\
+  \\x73\x4d\x65\x74\x68\x6f\x64\x44\x65\x6c\x65\x67\x61\x74\x65\x33\x00\x70\x00\x70\
+  \\x61\x72\x61\x6d\x65\x74\x65\x72\x73\x00\x4c\x64\x61\x72\x67\x5f\x32\x00\x4c\x64\
+  \\x61\x72\x67\x5f\x33\x00\x4c\x64\x61\x72\x67\x5f\x53\x00\x4c\x64\x61\x72\x67\x00\
+  \\x78\x31\x00\x00\x00\x1f\x44\x00\x79\x00\x6e\x00\x61\x00\x6d\x00\x69\x00\x63\x00\
+  \\x41\x00\x73\x00\x73\x00\x65\x00\x6d\x00\x62\x00\x6c\x00\x79\x00\x00\x1b\x44\x00\
+  \\x79\x00\x6e\x00\x61\x00\x6d\x00\x69\x00\x63\x00\x4d\x00\x6f\x00\x64\x00\x75\x00\
+  \\x6c\x00\x65\x00\x00\x17\x44\x00\x79\x00\x6e\x00\x61\x00\x6d\x00\x69\x00\x63\x00\
+  \\x2e\x00\x64\x00\x6c\x00\x6c\x00\x00\x0b\x53\x00\x74\x00\x75\x00\x62\x00\x73\x00\
+  \\x00\x25\x47\x00\x65\x00\x74\x00\x50\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\x65\x00\
+  \\x72\x00\x54\x00\x6f\x00\x4d\x00\x65\x00\x74\x00\x68\x00\x6f\x00\x64\x00\x00\x23\
+  \\x4d\x00\x65\x00\x74\x00\x68\x00\x6f\x00\x64\x00\x20\x00\x6e\x00\x6f\x00\x74\x00\
+  \\x20\x00\x66\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x2e\x00\x00\x15\x6d\x00\x65\x00\
+  \\x74\x00\x68\x00\x6f\x00\x64\x00\x4e\x00\x61\x00\x6d\x00\x65\x00\x00\x33\x53\x00\
+  \\x61\x00\x76\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x64\x00\x79\x00\x6e\x00\x61\x00\
+  \\x6d\x00\x69\x00\x63\x00\x20\x00\x61\x00\x73\x00\x73\x00\x65\x00\x6d\x00\x62\x00\
+  \\x6c\x00\x79\x00\x3a\x00\x20\x00\x00\x0b\x2e\x00\x63\x00\x74\x00\x6f\x00\x72\x00\
+  \\x00\x35\x4e\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\
+  \\x20\x00\x65\x00\x78\x00\x69\x00\x73\x00\x74\x00\x73\x00\x20\x00\x77\x00\x69\x00\
+  \\x74\x00\x68\x00\x20\x00\x69\x00\x64\x00\x3a\x00\x20\x00\x00\x65\x27\x00\x63\x00\
+  \\x6f\x00\x6e\x00\x27\x00\x20\x00\x63\x00\x61\x00\x6e\x00\x6e\x00\x6f\x00\x74\x00\
+  \\x20\x00\x62\x00\x65\x00\x20\x00\x6e\x00\x75\x00\x6c\x00\x6c\x00\x20\x00\x69\x00\
+  \\x66\x00\x20\x00\x63\x00\x72\x00\x65\x00\x61\x00\x74\x00\x69\x00\x6e\x00\x67\x00\
+  \\x20\x00\x61\x00\x20\x00\x72\x00\x65\x00\x66\x00\x65\x00\x72\x00\x65\x00\x6e\x00\
+  \\x63\x00\x65\x00\x20\x00\x74\x00\x79\x00\x70\x00\x65\x00\x2e\x00\x01\x07\x4e\x00\
+  \\x65\x00\x77\x00\x00\x03\x5f\x00\x00\x0d\x49\x00\x6e\x00\x76\x00\x6f\x00\x6b\x00\
+  \\x65\x00\x00\x17\x5f\x00\x66\x00\x69\x00\x65\x00\x6c\x00\x64\x00\x5f\x00\x67\x00\
+  \\x65\x00\x74\x00\x5f\x00\x00\x17\x5f\x00\x66\x00\x69\x00\x65\x00\x6c\x00\x64\x00\
+  \\x5f\x00\x73\x00\x65\x00\x74\x00\x5f\x00\x00\x09\x62\x00\x6f\x00\x78\x00\x5f\x00\
+  \\x00\x0f\x57\x00\x72\x00\x61\x00\x70\x00\x70\x00\x65\x00\x72\x00\x00\x1d\x5f\x00\
+  \\x74\x00\x68\x00\x75\x00\x6e\x00\x6b\x00\x44\x00\x65\x00\x6c\x00\x65\x00\x67\x00\
+  \\x61\x00\x74\x00\x65\x00\x00\x11\x46\x00\x69\x00\x6e\x00\x61\x00\x6c\x00\x69\x00\
+  \\x7a\x00\x65\x00\x00\x05\x54\x00\x6f\x00\x00\x11\x44\x00\x65\x00\x6c\x00\x65\x00\
+  \\x67\x00\x61\x00\x74\x00\x65\x00\x00\x23\x47\x00\x65\x00\x74\x00\x54\x00\x79\x00\
+  \\x70\x00\x65\x00\x46\x00\x72\x00\x6f\x00\x6d\x00\x48\x00\x61\x00\x6e\x00\x64\x00\
+  \\x6c\x00\x65\x00\x00\x3b\x47\x00\x65\x00\x74\x00\x44\x00\x65\x00\x6c\x00\x65\x00\
+  \\x67\x00\x61\x00\x74\x00\x65\x00\x46\x00\x6f\x00\x72\x00\x46\x00\x75\x00\x6e\x00\
+  \\x63\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x50\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\
+  \\x65\x00\x72\x00\x00\x3b\x47\x00\x65\x00\x74\x00\x46\x00\x75\x00\x6e\x00\x63\x00\
+  \\x74\x00\x69\x00\x6f\x00\x6e\x00\x50\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\x65\x00\
+  \\x72\x00\x46\x00\x6f\x00\x72\x00\x44\x00\x65\x00\x6c\x00\x65\x00\x67\x00\x61\x00\
+  \\x74\x00\x65\x00\x00\x25\x53\x00\x74\x00\x72\x00\x69\x00\x6e\x00\x67\x00\x54\x00\
+  \\x6f\x00\x48\x00\x47\x00\x6c\x00\x6f\x00\x62\x00\x61\x00\x6c\x00\x55\x00\x6e\x00\
+  \\x69\x00\x00\x27\x53\x00\x74\x00\x72\x00\x69\x00\x6e\x00\x67\x00\x54\x00\x6f\x00\
+  \\x48\x00\x47\x00\x6c\x00\x6f\x00\x62\x00\x61\x00\x6c\x00\x41\x00\x6e\x00\x73\x00\
+  \\x69\x00\x00\x23\x46\x00\x72\x00\x65\x00\x65\x00\x48\x00\x61\x00\x73\x00\x6b\x00\
+  \\x65\x00\x6c\x00\x6c\x00\x46\x00\x75\x00\x6e\x00\x50\x00\x74\x00\x72\x00\x00\x1d\
+  \\x52\x00\x65\x00\x67\x00\x69\x00\x73\x00\x74\x00\x65\x00\x72\x00\x4f\x00\x62\x00\
+  \\x6a\x00\x65\x00\x63\x00\x74\x00\x00\x13\x47\x00\x65\x00\x74\x00\x4f\x00\x62\x00\
+  \\x6a\x00\x65\x00\x63\x00\x74\x00\x00\x00\x00\x00\xa7\xb1\x8f\x02\x0b\xf8\x6c\x46\
+  \\x97\xa3\x4b\x79\x11\xde\xca\xdf\x00\x08\xb7\x7a\x5c\x56\x19\x34\xe0\x89\x03\x06\
+  \\x12\x11\x03\x06\x12\x15\x03\x06\x12\x19\x03\x00\x00\x01\x03\x00\x00\x18\x04\x00\
+  \\x01\x18\x0e\x04\x00\x01\x01\x18\x03\x06\x12\x14\x06\x00\x03\x18\x0e\x0e\x0e\x05\
+  \\x00\x02\x18\x0e\x0e\x07\x06\x15\x12\x1d\x02\x08\x1c\x02\x06\x08\x04\x00\x01\x08\
+  \\x1c\x04\x00\x01\x1c\x08\x03\x06\x12\x0c\x04\x00\x01\x01\x08\x08\x06\x15\x12\x1d\
+  \\x02\x18\x12\x21\x05\x00\x01\x18\x12\x21\x08\x00\x03\x18\x0e\x11\x10\x12\x18\x05\
+  \\x00\x01\x18\x12\x25\x05\x00\x01\x18\x12\x29\x05\x00\x01\x18\x12\x2d\x05\x00\x01\
+  \\x18\x12\x31\x05\x00\x01\x02\x12\x2d\x0a\x00\x01\x15\x11\x35\x01\x11\x39\x12\x2d\
+  \\x08\x00\x01\x1d\x12\x2d\x1d\x12\x2d\x06\x00\x01\x12\x2d\x12\x2d\x08\x00\x03\x01\
+  \\x12\x3d\x08\x12\x2d\x07\x00\x02\x01\x12\x3d\x12\x2d\x0c\x00\x03\x01\x12\x3d\x08\
+  \\x15\x12\x41\x01\x12\x45\x07\x00\x02\x01\x12\x3d\x12\x45\x08\x06\x15\x12\x1d\x02\
+  \\x0e\x12\x2d\x07\x00\x02\x12\x2d\x0e\x12\x2d\x03\x20\x00\x01\x05\x20\x02\x01\x1c\
+  \\x18\x04\x20\x01\x01\x08\x08\x20\x03\x12\x49\x08\x12\x4d\x1c\x05\x20\x01\x01\x12\
+  \\x49\x03\x06\x12\x2d\x04\x06\x1d\x12\x2d\x04\x20\x00\x12\x2d\x05\x20\x00\x1d\x12\
+  \\x2d\x08\x20\x02\x01\x12\x2d\x1d\x12\x2d\x03\x20\x00\x0e\x06\x00\x01\x11\x10\x12\
+  \\x2d\x05\x20\x01\x12\x2d\x0e\x04\x28\x00\x12\x2d\x05\x28\x00\x1d\x12\x2d\x04\x20\
+  \\x01\x01\x18\x08\x20\x03\x12\x49\x18\x12\x4d\x1c\x05\x20\x01\x01\x12\x3d\x09\x20\
+  \\x03\x12\x49\x12\x3d\x12\x4d\x1c\x03\x06\x12\x29\x03\x06\x12\x25\x03\x06\x12\x31\
+  \\x05\x00\x01\x12\x2d\x0e\x06\x00\x01\x1d\x12\x2d\x0e\x0c\x10\x01\x02\x1d\x1e\x00\
+  \\x1d\x1e\x00\x1d\x1e\x00\x0b\x10\x01\x02\x1d\x1e\x00\x1e\x00\x1d\x1e\x00\x11\x10\
+  \\x02\x02\x1d\x1e\x01\x15\x12\x24\x02\x1e\x00\x1e\x01\x1d\x1e\x00\x08\x00\x01\x1d\
+  \\x12\x2d\x1d\x12\x45\x06\x00\x02\x01\x12\x3d\x08\x06\x20\x01\x13\x01\x13\x00\x09\
+  \\x20\x03\x12\x49\x13\x00\x12\x4d\x1c\x06\x20\x01\x13\x01\x12\x49\x04\x20\x01\x01\
+  \\x0e\x06\x15\x12\x1d\x02\x08\x1c\x07\x15\x12\x1d\x02\x18\x12\x21\x07\x15\x12\x1d\
+  \\x02\x0e\x12\x2d\x04\x00\x00\x12\x75\x05\x20\x01\x08\x12\x7d\x05\x00\x00\x12\x80\
+  \\x85\x0a\x20\x02\x12\x11\x12\x80\x89\x11\x80\x8d\x06\x20\x02\x12\x15\x0e\x0e\x05\
+  \\x20\x01\x12\x19\x0e\x07\x20\x02\x01\x13\x00\x13\x01\x07\x00\x01\x12\x2d\x11\x80\
+  \\x95\x05\x20\x01\x12\x29\x0e\x05\x20\x02\x01\x0e\x0e\x04\x07\x01\x12\x29\x02\x06\
+  \\x18\x05\x00\x02\x02\x18\x18\x07\x00\x02\x12\x21\x18\x12\x2d\x04\x00\x01\x0e\x0e\
+  \\x05\x00\x02\x0e\x0e\x0e\x04\x00\x01\x01\x0e\x03\x07\x01\x0e\x05\x00\x02\x02\x0e\
+  \\x0e\x07\x20\x01\x12\x25\x1d\x12\x2d\x08\x20\x02\x12\x29\x0e\x1d\x12\x2d\x06\x07\
+  \\x02\x12\x25\x12\x29\x04\x07\x01\x12\x2d\x05\x20\x01\x12\x31\x0e\x04\x07\x01\x12\
+  \\x31\x05\x15\x11\x35\x01\x02\x04\x00\x01\x01\x1c\x0a\x07\x03\x02\x08\x15\x12\x1d\
+  \\x02\x08\x1c\x08\x20\x02\x02\x13\x00\x10\x13\x01\x05\x00\x02\x0e\x1c\x1c\x0a\x07\
+  \\x03\x1c\x1c\x15\x12\x1d\x02\x08\x1c\x05\x20\x01\x02\x13\x00\x08\x07\x01\x15\x12\
+  \\x1d\x02\x08\x1c\x0a\x07\x02\x18\x15\x12\x1d\x02\x18\x12\x21\x09\x07\x01\x15\x12\
+  \\x1d\x02\x18\x12\x21\x0e\x20\x04\x12\x80\xbd\x0e\x11\x80\xc1\x12\x2d\x1d\x12\x2d\
+  \\x04\x20\x00\x12\x3d\x0b\x20\x04\x01\x0e\x12\x2d\x1d\x12\x2d\x12\x2d\x06\x20\x01\
+  \\x12\x21\x12\x2d\x08\x07\x02\x12\x80\xbd\x12\x80\xc5\x07\x20\x01\x12\x80\xc9\x12\
+  \\x2d\x04\x06\x11\x80\xd1\x07\x20\x02\x01\x11\x80\xd1\x05\x08\x20\x02\x01\x11\x80\
+  \\xd1\x12\x2d\x06\x20\x01\x01\x11\x80\xd1\x05\x20\x00\x1d\x12\x45\x08\x20\x02\x01\
+  \\x11\x80\xd1\x12\x25\x03\x20\x00\x02\x06\x07\x02\x11\x10\x12\x28\x08\x20\x02\x01\
+  \\x11\x80\xd1\x12\x29\x04\x20\x00\x12\x45\x04\x0a\x01\x12\x2d\x06\x00\x03\x0e\x0e\
+  \\x0e\x0e\x08\x07\x03\x12\x2d\x11\x10\x12\x2c\x08\x07\x02\x1d\x12\x2d\x1d\x12\x2d\
+  \\x09\x07\x03\x11\x10\x12\x30\x1d\x12\x2d\x03\x20\x00\x1c\x07\x20\x02\x01\x11\x80\
+  \\xd1\x08\x08\x20\x02\x01\x11\x80\xd1\x12\x31\x03\x07\x01\x1c\x09\x07\x03\x11\x10\
+  \\x12\x34\x1d\x12\x2d\x0c\x07\x04\x11\x10\x12\x38\x1d\x12\x2d\x1d\x12\x2d\x09\x07\
+  \\x03\x11\x10\x12\x3c\x1d\x12\x2d\x06\x15\x11\x35\x01\x11\x39\x05\x20\x01\x01\x13\
+  \\x00\x08\x07\x01\x15\x11\x35\x01\x11\x39\x08\x15\x12\x24\x02\x12\x2d\x12\x2d\x06\
+  \\x0a\x02\x12\x2d\x12\x2d\x06\x15\x12\x41\x01\x12\x45\x09\x20\x00\x15\x12\x80\xe5\
+  \\x01\x13\x00\x07\x15\x12\x80\xe5\x01\x12\x45\x04\x20\x00\x13\x00\x0e\x07\x04\x08\
+  \\x12\x45\x12\x2d\x15\x12\x80\xe5\x01\x12\x45\x0e\x07\x04\x0e\x12\x2d\x12\x2d\x15\
+  \\x12\x1d\x02\x0e\x12\x2d\x08\x20\x02\x12\x19\x0e\x11\x80\xf1\x0b\x20\x03\x12\x80\
+  \\xf5\x0e\x12\x2d\x11\x80\xf9\x0e\x20\x03\x12\x80\xfd\x11\x80\xc1\x11\x81\x01\x1d\
+  \\x12\x2d\x09\x20\x02\x12\x80\xbd\x0e\x11\x80\xc1\x06\x20\x01\x01\x11\x81\x05\x05\
+  \\x20\x00\x11\x81\x09\x09\x20\x02\x01\x11\x80\xd1\x11\x81\x09\x06\x20\x01\x01\x11\
+  \\x81\x09\x23\x07\x0e\x11\x10\x12\x2d\x12\x19\x12\x80\xf5\x12\x80\xfd\x12\x3d\x12\
+  \\x80\xbd\x12\x3d\x11\x81\x09\x12\x80\xbd\x12\x3d\x08\x11\x10\x1d\x12\x2d\x06\x20\
+  \\x01\x01\x11\x81\x11\x08\x01\x00\x03\x00\x00\x00\x00\x00\x06\x20\x01\x01\x11\x81\
+  \\x19\x06\x20\x01\x12\x81\x1d\x0e\x0b\x07\x04\x12\x81\x1d\x12\x2d\x1d\x12\x2d\x08\
+  \\x0a\x20\x03\x12\x19\x0e\x11\x80\xf1\x12\x2d\x07\x20\x02\x01\x12\x25\x1d\x1c\x06\
+  \\x20\x01\x01\x12\x81\x21\x0a\x20\x03\x12\x81\x25\x08\x11\x81\x29\x0e\x21\x07\x0b\
+  \\x12\x19\x12\x80\xfd\x12\x80\xbd\x08\x15\x11\x35\x01\x11\x39\x12\x81\x25\x1d\x12\
+  \\x2d\x1d\x1c\x1d\x12\x2d\x1d\x12\x2d\x1d\x1c\x04\x01\x00\x00\x00\x08\x20\x02\x12\
+  \\x31\x0e\x11\x81\x35\x08\x20\x02\x12\x29\x0e\x11\x81\x35\x06\x00\x02\x12\x2d\x0e\
+  \\x02\x08\x06\x15\x12\x24\x02\x0e\x12\x2d\x07\x15\x12\x24\x02\x0e\x12\x2d\x09\x20\
+  \\x02\x1d\x0e\x1d\x03\x11\x81\x3d\x05\x0a\x02\x0e\x12\x2d\x04\x07\x01\x1d\x03\x02\
+  \\x1e\x00\x07\x07\x03\x1d\x1e\x00\x08\x08\x06\x07\x02\x1d\x1e\x00\x08\x02\x1e\x01\
+  \\x08\x15\x12\x24\x02\x1e\x00\x1e\x01\x06\x07\x02\x1d\x1e\x01\x08\x06\x00\x01\x12\
+  \\x2d\x12\x45\x09\x06\x15\x12\x24\x02\x12\x45\x12\x2d\x08\x15\x12\x24\x02\x12\x45\
+  \\x12\x2d\x06\x0a\x02\x12\x45\x12\x2d\x0c\x01\x00\x07\x31\x2e\x30\x2e\x30\x2e\x30\
+  \\x00\x00\x2c\x01\x00\x27\x43\x6f\x70\x79\x72\x69\x67\x68\x74\x20\xc2\xa9\x20\x32\
+  \\x30\x30\x37\x2d\x32\x30\x30\x38\x20\x41\x6e\x64\x72\x65\x77\x20\x41\x70\x70\x6c\
+  \\x65\x79\x61\x72\x64\x00\x00\x0a\x01\x00\x05\x53\x61\x6c\x73\x61\x00\x00\x1c\x01\
+  \\x00\x17\x2e\x4e\x45\x54\x20\x42\x72\x69\x64\x67\x65\x20\x66\x6f\x72\x20\x48\x61\
+  \\x73\x6b\x65\x6c\x6c\x00\x00\x08\x01\x00\x08\x00\x00\x00\x00\x00\x1e\x01\x00\x01\
+  \\x00\x54\x02\x16\x57\x72\x61\x70\x4e\x6f\x6e\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\
+  \\x54\x68\x72\x6f\x77\x73\x01\x00\x10\x61\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x2e\x61\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x20\x61\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x5f\x43\x6f\x72\x44\x6c\x6c\x4d\x61\x69\x6e\x00\x6d\x73\
+  \\x63\x6f\x72\x65\x65\x2e\x64\x6c\x6c\x00\x00\x00\x00\x00\xff\x25\x00\x20\x40\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x01\x00\x10\x00\x00\x00\x18\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x30\x00\x00\x80\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x48\x00\x00\x00\
+  \\x58\x80\x00\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x03\x34\x00\
+  \\x00\x00\x56\x00\x53\x00\x5f\x00\x56\x00\x45\x00\x52\x00\x53\x00\x49\x00\x4f\x00\
+  \\x4e\x00\x5f\x00\x49\x00\x4e\x00\x46\x00\x4f\x00\x00\x00\x00\x00\xbd\x04\xef\xfe\
+  \\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\
+  \\x3f\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x44\x00\x00\x00\x01\x00\x56\x00\x61\x00\x72\x00\
+  \\x46\x00\x69\x00\x6c\x00\x65\x00\x49\x00\x6e\x00\x66\x00\x6f\x00\x00\x00\x00\x00\
+  \\x24\x00\x04\x00\x00\x00\x54\x00\x72\x00\x61\x00\x6e\x00\x73\x00\x6c\x00\x61\x00\
+  \\x74\x00\x69\x00\x6f\x00\x6e\x00\x00\x00\x00\x00\x00\x00\xb0\x04\x64\x02\x00\x00\
+  \\x01\x00\x53\x00\x74\x00\x72\x00\x69\x00\x6e\x00\x67\x00\x46\x00\x69\x00\x6c\x00\
+  \\x65\x00\x49\x00\x6e\x00\x66\x00\x6f\x00\x00\x00\x40\x02\x00\x00\x01\x00\x30\x00\
+  \\x30\x00\x30\x00\x30\x00\x30\x00\x34\x00\x62\x00\x30\x00\x00\x00\x48\x00\x18\x00\
+  \\x01\x00\x43\x00\x6f\x00\x6d\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x73\x00\x00\x00\
+  \\x2e\x00\x4e\x00\x45\x00\x54\x00\x20\x00\x42\x00\x72\x00\x69\x00\x64\x00\x67\x00\
+  \\x65\x00\x20\x00\x66\x00\x6f\x00\x72\x00\x20\x00\x48\x00\x61\x00\x73\x00\x6b\x00\
+  \\x65\x00\x6c\x00\x6c\x00\x00\x00\x34\x00\x06\x00\x01\x00\x46\x00\x69\x00\x6c\x00\
+  \\x65\x00\x44\x00\x65\x00\x73\x00\x63\x00\x72\x00\x69\x00\x70\x00\x74\x00\x69\x00\
+  \\x6f\x00\x6e\x00\x00\x00\x00\x00\x53\x00\x61\x00\x6c\x00\x73\x00\x61\x00\x00\x00\
+  \\x30\x00\x08\x00\x01\x00\x46\x00\x69\x00\x6c\x00\x65\x00\x56\x00\x65\x00\x72\x00\
+  \\x73\x00\x69\x00\x6f\x00\x6e\x00\x00\x00\x00\x00\x31\x00\x2e\x00\x30\x00\x2e\x00\
+  \\x30\x00\x2e\x00\x30\x00\x00\x00\x34\x00\x0a\x00\x01\x00\x49\x00\x6e\x00\x74\x00\
+  \\x65\x00\x72\x00\x6e\x00\x61\x00\x6c\x00\x4e\x00\x61\x00\x6d\x00\x65\x00\x00\x00\
+  \\x53\x00\x61\x00\x6c\x00\x73\x00\x61\x00\x2e\x00\x64\x00\x6c\x00\x6c\x00\x00\x00\
+  \\x74\x00\x27\x00\x01\x00\x4c\x00\x65\x00\x67\x00\x61\x00\x6c\x00\x43\x00\x6f\x00\
+  \\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x00\x00\x43\x00\x6f\x00\
+  \\x70\x00\x79\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x20\x00\xa9\x00\x20\x00\
+  \\x32\x00\x30\x00\x30\x00\x37\x00\x2d\x00\x32\x00\x30\x00\x30\x00\x38\x00\x20\x00\
+  \\x41\x00\x6e\x00\x64\x00\x72\x00\x65\x00\x77\x00\x20\x00\x41\x00\x70\x00\x70\x00\
+  \\x6c\x00\x65\x00\x79\x00\x61\x00\x72\x00\x64\x00\x00\x00\x00\x00\x3c\x00\x0a\x00\
+  \\x01\x00\x4f\x00\x72\x00\x69\x00\x67\x00\x69\x00\x6e\x00\x61\x00\x6c\x00\x46\x00\
+  \\x69\x00\x6c\x00\x65\x00\x6e\x00\x61\x00\x6d\x00\x65\x00\x00\x00\x53\x00\x61\x00\
+  \\x6c\x00\x73\x00\x61\x00\x2e\x00\x64\x00\x6c\x00\x6c\x00\x00\x00\x2c\x00\x06\x00\
+  \\x01\x00\x50\x00\x72\x00\x6f\x00\x64\x00\x75\x00\x63\x00\x74\x00\x4e\x00\x61\x00\
+  \\x6d\x00\x65\x00\x00\x00\x00\x00\x53\x00\x61\x00\x6c\x00\x73\x00\x61\x00\x00\x00\
+  \\x34\x00\x08\x00\x01\x00\x50\x00\x72\x00\x6f\x00\x64\x00\x75\x00\x63\x00\x74\x00\
+  \\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x00\x00\x31\x00\x2e\x00\
+  \\x30\x00\x2e\x00\x30\x00\x2e\x00\x30\x00\x00\x00\x38\x00\x08\x00\x01\x00\x41\x00\
+  \\x73\x00\x73\x00\x65\x00\x6d\x00\x62\x00\x6c\x00\x79\x00\x20\x00\x56\x00\x65\x00\
+  \\x72\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x00\x00\x31\x00\x2e\x00\x30\x00\x2e\x00\
+  \\x30\x00\x2e\x00\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x0c\x00\x00\x00\
+  \\x40\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+  \\x00\x00\x00\x00"
+ Foreign/Salsa/Resolver.hs view
@@ -0,0 +1,261 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, EmptyDataDecls, TypeOperators #-}+{-# OPTIONS_GHC -fallow-undecidable-instances #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.Resolver+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Contains a type-level implementation of the C# function member overload+-- resolution algorithm, as described in the \"C# Language Specification\"+-- (particularly, section 7.4.2).+--+-----------------------------------------------------------------------------+module Foreign.Salsa.Resolver where++import Foreign.Salsa.Common+import Foreign.Salsa.TypePrelude++--+-- Basic predicates+--++type family    IsPrim t+type instance  IsPrim Int32      = TTrue+type instance  IsPrim String     = TTrue+type instance  IsPrim Bool       = TTrue+type instance  IsPrim Double     = TTrue+type instance  IsPrim (Obj t)    = TFalse++type family    IsRef t+type instance  IsRef t = TNot (IsPrim t)+-- FIXME: This definition of IsRef is incorrect.  String is a reference+--        type (in .NET) but it is also a primitive bridge type.++--+-- Operations on the encoded (Gödel) representations of .NET types:+--++-- | 'TyCode' maps labels representing .NET types to a type-level list of hexadecimal+--   values (similar to Gödel numbering) which can (then) be compared for equality.+--   This avoids having to define a large type function for comparing every pair+--   of labels used to represent .NET types.+type family TyCode t++type instance TyCode Int32              = D0 ::: TNil+type instance TyCode String             = D1 ::: TNil+type instance TyCode Bool               = D2 ::: TNil+type instance TyCode Double             = D3 ::: TNil+type instance TyCode (Obj Null)         = D4 ::: TNil+type instance TyCode (Maybe Bool)       = D5 ::: TNil -- Temporary HACK+++type family FromTyCode t+type instance FromTyCode (D0 ::: TNil) = Int32+type instance FromTyCode (D1 ::: TNil) = String+type instance FromTyCode (D2 ::: TNil) = Bool+type instance FromTyCode (D3 ::: TNil) = Double+type instance FromTyCode (D4 ::: TNil) = Obj Null+type instance FromTyCode (D5 ::: TNil) = Maybe Bool+++-- | 'TyEq t1 t2' is true iff the types @t1@ and @t2@ are the same .NET type+--   (as indicated by their code).+type family TyEq t1 t2+type instance TyEq t1 t2 = DigitsEq (TyCode t1) (TyCode t2)+++-- | 'MemberEq m n' is true iff the members 'm' and 'n' have the same types.+type family MemberEq m n+type instance MemberEq TNil       TNil       = TTrue+type instance MemberEq TNil       (n ::: ns) = TFalse+type instance MemberEq (m ::: ms) TNil       = TFalse+type instance MemberEq (m ::: ms) (n ::: ns) = TAnd (TyEq m n) (MemberEq ms ns)++-- | @'TyElem' t ts@ is true iff the type @t@ is present in the list @ts@+--   (containing coded type representations).+type family    TyElem t1 ts+type instance  TyElem t1 TNil        = TFalse+type instance  TyElem t1 (t ::: ts)  = TOr (TyEq t1 t) (TyElem t1 ts)++--+-- Overload resolution algorithm:+--++-- | @'ResolveMember' ms as@ returns the best applicable function member from @ms@+--   with respect to the argument list @as@ (if there is exactly one such member)+--   (ref 7.4.2).+--+--     resolveMember :: [Member] -> [Type] -> Member+--     resolveMember ms as =+--         case (filterBestMembers as applicables applicables) of+--             [m] -> m+--             _   -> error "Ambiguous or no match"+--         where applicables = filterApplicables as ms+--+type family ResolveMember as ms+type instance ResolveMember as ms = ResolveMember' as (FilterApp as ms)+-- was: FromSingleton (Error NoMatch) (FilterBestMembers as (FilterApp as ms) (FilterApp as ms))++type family ResolveMember' as fa+type instance ResolveMember' as fa = FromSingleton (Error NoMatch) (FilterBestMembers as fa fa)+++data Error x+data NoMatch+++-- | @'FilterBestMembers' as ms ms@ returns the list of members from @ms@ that are+--   better than all the other members in @ms@ (with respect to the argument list+--   @as@). +--+--     filterBestMembers :: [Type] -> [Member] -> [Member] -> [Member]+--     filterBestMembers as ms ns = filter (isBestMember as ms) ns+--+type family FilterBestMembers as ms ns+type instance FilterBestMembers as ms TNil       = TNil+type instance FilterBestMembers as ms (n ::: ns) = FilterBestMembers' as ms n (FilterBestMembers as ms ns)+-- was: If (IsBestMember as ms n) (n ::: (FilterBestMembers as ms ns))+--                                (FilterBestMembers as ms ns)++type family FilterBestMembers' as ms n fbms+type instance FilterBestMembers' as ms n fbms = If (IsBestMember as ms n) (n ::: fbms) fbms+++-- | @'IsBestMember' as ms n@ is true iff the member @n@ is better than all+--   the (other) members in @ms@ with respect to the argument list @as@. +--+--     isBestMember :: [Type] -> [Member] -> Member -> Bool+--     isBestMember _  []     _ = True+--     isBestMember as (m:ms) n+--         | m /= n    = isBetterMember as n m && isBestMember as ms n+--         | otherwise = isBestMember as ms n -- skip members equal to 'n'+--+type family IsBestMember as ms n+type instance IsBestMember as TNil       n = TTrue+type instance IsBestMember as (m ::: ms) n =+    If (MemberEq m n) (IsBestMember as ms n)+                      (TAnd (IsBetterMember as n m) (IsBestMember as ms n))+++-- | @'FilterApp' as ms@ returns the list of members from @ms@ that are+--   applicable with respect to the argument list @as@.+type family    FilterApp  as  ms+type instance  FilterApp  as  TNil        = TNil+type instance  FilterApp  as  (m ::: ms)  = FilterApp' as m (FilterApp as ms)+-- was: If (IsApp as m) (m ::: FilterApp as ms)+--                      (FilterApp as ms)++-- Note: use of FilterApp' increases compilation speed by a factor of 10 (!)+type family    FilterApp' as m fas+type instance  FilterApp' as m fas = If (IsApp as m) (m ::: fas) fas+++-- | @'IsApp' as ps@ is true iff the function member defined by the +--   parameters @ps@ is applicable with respect to the argument list @as@+--   (ref 7.4.2.1).  This means they of the same length and an implicit+--   conversion exists from the argument type to the corresponding+--   parameter on the function member.+type family    IsApp  as          ps+type instance  IsApp  TNil        TNil       = TTrue+type instance  IsApp  TNil        (p ::: ps) = TFalse -- different lengths+type instance  IsApp  (a ::: as)  TNil       = TFalse -- different lengths+type instance  IsApp  (a ::: as)  (p ::: ps) = TAnd (ConvertsTo a p) (IsApp as ps)+++-- | @'IsBetterMember' as ps qs@ returns true iff the function member defined by the+--   parameters @ps@ is better than that given by parameters @qs@ given the list of+--   argument types @as@ (ref 7.4.2.2).+--+--     isBetterMember :: [Type] -> Member -> Member -> Bool+--     isBetterMember as ps qs = someBetter as ps qs && not (someBetter as qs ps)+--+type family IsBetterMember as ps qs+type instance IsBetterMember as ps qs =+    TAnd (AnyBetterConv as ps qs) +         (TNot (AnyBetterConv as qs ps))+++type family    AnyBetterConv  as          ss          ts+type instance  AnyBetterConv  TNil        TNil        TNil        = TFalse+type instance  AnyBetterConv  (a ::: as)  (s ::: ss)  (t ::: ts)  =+    TOr (IsBetterConv a s t) (AnyBetterConv as ss ts)+++type family    IsBetterConv t t1 t2+type instance  IsBetterConv t t1 t2 =+    TOr  (TAnd (TyEq t t1) (TNot (TyEq t t2)))+         (TAnd (ConvertsTo t1 t2) (TNot (ConvertsTo t2 t1)))++--+-- Original:+--+-- type instance  ConvertsTo t1 t2 =+--     (TOr  (TyEq t1 t2)+--     (TOr  (TAnd (IsPrim t1)           (TyEq t2 (Obj Object_)))+--     (TOr  (TAnd (TyEq t1 Int32)       (TyEq t2 Double))+--     (TOr  (TAnd (TyEq t1 (Obj Null))  (IsRef t2))+--           (TAnd (TAnd (IsRef t1) (IsRef t2))+--                 (IsSubtypeOf t1 t2))))))+--++-- | @'ConvertsTo' s t@ returns true iff there is an implicit conversion from @s@+--   to @t@ (ref 6.1).+type family    ConvertsTo t1 t2+type instance  ConvertsTo t1 t2 =+    (TOr  (TyEq t1 t2)+    (TOr  (TAnd (IsPrim t1)           (TyEq t2 (Obj Object_)))+    (TOr  (TAnd (TyEq t1 Int32)       (TyEq t2 Double))+    (TOr  (TAnd (TyEq t1 (Obj Null))  (IsRef t2))+    (TOr  (TAnd (TAnd (IsArr t1) (IsArr t2))+                (IsSubtypeOf' (ArrElemTy t1) (ArrElemTy t2)))+          (TAnd (TAnd (IsRef t1) (IsRef t2))+                (IsSubtypeOf t1 t2)))))))+++--    (TOr5 (TyEq t1 t2)+--          (TAnd (IsPrim t1)           (TyEq t2 (Obj Object_)))+--          (TAnd (TyEq t1 Int32)       (TyEq t2 Double))+--          (TAnd (TyEq t1 (Obj Null))  (IsRef t2))+--          (TAnd3 (IsRef t1) (IsRef t2) (IsSubtypeOf t1 t2)))+-- Note: using TOr5 instead of a nested set of TOr's only gives a small performance improvement.+++type family    IsSubtypeOf t1 t2+type instance  IsSubtypeOf t1 t2  = +    TOr (TyEq t1 t2)+        (TyElem t2 (SupertypesOf t1))++type family    IsArr t+type instance  IsArr t = TAnd (TNot (TyEq t (Obj Array_)))+                              (IsSubtypeOf t (Obj Array_))++type family   ArrElemTy t+type instance ArrElemTy t =+    ArrElemTy' (TyCode t)++type family   ArrElemTy' tc+type instance ArrElemTy' (D0 ::: DF ::: tc) = tc+type family    IsSubtypeOf' t1 t2+type instance  IsSubtypeOf' t1 TNil = TFalse -- we need this so that we can short-circuit evaluation+type instance  IsSubtypeOf' t1 (t2 ::: t2s) = +    TOr (TyEq' t1 (t2 ::: t2s))+        (TyElem' (t2 ::: t2s) (SupertypesOf (FromTyCode t1)))++type family   TyEq' t1 t2+type instance TyEq' t1 t2 = DigitsEq t1 t2++type family    TyElem' t1 ts+type instance  TyElem' t1 TNil        = TFalse+type instance  TyElem' t1 (t ::: ts)  = TOr (TyEq' t1 (TyCode t)) (TyElem' t1 ts) -- UGLY!++-- | @'SupertypesOf' t@ is the list of supertypes of @t@.+type family SupertypesOf t++type instance SupertypesOf String          = TNil+type instance SupertypesOf Int32           = TNil+type instance SupertypesOf Bool            = TNil+type instance SupertypesOf Double          = TNil+type instance SupertypesOf (Obj Null)      = TNil++-- vim:set sw=4 ts=4 expandtab:
+ Foreign/Salsa/TypePrelude.hs view
@@ -0,0 +1,364 @@+{-# LANGUAGE TypeFamilies, TypeOperators, EmptyDataDecls #-}+{-# OPTIONS_GHC -fallow-undecidable-instances #-}+-----------------------------------------------------------------------------+-- |+-- Module      : Foreign.Salsa.TypePrelude+-- Copyright   : (c) 2007-2008 Andrew Appleyard+-- Licence     : BSD-style (see LICENSE)+-- +-- Type-level implementations of some standard boolean and list functions.+-- Including short-circuited 'and' and 'or' logic functions.+--+-----------------------------------------------------------------------------+module Foreign.Salsa.TypePrelude where++--+-- Type-level booleans and boolean operations:+--++data TTrue  = TTrue+data TFalse = TFalse++type family TOr x y+type instance TOr TTrue  x  = TTrue+type instance TOr TFalse x  = x++type family TAnd x y+type instance TAnd TFalse x  = TFalse+type instance TAnd TTrue  x  = x++type family TNot x+type instance TNot TTrue  = TFalse+type instance TNot TFalse = TTrue++type family If c a b+type instance If TTrue  a b = a+type instance If TFalse a b = b++--type family TAnd3 x y z+--type instance TAnd3 TFalse y      z = TFalse+--type instance TAnd3 TTrue  TFalse z = TFalse+--type instance TAnd3 TTrue  TTrue  z = z++--type family TOr5 a b c d e+--type instance TOr5 TTrue  b      c      d      e = TTrue+--type instance TOr5 TFalse TTrue  c      d      e = TTrue+--type instance TOr5 TFalse TFalse TTrue  d      e = TTrue+--type instance TOr5 TFalse TFalse TFalse TTrue  e = TTrue+--type instance TOr5 TFalse TFalse TFalse TFalse e = e++--+-- Type-level lists and associated operations:+--++data TNil+data x ::: xs -- = x ::: xs+infixr 5 :::++type family    BoolEq x       y+type instance  BoolEq TTrue   TTrue   = TTrue+type instance  BoolEq TFalse  TFalse  = TTrue+type instance  BoolEq TFalse  TTrue   = TFalse+type instance  BoolEq TTrue   TFalse  = TFalse++-- | 'ListEq xs ys' is true if the given type-level boolean lists contain +--   the same boolean values, and false otherwise.+type family    ListEq xs          ys+type instance  ListEq TNil        TNil        = TTrue+type instance  ListEq (x ::: xs)  TNil        = TFalse+type instance  ListEq TNil        (x ::: xs)  = TFalse+type instance  ListEq (x ::: xs)  (y ::: ys)  = TAnd (BoolEq x y) (ListEq xs ys)++-- | @'FromSingleton' xs def@ returns the only element of the list @xs@ (if it is a+--   single element list), otherwise it returns the default value @def@.+type family FromSingleton def xs+type instance FromSingleton def TNil            = def+type instance FromSingleton def (x ::: TNil)    = x+type instance FromSingleton def (x ::: y ::: z) = def++-- +-- Type-level base-16 digits and equality:+--++data D0 = D0+data D1 = D1+data D2 = D2+data D3 = D3+data D4 = D4+data D5 = D5+data D6 = D6+data D7 = D7+data D8 = D8+data D9 = D9+data DA = DA+data DB = DB+data DC = DC+data DD = DD+data DE = DE+data DF = DF++type family    DigitEq x  y+type instance  DigitEq D0 D0 = TTrue+type instance  DigitEq D1 D0 = TFalse+type instance  DigitEq D2 D0 = TFalse+type instance  DigitEq D3 D0 = TFalse+type instance  DigitEq D4 D0 = TFalse+type instance  DigitEq D5 D0 = TFalse+type instance  DigitEq D6 D0 = TFalse+type instance  DigitEq D7 D0 = TFalse+type instance  DigitEq D8 D0 = TFalse+type instance  DigitEq D9 D0 = TFalse+type instance  DigitEq DA D0 = TFalse+type instance  DigitEq DB D0 = TFalse+type instance  DigitEq DC D0 = TFalse+type instance  DigitEq DD D0 = TFalse+type instance  DigitEq DE D0 = TFalse+type instance  DigitEq DF D0 = TFalse+type instance  DigitEq D0 D1 = TFalse+type instance  DigitEq D1 D1 = TTrue+type instance  DigitEq D2 D1 = TFalse+type instance  DigitEq D3 D1 = TFalse+type instance  DigitEq D4 D1 = TFalse+type instance  DigitEq D5 D1 = TFalse+type instance  DigitEq D6 D1 = TFalse+type instance  DigitEq D7 D1 = TFalse+type instance  DigitEq D8 D1 = TFalse+type instance  DigitEq D9 D1 = TFalse+type instance  DigitEq DA D1 = TFalse+type instance  DigitEq DB D1 = TFalse+type instance  DigitEq DC D1 = TFalse+type instance  DigitEq DD D1 = TFalse+type instance  DigitEq DE D1 = TFalse+type instance  DigitEq DF D1 = TFalse+type instance  DigitEq D0 D2 = TFalse+type instance  DigitEq D1 D2 = TFalse+type instance  DigitEq D2 D2 = TTrue+type instance  DigitEq D3 D2 = TFalse+type instance  DigitEq D4 D2 = TFalse+type instance  DigitEq D5 D2 = TFalse+type instance  DigitEq D6 D2 = TFalse+type instance  DigitEq D7 D2 = TFalse+type instance  DigitEq D8 D2 = TFalse+type instance  DigitEq D9 D2 = TFalse+type instance  DigitEq DA D2 = TFalse+type instance  DigitEq DB D2 = TFalse+type instance  DigitEq DC D2 = TFalse+type instance  DigitEq DD D2 = TFalse+type instance  DigitEq DE D2 = TFalse+type instance  DigitEq DF D2 = TFalse+type instance  DigitEq D0 D3 = TFalse+type instance  DigitEq D1 D3 = TFalse+type instance  DigitEq D2 D3 = TFalse+type instance  DigitEq D3 D3 = TTrue+type instance  DigitEq D4 D3 = TFalse+type instance  DigitEq D5 D3 = TFalse+type instance  DigitEq D6 D3 = TFalse+type instance  DigitEq D7 D3 = TFalse+type instance  DigitEq D8 D3 = TFalse+type instance  DigitEq D9 D3 = TFalse+type instance  DigitEq DA D3 = TFalse+type instance  DigitEq DB D3 = TFalse+type instance  DigitEq DC D3 = TFalse+type instance  DigitEq DD D3 = TFalse+type instance  DigitEq DE D3 = TFalse+type instance  DigitEq DF D3 = TFalse+type instance  DigitEq D0 D4 = TFalse+type instance  DigitEq D1 D4 = TFalse+type instance  DigitEq D2 D4 = TFalse+type instance  DigitEq D3 D4 = TFalse+type instance  DigitEq D4 D4 = TTrue+type instance  DigitEq D5 D4 = TFalse+type instance  DigitEq D6 D4 = TFalse+type instance  DigitEq D7 D4 = TFalse+type instance  DigitEq D8 D4 = TFalse+type instance  DigitEq D9 D4 = TFalse+type instance  DigitEq DA D4 = TFalse+type instance  DigitEq DB D4 = TFalse+type instance  DigitEq DC D4 = TFalse+type instance  DigitEq DD D4 = TFalse+type instance  DigitEq DE D4 = TFalse+type instance  DigitEq DF D4 = TFalse+type instance  DigitEq D0 D5 = TFalse+type instance  DigitEq D1 D5 = TFalse+type instance  DigitEq D2 D5 = TFalse+type instance  DigitEq D3 D5 = TFalse+type instance  DigitEq D4 D5 = TFalse+type instance  DigitEq D5 D5 = TTrue+type instance  DigitEq D6 D5 = TFalse+type instance  DigitEq D7 D5 = TFalse+type instance  DigitEq D8 D5 = TFalse+type instance  DigitEq D9 D5 = TFalse+type instance  DigitEq DA D5 = TFalse+type instance  DigitEq DB D5 = TFalse+type instance  DigitEq DC D5 = TFalse+type instance  DigitEq DD D5 = TFalse+type instance  DigitEq DE D5 = TFalse+type instance  DigitEq DF D5 = TFalse+type instance  DigitEq D0 D6 = TFalse+type instance  DigitEq D1 D6 = TFalse+type instance  DigitEq D2 D6 = TFalse+type instance  DigitEq D3 D6 = TFalse+type instance  DigitEq D4 D6 = TFalse+type instance  DigitEq D5 D6 = TFalse+type instance  DigitEq D6 D6 = TTrue+type instance  DigitEq D7 D6 = TFalse+type instance  DigitEq D8 D6 = TFalse+type instance  DigitEq D9 D6 = TFalse+type instance  DigitEq DA D6 = TFalse+type instance  DigitEq DB D6 = TFalse+type instance  DigitEq DC D6 = TFalse+type instance  DigitEq DD D6 = TFalse+type instance  DigitEq DE D6 = TFalse+type instance  DigitEq DF D6 = TFalse+type instance  DigitEq D0 D7 = TFalse+type instance  DigitEq D1 D7 = TFalse+type instance  DigitEq D2 D7 = TFalse+type instance  DigitEq D3 D7 = TFalse+type instance  DigitEq D4 D7 = TFalse+type instance  DigitEq D5 D7 = TFalse+type instance  DigitEq D6 D7 = TFalse+type instance  DigitEq D7 D7 = TTrue+type instance  DigitEq D8 D7 = TFalse+type instance  DigitEq D9 D7 = TFalse+type instance  DigitEq DA D7 = TFalse+type instance  DigitEq DB D7 = TFalse+type instance  DigitEq DC D7 = TFalse+type instance  DigitEq DD D7 = TFalse+type instance  DigitEq DE D7 = TFalse+type instance  DigitEq DF D7 = TFalse+type instance  DigitEq D0 D8 = TFalse+type instance  DigitEq D1 D8 = TFalse+type instance  DigitEq D2 D8 = TFalse+type instance  DigitEq D3 D8 = TFalse+type instance  DigitEq D4 D8 = TFalse+type instance  DigitEq D5 D8 = TFalse+type instance  DigitEq D6 D8 = TFalse+type instance  DigitEq D7 D8 = TFalse+type instance  DigitEq D8 D8 = TTrue+type instance  DigitEq D9 D8 = TFalse+type instance  DigitEq DA D8 = TFalse+type instance  DigitEq DB D8 = TFalse+type instance  DigitEq DC D8 = TFalse+type instance  DigitEq DD D8 = TFalse+type instance  DigitEq DE D8 = TFalse+type instance  DigitEq DF D8 = TFalse+type instance  DigitEq D0 D9 = TFalse+type instance  DigitEq D1 D9 = TFalse+type instance  DigitEq D2 D9 = TFalse+type instance  DigitEq D3 D9 = TFalse+type instance  DigitEq D4 D9 = TFalse+type instance  DigitEq D5 D9 = TFalse+type instance  DigitEq D6 D9 = TFalse+type instance  DigitEq D7 D9 = TFalse+type instance  DigitEq D8 D9 = TFalse+type instance  DigitEq D9 D9 = TTrue+type instance  DigitEq DA D9 = TFalse+type instance  DigitEq DB D9 = TFalse+type instance  DigitEq DC D9 = TFalse+type instance  DigitEq DD D9 = TFalse+type instance  DigitEq DE D9 = TFalse+type instance  DigitEq DF D9 = TFalse+type instance  DigitEq D0 DA = TFalse+type instance  DigitEq D1 DA = TFalse+type instance  DigitEq D2 DA = TFalse+type instance  DigitEq D3 DA = TFalse+type instance  DigitEq D4 DA = TFalse+type instance  DigitEq D5 DA = TFalse+type instance  DigitEq D6 DA = TFalse+type instance  DigitEq D7 DA = TFalse+type instance  DigitEq D8 DA = TFalse+type instance  DigitEq D9 DA = TFalse+type instance  DigitEq DA DA = TTrue+type instance  DigitEq DB DA = TFalse+type instance  DigitEq DC DA = TFalse+type instance  DigitEq DD DA = TFalse+type instance  DigitEq DE DA = TFalse+type instance  DigitEq DF DA = TFalse+type instance  DigitEq D0 DB = TFalse+type instance  DigitEq D1 DB = TFalse+type instance  DigitEq D2 DB = TFalse+type instance  DigitEq D3 DB = TFalse+type instance  DigitEq D4 DB = TFalse+type instance  DigitEq D5 DB = TFalse+type instance  DigitEq D6 DB = TFalse+type instance  DigitEq D7 DB = TFalse+type instance  DigitEq D8 DB = TFalse+type instance  DigitEq D9 DB = TFalse+type instance  DigitEq DA DB = TFalse+type instance  DigitEq DB DB = TTrue+type instance  DigitEq DC DB = TFalse+type instance  DigitEq DD DB = TFalse+type instance  DigitEq DE DB = TFalse+type instance  DigitEq DF DB = TFalse+type instance  DigitEq D0 DC = TFalse+type instance  DigitEq D1 DC = TFalse+type instance  DigitEq D2 DC = TFalse+type instance  DigitEq D3 DC = TFalse+type instance  DigitEq D4 DC = TFalse+type instance  DigitEq D5 DC = TFalse+type instance  DigitEq D6 DC = TFalse+type instance  DigitEq D7 DC = TFalse+type instance  DigitEq D8 DC = TFalse+type instance  DigitEq D9 DC = TFalse+type instance  DigitEq DA DC = TFalse+type instance  DigitEq DB DC = TFalse+type instance  DigitEq DC DC = TTrue+type instance  DigitEq DD DC = TFalse+type instance  DigitEq DE DC = TFalse+type instance  DigitEq DF DC = TFalse+type instance  DigitEq D0 DD = TFalse+type instance  DigitEq D1 DD = TFalse+type instance  DigitEq D2 DD = TFalse+type instance  DigitEq D3 DD = TFalse+type instance  DigitEq D4 DD = TFalse+type instance  DigitEq D5 DD = TFalse+type instance  DigitEq D6 DD = TFalse+type instance  DigitEq D7 DD = TFalse+type instance  DigitEq D8 DD = TFalse+type instance  DigitEq D9 DD = TFalse+type instance  DigitEq DA DD = TFalse+type instance  DigitEq DB DD = TFalse+type instance  DigitEq DC DD = TFalse+type instance  DigitEq DD DD = TTrue+type instance  DigitEq DE DD = TFalse+type instance  DigitEq DF DD = TFalse+type instance  DigitEq D0 DE = TFalse+type instance  DigitEq D1 DE = TFalse+type instance  DigitEq D2 DE = TFalse+type instance  DigitEq D3 DE = TFalse+type instance  DigitEq D4 DE = TFalse+type instance  DigitEq D5 DE = TFalse+type instance  DigitEq D6 DE = TFalse+type instance  DigitEq D7 DE = TFalse+type instance  DigitEq D8 DE = TFalse+type instance  DigitEq D9 DE = TFalse+type instance  DigitEq DA DE = TFalse+type instance  DigitEq DB DE = TFalse+type instance  DigitEq DC DE = TFalse+type instance  DigitEq DD DE = TFalse+type instance  DigitEq DE DE = TTrue+type instance  DigitEq DF DE = TFalse+type instance  DigitEq D0 DF = TFalse+type instance  DigitEq D1 DF = TFalse+type instance  DigitEq D2 DF = TFalse+type instance  DigitEq D3 DF = TFalse+type instance  DigitEq D4 DF = TFalse+type instance  DigitEq D5 DF = TFalse+type instance  DigitEq D6 DF = TFalse+type instance  DigitEq D7 DF = TFalse+type instance  DigitEq D8 DF = TFalse+type instance  DigitEq D9 DF = TFalse+type instance  DigitEq DA DF = TFalse+type instance  DigitEq DB DF = TFalse+type instance  DigitEq DC DF = TFalse+type instance  DigitEq DD DF = TFalse+type instance  DigitEq DE DF = TFalse+type instance  DigitEq DF DF = TTrue++type family    DigitsEq xs          ys+type instance  DigitsEq TNil        TNil        = TTrue+type instance  DigitsEq (x ::: xs)  TNil        = TFalse+type instance  DigitsEq TNil        (x ::: xs)  = TFalse+type instance  DigitsEq (x ::: xs)  (y ::: ys)  = TAnd (DigitEq x y) (DigitsEq xs ys)++-- vim:set sw=4 ts=4 expandtab:
+ Generator/Array.hs view
@@ -0,0 +1,47 @@+--
+-- Define instance members (Candidates and Invoker), 
+--        constructors (Candidates and Invoker),
+--        properties, and
+--        supertypes (SupertypesOf)
+-- for all array types, in terms of the System.Array members they inherit.
+--
+-- Note that .NET arrays have no static members.
+--
+
+-- Instance methods for arrays are the same as the System.Array instance methods:
+type instance Candidates (Obj (Arr t)) member = Candidates (Obj Array_) member
+
+-- Delegate all array instance method invocations to System.Array:
+instance Invoker (Obj Array_) m args => Invoker (Obj (Arr t)) m args where
+  type Result (Obj (Arr t)) m args = Result (Obj Array_) m args
+  rawInvoke t m args = rawInvoke (convert t :: Obj Array_) m args
+
+
+-- There is one constructor for single-dimensional arrays which just calls the
+-- static Array.CreateInstance method passing the appropriate type and length:
+type instance Candidates (Arr t) Ctor = (Int32 ::: TNil) ::: TNil
+instance Typeable t => Invoker (Arr t) Ctor (Int32) where
+  type Result (Arr t) Ctor (Int32) = IO (Obj (Arr t))
+  rawInvoke t m (len) = liftM cast $ _Array # _createInstance (typeOf (undefined :: t), len)
+
+
+-- Delegate all array instance property gets/sets to System.Array:
+instance Prop (Obj Array_) pn => Prop (Obj (Arr t)) pn where
+  type PropGT (Obj (Arr t)) pn = PropGT (Obj Array_) pn
+  getProp t = getProp (convert t :: Obj Array_)
+  type PropST (Obj (Arr t)) pn = PropST (Obj Array_) pn
+  setProp t = setProp (convert t :: Obj Array_)
+
+-- All arrays derive directly from System.Array:
+type instance SupertypesOf (Obj (Arr t)) = (Obj Array_) ::: SupertypesOf (Obj Array_)
+
+
+-- Define the type code of single-dimension arrays in terms of the underlying
+-- element type:
+type instance TyCode (Obj (Arr t)) = D0 ::: DF ::: TyCode t
+-- (Note the use of 'DF' to separate the type code of the element from the type code 
+-- of arrays in general.)
+
+-- EXPERIMENTAL:
+type instance FromTyCode (D0 ::: DF ::: t) = Obj (Arr (FromTyCode t))
+
+ Generator/Generator.cs view
@@ -0,0 +1,1326 @@+//
+// Salsa Binding Generator
+//
+// Copyright: (c) 2007-2008 Andrew Appleyard
+// Licence:   BSD3 (see LICENSE)
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Reflection;
+using System.Linq;
+
+namespace Generator
+{
+    class Generator
+    {
+        static void Main(string[] args)
+        {
+            if (args.Length == 0)
+            {
+                Console.WriteLine("Usage: {0} [input-files]",
+                    Path.GetFileName(Environment.GetCommandLineArgs()[0]));
+            }
+            else
+                new Generator().Run(args);
+        }
+
+        private TextWriter w;
+
+        private Set<string> _labels = new Set<string>();
+        private Set<string> _invokers = new Set<string>();
+
+        /// <summary>
+        /// Instead of using long strings for identifiers inside the binding, we generate 
+        /// shorter, unique ids using this dictionary.
+        /// </summary>
+        private Dictionary<string, long> _uniqueIds = new Dictionary<string, long>();
+
+        private int _typeCodeMaxValue = 15;
+        private int _typeCodeValue = 7; // Leave first 7 codes available for primitive types
+
+        /// <summary>
+        /// Set of types that are required by the types generated so far.
+        /// </summary>
+        private Set<Type> _requiredTypes = new Set<Type>();
+
+        /// <summary>
+        /// Set of types that have been generated so far.
+        /// </summary>
+        private Set<Type> _generatedTypes = new Set<Type>();
+
+        /// <summary>
+        /// Set of types that were originally requested to be generated.
+        /// </summary>
+        private Set<Type> _requestedTypes = new Set<Type>();
+
+        private Dictionary<Type, List<string>> _requestedMembers = new Dictionary<Type, List<string>>();
+
+        private long GetUnique(params string[] keys)
+        {
+            string key = Util.Join("\0", keys); // Combine the keys
+            long id;
+            if (_uniqueIds.TryGetValue(key, out id))
+                return id;
+            else
+            {
+                id = _uniqueIds.Count + 1;
+                _uniqueIds.Add(key, id);
+                return id;
+            }
+        }
+
+        /// <summary>
+        /// Returns a unique type-level list of booleans, which can be used as a type code.
+        /// </summary>
+        private string GetNextTypeCode()
+        {
+            const int encodingBase = 15; 
+            // Note: This is not 16, thus leaving 'DF' available to use as a delimiter in type codes
+            //       for parameterised types (like arrays).
+
+            // Build a string for type code (as a Haskell type)
+            StringBuilder s = new StringBuilder();
+            int x = _typeCodeValue;
+            int b = _typeCodeMaxValue;
+            while (b > 1)
+            {
+                s.AppendFormat("{0} ::: ", 
+                    new string[] { 
+                        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", 
+                        "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF" }[x % encodingBase]);
+                x /= encodingBase;
+                b /= encodingBase; 
+            }
+            s.Append("TNil");
+
+            // Obtain the next type code
+            _typeCodeValue += 1;
+            if (_typeCodeValue == _typeCodeMaxValue)
+            {
+                _typeCodeValue = 0;
+                _typeCodeMaxValue *= encodingBase;
+            }
+
+            return s.ToString();
+        }
+
+        private void RequestAll(Type t)
+        {
+            _requestedTypes.Add(t);
+
+            List<string> ms;// = new List<string>();
+            if (!_requestedMembers.TryGetValue(t, out ms))
+                ms = new List<string>();
+
+            foreach (MemberInfo mi in t.GetMembers(BindingFlags.Public |
+                BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
+                ms.Add(mi.Name);  
+
+            _requestedMembers[t] = ms;
+        }
+
+        private void Request(Type t, params string[] members)
+        {
+            _requestedTypes.Add(t);
+
+            List<string> ms;// = new List<string>();
+            if (!_requestedMembers.TryGetValue(t, out ms))
+                ms = new List<string>();
+            ms.AddRange(members);
+            _requestedMembers[t] = ms;
+        }
+
+        /// <summary>
+        /// Returns true iff the given member 'm' in type 't' has been requested,
+        /// either directly or indirectly (i.e. if 'm' is inherited from a 
+        /// requested member).
+        /// </summary>
+        private bool IsMemberRequested(Type targetType, string m)
+        {
+            List<string> ms;
+
+            foreach (Type t in EnumerateAncestors(targetType))
+            {
+                // Was the member requested in a supertype?
+                if (_requestedMembers.TryGetValue(t, out ms))
+                {
+                    if (ms.Contains(m))
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        private void ReadImports(string path)
+        {
+            List<Assembly> references = new List<Assembly>();
+            references.Add(Assembly.GetAssembly(typeof(object)));
+
+            using (StreamReader r = File.OpenText(path))
+            {
+                string line;
+                while ((line = r.ReadLine()) != null)
+                {
+                    if (line.Trim() == string.Empty) continue;
+                    if (line.StartsWith("--") || line.StartsWith("#"))
+                        continue;
+
+                    string[] sides = line.Split(new char[] { ':', ' ', '\t' }, 2,
+                        StringSplitOptions.RemoveEmptyEntries);
+
+
+                    if (sides[0] == "reference")
+                    {
+                        if (sides.Length != 2)
+                            throw new Exception("Must specify assembly name after 'reference'");
+                        references.Add(Assembly.LoadFile(Path.GetFullPath(sides[1])));
+                    }
+                    else
+                    {
+                        string[] members;
+                        if (sides.Length > 1)
+                            members = sides[1].Split(new char[] { ',', ' ', '\t' },
+                                StringSplitOptions.RemoveEmptyEntries);
+                        else
+                            members = new string[0];
+
+                        bool foundType = false;
+                        foreach (Assembly a in references)
+                        {
+                            Type t = a.GetType(sides[0]);
+                            if (t != null)
+                            {
+                                if (members.Length > 0 && members[0] == "*")
+                                    RequestAll(t);
+                                else
+                                    Request(t, members);
+                                foundType = true;
+                                break;
+                            }
+                        }
+
+                        if (!foundType)
+                            throw new Exception(string.Format(
+                                "The type '{0}' does not exist (are you missing an assembly reference?)",
+                                sides[0]));
+                    }
+                }
+            }
+        }
+
+        private void Run(string[] args)
+        {
+            string outputPath = @".";
+
+            foreach (string arg in args)
+                ReadImports(arg);
+
+            // Require System.Array (the base class of all arrays), and its
+            // CreateInstance method, because the Salsa library uses it to 
+            // instantiate arrays.
+            Request(typeof(System.Array), "CreateInstance");
+
+            using (w = File.CreateText(Path.Combine(outputPath, "Bindings.hs")))
+            {
+                // Explicitly request all supertypes too (since their members are inherited 
+                // by the requested types)
+                foreach (Type requestedType in Enumerable.ToList(_requestedTypes))
+                {
+                    foreach (Type superRequestedType in EnumerateAncestors(requestedType))
+                    {
+                        _requestedTypes.Add(superRequestedType);
+                        
+                        if (_requestedMembers.ContainsKey(requestedType))
+                            Request(superRequestedType, _requestedMembers[requestedType].ToArray());
+                    }
+                }
+
+                foreach (Type requestedType in _requestedTypes)
+                {
+                    RequireType(requestedType);
+                    if (!_requestedMembers.ContainsKey(requestedType))
+                        _requestedMembers.Add(requestedType, new List<string>());
+                }
+
+                w.WriteLine("{-# LANGUAGE ForeignFunctionInterface, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, TypeOperators, TypeSynonymInstances #-}");
+                w.WriteLine("{-# OPTIONS_GHC -fallow-undecidable-instances #-}");
+
+                w.WriteLine("module {0} (", "Bindings");
+                w.WriteLine("  module Labels");
+                w.WriteLine("  ) where");
+                w.WriteLine();
+                w.WriteLine("import Labels");
+                w.WriteLine("import Foreign.Salsa.Binding");
+
+                while (_requiredTypes.Count > 0)
+                {
+                    Type t = _requiredTypes.Pop();
+                    if (_generatedTypes.Contains(t)) continue; // Already generated
+
+                    if (IsUnsupportedType(t)) continue;
+                    if (IsPrim(t)) continue; // TODO: Support boxed primitive types later.
+
+                    Console.WriteLine("Binding " + t.ToString());
+                    WriteClass(t);
+
+                    _generatedTypes.Add(t);
+                }
+
+                Console.WriteLine("Generated bindings for {0} classes", _generatedTypes.Count);
+            }
+
+            using (w = File.CreateText(Path.Combine(outputPath, "Labels.hs")))
+            {
+                w.WriteLine("module Labels where");
+                w.WriteLine("import Foreign.Salsa (invoke)");
+                w.WriteLine();
+                WriteLabels();
+                WriteInvokers();
+            }
+        }
+
+        /// <summary>
+        /// Indicates that a particular type should be generated (if it hasn't
+        /// already been generated).
+        /// </summary>
+        private void RequireType(Type t)
+        {
+            if (!_generatedTypes.Contains(t))
+                _requiredTypes.Add(t);
+        }
+
+        private void WriteClass(Type targetType)
+        {
+            if (targetType.IsArray)
+            {
+                // Explicit bindings for array types are not generated by the code generator.
+                // We only need to generate bindings for the element type, the base type
+                // (System.Array) (which is always generated) and the parameterised 'Arr t'
+                // type (see end of this method).
+
+                // Require the element type of the array
+                RequireType(targetType.GetElementType());
+
+                return;
+            }
+
+            string classLabel = TypeToLabel(targetType);
+
+            w.WriteLine();
+            w.WriteLine("--");
+            w.WriteLine("-- Class: {0}", targetType.FullName);
+            w.WriteLine("--");
+            w.WriteLine();
+
+
+            //
+            // Write a Salsa.Typeable instance for this class
+            //
+            // Note: Type.GetType always returns the same instance for a given type, so it is 
+            //       safe to use 'unsafePerformIO' below.
+            //
+            w.WriteLine("instance Typeable {0} where", classLabel);
+            w.WriteLine("  typeOf _ = unsafePerformIO $ type_GetType \"{0}\"", targetType.AssemblyQualifiedName);
+            w.WriteLine();
+
+            // TODO: Cache result of 'typeOf' in an IORef?
+
+            {
+                //
+                // Instance and static methods
+                //
+                {
+                    // Build a list of relevant instance methods for the target class.
+                    // Filter out 'override' methods and 'get/set/add/remove' methods.
+                    // Also filter out methods with the same name and signature in a base 
+                    // class (i.e. hide by signature).
+                    List<MemberInfo> relevantMethods = new List<MemberInfo>();
+
+                    // Go down the inheritance tree from object to the target type
+                    foreach (Type implementedType in Enumerable.Reverse(EnumerateAncestors(targetType)))
+                    {
+                        foreach (MethodInfo mi in implementedType.GetMethods(
+                            BindingFlags.DeclaredOnly | BindingFlags.Public |
+                            BindingFlags.Instance | BindingFlags.Static))
+                        {
+                            if (mi.IsSpecialName) continue; // Skip get/set/add/remove methods
+
+                            // Skip overridden (virtual but not a new slot) methods
+                            if (mi.IsVirtual && (mi.Attributes & MethodAttributes.NewSlot) == 0) continue;
+
+                            // Ignore methods containing parameters of unsupported types, or an 
+                            // unsupported result type
+                            if (IsUnsupportedType(mi.ReturnType) ||
+                                Enumerable.Any(mi.GetParameters(),
+                                    delegate(ParameterInfo pi) { return IsUnsupportedType(pi.ParameterType); }))
+                                continue;
+
+                            // Remove any methods (from base classes) with this name and signature
+                            // (i.e. implement hide-by-signature semantics, like C#)
+                            relevantMethods.RemoveAll(delegate(MemberInfo mi2)
+                            {
+                                return HasSameSignature((MethodInfo)mi, (MethodInfo)mi2);
+                            });
+
+                            relevantMethods.Add(mi);
+                        }
+                    }
+
+                    // Enumerate over the method groups in the relevant instance methods,
+                    // generating bindings for each group
+                    foreach (IGrouping<string, MemberInfo> mg in Enumerable.GroupBy<MemberInfo, string>(
+                        relevantMethods, delegate(MemberInfo mi)
+                        {
+                            return (((MethodInfo)mi).IsStatic ? "static " : "") + mi.Name;
+                        }))
+                    {
+                        if (!IsMemberRequested(targetType, Enumerable.First(mg).Name)) continue;
+
+                        w.WriteLine("-- " + mg.Key);
+
+                        WriteMethodGroup(mg, targetType);
+                    }
+                }
+
+                //
+                // Constructors
+                //
+                if (typeof(Delegate).IsAssignableFrom(targetType))
+                {
+                    // Delegate constructors are special, since they accept a normal 
+                    // Haskell function as an argument
+                    WriteDelegateConstructor(targetType);
+                }
+                else
+                {
+                    // Build a list of relevant constructors for the target class (if any)
+                    List<ConstructorInfo> relevantConstructors = new List<ConstructorInfo>();
+                    foreach (ConstructorInfo ci in targetType.GetConstructors())
+                    {
+                        // Ignore methods containing parameters of unsupported types
+                        if (Enumerable.Any(ci.GetParameters(),
+                            delegate(ParameterInfo pi) { return IsUnsupportedType(pi.ParameterType); }))
+                            continue;
+
+                        relevantConstructors.Add(ci);
+                    }
+
+                    if (relevantConstructors.Count > 0)
+                    {
+                        // Generate bindings for the constructors (treated as a single method group)
+                        w.WriteLine("-- Constructors");
+                        WriteConstructorGroup(relevantConstructors, targetType);
+                        w.WriteLine();
+                    }
+                }
+
+                //
+                // Instance and static properties
+                //
+                {
+                    // Build a list accessors for accessable, non-indexed, properties in the target class
+                    List<AccessorInfo<PropertyInfo>> relevantPropertyAccessors =
+                        new List<AccessorInfo<PropertyInfo>>();
+
+                    // Go down the inheritance tree from object to the target type
+                    foreach (Type implementedType in Enumerable.Reverse(EnumerateAncestors(targetType)))
+                    {
+                        foreach (PropertyInfo pi in implementedType.GetProperties(
+                            BindingFlags.DeclaredOnly | BindingFlags.Public |
+                            BindingFlags.Instance | BindingFlags.Static))
+                        {
+                            // Ignore indexed properties (since they're currently out of scope, FIXME)
+                            if (pi.GetIndexParameters().Length > 0)
+                                continue;
+
+                            // Ignore properties of unsupported types
+                            if (IsUnsupportedType(pi.PropertyType)) continue;
+
+                            foreach (MethodInfo mi in pi.GetAccessors())
+                            {
+                                // Skip static properties declared outside of the target type
+                                AccessorInfo<PropertyInfo> ai = new AccessorInfo<PropertyInfo>(
+                                    mi == pi.GetGetMethod() ? AccessorType.Get : AccessorType.Set,
+                                    pi, mi);
+
+                                // Remove any shadowed properties (from base classes)
+                                relevantPropertyAccessors.RemoveAll(
+                                    delegate(AccessorInfo<PropertyInfo> ai2)
+                                    {
+                                        return HasSameSignature(ai.Accessor, ai2.Accessor);
+                                    });
+
+                                relevantPropertyAccessors.Add(ai);
+                            }
+                        }
+                    }
+
+                    // Enumerate over the properties and generate attribute bindings for each
+                    // pair of get/set accessors
+                    foreach (IGrouping<string, AccessorInfo<PropertyInfo>> mg in
+                        Enumerable.GroupBy<AccessorInfo<PropertyInfo>, string>(
+                            relevantPropertyAccessors,
+                            delegate(AccessorInfo<PropertyInfo> ai)
+                            {
+                                return (ai.Accessor.IsStatic ? "static " : "") + ai.Owner.Name;
+                            }))
+                    {
+                        if (!IsMemberRequested(targetType, Enumerable.First(mg).Owner.Name)) continue;
+
+                        WriteProperty(mg, targetType);
+                    }
+                }
+
+                //
+                // Static and instance events
+                //
+                {
+                    // Build a list accessors for events in the target class
+                    List<AccessorInfo<EventInfo>> relevantEventAccessors =
+                        new List<AccessorInfo<EventInfo>>();
+
+                    // Go down the inheritance tree from object to the target type
+                    foreach (Type implementedType in Enumerable.Reverse(EnumerateAncestors(targetType)))
+                    {
+                        foreach (EventInfo ei in implementedType.GetEvents(
+                            BindingFlags.DeclaredOnly | BindingFlags.Public |
+                            BindingFlags.Instance | BindingFlags.Static))
+                        {
+                            // Ignore events of unsupported types
+                            if (IsUnsupportedType(ei.EventHandlerType)) continue;
+
+                            foreach (MethodInfo mi in new MethodInfo[] {
+                            ei.GetAddMethod(), ei.GetRemoveMethod() })
+                            {
+                                // Skip static events declared outside of the target type
+                                AccessorInfo<EventInfo> ai = new AccessorInfo<EventInfo>(
+                                    mi == ei.GetAddMethod() ? AccessorType.Add : AccessorType.Remove,
+                                    ei, mi);
+
+                                // Remove any shadowed events (from base classes)
+                                relevantEventAccessors.RemoveAll(
+                                    delegate(AccessorInfo<EventInfo> ai2)
+                                    {
+                                        return HasSameSignature(ai.Accessor, ai2.Accessor);
+                                    });
+
+                                relevantEventAccessors.Add(ai);
+                            }
+                        }
+                    }
+
+                    // Enumerate over the events and generate attribute bindings for each
+                    // pair of add/remove accessors
+                    foreach (IGrouping<string, AccessorInfo<EventInfo>> mg in
+                        Enumerable.GroupBy<AccessorInfo<EventInfo>, string>(
+                            relevantEventAccessors,
+                            delegate(AccessorInfo<EventInfo> ai)
+                            {
+                                return (ai.Accessor.IsStatic ? "static " : "") + ai.Owner.Name;
+                            }))
+                    {
+                        if (!IsMemberRequested(targetType, Enumerable.First(mg).Owner.Name)) continue;
+
+                        WriteEvent(mg, targetType);
+                    }
+                }
+
+                //
+                // Instance and static fields
+                //
+                {
+                    // Build a list accessible fields in the target class
+                    List<FieldInfo> relevantFields = new List<FieldInfo>();
+
+                    // Go down the inheritance tree from object to the target type
+                    foreach (Type implementedType in Enumerable.Reverse(EnumerateAncestors(targetType)))
+                    {
+                        foreach (FieldInfo fi in implementedType.GetFields(
+                            BindingFlags.DeclaredOnly | BindingFlags.Public |
+                            BindingFlags.Instance | BindingFlags.Static))
+                        {
+                            // Ignore fields of unsupported types
+                            if (IsUnsupportedType(fi.FieldType)) continue;
+
+                            // Remove any shadowed fields (from base classes)
+                            relevantFields.RemoveAll(
+                                delegate(FieldInfo fi2)
+                                {
+                                    return fi.Name == fi2.Name;
+                                });
+
+                            relevantFields.Add(fi);
+                        }
+                    }
+
+                    // Enumerate over the fields and generate bindings for each
+                    foreach (FieldInfo fi in relevantFields)
+                    {
+                        if (!IsMemberRequested(targetType, fi.Name)) continue;
+
+                        WriteField(fi, targetType);
+                    }
+                }
+            }
+
+            //
+            // Ancestors
+            //
+
+            List<Type> supertypes = new List<Type>();
+
+            foreach (Type t in EnumerateAncestors(targetType))
+                supertypes.Add(t);
+
+            supertypes.AddRange(targetType.GetInterfaces());
+
+            // Remove any unsupported types from 'supertypes'
+            foreach (Type t in Enumerable.ToList(supertypes))
+            {
+                if (IsUnsupportedType(t))
+                    supertypes.Remove(t);
+            }
+
+            w.WriteLine("type instance SupertypesOf {0} = {1}", 
+                ToHaskellType(targetType),
+                Util.JoinSuffix(" ::: ", Enumerable.Select<Type, string>(supertypes,
+                    delegate(Type t) { return ToHaskellType(t); }), "TNil"));
+
+            foreach (Type supertype in supertypes)
+                RequireType(supertype);
+
+            //
+            // Type code
+            //
+            string typeCode = GetNextTypeCode();
+            w.WriteLine("type instance TyCode {0} = {1}", ToHaskellType(targetType), typeCode);
+            w.WriteLine("type instance FromTyCode ({1}) = {0}", ToHaskellType(targetType), typeCode); // EXPERIMENTAL
+            w.WriteLine();
+
+            if (targetType == typeof(System.Array))
+            {
+                //
+                // Delegate the members of any array type (i.e. any 'Arr t') to System.Array
+                //
+                w.WriteLine();
+                w.WriteLine("--");
+                w.WriteLine("-- 'Arr t' to 'System.Array' delegation code");
+                w.WriteLine("--");
+                w.WriteLine();
+                Console.WriteLine(string.Join(", ", Assembly.GetExecutingAssembly().GetManifestResourceNames()));
+                using (StreamReader r = new StreamReader(
+                    Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof(Generator), "Array.hs")))
+                {
+                    string line;
+                    while ((line = r.ReadLine()) != null)
+                        w.WriteLine(line);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Generates bindings for a delegate constructor for the given delegate type.
+        /// </summary>
+        private void WriteDelegateConstructor(Type delegateType)
+        {
+            string classLabel = TypeToLabel(delegateType);
+
+            w.WriteLine();
+            w.WriteLine("--");
+            w.WriteLine("-- Delegate: {0}", delegateType.Name);
+            w.WriteLine("--");
+            w.WriteLine();
+
+            if (delegateType != typeof(Delegate) &&
+                delegateType != typeof(MulticastDelegate))
+            {
+                ConstructorInfo constructorCi = delegateType.GetConstructors()[0];
+                MethodInfo invokerMi = delegateType.GetMethod("Invoke");
+
+                string target = TypeToLabel(delegateType);
+
+                string stubFunction = ToStubName(constructorCi);
+                string wrapperFunction = "wrap_" + stubFunction;
+                string wrapperType = "Type_" + wrapperFunction;
+
+                ParameterInfo[] parameters = GetParameters(invokerMi);
+
+                // Generate the base type signature for Haskell implementation of the delegate
+                w.WriteLine("type {0} = {1}", wrapperType,
+                    Util.JoinSuffix(" -> ", Enumerable.Select<ParameterInfo, string>(parameters,
+                        delegate(ParameterInfo pi) { return ToBaseType(pi.ParameterType); }),
+                        ToBaseReturnType(GetMemberReturnType(invokerMi))));
+
+                w.WriteLine("foreign import stdcall \"wrapper\" {0} :: {1} -> (IO (FunPtr {1}))",
+                    wrapperFunction, wrapperType);
+                w.WriteLine();
+
+                // Generate the delegate-object-generating stub function
+                w.WriteLine("{{-# NOINLINE {0} #-}}", stubFunction);
+                w.WriteLine("{0} :: {1} -> IO ObjectId", stubFunction, wrapperType);
+                w.WriteLine("{0} = unsafePerformIO $ getDelegateConstructorStub", stubFunction);
+                w.WriteLine("    \"{0}\"", delegateType.AssemblyQualifiedName);
+                w.WriteLine("    {0}", wrapperFunction);
+                w.WriteLine();
+
+                // Generate the 'delegate' instance for calling the delegate constructor
+                w.WriteLine("instance Delegate {0} where", target);
+                w.WriteLine("    type DelegateT {0} = {1}", target,
+                    Util.JoinSuffix(" -> ", Enumerable.Select<ParameterInfo, string>(parameters,
+                        delegate(ParameterInfo pi) { return ToHaskellType(pi.ParameterType); }),
+                        ToReturnType(GetMemberReturnType(invokerMi))));
+                w.WriteLine("    delegate _ handler = {0} (marshalFn{1} handler) >>= unmarshal",
+                    stubFunction, parameters.Length);
+                w.WriteLine();
+            }
+
+            w.WriteLine();
+        }
+        
+        /// <summary>
+        /// Generates bindings for a method group containing: all instance methods,
+        /// all static methods, or all instance constructors.
+        /// </summary>
+        private void WriteMethodGroup(IEnumerable<MemberInfo> members, Type forType)
+        {
+            MemberInfo firstMi = Enumerable.First(members);
+
+            Console.WriteLine("  {0}", firstMi.Name);
+
+            ParameterInfo[] parameters = GetParameters(firstMi);
+            Type returnType = GetMemberReturnType(firstMi);
+            bool isStatic = IsMemberStatic(firstMi);
+
+            string label = GetMemberLabel(firstMi);
+            string target = isStatic ? TypeToLabel(forType) : ToHaskellType(forType);
+
+            // Output the parameter lists for the members of the method group
+            w.WriteLine("type instance Candidates {0} {1} = {2}",
+                target, label,
+                Util.JoinSuffix(" ::: ", Enumerable.Select<MemberInfo, string>(members,
+                    delegate(MemberInfo mi) { return ToListType(GetParameters(mi)); }), "TNil"));
+
+            // Output instances for invoking each method group member
+            foreach (MemberInfo mi in members)
+                WriteMethod(mi, forType);
+            w.WriteLine();
+
+            // Require the return type of this method
+            RequireType(returnType);
+        }
+
+        /// <summary>
+        /// Generates bindings for a group of instance constructors.
+        /// </summary>
+        private void WriteConstructorGroup(IEnumerable<ConstructorInfo> members, Type forType)
+        {
+            ConstructorInfo firstCi = Enumerable.First(members);
+            string target = TypeToLabel(forType);
+            string label = "Ctor";
+
+            // Output the parameter lists for the constructors
+            w.WriteLine("type instance Candidates {0} {1} = {2}",
+                target, label,
+                Util.JoinSuffix(" ::: ", Enumerable.Select<ConstructorInfo, string>(members,
+                    delegate(ConstructorInfo ci) { return ToListType(ci.GetParameters()); }), "TNil"));
+
+            // Output instances for invoking each constructor
+            foreach (ConstructorInfo ci in members)
+                WriteMethod(ci, forType);
+        }
+
+        /// <summary>
+        /// Generate bindings for a static method, instance method, or instance constructor,
+        /// for use in a particular class (which, in the case of an instance method, may be a
+        /// descendant of the class in which the method was declared).
+        /// </summary>
+        private void WriteMethod(MemberInfo mi, Type forType)
+        {
+            // If the method was declared on the target type (forType), then produce
+            // the FFI stub function (which is called by Invoker instances down the
+            // hierarchy)
+            if (mi.DeclaringType == forType)
+                WriteMethodStub(mi);
+
+            // Invoker instance:
+            w.WriteLine("instance Invoker {0} {1} {2} where",
+                IsMemberStatic(mi) ? TypeToLabel(forType) : ToHaskellType(forType),
+                GetMemberLabel(mi), ToTupleType(GetParameters(mi)));
+            w.WriteLine("  type Result {0} {1} {2} = {3}",
+                IsMemberStatic(mi) ? TypeToLabel(forType) : ToHaskellType(forType),
+                GetMemberLabel(mi), ToTupleType(GetParameters(mi)),
+                ToReturnType(GetMemberReturnType(mi)));
+            w.WriteLine("  rawInvoke = {0}", ToMethodMarshaler(mi));
+
+            // Require any parameter types for this method/constructor
+            foreach (ParameterInfo pi in GetParameters(mi))
+                RequireType(pi.ParameterType);
+        }
+        
+        /// <summary>
+        /// Returns true iff the given member should be treated as a static member.
+        /// Static methods, static properties, and instance constructors are all
+        /// treated as static members.
+        /// </summary>
+        private bool IsMemberStatic(MemberInfo mi)
+        {
+            if (mi is ConstructorInfo)
+                return true;
+            if (mi is MethodInfo)
+                return ((MethodInfo)mi).IsStatic;
+            if (mi is FieldInfo)
+                return ((FieldInfo)mi).IsStatic;
+            throw new ArgumentException("Expected a ConstructorInfo, MethodInfo or FieldInfo.");
+        }
+
+        /// <summary>
+        /// Returns the Haskell code for a function that calls the given method, 
+        /// constructor, or property accessor, marshaling the arguments and result 
+        /// value as necessary.
+        /// </summary>
+        private string ToMethodMarshaler(MemberInfo mi)
+        {
+            return string.Format("marshalMethod{0}{1} {2}",
+                GetParameters(mi).Length, IsMemberStatic(mi) ? "s" : "i",
+                ToStubName(mi));
+        }
+
+        /// <summary>
+        /// Generates an FFI stub function for calling a particular .NET method
+        /// or property accessor.
+        /// </summary>
+        private void WriteMethodStub(MemberInfo mi)
+        {
+            // TODO: Perhaps use unboxed string literals?
+
+            string stubFunction = ToStubName(mi);
+            string stubType = "Type_" + stubFunction;
+            string makeFunction = "make_" + stubFunction;
+
+            w.WriteLine();
+            w.WriteLine("-- Foreign Interface Stub for {0}.{1}:",
+                mi.DeclaringType.Name, mi.Name);
+            w.WriteLine("type {0} = {1}{2}", stubType,
+                IsMemberStatic(mi) ? "" : (ToBaseType(mi.DeclaringType) + " -> "),
+                Util.JoinSuffix(" -> ", Enumerable.Select<ParameterInfo, string>(GetParameters(mi),
+                    delegate(ParameterInfo pi) { return ToBaseType(pi.ParameterType); }),
+                    ToBaseReturnType(GetMemberReturnType(mi))));
+            w.WriteLine("foreign import stdcall \"dynamic\" {0} :: FunPtr {1} -> {1}",
+                makeFunction, stubType);
+            w.WriteLine();
+            w.WriteLine("{{-# NOINLINE {0} #-}}", stubFunction);
+            w.WriteLine("{0} :: {1}", stubFunction, stubType);
+            w.WriteLine("{0} = {1} $ unsafePerformIO $ getMethodStub", stubFunction, makeFunction);
+            w.WriteLine("    \"{0}\" \"{1}\"", mi.DeclaringType.AssemblyQualifiedName, mi.Name);
+            w.WriteLine("    \"{0}\"",
+                Util.Join(";", Enumerable.Select<ParameterInfo, string>(GetParameters(mi),
+                    delegate(ParameterInfo pi) { return ToQualifiedType(pi.ParameterType); })));
+            w.WriteLine();
+        }
+
+        /// <summary>
+        /// Generates FFI stub functions for retrieving or setting a particular .NET field.
+        /// </summary>
+        private void WriteFieldStub(FieldInfo fi, AccessorType accessorType)
+        {
+            bool isGet = (accessorType == AccessorType.Get);
+            string stubFunction = ToStubName(fi) + "_" + (isGet ? "get" : "set");
+            string stubType = "Type_" + stubFunction;
+            string makeFunction = "make_" + stubFunction;
+
+            w.WriteLine();
+            w.WriteLine("-- Field accessor stub for {0}.{1}:", fi.DeclaringType.Name, fi.Name);
+            w.WriteLine("type {0} = {1}{2}{3}", 
+                stubType,
+                fi.IsStatic ? "" : (ToBaseType(fi.DeclaringType) + " -> "),
+                isGet ? "" : (ToBaseType(fi.FieldType) + " -> "),
+                isGet ? ToBaseReturnType(fi.FieldType) : "IO ()");
+
+            w.WriteLine("foreign import stdcall \"dynamic\" {0} :: FunPtr {1} -> {1}",
+                makeFunction, stubType);
+
+            w.WriteLine();
+            w.WriteLine("{{-# NOINLINE {0} #-}}", stubFunction);
+            w.WriteLine("{0} :: {1}", stubFunction, stubType);
+            w.WriteLine("{0} = {1} $ unsafePerformIO $ {2}", stubFunction, makeFunction,
+                isGet ? "getFieldGetStub" : "getFieldSetStub");
+            w.WriteLine("    \"{0}\" \"{1}\"", fi.DeclaringType.AssemblyQualifiedName, fi.Name);
+            w.WriteLine();
+        }
+
+        private void WriteProperty(IEnumerable<AccessorInfo<PropertyInfo>> accessors, Type forType)
+        {
+            AccessorInfo<PropertyInfo> firstAccessor = Enumerable.First(accessors);
+            bool isStatic = IsMemberStatic(firstAccessor.Accessor);
+
+            string target = isStatic ? TypeToLabel(forType) : ToHaskellType(forType);
+            string label = ToLabelType(firstAccessor.Owner.Name);
+
+            w.WriteLine("instance Prop {0} {1} where", target, label);
+
+            AccessorInfo<PropertyInfo> getAccessor = Enumerable.FirstOrDefault(accessors,
+                delegate(AccessorInfo<PropertyInfo> ai) { return ai.Type == AccessorType.Get; });
+            AccessorInfo<PropertyInfo> setAccessor = Enumerable.FirstOrDefault(accessors,
+                delegate(AccessorInfo<PropertyInfo> ai) { return ai.Type == AccessorType.Set; });
+
+            if (getAccessor != null)
+            {
+                w.WriteLine("    type PropGT {0} {1} = {2}", target, label,
+                    ToHaskellType(getAccessor.Owner.PropertyType));
+                w.WriteLine("    getProp t pn = {0} t pn ()", ToMethodMarshaler(getAccessor.Accessor));
+            }
+            else
+            {
+                w.WriteLine("    type PropGT {0} {1} = ()", target, label);
+                w.WriteLine("    getProp _ _ = return ()"); // Return nothing
+            }
+
+            if (setAccessor != null)
+            {
+                w.WriteLine("    type PropST {0} {1} = {2}", target, label,
+                    ToHaskellType(setAccessor.Owner.PropertyType));
+                w.WriteLine("    setProp = {0}", ToMethodMarshaler(setAccessor.Accessor));
+            }
+            else
+            {
+                w.WriteLine("    type PropST {0} {1} = ()", target, label);
+                w.WriteLine("    setProp _ _ _ = return ()"); // Do nothing
+            }
+            
+            foreach (AccessorInfo<PropertyInfo> accessor in accessors)
+            {
+                // Generate the get/set stub caller (in declared type only)
+                if (accessor.Accessor.DeclaringType == forType)
+                    WriteMethodStub(accessor.Accessor);
+            }
+
+            w.WriteLine();
+        }
+
+        private void WriteEvent(IEnumerable<AccessorInfo<EventInfo>> accessors, Type forType)
+        {
+            AccessorInfo<EventInfo> firstAccessor = Enumerable.First(accessors);
+            bool isStatic = IsMemberStatic(firstAccessor.Accessor);
+
+            string target = isStatic ? TypeToLabel(forType) : ToHaskellType(forType);
+            string label = ToLabelType(firstAccessor.Owner.Name);
+
+            w.WriteLine("instance Event {0} {1} where", target, label);
+            w.WriteLine("    type EventT {0} {1} = {2}", target, label,
+                ToHaskellType(firstAccessor.Owner.EventHandlerType));
+
+            foreach (AccessorInfo<EventInfo> accessor in accessors)
+            {
+                if (accessor.Type == AccessorType.Add)
+                    w.WriteLine("    addEvent    = {0}", ToMethodMarshaler(accessor.Accessor));
+                else // AccessorType.Remove
+                    w.WriteLine("    removeEvent = {0}", ToMethodMarshaler(accessor.Accessor));
+            }
+
+            foreach (AccessorInfo<EventInfo> accessor in accessors)
+            {
+                // Generate the add/remove stub caller (in declared type only)
+                if (accessor.Accessor.DeclaringType == forType)
+                    WriteMethodStub(accessor.Accessor);
+            }
+
+            w.WriteLine();
+
+            // Require the event type of this event
+            RequireType(firstAccessor.Owner.EventHandlerType);
+        }
+
+        private void WriteField(FieldInfo field, Type forType)
+        {
+            bool isStatic = field.IsStatic;
+            bool isReadOnly = field.IsLiteral || field.IsInitOnly;
+
+            // TODO: Add support for literal fields.  The constant value from
+            //       the metadata should be included in the generated code.
+
+            string target = isStatic ? TypeToLabel(forType) : ToHaskellType(forType);
+            string label = ToLabelType(field.Name);
+
+            w.WriteLine("instance Prop {0} {1} where", target, label);
+
+            w.WriteLine("    type PropGT {0} {1} = {2}", target, label, ToHaskellType(field.FieldType));
+            w.WriteLine("    getProp t pn = marshalMethod0{0} {1}_get t pn ()",
+                isStatic ? "s" : "i", ToStubName(field));
+
+            if (!isReadOnly)
+            {
+                w.WriteLine("    type PropST {0} {1} = {2}", target, label, ToHaskellType(field.FieldType));
+                w.WriteLine("    setProp = marshalMethod1{0} {1}_set", 
+                    isStatic ? "s" : "i", ToStubName(field));
+            }
+            else
+            {
+                w.WriteLine("    type PropST {0} {1} = ()", target, label);
+                w.WriteLine("    setProp _ _ _ = return ()"); // Do nothing
+            }
+
+            // Generate the get/set stub caller (in declared type only)
+            if (field.DeclaringType == forType)
+            {
+                if (!isReadOnly)
+                    WriteFieldStub(field, AccessorType.Set);
+                WriteFieldStub(field, AccessorType.Get);
+            }
+
+            // For readonly fields, generate an IO-less method getting the value
+            if (isReadOnly)
+            {
+                // Ensure that an invoker is generated for invoking the label with '#'
+                ToInvoker(field.Name);
+
+                w.WriteLine("type instance Candidates {0} {1} = TNil ::: TNil", target, label);
+
+                w.WriteLine("instance Invoker {0} {1} () where", target, label);
+                w.WriteLine("  type Result {0} {1} () = {2}", target, label, ToHaskellType(field.FieldType));
+                w.WriteLine("  rawInvoke t m () = unsafePerformIO $ get t m ");
+            }
+
+            w.WriteLine();
+        }
+
+        private string ToHaskellType(Type t)
+        {
+            if (t == typeof(void)) return "()";
+            if (t == typeof(int)) return "Int32";
+            if (t == typeof(string)) return "String";
+            if (t == typeof(bool)) return "Bool";
+            if (t == typeof(Double)) return "Double";
+            if (t == typeof(bool?)) return "(Maybe Bool)";
+            if (t.IsArray) 
+                return string.Format("(Obj (Arr {0}))", ToHaskellType(t.GetElementType()));
+            return "(Obj " + TypeToLabel(t) + ")";
+        }
+
+        private string ToReturnType(Type t)
+        {
+            return "IO " + ToHaskellType(t);
+        }
+
+        /// <summary>
+        /// Gives the low-level Haskell type for the given .NET type 't'.  This is the
+        /// base type used in FFI declarations.
+        /// </summary>
+        private string ToBaseType(Type t)
+        {
+            if (t == typeof(void)) return "()";
+            if (t == typeof(Int32)) return "Int32";
+            if (t == typeof(String)) return "CWString";
+            if (t == typeof(Boolean)) return "Bool";
+            if (t == typeof(Double)) return "Double";
+            return "ObjectId";
+        }
+
+        private string ToBaseReturnType(Type t)
+        {
+            return "IO " + ToBaseType(t);
+        }
+
+        private bool IsPrim(Type t)
+        {
+            return
+                t == typeof(void) ||
+                t == typeof(Int32) ||
+                t == typeof(String) ||
+                t == typeof(Boolean) ||
+                t == typeof(Double);
+        }
+
+        private bool IsUnsupportedType(Type t)
+        {
+            return
+                t.Name.StartsWith("_") ||
+                t.IsByRef ||        // FIXME: Support this?
+                t.IsPointer ||
+                // Salsa doesn't support generic types yet, but there's a special case for Nullable<bool>
+                (t.IsGenericType && t != typeof(Nullable<bool>)) ||
+                t.IsGenericParameter ||
+                // Salsa only supports arrays of non-generic types at present
+                (t.IsArray && IsUnsupportedType(t.GetElementType()));
+        }
+
+        /// <summary>
+        /// Returns a tuple of high-level Haskell types corresponding to the given
+        /// list of method parameters.
+        /// </summary>
+        private string ToTupleType(ParameterInfo[] ts)
+        {
+            return "(" + Util.Join(", ", Enumerable.Select<ParameterInfo, string>(ts,
+                delegate(ParameterInfo pi) { return ToHaskellType(pi.ParameterType); } )) + ")";
+        }
+
+        /// <summary>
+        /// Returns a type-level list of high-level Haskell types corresponding to 
+        /// the given list of method parameters.
+        /// </summary>
+        private string ToListType(ParameterInfo[] ts)
+        {
+            return "(" + Util.JoinSuffix(" ::: ", Enumerable.Select<ParameterInfo, string>(ts,
+                delegate(ParameterInfo pi) { return ToHaskellType(pi.ParameterType); } ), "TNil") + ")";
+        }
+
+        /// <summary>
+        /// Returns the name of the raw FFI stub method associated with the given .NET method
+        /// or constructor.  There is a unique stub name for every declared method overload,
+        /// and constructor.
+        /// </summary>
+        private string ToStubName(MemberInfo mi)
+        {
+            string parameterDetails = "";
+            if (mi is ConstructorInfo || mi is MethodInfo)
+                parameterDetails = Util.Join(" ", Enumerable.Select<ParameterInfo, string>(GetParameters(mi),
+                        delegate(ParameterInfo pi) { return pi.ParameterType.AssemblyQualifiedName; }));
+
+            return string.Format("stub_{0}",
+                GetUnique("stub",
+                    mi.DeclaringType.AssemblyQualifiedName,
+                    mi.Name,
+                    parameterDetails));
+        }
+
+        /// <summary>
+        /// Returns the name of the FFI wrapper function that is used to wrap Haskell 
+        /// functions that implement the given .NET delegate type.
+        /// </summary>
+        private string ToWrapperName(Type dt)
+        {
+            return string.Format("wrap_{0}",
+                GetUnique("wrap", dt.AssemblyQualifiedName));
+        }
+
+        /// <summary>
+        /// Returns a string that uniquely identifies the given type.  It is 
+        /// used to retrieve stub functions for the particular type at runtime.
+        /// </summary>
+        private string ToQualifiedType(Type t)
+        {
+            // Unless the type is in mscorlib, use the (long) assembly qualified name
+            if (t.Assembly == typeof(object).Assembly)
+                return t.FullName;
+            else
+                return t.AssemblyQualifiedName;
+        }
+
+        private ParameterInfo[] GetParameters(MemberInfo mi)
+        {
+            if (mi is MethodInfo)
+                return ((MethodInfo)mi).GetParameters();
+            if (mi is ConstructorInfo)
+                return ((ConstructorInfo)mi).GetParameters();
+            throw new ArgumentException("Must be a MethodInfo or ConstructorInfo.", "mi");
+        }
+
+        private Type GetMemberReturnType(MemberInfo mi)
+        {
+            if (mi is MethodInfo)
+                return ((MethodInfo)mi).ReturnType;
+            if (mi is ConstructorInfo)
+                return ((ConstructorInfo)mi).DeclaringType;
+            throw new ArgumentException("Must be a MethodInfo or ConstructorInfo.", "mi");
+        }
+
+        private string GetMemberLabel(MemberInfo mi)
+        {
+            if (mi is MethodInfo)
+                return MethodToLabel((MethodInfo)mi);
+            if (mi is ConstructorInfo)
+                return "Ctor";
+            throw new ArgumentException("Must be a MethodInfo or ConstructorInfo.", "mi");
+        }
+
+        /// <summary>
+        /// Returns true iff the given methods have the same name, number and type of 
+        /// parameters.
+        /// </summary>
+        private bool HasSameSignature(MethodInfo mi1, MethodInfo mi2)
+        {
+            if (mi1.Name != mi2.Name) return false;
+            ParameterInfo[] pi1 = mi1.GetParameters();
+            ParameterInfo[] pi2 = mi2.GetParameters();
+            if (pi1.Length != pi2.Length) return false;
+            for (int i = 0; i < pi1.Length; i++)
+            {
+                if (pi1[i].ParameterType != pi2[i].ParameterType)
+                    return false;
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns an irrefutable Haskell pattern for matching a value of the given type.
+        /// 'index' is included in the identified used (if any).
+        /// </summary>
+        private string ToPattern(Type t, int index)
+        {
+            if (t == typeof(void)) return "()";
+            if (t == typeof(int) || t == typeof(bool) || t == typeof(string))
+                return string.Format("a{0}", index);
+            return string.Format("(Obj a{0})", index);
+        }
+
+        /// <summary>
+        /// Enumerate ancestors of 't', starting with 't' and finishing with object.
+        /// </summary>
+        private IEnumerable<Type> EnumerateAncestors(Type t)
+        {
+            while (t != null)
+            {
+                yield return t;
+                t = t.BaseType;
+            }
+        }
+
+        private string MethodToLabel(MethodInfo mi)
+        {
+            ToInvoker(mi.Name);
+            return ToLabelType(mi.Name);
+        }
+
+        private string TypeToLabel(Type t)
+        {
+            if (IsUnsupportedType(t)) return ToLabelType("NotSupported"); 
+
+            if (t.IsNested && t.DeclaringType != null)
+            {
+                // FIXME: This only handles one level of nested classes 
+                //        (and it doesn't handle nested generic types)
+                return ToLabelType(t.DeclaringType.Name + "_" + t.Name);
+            }
+            else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
+            {
+                return string.Format("(Maybe {0})", TypeToLabel(t.GetGenericArguments()[0]));
+            }
+            else
+                return ToLabelType(t.Name);
+        }
+
+        private string ToLabelHelper(string s)
+        {
+            if (string.IsNullOrEmpty(s))
+                throw new ArgumentException("Expected non-empty string.");
+            s = char.ToUpper(s[0]) + s.Substring(1);
+            if (!_labels.Contains(s) && 
+                s != "Object" && s != "Type" && s != "Array") // These labels are defined in the Salsa library
+                _labels.Add(s);
+            return s;
+        }
+
+        private string ToLabelValue(string s)
+        {
+            return "_" + ToLabelHelper(s);
+        }
+
+        private string ToLabelType(string s)
+        {
+            return ToLabelHelper(s) + "_";
+        }
+
+        private void WriteLabels()
+        {
+            w.WriteLine("-- Labels for .NET types, methods, properties, fields and events");
+            foreach (string label in _labels)
+                w.WriteLine("data {0,-25}", ToLabelType(label));
+            w.WriteLine();
+            foreach (string label in _labels)
+                w.WriteLine("{0,-30} = undefined :: {1}", ToLabelValue(label), ToLabelType(label));
+            w.WriteLine();
+        }
+
+        private string ToInvoker(string s)
+        {
+            s = Util.ToLowerFirst(s);
+            if (!_invokers.Contains(s))
+                _invokers.Add(s);
+            return "_" + s;
+        }
+
+        private void WriteInvokers()
+        {
+            w.WriteLine("-- Functions for invoking methods with '#'");
+            foreach (string invoker in _invokers)
+            {
+                // Output an invoker (and a unit invoker, for convenience and consistency)
+                w.WriteLine("{0} args target = invoke target {1} args", ToInvoker(invoker), ToLabelValue(invoker));
+                w.WriteLine("{0}_ target = invoke target {1} ()", ToInvoker(invoker), ToLabelValue(invoker));
+            }
+            w.WriteLine();
+        }
+    }
+
+    public static class Util
+    {
+        public static string Join(string separator, IEnumerable<string> xs)
+        {
+            StringBuilder sb = new StringBuilder();
+            foreach (string x in xs)
+            {
+                sb.Append(x);
+                sb.Append(separator);
+            }
+            if (sb.Length > 0) sb.Length -= separator.Length;
+            return sb.ToString();
+        }
+
+        public static string JoinSuffix(string separator, IEnumerable<string> xs, string end)
+        {
+            StringBuilder sb = new StringBuilder();
+            foreach (string x in xs)
+            {
+                sb.Append(x);
+                sb.Append(separator);
+            }
+            sb.Append(end);
+            return sb.ToString();
+        }
+
+        public static string ToLowerFirst(string s)
+        {
+            if (s == "") return "";
+            return s.Substring(0, 1).ToLower() + s.Substring(1);
+        }
+
+        public static string ToUpperFirst(string s)
+        {
+            if (s == "") return "";
+            return s.Substring(0, 1).ToUpper() + s.Substring(1);
+        }
+    }
+
+    public class AccessorInfo<T> where T : MemberInfo
+    {
+        private AccessorType _type;
+        private T _owner;
+        private MethodInfo _accessor;
+
+        public AccessorInfo(AccessorType type, T owner, MethodInfo accessor)
+        {
+            _type = type;
+            _owner = owner;
+            _accessor = accessor;
+        }
+
+        public AccessorType Type
+        {
+            get { return _type; }
+        }
+
+        public MethodInfo Accessor
+        {
+            get { return _accessor; }
+        }
+
+        public T Owner
+        {
+            get { return _owner; }
+        }
+    }
+
+    public enum AccessorType { Get, Set, Add, Remove };
+}
+ Generator/Generator.csproj view
@@ -0,0 +1,92 @@+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{53648C35-67B5-4903-999C-54B19F4DEE75}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Generator</RootNamespace>
+    <AssemblyName>Generator</AssemblyName>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>2.0</OldToolsVersion>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Generator.cs" />
+    <Compile Include="Set.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Array.hs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
+ Generator/README view
@@ -0,0 +1,33 @@+
+                           The Salsa Binding Generator
+
+  Generates Haskell modules (called 'Bindings' and 'Labels') that together
+  contain the binding code required to interface with specific .NET classes and
+  their members.  An import file provides a list of the classes and their
+  assemblies.
+
+Usage:
+
+  Generator.exe Project.imports
+
+  where 'Project.imports' is a file that lists (on separate lines):
+
+    * The classes to import (optionally followed by a comma-separated list of
+      the members from the class to import).  For example:
+
+      System.Environment                  (binds all members of the Environment
+                                           class)
+
+      System.Console: Write, WriteLine    (binds only the Write and WriteLine
+                                           methods of the Console class)
+
+    * The assemblies that hold the imported classes.  For example:
+
+      reference C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll
+
+      (to make a reference to the .NET 2.0 System assembly)
+
+Building:
+
+  Run 'msbuild' in the 'Generator' directory.
+
+ Generator/Set.cs view
@@ -0,0 +1,61 @@+//
+// Salsa Binding Generator
+//
+// Copyright: (c) 2007-2008 Andrew Appleyard
+// Licence:   BSD3 (see LICENSE)
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Generator
+{
+    public class Set<T> : IEnumerable<T>
+    {
+        private Dictionary<T, object> _store = new Dictionary<T, object>();
+
+        public void Add(T v)
+        {
+            if (!_store.ContainsKey(v))
+                _store.Add(v, null);
+        }
+
+        public int Count
+        {
+            get { return _store.Count; }
+        }
+
+        public bool Contains(T v)
+        {
+            return _store.ContainsKey(v);
+        }
+
+        /// <summary>
+        /// Removes an item from the set and returns it.
+        /// </summary>
+        public T Pop()
+        {
+            foreach (T v in _store.Keys)
+            {
+                _store.Remove(v);
+                return v;
+            }
+            throw new InvalidOperationException("Set is empty.");
+        }
+
+        #region IEnumerable<T> implementation
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return _store.Keys.GetEnumerator();
+        }
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return _store.Keys.GetEnumerator();
+        }
+
+        #endregion
+    }
+}
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2007-2008, Andrew Appleyard.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * The name of the copyright holder may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README view
@@ -0,0 +1,77 @@+
+                      Salsa: a .NET bridge for Haskell
+                     
+  Salsa is an experimental Haskell library and code generator that allows
+  Haskell programs to host the .NET runtime and interact with .NET libraries.
+  It uses type families extensively to provide a type-safe mapping of the .NET
+  object model in the Haskell type system.
+
+What's in the package:
+
+  * 'Foreign' contains the Haskell library 'Foreign.Salsa'.  
+
+    This library provides the Haskell-side interface to Salsa, including:
+    functions to load the .NET runtime into the process, functions for
+    interacting with .NET classes and objects, and the required type-level
+    machinery.  It works together with the Haskell modules created by the
+    generator (see below) to provide access to .NET classes and their members.
+
+  * 'Driver' contains the Salsa .NET driver assembly (Salsa.dll).
+
+    The driver assembly contains .NET code that is loaded automatically by the
+    Salsa library when the .NET runtime is loaded into the process.  It
+    provides run-time code generation facilities for calling in and out of the
+    .NET runtime from Haskell.  The assembly binary (Salsa.dll) is embedded in
+    'Foreign\Salsa\Driver.hs' using the 'Embed.hs' utility program.
+
+  * 'Generator' contains the Salsa binding generator.
+
+    The generator is a C# program that creates Haskell modules from .NET
+    metadata to provide type-safe access to the requested .NET classes and
+    methods in .NET assembilies.
+    
+    Note: the generator requires .NET 3.5 because it uses the 'System.Linq'
+          namespace.
+
+  * 'Samples' contains a few Haskell programs that use Salsa.
+
+    - Hello:   a basic console 'Hello World' program.
+
+    - Weather: a console program that asynchronously downloads the Sydney
+               weather forecast and displays it.
+
+    - Conway:  a simulator for Conway's Game of Life with a Windows
+               Presentation Foundation GUI.  (Requires .NET 3.0 or later.)
+
+Requirements:
+
+  * GHC 6.8
+  
+    Salsa makes extensive use of type families and thus requires at least
+    version 6.8 of GHC.
+
+  * Microsoft .NET Framework 3.5
+
+    Since the Generator requires .NET 3.5, any Salsa development also requires
+    this version.  Executables produced with Salsa however will run with just
+    .NET 2.0 (provided that only .NET 2.0 assemblies are used by the program).
+
+    Salsa will not work with versions 1.0/1.1 of the .NET Framework, or with
+    Mono.  (Supporting Mono shouldn't be too much work though.)
+
+Building:
+
+  Build the Salsa library using Cabal (version 1.2) as usual:
+
+    runhaskell Setup.hs configure
+    runhaskell Setup.hs build
+    runhaskell Setup.hs install
+
+  The generator, driver, and each of the samples can be built with MSBuild;
+  just run 'msbuild' in the appropriate directory.  (The msbuild binary can be
+  found in '%WINDIR%\Microsoft.NET\Framework\v2.0.50272').
+
+Author:
+
+  Andrew Appleyard
+
+ Salsa.cabal view
@@ -0,0 +1,70 @@+Cabal-Version:  >= 1.2
+
+Name:           Salsa
+Version:        0.1.0.1
+Build-Type:     Simple
+
+Category:       Foreign
+Synopsis:       A .NET Bridge for Haskell
+Description:
+  Salsa is an experimental Haskell library and code generator that allows
+  Haskell programs to host the .NET runtime and interact with .NET libraries.
+  It uses type families extensively to provide a type-safe mapping of the .NET
+  object model in the Haskell type system.
+
+Author:         Andrew Appleyard
+Maintainer:     andrew.appleyard@gmail.com
+Homepage:       http://haskell.org/haskellwiki/Salsa
+
+License:        BSD3
+License-File:   LICENSE
+Copyright:      (c) 2007-2008 Andrew Appleyard
+
+Stability:      Experimental
+Tested-With:    GHC==6.8.3
+
+Extra-Source-Files:
+  README
+
+  Driver/README
+  Driver/Driver.proj
+  Driver/Driver.cs
+  Driver/Embed.hs
+
+  Generator/README
+  Generator/Generator.csproj
+  Generator/Generator.cs
+  Generator/Set.cs
+  Generator/Array.hs
+
+  Samples/Hello/Hello.proj
+  Samples/Hello/Hello.hs
+  Samples/Hello/Hello.imports
+
+  Samples/Weather/Weather.proj
+  Samples/Weather/Weather.hs
+  Samples/Weather/Weather.imports
+
+  Samples/Conway/Conway.proj
+  Samples/Conway/Conway.hs
+  Samples/Conway/Conway.imports
+  Samples/Conway/Conway.xaml
+
+  Docs/Thesis.pdf
+
+Library
+  Build-Depends: base, Win32, bytestring
+
+  Exposed-modules:
+    Foreign.Salsa
+    Foreign.Salsa.Binding
+
+  Other-Modules:
+    Foreign.Salsa.CLR, Foreign.Salsa.CLRHost, Foreign.Salsa.Common,
+    Foreign.Salsa.Core, Foreign.Salsa.Resolver, Foreign.Salsa.TypePrelude,
+    Foreign.Salsa.Driver
+
+  Extra-Libraries: oleaut32, ole32
+
+  Extensions: ForeignFunctionInterface
+
+ Samples/Conway/Conway.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE PatternSignatures, FlexibleContexts #-}+module Main where++import Foreign.Salsa+import Bindings++import Control.Monad+import Data.Array+import Data.Maybe++loadXaml :: Coercible (Obj Object_) a => String -> IO a+loadXaml xamlPath = do+    uri <- new _Uri (xamlPath, _UriKind # _relative_)+    streamInfo <- _Application # _getRemoteStream (uri)+    xamlReader <- new _XamlReader ()+    stream     <- get streamInfo _Stream+    get streamInfo _Stream >>= \s -> xamlReader # _loadAsync s >>= cast++-- | @'neighbors' states cell@ is the number of alive cells adjacent to @cell@ in @states@.+neighbors :: Array (Int,Int) Bool -> (Int,Int) -> Int+neighbors states (row,col) =+    length $ filter (== True) [ states ! cell | cell <- neighborCells ]+    where +        neighborCells = [ wrap (r,c) | r <- [row-1..row+1],+                                       c <- [col-1..col+1],+                                       wrap (r,c) /= (row,col) ]+        wrap (r,c) = (r `mod` (maxRow+1), c `mod` (maxCol+1))+        (_, (maxRow,maxCol)) = bounds states++step :: Array (Int,Int) (Obj ToggleButton_) -> IO ()+step buttons = do+    buttonStates <- mapM (\b -> get b _IsChecked) (elems buttons)+    let states = listArray (bounds buttons) (map fromJust buttonStates)+    sequence_ $ do+        cell <- indices states+        let state' = case neighbors states cell of+                        2         -> Nothing    -- unchanged+                        3         -> Just True  -- comes to life+                        otherwise -> Just False -- dies+        case state' of+            Nothing   -> mzero+            otherwise -> return $ set (buttons ! cell) [ _IsChecked :== state' ]++main :: IO ()+main = withCLR $ do+    win :: Obj Window_ <- loadXaml "/Conway.xaml"++    -- Build an array of toggle buttons in 'grid'+    grid :: Obj UniformGrid_ <- win # _findName ("grid") >>= cast+    let (rows,cols) = (12,20)+    set grid [_Columns :== fromIntegral cols]+    buttonList <- sequence $ replicate (rows * cols) $ do+        b <- new _ToggleButton ()+        get grid _Children >>=# _add (b)+        return b+    let buttons = listArray ((0,0),(rows-1,cols-1)) buttonList++    timer <- new _DispatcherTimer ()+    set timer [_Tick     :+> delegate _EventHandler (\_ _ -> step buttons),+               _Interval :=> _TimeSpan # _fromSeconds (0.1::Double)]++    runButton :: Obj ToggleButton_ <- win # _findName ("runButton") >>= cast+    set runButton [_Click :+> delegate _RoutedEventHandler+        (\_ _ -> do Just run <- get runButton _IsChecked+                    if run then timer # _start ()+                           else timer # _stop ())]++    clearButton :: Obj Button_ <- win # _findName ("clearButton") >>= cast+    set clearButton [_Click :+> delegate _RoutedEventHandler+        (\_ _ -> mapM_ (flip set [ _IsChecked :== Just False ]) (elems buttons))]+        +    exitButton :: Obj Button_ <- win # _findName ("exitButton") >>= cast+    set exitButton [_Click :+> delegate _RoutedEventHandler (\_ _ -> win # _close_)]+    +    app <- new _Application ()+    app # _run (win)++    return ()++-- vim:set sw=4 ts=4 expandtab:
+ Samples/Conway/Conway.imports view
@@ -0,0 +1,49 @@+reference C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll+reference C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationCore.dll+reference C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationFramework.dll +reference C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll++System.Windows.Controls.Primitives.ToggleButton: IsChecked++System.Windows.Threading.DispatcherTimer: Tick, Interval, Start, Stop, IsEnabled++System.Uri+System.UriKind: *+System.Windows.Markup.XamlReader: LoadAsync+System.Windows.Resources.StreamResourceInfo: Stream ++System.Windows.Media.Pen+System.Windows.Point+System.Windows.Media.GeometryGroup: Children+System.Windows.Media.Geometry+System.Windows.Media.LineGeometry+System.Windows.Media.EllipseGeometry: RadiusX, RadiusY+System.Windows.Media.GeometryCollection: Add, Clear+System.Windows.Media.RectangleGeometry+System.Windows.Media.CombinedGeometry: GeometryCombineMode+System.Windows.Media.GeometryDrawing: Geometry, Brush, Pen+System.Windows.Media.DrawingImage: Freeze+System.Windows.Controls.Image: Source, Stretch+System.Windows.Media.Stretch: None+System.Windows.Media.GeometryCombineMode: *+System.Windows.Application: Run, GetRemoteStream+System.Windows.Window: Title, Top, Close+System.Windows.Controls.Button: Click+System.Windows.Controls.Primitives.ToggleButton: Click+System.Windows.Controls.ContentControl: Content+System.Windows.Controls.StackPanel+System.Windows.Controls.Primitives.UniformGrid: Columns+System.Windows.Controls.Panel: Children+System.Windows.Controls.UIElementCollection: Add+System.Windows.Duration+System.TimeSpan: FromSeconds+System.Windows.Media.Colors: Red, Black+System.Windows.Media.Brushes: Red, Black, Green+System.Windows.Media.SolidColorBrush: ColorProperty+System.Windows.Media.Animation.ColorAnimation+System.Windows.Media.Animation.RepeatBehavior: Forever+System.Windows.Media.Animation.Animatable: BeginAnimation+System.Windows.Media.Animation.Timeline: AutoReverse, RepeatBehavior+System.Windows.FrameworkElement: Width, Height, FindName+System.Windows.Controls.Control: BackgroundProperty, Background+System.Windows.RoutedEventHandler
+ Samples/Conway/Conway.proj view
@@ -0,0 +1,49 @@+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Module>Conway</Module>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Generate Include="$(Module).imports" />
+  </ItemGroup>
+  <ItemGroup>
+    <BindingFiles Include="Bindings.hs;Labels.hs" />
+  </ItemGroup>
+  <ItemGroup>
+    <IntermediateFiles Include="*.hi;*.o" />
+  </ItemGroup>
+
+  <!-- Build the 'Generator' program if necessary -->
+  <Target Name="BuildGenerator">
+    <MSBuild Projects="..\..\Generator\Generator.csproj"
+             ContinueOnError="false"
+             Properties="Configuration=Release">
+      <Output TaskParameter="TargetOutputs" ItemName="Generator" />
+    </MSBuild>
+  </Target>
+
+  <!-- Call 'Generator' to create the binding files from the import files -->
+  <Target Name="GenerateBindings" 
+          Inputs="@(Generate);@(Generator)"
+          Outputs="@(BindingFiles)"
+          DependsOnTargets="BuildGenerator">
+    <Exec Command="@(Generator) @(Generate)" />
+  </Target>
+
+  <!-- Run GHC to build the main program -->
+  <Target Name="Build"
+          DependsOnTargets="GenerateBindings">
+    <Exec Command="ghc --make $(Module) -fglasgow-exts -threaded" />
+  </Target>
+
+  <Target Name="Clean" >
+    <Delete Files="$(Module).exe" />
+    <Delete Files="$(Module).exe.manifest" />
+    <Delete Files="@(BindingFiles)" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.c')" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.h')" />
+    <Delete Files="@(IntermediateFiles)" />
+  </Target>
+
+  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
+</Project>
+ Samples/Conway/Conway.xaml view
@@ -0,0 +1,59 @@+<Window +    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"+    Title="Game of Life" Width="424" Height="310">++  <Window.Resources>+    <LinearGradientBrush x:Key="alive">+      <GradientStop Color="White" Offset="0.0" />+      <GradientStop Color="Black" Offset="1.0" />+    </LinearGradientBrush>+    <RadialGradientBrush x:Key="dead">+      <GradientStop Color="Transparent" Offset="0.0" />+      <GradientStop Color="White"       Offset="0.1" />+      <GradientStop Color="Transparent" Offset="0.1" />+    </RadialGradientBrush>+  </Window.Resources>++  <Window.Background>+    <LinearGradientBrush>+      <GradientStop Color="White" Offset="0.0" />+      <GradientStop Color="Gray" Offset="1.0" />+    </LinearGradientBrush>+  </Window.Background>++  <DockPanel Margin="2">+    <DockPanel DockPanel.Dock="Bottom" Margin="2" LastChildFill="False">+      <ToggleButton Name="runButton" DockPanel.Dock="Left" Width="60"+                    Margin="0,0,4,0" FontWeight="Bold">_Run!</ToggleButton>+      <Button Name="clearButton" DockPanel.Dock="Left" Width="60">_Clear</Button>+      <Button Name="exitButton" DockPanel.Dock="Right" Width="60">E_xit</Button>+    </DockPanel>+    <UniformGrid x:Name="grid" Margin="2">+      <UniformGrid.Resources>+        <Style TargetType="{x:Type ToggleButton}">+          <Style.Triggers>+            <Trigger Property="ToggleButton.IsChecked" Value="True">+              <Setter Property="Background" Value="White" />+              <Setter Property="Foreground" Value="{StaticResource alive}" />+            </Trigger>+          </Style.Triggers>+          <Setter Property="Foreground" Value="Transparent" />+          <Setter Property="Background" Value="{StaticResource dead}" />+          <Setter Property="Template">+            <Setter.Value>+              <ControlTemplate>+                <Rectangle Fill="{TemplateBinding Background}"+                           Stroke="{TemplateBinding Foreground}"+                           RadiusX="2" RadiusY="2"+                           Margin="1" />+              </ControlTemplate>+            </Setter.Value>+          </Setter>+        </Style>+      </UniformGrid.Resources>+      <!-- Insert ToggleButton's in Haskell code -->+    </UniformGrid>+  </DockPanel>+</Window>+<!-- vim:set ts=2 sw=2 expandtab syntax=xml: -->
+ Samples/Hello/Hello.hs view
@@ -0,0 +1,14 @@+module Main where++--+-- Displays 'Hello .NET World!' using .NET's Console.WriteLine() method.+--++import Foreign.Salsa+import Bindings++main :: IO ()+main = withCLR $ do+    _Console # _writeLine ("Hello .NET World!")++-- vim:set sw=4 ts=4 expandtab:
+ Samples/Hello/Hello.imports view
@@ -0,0 +1,2 @@+reference C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll+System.Console: WriteLine
+ Samples/Hello/Hello.proj view
@@ -0,0 +1,49 @@+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Module>Hello</Module>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Generate Include="$(Module).imports" />
+  </ItemGroup>
+  <ItemGroup>
+    <BindingFiles Include="Bindings.hs;Labels.hs" />
+  </ItemGroup>
+  <ItemGroup>
+    <IntermediateFiles Include="*.hi;*.o" />
+  </ItemGroup>
+
+  <!-- Build the 'Generator' program if necessary -->
+  <Target Name="BuildGenerator">
+    <MSBuild Projects="..\..\Generator\Generator.csproj"
+             ContinueOnError="false"
+             Properties="Configuration=Release">
+      <Output TaskParameter="TargetOutputs" ItemName="Generator" />
+    </MSBuild>
+  </Target>
+
+  <!-- Call 'Generator' to create the binding files from the import files -->
+  <Target Name="GenerateBindings" 
+          Inputs="@(Generate);@(Generator)"
+          Outputs="@(BindingFiles)"
+          DependsOnTargets="BuildGenerator">
+    <Exec Command="@(Generator) @(Generate)" />
+  </Target>
+
+  <!-- Run GHC to build the main program -->
+  <Target Name="Build"
+          DependsOnTargets="GenerateBindings">
+    <Exec Command="ghc --make $(Module) -fglasgow-exts -threaded" />
+  </Target>
+
+  <Target Name="Clean" >
+    <Delete Files="$(Module).exe" />
+    <Delete Files="$(Module).exe.manifest" />
+    <Delete Files="@(BindingFiles)" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.c')" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.h')" />
+    <Delete Files="@(IntermediateFiles)" />
+  </Target>
+
+  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
+</Project>
+ Samples/Weather/Weather.hs view
@@ -0,0 +1,61 @@+module Main where++--+-- Asynchronously downloads the Sydney weather forecast from the Australian+-- Bureau of Meterology FTP site (using a worker thread) and displays the+-- result.  A progress indicator is displayed during the download.+--++import Control.Concurrent.MVar+import Control.Monad+import System.IO++import Foreign.Salsa+import Bindings++main :: IO ()+main = withCLR $ do+    hSetBuffering stdout NoBuffering++    -- Make an MVar to hold the result of the download when it has completed+    done <- newEmptyMVar ++    -- Create a delegate that accepts a single argument and puts it into the+    -- MVar when called+    finished <- delegate _ParameterizedThreadStart (putMVar done)++    -- Instantiate a WebClient for downloading the weather forecast, and set+    -- the DownloadStringCompleted event to the @downloaded@ function.+    client <- new _WebClient ()+    set client [ _DownloadStringCompleted :+> delegate _DownloadStringCompletedEventHandler downloaded ]++    -- Download the weather forecast asynchronously, using the @finished@+    -- delegate as user state for the handler.+    uri <- new _Uri ("ftp://ftp2.bom.gov.au/anon/gen/fwo/IDN10064.txt")+    client # _downloadStringAsync (uri, cast finished :: Obj Object_)++    putStr "Downloading... |"++    -- Display an animated progress indicator until the MVar is filled+    let wait (c:cs) = do putStr ('\b':[c])+                         _Thread # _sleep (250 :: Int32)+                         isNotDone <- isEmptyMVar done+                         when isNotDone $ wait (cs ++ [c])+                         putStr "\b \n"+    wait "/-\\|"++    -- Display the result from the MVar+    s <- takeMVar done+    s # _toString () >>= putStrLn++downloaded :: Obj Object_ -> Obj DownloadStringCompletedEventArgs_ -> IO ()+downloaded _ e = do+    -- Get the result object (it will be a .NET string instance), and the+    -- finished object delegate (it will be a .NET delegate instance)+    result   <- get e _Result+    finished <- get e _UserState ++    -- Invoke the finished delegate, passing it the result+    (cast $ finished :: Obj ParameterizedThreadStart_) # _invoke result+    +-- vim:set sw=4 ts=4 expandtab:
+ Samples/Weather/Weather.imports view
@@ -0,0 +1,8 @@+reference C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll+System.Console: WriteLine+System.Net.WebClient: DownloadStringAsync, DownloadStringCompleted, DownloadString, DownloadStringCompletedEventHandler+System.Net.DownloadStringCompletedEventArgs: Result, UserState+System.Uri+System.Threading.Thread: Sleep+System.Threading.ParameterizedThreadStart: Invoke+System.Object: ToString
+ Samples/Weather/Weather.proj view
@@ -0,0 +1,49 @@+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Module>Weather</Module>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Generate Include="$(Module).imports" />
+  </ItemGroup>
+  <ItemGroup>
+    <BindingFiles Include="Bindings.hs;Labels.hs" />
+  </ItemGroup>
+  <ItemGroup>
+    <IntermediateFiles Include="*.hi;*.o" />
+  </ItemGroup>
+
+  <!-- Build the 'Generator' program if necessary -->
+  <Target Name="BuildGenerator">
+    <MSBuild Projects="..\..\Generator\Generator.csproj"
+             ContinueOnError="false"
+             Properties="Configuration=Release">
+      <Output TaskParameter="TargetOutputs" ItemName="Generator" />
+    </MSBuild>
+  </Target>
+
+  <!-- Call 'Generator' to create the binding files from the import files -->
+  <Target Name="GenerateBindings" 
+          Inputs="@(Generate);@(Generator)"
+          Outputs="@(BindingFiles)"
+          DependsOnTargets="BuildGenerator">
+    <Exec Command="@(Generator) @(Generate)" />
+  </Target>
+
+  <!-- Run GHC to build the main program -->
+  <Target Name="Build"
+          DependsOnTargets="GenerateBindings">
+    <Exec Command="ghc --make $(Module) -fglasgow-exts -threaded" />
+  </Target>
+
+  <Target Name="Clean" >
+    <Delete Files="$(Module).exe" />
+    <Delete Files="$(Module).exe.manifest" />
+    <Delete Files="@(BindingFiles)" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.c')" />
+    <Delete Files="@(BindingFiles -> '%(Filename)_stub.h')" />
+    <Delete Files="@(IntermediateFiles)" />
+  </Target>
+
+  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
+</Project>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain