CompilationUtil.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Compilation / CompilationUtil.cs / 1305376 / CompilationUtil.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 * Code related to the  config section 
 *
 * Copyright (c) 1999 Microsoft Corporation 
 */
namespace System.Web.Compilation {

    using System; 
    using System.Web;
    using System.Configuration; 
    using System.Web.UI; 
    using System.Web.Configuration;
    using System.Web.Hosting; 
    using System.Web.Util;
    using System.Globalization;
    using System.Collections;
    using System.Collections.Generic; 
    using System.CodeDom.Compiler;
    using System.Security; 
    using System.Security.Permissions; 
    using System.Reflection;
 

    internal static class CompilationUtil {

        internal const string CodeDomProviderOptionPath = "system.codedom/compilers/compiler/ProviderOption/"; 
        private const string CompilerDirectoryPath = "CompilerDirectoryPath";
 
        internal static bool IsDebuggingEnabled(HttpContext context) { 
            CompilationSection compConfig = MTConfigUtil.GetCompilationConfig(context);
            return compConfig.Debug; 
        }

        internal static bool IsBatchingEnabled(string configPath) {
            CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 
            return config.Batch;
        } 
 
        internal static int GetRecompilationsBeforeAppRestarts() {
            CompilationSection config = MTConfigUtil.GetCompilationAppConfig(); 
            return config.NumRecompilesBeforeAppRestart;
        }

        internal static CompilerType GetCodeDefaultLanguageCompilerInfo() { 
            return new CompilerType(typeof(Microsoft.VisualBasic.VBCodeProvider), null);
        } 
 
        internal static CompilerType GetDefaultLanguageCompilerInfo(CompilationSection compConfig, VirtualPath configPath) {
            if (compConfig == null) { 
                // Get the  config object
                compConfig = MTConfigUtil.GetCompilationConfig(configPath);
            }
 
            // If no default language was specified in config, use VB
            if (compConfig.DefaultLanguage == null) { 
                return GetCodeDefaultLanguageCompilerInfo(); 
            }
            else { 
                return compConfig.GetCompilerInfoFromLanguage(compConfig.DefaultLanguage);
            }
        }
 
        /*
         * Return a CompilerType that a file name's extension maps to. 
         */ 
        internal static CompilerType GetCompilerInfoFromVirtualPath(VirtualPath virtualPath) {
 
            // Get the extension of the source file to compile
            string extension = virtualPath.Extension;

            // Make sure there is an extension 
            if (extension.Length == 0) {
                throw new HttpException( 
                    SR.GetString(SR.Empty_extension, virtualPath)); 
            }
 
            return GetCompilerInfoFromExtension(virtualPath, extension);
        }

        /* 
         * Return a CompilerType that a extension maps to.
         */ 
        private static CompilerType GetCompilerInfoFromExtension(VirtualPath configPath, string extension) { 
            // Get the  config object
            CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 

            return config.GetCompilerInfoFromExtension(extension, true /*throwOnFail*/);
        }
 
        /*
         * Return a CompilerType that a language maps to. 
         */ 
        internal static CompilerType GetCompilerInfoFromLanguage(VirtualPath configPath, string language) {
            // Get the  config object 
            CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath);

            return config.GetCompilerInfoFromLanguage(language);
        } 

        internal static CompilerType GetCSharpCompilerInfo( 
            CompilationSection compConfig, VirtualPath configPath) { 

            if (compConfig == null) { 
                // Get the  config object
                compConfig = MTConfigUtil.GetCompilationConfig(configPath);
            }
 
            if (compConfig.DefaultLanguage == null)
                return new CompilerType(typeof(Microsoft.CSharp.CSharpCodeProvider), null); 
 
            return compConfig.GetCompilerInfoFromLanguage("c#");
        } 

