public static byte[] CreateReport(this WordTemplateEntity template, Entity entity, ISystemWordTemplate systemWordTemplate = null, bool avoidConversion = false)
        {

            if (systemWordTemplate != null && template.SystemWordTemplate.FullClassName != systemWordTemplate.GetType().FullName)
                throw new ArgumentException("systemWordTemplate should be a {0} instead of {1}".FormatWith(template.SystemWordTemplate.FullClassName, systemWordTemplate.GetType().FullName));

            using (template.DisableAuthorization ? ExecutionMode.Global() : null)
            {
                QueryDescription qd = DynamicQueryManager.Current.QueryDescription(template.Query.ToQueryName());

                 using (var memory = new MemoryStream())
                 {
                     memory.WriteAllBytes(template.Template.Retrieve().BinaryFile);

                     using (WordprocessingDocument document = WordprocessingDocument.Open(memory, true))
                     {
                         Dump(document, "0.Original.txt");

                         var parser = new WordTemplateParser(document, qd, template.SystemWordTemplate.ToType());
                         parser.ParseDocument(); Dump(document, "1.Match.txt");
                         parser.CreateNodes(); Dump(document, "2.BaseNode.txt");
                         parser.AssertClean();

                         var renderer = new WordTemplateRenderer(document, qd, entity, template.Culture.ToCultureInfo(), systemWordTemplate);
                         renderer.MakeQuery();
                         renderer.RenderNodes(); Dump(document, "3.Replaced.txt");
                         renderer.AssertClean();

                         FixDocument(document); Dump(document, "4.Fixed.txt");

                         if (template.WordTransformer != null)
                             Transformers.GetOrThrow(template.WordTransformer)(template, entity, document);
                     }

                     var array = memory.ToArray();

                     if (!avoidConversion && template.WordConverter != null)
                         array = Converters.GetOrThrow(template.WordConverter)(template, entity, array);

                     return array;
                 }
            }
        }
        internal static SqlPreCommand SynchronizeWordTemplate(Replacements replacements, WordTemplateEntity template, StringDistance sd)
        {
            try
            {
                if (template.Template == null)
                    return null;

                var queryName = QueryLogic.ToQueryName(template.Query.Key);

                QueryDescription qd = DynamicQueryManager.Current.QueryDescription(queryName);

                Console.Clear();

                SafeConsole.WriteLineColor(ConsoleColor.White, "WordTemplate: " + template.Name);
                Console.WriteLine(" Query: " + template.Query.Key);

                var file = template.Template.Retrieve();

                try
                {
                    using (var memory = new MemoryStream())
                    {
                        memory.WriteAllBytes(file.BinaryFile);

                        using (WordprocessingDocument document = WordprocessingDocument.Open(memory, true))
                        {
                            Dump(document, "0.Original.txt");

                            var parser = new WordTemplateParser(document, qd, template.SystemWordTemplate.ToType());
                            parser.ParseDocument(); Dump(document, "1.Match.txt");
                            parser.CreateNodes(); Dump(document, "2.BaseNode.txt");
                            parser.AssertClean();

                            SyncronizationContext sc = new SyncronizationContext
                            {
                                ModelType = template.SystemWordTemplate.ToType(),
                                QueryDescription = qd,
                                Replacements = replacements,
                                StringDistance = sd,
                                HasChanges = false,
                                Variables = new ScopedDictionary<string, ValueProviderBase>(null),
                            };


                            foreach (var root in document.RecursivePartsRootElements())
                            {
                                foreach (var node in root.Descendants<BaseNode>().ToList())
                                {
                                    node.Synchronize(sc);
                                }
                            }

                            if (!sc.HasChanges)
                                return null;

                            Dump(document, "3.Synchronized.txt");
                            var variables = new ScopedDictionary<string, ValueProviderBase>(null);
                            foreach (var root in document.RecursivePartsRootElements())
                            {
                                foreach (var node in root.Descendants<BaseNode>().ToList())
                                {
                                    node.RenderTemplate(variables);
                                }
                            }

                            Dump(document, "4.Rendered.txt");
                        }

                        file.AllowChange = true;
                        file.BinaryFile = memory.ToArray();

                        using (replacements.WithReplacedDatabaseName())
                            return Schema.Current.Table<FileEntity>().UpdateSqlSync(file, comment: "WordTemplate: " + template.Name);
                    }                 
                }
                catch (TemplateSyncException ex)
                {
                    if (ex.Result == FixTokenResult.SkipEntity)
                        return null;

                    if (ex.Result == FixTokenResult.DeleteEntity)
                        return SqlPreCommandConcat.Combine(Spacing.Simple,
                            Schema.Current.Table<WordTemplateEntity>().DeleteSqlSync(template),
                            Schema.Current.Table<FileEntity>().DeleteSqlSync(file));

                    if (ex.Result == FixTokenResult.ReGenerateEntity)
                        return Regenerate(template, replacements);

                    throw new InvalidOperationException("Unexcpected {0}".FormatWith(ex.Result));
                }
                finally
                {
                    Console.Clear();
                }
            }
            catch (Exception e)
            {
                return new SqlPreCommandSimple("-- Exception in {0}: {1}".FormatWith(template.BaseToString(), e.Message));
            }
        }
        static string ValidateTemplate(WordTemplateEntity template, PropertyInfo pi)
        {
            if (template.Template == null)
                return null;

            using (template.DisableAuthorization ? ExecutionMode.Global() : null)
            {
                QueryDescription qd = DynamicQueryManager.Current.QueryDescription(template.Query.ToQueryName());

                using (var memory = new MemoryStream())
                {
                    memory.WriteAllBytes(template.Template.Retrieve().BinaryFile);

                    using (WordprocessingDocument document = WordprocessingDocument.Open(memory, true))
                    {
                        Dump(document, "0.Original.txt");

                        var parser = new WordTemplateParser(document, qd, template.SystemWordTemplate.ToType());
                        parser.ParseDocument(); Dump(document, "1.Match.txt");
                        parser.CreateNodes(); Dump(document, "2.BaseNode.txt");
                        parser.AssertClean();

                        if (parser.Errors.IsEmpty())
                            return null;

                        return parser.Errors.ToString(e => e.Message, "\r\n");
                    }
                }
            }
        }