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 binary
- Driver/Driver.cs +1146/−0
- Driver/Driver.proj +35/−0
- Driver/Embed.hs +37/−0
- Driver/README +12/−0
- Foreign/Salsa.hs +30/−0
- Foreign/Salsa/Binding.hs +89/−0
- Foreign/Salsa/CLR.hs +278/−0
- Foreign/Salsa/CLRHost.hs +383/−0
- Foreign/Salsa/Common.hs +63/−0
- Foreign/Salsa/Core.hs +446/−0
- Foreign/Salsa/Driver.hs +953/−0
- Foreign/Salsa/Resolver.hs +261/−0
- Foreign/Salsa/TypePrelude.hs +364/−0
- Generator/Array.hs +47/−0
- Generator/Generator.cs +1326/−0
- Generator/Generator.csproj +92/−0
- Generator/README +33/−0
- Generator/Set.cs +61/−0
- LICENSE +26/−0
- README +77/−0
- Salsa.cabal +70/−0
- Samples/Conway/Conway.hs +80/−0
- Samples/Conway/Conway.imports +49/−0
- Samples/Conway/Conway.proj +49/−0
- Samples/Conway/Conway.xaml +59/−0
- Samples/Hello/Hello.hs +14/−0
- Samples/Hello/Hello.imports +2/−0
- Samples/Hello/Hello.proj +49/−0
- Samples/Weather/Weather.hs +61/−0
- Samples/Weather/Weather.imports +8/−0
- Samples/Weather/Weather.proj +49/−0
- Setup.hs +2/−0
+ 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