        internal static CodeSubDirectoriesCollection GetCodeSubDirectories() {
            // Get the  config object
            CompilationSection config = MTConfigUtil.GetCompilationAppConfig(); 

            CodeSubDirectoriesCollection codeSubDirectories = config.CodeSubDirectories; 
 
            // Make sure the config data is valid
            if (codeSubDirectories != null) { 
                codeSubDirectories.EnsureRuntimeValidation();
            }

            return codeSubDirectories; 
        }
 
        internal static long GetRecompilationHash(CompilationSection ps) { 
            HashCodeCombiner recompilationHash = new HashCodeCombiner();
            AssemblyCollection assemblies; 
            BuildProviderCollection builders;
            FolderLevelBuildProviderCollection buildProviders;
            CodeSubDirectoriesCollection codeSubDirs;
 
            // Combine items from Compilation section
            recompilationHash.AddObject(ps.Debug); 
            recompilationHash.AddObject(ps.TargetFramework); 
            recompilationHash.AddObject(ps.Strict);
            recompilationHash.AddObject(ps.Explicit); 
            recompilationHash.AddObject(ps.Batch);
            recompilationHash.AddObject(ps.OptimizeCompilations);
            recompilationHash.AddObject(ps.BatchTimeout);
            recompilationHash.AddObject(ps.MaxBatchGeneratedFileSize); 
            recompilationHash.AddObject(ps.MaxBatchSize);
            recompilationHash.AddObject(ps.NumRecompilesBeforeAppRestart); 
            recompilationHash.AddObject(ps.DefaultLanguage); 
            recompilationHash.AddObject(ps.UrlLinePragmas);
            if (ps.AssemblyPostProcessorTypeInternal != null) { 
                recompilationHash.AddObject(ps.AssemblyPostProcessorTypeInternal.FullName);
            }

            // Combine items from Compilers collection 
            foreach (Compiler compiler in ps.Compilers) {
                recompilationHash.AddObject(compiler.Language); 
                recompilationHash.AddObject(compiler.Extension); 
                recompilationHash.AddObject(compiler.Type);
                recompilationHash.AddObject(compiler.WarningLevel); 
                recompilationHash.AddObject(compiler.CompilerOptions);
            }

            // Combine items from  section 
            foreach (System.Web.Configuration.ExpressionBuilder eb in ps.ExpressionBuilders) {
                recompilationHash.AddObject(eb.ExpressionPrefix); 
                recompilationHash.AddObject(eb.Type); 
            }
 
            // Combine items from the Assembly collection
            assemblies = ps.Assemblies;

            if (assemblies.Count == 0) { 
                recompilationHash.AddObject("__clearassemblies");
            } 
            else { 
                foreach (AssemblyInfo ai in assemblies) {
                    recompilationHash.AddObject(ai.Assembly); 
                }
            }

            // Combine items from the Builders Collection 
            builders = ps.BuildProviders;
 
            if (builders.Count == 0) { 
                recompilationHash.AddObject("__clearbuildproviders");
            } 
            else {
                foreach (System.Web.Configuration.BuildProvider bp in builders) {
                    recompilationHash.AddObject(bp.Type);
                    recompilationHash.AddObject(bp.Extension); 
                }
            } 
 
            // Combine items from the FolderLevelBuildProviderCollection
            buildProviders = ps.FolderLevelBuildProviders; 

            if (buildProviders.Count == 0) {
                recompilationHash.AddObject("__clearfolderlevelbuildproviders");
            } 
            else {
                foreach (System.Web.Configuration.FolderLevelBuildProvider bp in buildProviders) { 
                    recompilationHash.AddObject(bp.Type); 
                    recompilationHash.AddObject(bp.Name);
                } 
            }

            codeSubDirs = ps.CodeSubDirectories;
            if (codeSubDirs.Count == 0) { 
                recompilationHash.AddObject("__clearcodesubdirs");
            } 
            else { 
                foreach (CodeSubDirectory csd in codeSubDirs) {
                    recompilationHash.AddObject(csd.DirectoryName); 
                }
            }

            // Make sure the  section is hashed properly. 
            CompilerInfo[] compilerInfoArray = CodeDomProvider.GetAllCompilerInfo();
            if (compilerInfoArray != null) { 
                foreach (CompilerInfo info in compilerInfoArray) { 
                    // Ignore it if the type is not valid.
                    if (!info.IsCodeDomProviderTypeValid) { 
                        continue;
                    }

                    CompilerParameters parameters = info.CreateDefaultCompilerParameters(); 
                    string option = parameters.CompilerOptions;
                    if (!String.IsNullOrEmpty(option)) { 
                        Type type = info.CodeDomProviderType; 
                        if (type != null) {
                            recompilationHash.AddObject(type.FullName); 
                        }
                        // compilerOptions need to be hashed.
                        recompilationHash.AddObject(option);
                    } 

                    // DevDiv 62998 
                    // The tag providerOption needs to be added to the hash, 
                    // as the user could switch between v2 and v3.5.
                    if (info.CodeDomProviderType == null) 
                        continue;

                    // Add a hash for each providerOption added, specific for each codeDomProvider, so that
                    // if some codedom setting has changed, we know we have to recompile. 
                    IDictionary providerOptions = GetProviderOptions(info);
                    if (providerOptions != null && providerOptions.Count > 0) { 
                        string codeDomProviderType = info.CodeDomProviderType.FullName; 
                        foreach (string key in providerOptions.Keys) {
                            string value = providerOptions[key]; 
                            recompilationHash.AddObject(codeDomProviderType + ":" +  key + "=" + value);
                        }
                    }
                } 
            }
 
            return recompilationHash.CombinedHash; 
        }
 

