diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs index f66b7a841278a2cfdc2012cabe76a7475c3d0617..b01c188cbc033e54f6ddb2a69ce82e4611eafe5e 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs @@ -23,8 +23,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var generatedCodeRecognitionService = workspace.Services.GetService(); - if (generatedCodeRecognitionService.IsGeneratedCode(document)) + if (document.IsGeneratedCode()) { return; } diff --git a/src/Features/Core/Portable/DocumentSpan.cs b/src/Features/Core/Portable/DocumentSpan.cs index 16f7734cb56197db14e49ad495a698367e094ad4..d8e577ce03322f5433f9f609a34cc763f1091836 100644 --- a/src/Features/Core/Portable/DocumentSpan.cs +++ b/src/Features/Core/Portable/DocumentSpan.cs @@ -1,7 +1,11 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.GeneratedCodeRecognition; using Microsoft.CodeAnalysis.Navigation; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -37,21 +41,37 @@ public override int GetHashCode() => Hash.Combine( this.Document, this.SourceSpan.GetHashCode()); + } - public bool CanNavigateTo() + internal static class DocumentSpanExtensions + { + public static bool CanNavigateTo(this DocumentSpan documentSpan) { - var workspace = Document.Project.Solution.Workspace; + var workspace = documentSpan.Document.Project.Solution.Workspace; var service = workspace.Services.GetService(); - return service.CanNavigateToSpan(workspace, Document.Id, SourceSpan); + return service.CanNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan); } - public bool TryNavigateTo() + public static bool TryNavigateTo(this DocumentSpan documentSpan) { - var solution = Document.Project.Solution; + var solution = documentSpan.Document.Project.Solution; var workspace = solution.Workspace; var service = workspace.Services.GetService(); - return service.TryNavigateToSpan(workspace, Document.Id, SourceSpan, + return service.TryNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan, options: solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)); } + + public static async Task IsHiddenAsync( + this DocumentSpan documentSpan, CancellationToken cancellationToken) + { + var document = documentSpan.Document; + if (document.SupportsSyntaxTree) + { + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + return tree.IsHiddenPosition(documentSpan.SourceSpan.Start, cancellationToken); + } + + return false; + } } } \ No newline at end of file diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs index 2aaedf0b61c2b1ecc942b309be3ef46e9a9114a4..9822e96ef0c4a448462406ea5c2c3cac1451f9af 100644 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs +++ b/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs @@ -43,11 +43,10 @@ public static INavigableItem GetItemFromDeclaredSymbolInfo(DeclaredSymbolInfo de var sourceLocations = GetPreferredSourceLocations(symbol); - var generatedCodeRecognitionService = solution.Workspace.Services.GetService(); var candidateLocationGroups = from c in sourceLocations let doc = solution.GetDocument(c.SourceTree) where doc != null - group c by generatedCodeRecognitionService.IsGeneratedCode(doc); + group c by doc.IsGeneratedCode(); var generatedSourceLocations = candidateLocationGroups.SingleOrDefault(g => g.Key) ?? SpecializedCollections.EmptyEnumerable(); var nonGeneratedSourceLocations = candidateLocationGroups.SingleOrDefault(g => !g.Key) ?? SpecializedCollections.EmptyEnumerable(); @@ -69,12 +68,11 @@ private static IEnumerable GetPreferredSourceLocations(ISymbol symbol) public static IEnumerable GetPreferredNavigableItems(Solution solution, IEnumerable navigableItems) { - var generatedCodeRecognitionService = solution.Workspace.Services.GetService(); navigableItems = navigableItems.Where(n => n.Document != null); - var hasNonGeneratedCodeItem = navigableItems.Any(n => !generatedCodeRecognitionService.IsGeneratedCode(n.Document)); + var hasNonGeneratedCodeItem = navigableItems.Any(n => !n.Document.IsGeneratedCode()); return hasNonGeneratedCodeItem - ? navigableItems.Where(n => !generatedCodeRecognitionService.IsGeneratedCode(n.Document)) - : navigableItems.Where(n => generatedCodeRecognitionService.IsGeneratedCode(n.Document)); + ? navigableItems.Where(n => !n.Document.IsGeneratedCode()) + : navigableItems.Where(n => n.Document.IsGeneratedCode()); } public static ImmutableArray GetSymbolDisplayTaggedParts(Project project, ISymbol symbol) diff --git a/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs index a3ab38d53f789c2ea335af2a971694491003c405..111d80f03aaf375acc152902d360fe58aaa54d6b 100644 --- a/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Roslyn.Utilities; @@ -23,7 +24,6 @@ internal class GenerateTypeDialogViewModel : AbstractNotifyPropertyChanged private INotificationService _notificationService; private IProjectManagementService _projectManagementService; private ISyntaxFactsService _syntaxFactsService; - private IGeneratedCodeRecognitionService _generatedCodeService; private GenerateTypeDialogOptions _generateTypeDialogOptions; private string _typeName; private bool _isNewFile; @@ -530,13 +530,13 @@ public IEnumerable DocumentList // Populate the rest of the documents for the project _previouslyPopulatedDocumentList.AddRange(_document.Project.Documents - .Where(d => d != _document && !_generatedCodeService.IsGeneratedCode(d)) + .Where(d => d != _document && !d.IsGeneratedCode()) .Select(d => new DocumentSelectItem(d))); } else { _previouslyPopulatedDocumentList.AddRange(_selectedProject.Documents - .Where(d => !_generatedCodeService.IsGeneratedCode(d)) + .Where(d => !d.IsGeneratedCode()) .Select(d => new DocumentSelectItem(d))); this.SelectedDocument = _selectedProject.Documents.FirstOrDefault(); @@ -723,7 +723,6 @@ private string UpdateExtension(string currentFileName, string desiredFileExtensi INotificationService notificationService, IProjectManagementService projectManagementService, ISyntaxFactsService syntaxFactsService, - IGeneratedCodeRecognitionService generatedCodeService, GenerateTypeDialogOptions generateTypeDialogOptions, string typeName, string fileExtension, @@ -759,20 +758,19 @@ private string UpdateExtension(string currentFileName, string desiredFileExtensi this.SelectedProject = document.Project; this.SelectedDocument = document; _notificationService = notificationService; - _generatedCodeService = generatedCodeService; - this.AccessList = document.Project.Language == LanguageNames.CSharp ? - _csharpAccessList : - _visualBasicAccessList; - this.AccessSelectIndex = this.AccessList.Contains(accessSelectString) ? - this.AccessList.IndexOf(accessSelectString) : 0; + this.AccessList = document.Project.Language == LanguageNames.CSharp + ? _csharpAccessList + : _visualBasicAccessList; + this.AccessSelectIndex = this.AccessList.Contains(accessSelectString) + ? this.AccessList.IndexOf(accessSelectString) : 0; this.IsAccessListEnabled = true; - this.KindList = document.Project.Language == LanguageNames.CSharp ? - _csharpTypeKindList : - _visualBasicTypeKindList; - this.KindSelectIndex = this.KindList.Contains(typeKindSelectString) ? - this.KindList.IndexOf(typeKindSelectString) : 0; + this.KindList = document.Project.Language == LanguageNames.CSharp + ? _csharpTypeKindList + : _visualBasicTypeKindList; + this.KindSelectIndex = this.KindList.Contains(typeKindSelectString) + ? this.KindList.IndexOf(typeKindSelectString) : 0; this.ProjectSelectIndex = 0; this.DocumentSelectIndex = 0; diff --git a/src/VisualStudio/Core/Def/Implementation/GenerateType/VisualStudioGenerateTypeOptionsServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/GenerateType/VisualStudioGenerateTypeOptionsServiceFactory.cs index 13fffa26d1a237e63e3025e0be8b38760098ee3b..13176dfa3a44277af0b3252f065749a1b248055a 100644 --- a/src/VisualStudio/Core/Def/Implementation/GenerateType/VisualStudioGenerateTypeOptionsServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/GenerateType/VisualStudioGenerateTypeOptionsServiceFactory.cs @@ -19,8 +19,7 @@ internal class VisualStudioGenerateTypeOptionsServiceFactory : IWorkspaceService { public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { - var generatedCodeService = workspaceServices.GetService(); - return new VisualStudioGenerateTypeOptionsService(generatedCodeService); + return new VisualStudioGenerateTypeOptionsService(); } private class VisualStudioGenerateTypeOptionsService : IGenerateTypeOptionsService @@ -29,13 +28,6 @@ private class VisualStudioGenerateTypeOptionsService : IGenerateTypeOptionsServi private string _accessSelectString = ""; private string _typeKindSelectString = ""; - private IGeneratedCodeRecognitionService _generatedCodeService; - - public VisualStudioGenerateTypeOptionsService(IGeneratedCodeRecognitionService generatedCodeService) - { - _generatedCodeService = generatedCodeService; - } - public GenerateTypeOptionsResult GetGenerateTypeOptions( string typeName, GenerateTypeDialogOptions generateTypeDialogOptions, @@ -49,7 +41,6 @@ public VisualStudioGenerateTypeOptionsService(IGeneratedCodeRecognitionService g notificationService, projectManagementService, syntaxFactsService, - _generatedCodeService, generateTypeDialogOptions, typeName, document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb", diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs index f4ba507968e23576b5fcfa363ba47d179c0ada47..3920f3f82efc3524a59ea98825bdc1aac7c333c9 100644 --- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs @@ -285,8 +285,7 @@ public bool WouldNotifyToSpecificSymbol(ISymbol symbol, Solution solution, out s // documents we consider to be "generated" to give external language services the best // chance of participating. - var generatedCodeRecognitionService = solution.Workspace.Services.GetService(); - var generatedDocuments = documents.Where(d => generatedCodeRecognitionService.IsGeneratedCode(d)); + var generatedDocuments = documents.Where(d => d.IsGeneratedCode()); var documentToUse = generatedDocuments.FirstOrDefault() ?? documents.First(); if (!TryGetVsHierarchyAndItemId(documentToUse, out hierarchy, out itemID)) diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index beb6f9d654fc5821092a735d492035d58ec98587..4606c63d2491c16fcd1248fb6c5fc78555916a7f 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -634,8 +634,6 @@ protected bool TryGetElementFromSource(CodeModelState state, Project project, IT // 1. Prefer source files that we don't heuristically flag as generated code. // 2. If all of the source files are generated code, pick the first one. - var generatedCodeRecognitionService = project.Solution.Workspace.Services.GetService(); - Compilation compilation = null; Tuple generatedCode = null; @@ -652,7 +650,7 @@ protected bool TryGetElementFromSource(CodeModelState state, Project project, IT { var document = project.GetDocument(location.SourceTree); - if (generatedCodeRecognitionService?.IsGeneratedCode(document) == false) + if (document.IsGeneratedCode() == false) { chosenLocation = location; chosenDocumentId = document.Id; diff --git a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs index 7837f7d643ad84ead02e281fc2074b1cad2e8e70..dc43771b9171daf697b4c57197a2bd1dcbd1fc78 100644 --- a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs +++ b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.GeneratedCodeRecognition; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; using Microsoft.VisualStudio.LanguageServices.Implementation.Interop; @@ -143,7 +144,7 @@ internal override IInvisibleEditor OpenInvisibleEditor(IVisualStudioHostDocument if (this.CurrentSolution.ContainsDocument(hostDocument.Id)) { // Disable undo on generated documents - needsUndoDisabled = this.Services.GetService().IsGeneratedCode(this.CurrentSolution.GetDocument(hostDocument.Id)); + needsUndoDisabled = this.CurrentSolution.GetDocument(hostDocument.Id).IsGeneratedCode(); } else { diff --git a/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb b/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb index 7e05d3f3a842cfc595c79445cd25040b49aebb68..2654c1046e72308f5126a8c43dd8cee13b7e7d41 100644 --- a/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb +++ b/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb @@ -874,7 +874,6 @@ namespace A New TestNotificationService(), testProjectManagementService, syntaxFactsService, - workspace.Services.GetService(Of IGeneratedCodeRecognitionService)(), New GenerateTypeDialogOptions(isPublicOnlyAccessibility, typeKindvalue, isAttribute), typeName, If(document.Project.Language = LanguageNames.CSharp, ".cs", ".vb"), diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.DiagnosticProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.DiagnosticProvider.cs index 8ec1e2c919baea9847482c612c06526ceea58cbe..0a10e3e0293d0816d088f252a1b5db89c6560d6a 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.DiagnosticProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.DiagnosticProvider.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.GeneratedCodeRecognition; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes @@ -51,12 +52,11 @@ public abstract class DiagnosticProvider var document = fixAllContext.Document; var project = fixAllContext.Project; - var generatedCodeServices = project.Solution.Workspace.Services.GetService(); switch (fixAllContext.Scope) { case FixAllScope.Document: - if (document != null && !generatedCodeServices.IsGeneratedCode(document)) + if (document != null && !document.IsGeneratedCode()) { var documentDiagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); var kvp = SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(document, documentDiagnostics)); @@ -107,14 +107,14 @@ public abstract class DiagnosticProvider return ImmutableDictionary>.Empty; } - return await GetDocumentDiagnosticsToFixAsync(allDiagnostics, projectsToFix, generatedCodeServices.IsGeneratedCode, fixAllContext.CancellationToken).ConfigureAwait(false); + return await GetDocumentDiagnosticsToFixAsync(allDiagnostics, projectsToFix, fixAllContext.CancellationToken).ConfigureAwait(false); } } private async static Task>> GetDocumentDiagnosticsToFixAsync( ImmutableArray diagnostics, ImmutableArray projects, - Func isGeneratedCode, CancellationToken cancellationToken) + CancellationToken cancellationToken) { var treeToDocumentMap = await GetTreeToDocumentMapAsync(projects, cancellationToken).ConfigureAwait(false); @@ -123,7 +123,7 @@ public abstract class DiagnosticProvider { cancellationToken.ThrowIfCancellationRequested(); var document = documentAndDiagnostics.Key; - if (!isGeneratedCode(document)) + if (!document.IsGeneratedCode()) { var diagnosticsForDocument = documentAndDiagnostics.ToImmutableArray(); builder.Add(document, diagnosticsForDocument); diff --git a/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs b/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs index 5e54bee367a5843ef6a350aca8722438cd8f1715..2cde1853330b3c388c99404b58f6e38235e75947 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/AbstractCodeGenerationService_FindDeclaration.cs @@ -59,7 +59,7 @@ public bool CanAddTo(SyntaxNode destination, Solution solution, CancellationToke } private bool CanAddTo(SyntaxNode destination, Solution solution, CancellationToken cancellationToken, - out IList availableIndices, Func isGeneratedDocument = null) + out IList availableIndices, bool checkGeneratedCode = false) { availableIndices = null; if (destination == null) @@ -76,7 +76,7 @@ public bool CanAddTo(SyntaxNode destination, Solution solution, CancellationToke } // check for generated files if needed. - if (isGeneratedDocument != null && isGeneratedDocument(document)) + if (checkGeneratedCode && document.IsGeneratedCode()) { return false; } @@ -173,13 +173,10 @@ class NestedType } // If there is a declaration in a non auto-generated file, prefer it. - Func isGeneratedDocument = - solution.Workspace.Services.GetService().IsGeneratedCode; - foreach (var decl in declarations) { declaration = await decl.GetSyntaxAsync(cancellationToken).ConfigureAwait(false); - if (CanAddTo(declaration, solution, cancellationToken, out availableIndices, isGeneratedDocument)) + if (CanAddTo(declaration, solution, cancellationToken, out availableIndices, checkGeneratedCode: true)) { return Tuple.Create(declaration, availableIndices); } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs index 869e9c0a8a2508da154ce612722098ee5f4c5521..aac67b630c01bb0f6aa9ab860bdd636845e1a15e 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs @@ -14,15 +14,14 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.GeneratedCodeRecognition; namespace Microsoft.CodeAnalysis.Shared.Extensions { internal static partial class DocumentExtensions { public static TLanguageService GetLanguageService(this Document document) where TLanguageService : class, ILanguageService - { - return document?.Project?.LanguageServices?.GetService(); - } + => document?.Project?.LanguageServices?.GetService(); public static bool IsOpen(this Document document) { @@ -192,5 +191,12 @@ public static async Task GetPartialSemanticModelAsync(this Docume return await frozenDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); } } + + public static bool IsGeneratedCode(this Document document) + { + var solution = document.Project.Solution; + var generatedCodeRecognitionService = solution.Workspace.Services.GetService(); + return generatedCodeRecognitionService != null && generatedCodeRecognitionService.IsGeneratedCode(document); + } } -} +} \ No newline at end of file diff --git a/src/Workspaces/CoreTest/GeneratedCodeRecognitionTests.cs b/src/Workspaces/CoreTest/GeneratedCodeRecognitionTests.cs index f6e35178849127d5f25acefabb284fdd27aa1cf7..b37616b1201d309db89d4a93eb5cf3267f0d3a82 100644 --- a/src/Workspaces/CoreTest/GeneratedCodeRecognitionTests.cs +++ b/src/Workspaces/CoreTest/GeneratedCodeRecognitionTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.CodeAnalysis.GeneratedCodeRecognition; -using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Shared.Extensions; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests @@ -54,11 +53,11 @@ private static void TestFileNames(bool assertGenerated, params string[] fileName var document = project.AddDocument(fileName, ""); if (assertGenerated) { - Assert.True(IsGeneratedCode(document), string.Format("Expected file '{0}' to be interpreted as generated code", fileName)); + Assert.True(document.IsGeneratedCode(), string.Format("Expected file '{0}' to be interpreted as generated code", fileName)); } else { - Assert.False(IsGeneratedCode(document), string.Format("Did not expect file '{0}' to be interpreted as generated code", fileName)); + Assert.False(document.IsGeneratedCode(), string.Format("Did not expect file '{0}' to be interpreted as generated code", fileName)); } } } @@ -71,10 +70,5 @@ private static Project CreateProject(string language = LanguageNames.CSharp) .AddProject(projectId, projectName, projectName, LanguageNames.CSharp) .GetProject(projectId); } - - private static bool IsGeneratedCode(Document document) - { - return document.Project.Solution.Workspace.Services.GetService().IsGeneratedCode(document); - } } -} +} \ No newline at end of file