        /*
         * Return a file provider Type that an extension maps to.
         */ 
        internal static Type GetBuildProviderTypeFromExtension(VirtualPath configPath, string extension,
            BuildProviderAppliesTo neededFor, bool failIfUnknown) { 
 
            // Get the  config object
            CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 

            return GetBuildProviderTypeFromExtension(config, extension, neededFor, failIfUnknown);
        }
 
        internal static Type GetBuildProviderTypeFromExtension(CompilationSection config, string extension,
            BuildProviderAppliesTo neededFor, bool failIfUnknown) { 
 
            BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension);
 
            Type buildProviderType = null;
            // Never return an IgnoreFileBuildProvider/ForceCopyBuildProvider, since it's just a marker
            if (providerInfo != null &&
                providerInfo.Type != typeof(IgnoreFileBuildProvider) && 
                providerInfo.Type != typeof(ForceCopyBuildProvider)) {
                buildProviderType = providerInfo.Type; 
            } 

            // In updatable precomp mode, only aspx/ascx/master web files need processing.  Ignore the rest. 
            if (neededFor == BuildProviderAppliesTo.Web &&
                BuildManager.PrecompilingForUpdatableDeployment &&
                !typeof(BaseTemplateBuildProvider).IsAssignableFrom(buildProviderType)) {
                buildProviderType = null; 
            }
 
            if (buildProviderType != null) { 
                // Only return it if it applies to what it's needed for
                if ((neededFor & providerInfo.AppliesTo) != 0) 
                    return buildProviderType;
            }
            // If the extension is registered as a compiler extension, use
            // a SourceFileBuildProvider to handle it (not supported in Resources directory) 
            else if (neededFor != BuildProviderAppliesTo.Resources &&
                config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) { 
                return typeof(SourceFileBuildProvider); 
            }
 
            if (failIfUnknown) {
                throw new HttpException( SR.GetString(
                    SR.Unknown_buildprovider_extension, extension, neededFor.ToString()));
            } 

            return null; 
        } 

        // Returns the list of buildProvider types associated to the specified appliesTo 
        internal static List GetFolderLevelBuildProviderTypes(CompilationSection config,
            FolderLevelBuildProviderAppliesTo appliesTo) {
            FolderLevelBuildProviderCollection buildProviders = config.FolderLevelBuildProviders;
            return buildProviders.GetBuildProviderTypes(appliesTo); 
        }
 
        // In partial trust, do not allow the CompilerDirectoryPath provider option in codedom settings (Dev10 bug 462348) 
        internal static void CheckCompilerDirectoryPathAllowed(IDictionary providerOptions) {
            if (providerOptions == null) { 
                return;
            }
            if (!providerOptions.ContainsKey(CompilerDirectoryPath)) {
                return; 
            }
 
            if (!HttpRuntime.HasUnmanagedPermission()) { 
                string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, CompilerDirectoryPath);
                throw new HttpException(errorString); 
            }
        }

        internal static void CheckCompilerOptionsAllowed(string compilerOptions, bool config, string file, int line) { 

            // If it's empty, we never block it 
            if (String.IsNullOrEmpty(compilerOptions)) 
                return;
 
            // Only allow the use of compilerOptions when we have UnmanagedCode access (ASURT 73678)
            if (!HttpRuntime.HasUnmanagedPermission()) {
                string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, "compilerOptions");
 
                if (config)
                    throw new ConfigurationErrorsException(errorString, file, line); 
                else 
                    throw new HttpException(errorString);
            } 
        }

        // This is used to determine what files need to be copied, and what stub files
        // need to be created during deployment precompilation. 
        // Note: createStub only applies if the method returns false.
        internal static bool NeedToCopyFile(VirtualPath virtualPath, bool updatable, out bool createStub) { 
 
            createStub = false;
 
            // Get the  config object
            CompilationSection config = MTConfigUtil.GetCompilationConfig(virtualPath);

            string extension = virtualPath.Extension; 

            BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension); 
 
            if (providerInfo != null) {
                // We only care about 'web' providers.  Everything else we treat as static 
                if ((BuildProviderAppliesTo.Web & providerInfo.AppliesTo) == 0)
                    return true;

                // If the provider is a ForceCopyBuildProvider, treat as static 
                if (providerInfo.Type == typeof(ForceCopyBuildProvider))
                    return true; 
 
                // During updatable precomp, everything needs to be copied over.  However,
                // aspx files that use code beside will later be overwritten by modified 
                // versions (see TemplateParser.CreateModifiedMainDirectiveFileIfNeeded)
                if (providerInfo.Type != typeof(IgnoreFileBuildProvider) &&
                    BuildManager.PrecompilingForUpdatableDeployment) {
                    return true; 
                }
 
                // There is a real provider, so don't copy the file.  We also need to determine whether 
                // a stub file needs to be created.
 
                createStub = true;

                // Skip the stub file for some non-requestable types
                if (providerInfo.Type == typeof(UserControlBuildProvider) || 
                    providerInfo.Type == typeof(MasterPageBuildProvider) ||
                    providerInfo.Type == typeof(IgnoreFileBuildProvider)) { 
                    createStub = false; 
                }
 
                return false;
            }

            // If the extension is registered as a compiler extension, don't copy 
            if (config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) {
                return false; 
            } 

            // Skip the copying for asax and skin files, which are not static even though they 
            // don't have a registered BuildProvider (but don't skip .skin files during
            // updatable precomp).
            //
            if (StringUtil.EqualsIgnoreCase(extension, ".asax")) 
                return false;
            if (!updatable && StringUtil.EqualsIgnoreCase(extension, ThemeDirectoryCompiler.skinExtension)) 
                return false; 

            // 
            // If there is no BuildProvider registered, it's a static file, and should be copied
            //

            return true; 
        }
 
        internal static Type LoadTypeWithChecks(string typeName, Type requiredBaseType, Type requiredBaseType2, ConfigurationElement elem, string propertyName) { 
            Type t = ConfigUtil.GetType(typeName, propertyName, elem);
 
            if (requiredBaseType2 == null) {
                ConfigUtil.CheckAssignableType(requiredBaseType, t, elem, propertyName);
            }
            else { 
                ConfigUtil.CheckAssignableType(requiredBaseType, requiredBaseType2, t, elem, propertyName);
            } 
 
            return t;
        } 

        // Devdiv Bug 57600
        // We need to use the constructor with ProviderOptions to get the v3.5/v4.0 compiler that was possibly set in config.
        // We first check if there is any providerOptions and invoke the constructor if so. 
        // Otherwise, we fall back to the default constructor.
        internal static CodeDomProvider CreateCodeDomProvider(Type codeDomProviderType) { 
            CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType); 
            if (codeDomProvider != null) {
                return codeDomProvider; 
            }
            return (CodeDomProvider)Activator.CreateInstance(codeDomProviderType);
        }
 
        internal static CodeDomProvider CreateCodeDomProviderNonPublic(Type codeDomProviderType) {
            CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType); 
            if (codeDomProvider != null) { 
                return codeDomProvider;
            } 
            return (CodeDomProvider)HttpRuntime.CreateNonPublicInstance(codeDomProviderType);
        }

        [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] 
        private static CodeDomProvider CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType) {
            // The following resembles the code in System.CodeDom.CompilerInfo.CreateProvider 
 
            // Make a copy to avoid modifying the original.
            var originalProviderOptions = GetProviderOptions(codeDomProviderType); 
            IDictionary providerOptions = null;
            if (originalProviderOptions != null) {
                providerOptions = new Dictionary(originalProviderOptions);
            } 

            // Block CompilerDirectoryPath if we are in partial trust 
            CheckCompilerDirectoryPathAllowed(providerOptions); 

            // Check whether the user supplied the compilerDirectoryPath or was it added by us 
            bool addedCompilerDirectoryPath = false;

            if (MultiTargetingUtil.IsTargetFramework20) {
                // If the target framework is v2.0, there won't be any codedom settings, so we need 
                // to explicitly set the compiler to be the v2.0 compiler using compilerVersion=v2.0.
                if (providerOptions == null) { 
                    providerOptions = new Dictionary(); 
                }
                providerOptions["CompilerVersion"] = "v2.0"; 
            }
            else if (MultiTargetingUtil.IsTargetFramework35) {
                // We need to explicitly set to v3.5, as it is possible for the
                // user to only have specified it for one compiler but not 
                // the other.
                // Dev10 bug 809212 
                providerOptions["CompilerVersion"] = "v3.5"; 
            }
            else { 
                // If we are targeting 4.0 but the compiler version is less than 4.0, set it to 4.0.
                // This can happen if a user tries to run a 2.0/3.5 web site in a 4.0 application pool without
                // upgrading it, and the codedom section still has 3.5 as the compilerVersion,
                // so we have to set the compilerVersion to 4.0 explicitly. 
                string version = GetCompilerVersion(codeDomProviderType);
                Version v = GetVersionFromVString(version); 
                if (v != null && v < MultiTargetingUtil.Version40) { 
                    providerOptions["CompilerVersion"] = "v4.0";
                } 
            }

            if (providerOptions != null && providerOptions.Count > 0) {
                Debug.Assert(codeDomProviderType != null, "codeDomProviderType should not be null"); 
                // Check whether the codedom provider supports a constructor that takes in providerOptions.
                // Currently only VB and C# support providerOptions for sure, while others such as JScript might not. 
                ConstructorInfo ci = codeDomProviderType.GetConstructor(new Type[] { typeof(IDictionary) }); 
                CodeDomProvider provider = null;
                if (ci != null) { 
                    // First, obtain the language for the given codedom provider type.
                    CodeDomProvider defaultProvider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType);
                    string extension = defaultProvider.FileExtension;
                    // Then, use the new createProvider API to create an instance. 
                    provider = CodeDomProvider.CreateProvider(extension, providerOptions);
                } 
                // Restore the provider options if we previously manually added the compilerDirectoryPath. 
                // Otherwise, we might incorrectly invalidate the compilerDirectoryPath in medium trust (Dev10 bug 550299).
                if (addedCompilerDirectoryPath) { 
                    providerOptions.Remove(CompilerDirectoryPath);
                }
                return provider;
            } 

            return null; 
        } 

        [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] 
        internal static IDictionary GetProviderOptions(Type codeDomProviderType) {
            // Using reflection to get the property for the time being.
            // This could simply return CompilerInfo.PropertyOptions if it goes public in future.
            CodeDomProvider provider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType); 
            string extension = provider.FileExtension;
            if (CodeDomProvider.IsDefinedExtension(extension)) { 
                CompilerInfo ci = CodeDomProvider.GetCompilerInfo(CodeDomProvider.GetLanguageFromExtension(extension)); 
                return GetProviderOptions(ci);
            } 
            return null;
        }

        [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] 
        private static IDictionary GetProviderOptions(CompilerInfo ci) {
            Debug.Assert(ci != null, "CompilerInfo ci should not be null"); 
            PropertyInfo pi = ci.GetType().GetProperty("ProviderOptions", 
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
            if (pi != null) 
                return (IDictionary)pi.GetValue(ci, null);
            return null;
        }
 
        /// 
        /// Returns the compilerVersion providerOption specified for the codedom provider type. 
        /// Returns null if the providerOption is not found. 
        /// 
        internal static string GetCompilerVersion(Type codeDomProviderType) { 
            return GetProviderOption(codeDomProviderType, "CompilerVersion");
        }

        ///  
        /// Returns the value of the providerOption specified for the codedom provider type.
        /// Returns null if the providerOption is not found. 
        ///  
        internal static string GetProviderOption(Type codeDomProviderType, string providerOption) {
            IDictionary providerOptions = CompilationUtil.GetProviderOptions(codeDomProviderType); 
            if (providerOptions != null) {
                string version;
                if (providerOptions.TryGetValue(providerOption, out version)) {
                    return version; 
                }
            } 
            return null; 
        }
 
        /// 
        /// Returns true if the string matches "v3.5" exactly.
        /// 
        internal static bool IsCompilerVersion35(string compilerVersion) { 
            if (compilerVersion == "v3.5") {
                return true; 
            } 
            return false;
        } 

        /// 
        /// This returns true only if the codedom CompilverVersion provider option is exactly v3.5.
        ///  
        internal static bool IsCompilerVersion35(Type codeDomProviderType) {
            string compilerVersion = GetCompilerVersion(codeDomProviderType); 
            bool result = IsCompilerVersion35(compilerVersion); 
            return result;
        } 

        /// 
        /// Returns true if the codedom CompilerVersion provider option is at least v3.5.
        ///  
        /// 
        ///  
        internal static bool IsCompilerVersion35OrAbove(Type codeDomProviderType) { 
            string compilerVersion = GetCompilerVersion(codeDomProviderType);
            if (IsCompilerVersion35(compilerVersion)) { 
                return true;
            }
            // The compilerVersion provider option is known to exist only for v3.5.
            // If it does not exist, then we need to rely on the target framework version to 
            // determine whether we need to use the 2.0 or 4.0 compiler.
            if (MultiTargetingUtil.IsTargetFramework20) { 
                return false; 
            }
 
            // If it isn't 2.0 or 3.5, assume it is 4.0 and above.
            return true;
        }
 
        /// 
        /// Returns true if the codedom provider has warnAsError set to true 
        ///  
        internal static bool WarnAsError(Type codeDomProviderType) {
            string value = GetProviderOption(codeDomProviderType, "WarnAsError"); 
            bool result;
            if (value != null && bool.TryParse(value, out result)) {
                return result;
            } 

            // Assume false if the value wasn't set 
            return false; 
        }
 
        // Returns the version when given string of form "v4.0"
        internal static Version GetVersionFromVString(string version) {
            if (string.IsNullOrEmpty(version)) {
                return null; 
            }
            Debug.Assert(version.Length > 1, "Version has invalid length"); 
            return new Version(version.Substring(1)); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK